Home > OS >  memcpy zero bytes into const variable - undefined behavior?
memcpy zero bytes into const variable - undefined behavior?

Time:10-11

In C and C , is it undefined behavior to memcpy into a const variable when the number of bytes to be copied is zero?

int x = 0;
const int foo = 0;
memcpy( (void *)&foo, &x, 0 );

This question is not purely theoretical. I have a scenario in which memcpy is called and if the destination pointer points to const memory, then the size argument is guaranteed to be zero. So I'm wondering whether I need to handle it as a special case.

CodePudding user response:

The older question Is it guaranteed to be safe to perform memcpy(0,0,0)? points out 7.1.4p1:

Each of the following statements applies unless explicitly stated otherwise in the detailed descriptions that follow: If an argument to a function has an invalid value (such as a value outside the domain of the function, or a pointer outside the address space of the program, or a null pointer, or a pointer to non-modifiable storage when the corresponding parameter is not const-qualified) or a type (after promotion) not expected by a function with variable number of arguments, the behavior is undefined.

The prototype for memcpy is

void *memcpy(void * restrict s1, const void * restrict s2, size_t n);

where the first parameter is not const-qualified, and &foo points to non-modifiable storage. So this code is UB unless the description of memcpy explicitly states otherwise, which it does not. It merely says:

The memcpy function copies n characters from the object pointed to by s2 into the object pointed to by s1.

This implies that memcpy with a count of 0 does not copy any characters (which is also confirmed by 7.24.1p2 "copies zero characters", thanks Lundin), but it does not exempt you from the requirement to pass valid arguments.

CodePudding user response:

In situations the transitively applying parts of the Standard and/or the documentation for a compiler or execution environment would specify the behavior of some action, but some other part of the Standard could be read as characterizing it as Undefined Behavior, the question of whether to process the behavior in the specified meaningful fashion is a Quality of Implementation issue.

If for some reason, it would be expensive to ensure that memcpy always behaved as a no-op in all cases where the size argument was zero, even if one of the pointer arguments was invalid, the Standard would allow someone writing a conforming compiler to judge whether customers' needs could best be met by generating code that always treats a zero-size memcpy as a no-op, or by generating code which is faster when pointers can be guaranteed to identify valid storage for all values of size, but would require customers to manually deal with cases where a size of zero and the pointer would not be valid.

If code would ever need to run on a platform where there would be a good reason for a compiler to process memcpy in such an unusual fashion, or on a compiler whose maintainers might use the Standard's allowances as an excuse to process programs in gratuitously meaningless fashion, then one would need to clutter the program with code to work around such quirks in the implementation. If one is writing non-portable code for quality implementations, however, such workarounds would unnecessarily add clutter and degrade performance.

  • Related