> The compiler is the implementation; it cannot cause "undefined behavior".
The compiler is only part of the implementation. So is the standard library. So would be a processor. An implementation as a whole, perhaps, cannot be said to cause "undefined behavior", but I think it's correct to say it's parts certainly can.
If a preprocessor took valid C, and emitted valid C that could be fed into any other complete freestanding C implementation, would it not be accurate to say that this preprocessor introduced undefined behavior if it replaced, say, memmove(a, a, s) with memcpy(a, a, s) - sans any guarantees about which compiler it would have the emitted C fed into?
When it's LLVM IR invoking glibc's memcpy instead of a memmove, why is that not "causing undefined behavior"? Because it's not a C program? And if I misinvoke it via C++, is it only undefined behavior because the C++ standard references the C one? What if I use C# to invoke memcpy, which doesn't?
> An implementation is not bound by the standard in its own use of the standard library functions.
This is all well and true from a theoretical sense, but an implementation is bound to it's own standards as a means of achieving a conforming compiler, and in this case those standards are clearly documented to mirror the standard's standards. These standards are being violated, leading to possible future misbehavior when combined with other optimizations which may leave the code behaving in indeterminate ways - and, for that matter, current misbehavior in the form of triggered "false" positive valgrind checks.
> The implementation can use a function like memcpy in ways that would be formally undefined if they occured in user code; its implementation of memcpy just has to harmonize with that use, so that the intended behavior is ensured. This is because implementations can add their own requirements to areas that the standard leaves undefined. For instance, an implementation can add the requirement to its memcpy that the copy may overlap, if the destination has a lower address. Then, the implementation can generate code which uses memcpy that way, or make internal uses of memcpy from other library functions which use it that way. It's just using its own (possibly not publicly documented) extension.
It can do these things, if the implementation as a whole is coordinated in this way, but I would hope for sanity's sake it would not. And in this case the implementation as a whole has not been coordinated in this way.
Invoke copy_forward from memcpy if you like, where the former has fewer preconditions - but to write code that relies on an implementation's memcpy having fewer preconditions than the standard, even if you control the entire implementation, sounds untenable. Someone will forget that your memcpy has fewer preconditions, and write optimizations, debug checks, etc. which misassume additional preconditions that are outlined by the C++ standard. They will also also accidentally write code assuming fewer preconditions in another context where they're not guaranteed some specific implementation's relaxed preconditions.
The compiler is only part of the implementation. So is the standard library. So would be a processor. An implementation as a whole, perhaps, cannot be said to cause "undefined behavior", but I think it's correct to say it's parts certainly can.
If a preprocessor took valid C, and emitted valid C that could be fed into any other complete freestanding C implementation, would it not be accurate to say that this preprocessor introduced undefined behavior if it replaced, say, memmove(a, a, s) with memcpy(a, a, s) - sans any guarantees about which compiler it would have the emitted C fed into?
When it's LLVM IR invoking glibc's memcpy instead of a memmove, why is that not "causing undefined behavior"? Because it's not a C program? And if I misinvoke it via C++, is it only undefined behavior because the C++ standard references the C one? What if I use C# to invoke memcpy, which doesn't?
> An implementation is not bound by the standard in its own use of the standard library functions.
This is all well and true from a theoretical sense, but an implementation is bound to it's own standards as a means of achieving a conforming compiler, and in this case those standards are clearly documented to mirror the standard's standards. These standards are being violated, leading to possible future misbehavior when combined with other optimizations which may leave the code behaving in indeterminate ways - and, for that matter, current misbehavior in the form of triggered "false" positive valgrind checks.
> The implementation can use a function like memcpy in ways that would be formally undefined if they occured in user code; its implementation of memcpy just has to harmonize with that use, so that the intended behavior is ensured. This is because implementations can add their own requirements to areas that the standard leaves undefined. For instance, an implementation can add the requirement to its memcpy that the copy may overlap, if the destination has a lower address. Then, the implementation can generate code which uses memcpy that way, or make internal uses of memcpy from other library functions which use it that way. It's just using its own (possibly not publicly documented) extension.
It can do these things, if the implementation as a whole is coordinated in this way, but I would hope for sanity's sake it would not. And in this case the implementation as a whole has not been coordinated in this way.
Invoke copy_forward from memcpy if you like, where the former has fewer preconditions - but to write code that relies on an implementation's memcpy having fewer preconditions than the standard, even if you control the entire implementation, sounds untenable. Someone will forget that your memcpy has fewer preconditions, and write optimizations, debug checks, etc. which misassume additional preconditions that are outlined by the C++ standard. They will also also accidentally write code assuming fewer preconditions in another context where they're not guaranteed some specific implementation's relaxed preconditions.