Live data from Hacker News

Clang emits memcpy for std::swap, which can introduce undefined behavior

llvm.org

41–50 of 83 posts

Re: Clang emits memcpy for std::swap, which can introduce undefined behavior

#41

Earlier quoted context omitted.

Compilers are way too overzealous eliminating code because of undefined behavior. Legally it is allowed and I'm sure it helps in synthetic benchmarks. But writers of real programs won't be impressed of the perf gains when you stop running half their program.

Rather, they are getting zealous in eliminating code because of the assumption that there is no undefined behavior . The scope of what undefined behaviors do this is increasing and that breaks programs that make some assumptions on traditional compiler behavior, or that have hidden bugs. I believe that C should have safer semantics, plus standard-defined modes of operation which restore the unsafe semantics selective…

I agree you should be able to opt-in to a safety level. For example most programmers do expect signed integer overflows to follow 2s compliment behavior - regardless of what the standard says.

There really seems to be a large disconnect between the tool writers and the users of said tools. I've had countless discussions with compiler writers where we've essentially talked passed each other. The compiler writer arguing from a legalistic (and dare I say moral perspective) that the programmer must not write undefined code, and myself from the perspective that developers do write undefined code and we should therefore find a way to handle it in a safe way. Perhaps even by standardizing more than we do currently.

In reflection its not unlike the drug legalization debate.

Re: Clang emits memcpy for std::swap, which can introduce undefined behavior

#42
post #21

Earlier quoted context omitted.

Imagine reversing a string: while(pStart If swap doesn't work for a self swap, this code would break in the case of an odd length string. It's an easy fix in this case, but being able to swap an element with itself is convenient.

A more common case, would be swapping a vector element with the back of the vector and popping it off, which is kinda common.

It was common pre-C++11, but these days you should just be doing a move and pop rather than a swap and pop.

Re: Clang emits memcpy for std::swap, which can introduce undefined behavior

#43

Earlier quoted context omitted.

No, Clang cannot guarantee its own memcpy implementation will be used. But it can be aware of which implementation will be used and make specific assumptions about that implementation in some cases . The specific cases are when it has a genuine guarantee provided by that implementation vendor that it is OK. In the case discussed on this bug, at least one implementation provides that guarantee (Darwin). The problem is…

Clang is not a complete implementation without a library, right? Whoever puts Clang together with a library becomes an integrator who provides a language implementation. It's up to that integrator to ensure that the result conforms. Clang could be also used "freestanding". Then the user might be informed: please supply your own memcpy function with such and such characteristics, since generated code needs it. If thos…

Essentially.

But I think Clang can actually do better here. The open source project is essentially providing integration with glibc and other libcs and we don't do a reasonable job of being conservative there where we don't know what requirements that layer places upon things like memcpy.

Re: Clang emits memcpy for std::swap, which can introduce undefined behavior

#44

Earlier quoted context omitted.

Yes, if "undefined behavior" doesn't just mean "a situation where the ISO language standard doesn't impose a requirement", but has a broader meaning like "behavior not defined by anyone at all".

The compiler is using the ISO language standard to define the behavior of an internal piece. It is then using that piece in the wrong way. It's not generic "not defined" behavior, it is specific C "undefined behavior". Think of that part of the transformed code as still C for relevant purposes.

I want to assure you that the compiler does not exclusively use the ISO language standard to define the behavior of internal components of the implementation.

Re: Clang emits memcpy for std::swap, which can introduce undefined behavior

#45
Reading most thread of llvm bugs so far about there "undefined behaviours" I see a pattern.

Llvm goal is performance over correction. stop.

If old code breaks, it is you played with fire, correct your code to eliminate these undefined behaviours. Stop.

We made wonderful coloured warning to help you. Full Stop.

Well on one hand I get the point, people played with fire. Code should be "correct" by standards that are emerging, but I can predict one thing : before the new "correctness pattern" that enables lots of awesome robust high performing code spreads, there will be chaos.

My first self interrogation is in how much time llvm team can build a completly correct stable compiler without any surprises? It it takes 2 decades, it will be a lot of chaos involved...

My second interrogation is can the code that "is incorrect" per LLVM standard be obtained without rewriting the source code (I guess not), and how much will it costs before all the code is being "corrected". Do we even have the man power to do it?

You see, some C code may be used everyday but are so complex hardly any developers even well paid like to look at them. (openssl, gnutls, libpng, zlib, dhcpd, bind...). And with platform specific ASM, we may discover that code has lost portability, and it may take a lot of time to discover that it is already happening.

Don't we risk another strike of bad news one day like discovering old software/libraries are behaving differently and need to be rewritten and that no one want to do the same effort as libressl especially since some software have a LOT of dependencies on C code (I do not think to loud of PHP or python, or Perl).

Of course there are unit test, but there are so much of them, some tests (like for python on freeBSD with curses) have been disabled, because "no one has the time to fix them". It is ofc a bad example in this precise case, but in the context, it feels like a growing ghettoisation between the CPU/OS/langage with lots of eyeballs/investments, and the old/poor market. Especially non company backed open source software. A smell of obsolescence by attrition of resource to report bugs/rewrite code.

As a normal former experimental physicist I can feel a transition coming, it smells of chaos and instability, and the question is always, how long, how smooth before the new equilibrium if ever we reach it, and what will break in the process? And well since transitions are transitions, we may reach a new equilibrium, but nothing guarantees it will be reversible, hence some stuff may disappear in the process forever.

I don't know why, but I guess the most vulnerable ecosystem to the changes to come is the non commercial open source.

Re: Clang emits memcpy for std::swap, which can introduce undefined behavior

#46

The compiler is the implementation; it cannot cause "undefined behavior". What it can be is "nonconforming". A correct program which hits that situation continues to have well-defined behavior (which we know from the text of the program and the standard). Just the implementation isn't handling the requirements correctly; it is not conforming. An implementation is not bound by the standard in its own use of the standa…

> 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.

Re: Clang emits memcpy for std::swap, which can introduce undefined behavior

#47

The compiler is the implementation; it cannot cause "undefined behavior". What it can be is "nonconforming". A correct program which hits that situation continues to have well-defined behavior (which we know from the text of the program and the standard). Just the implementation isn't handling the requirements correctly; it is not conforming. An implementation is not bound by the standard in its own use of the standa…

[deleted]

Re: Clang emits memcpy for std::swap, which can introduce undefined behavior

#48

Given how aggressively compilers (including Clang) are exploiting undefined behavior these days, it is surprising to see Clang developers (I presume) on the bug being so blasé about introducing undefined behavior themselves.

Hi, LLVM and Clang developer here. I don't see anyone being blasé about this. The issue comes down to something really simple: - The compiler can emit substantially simpler code if it has a guarantee from the platform's implementation of memcpy. - The compiler authors thought they had such a guarantee and so chose to leverage it. Now, maybe they don't have that guarantee on all platforms. If that's the case, its flat…

Hi Chandler,

I should have clarified that the comments I was referring to were on this bug: https://llvm.org/bugs/show_bug.cgi?id=11763

I was surprised to see: "I don't think it's really worth warning about, considering I don't know of any real-world implementation where it doesn't work."

That sounds a lot like someone knowingly writing UB in a C program because no compiler they know of breaks the intended behavior. I doubt any memcpy() has ever guaranteed in any kind of official way that overlapping regions are ok, even if it has historically worked in practice.

I mean I'm sure it'll get fixed now, I was just surprised to see this kind of reasoning coming from someone who I presumes works on the compiler.

btw. I'm pretty sure I heard that glibc broke this behavior sometime recently. There's a new memcpy() symbol in glibc these days with a different symbol version that no longer provides correct behavior in the case of overlapping memory regions. This is all second-hand from some other people I was working with, but if I got their meaning correctly I think this issue will actually have relatively widespread impact.

Re: Clang emits memcpy for std::swap, which can introduce undefined behavior

#49

The compiler is the implementation; it cannot cause "undefined behavior". What it can be is "nonconforming". A correct program which hits that situation continues to have well-defined behavior (which we know from the text of the program and the standard). Just the implementation isn't handling the requirements correctly; it is not conforming. An implementation is not bound by the standard in its own use of the standa…

> An implementation is not bound by the standard in its own use of the standard library functions. 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.

Yes. But right now they do not do that, and it's not their implementation of memcpy they rely on, and they are exactly doing the kind of things they disallow their users to do, so the whole picture is just plain insane. They just call libc memcpy in some cases, and their rational is that "it happens to work". Except nobody is actually sure about that, it might be already buggy on PPC, and the guarantee is not documented anywhere. Completely insane - especially given their very own approach in similar situations. As usual, they are prioritizing "optimizations" over correctness, and lets not even think about defense in depth. It's a brand new level of insanity, even beyond their usual "the standard allows us to do that" excuse, because here it does not even allow that, and it seems that neither do officially all the used implementations!

Software engineers must loose the habit of taking all kind of crazy risks that can only lead to marginally faster execution of newly introduced bugs. That does not serve any purpose.

Re: Clang emits memcpy for std::swap, which can introduce undefined behavior

#50

Earlier quoted context omitted.

The compiler is using the ISO language standard to define the behavior of an internal piece. It is then using that piece in the wrong way. It's not generic "not defined" behavior, it is specific C "undefined behavior". Think of that part of the transformed code as still C for relevant purposes.

I want to assure you that the compiler does not exclusively use the ISO language standard to define the behavior of internal components of the implementation.

I'm talking about a specific component named memcpy. Obviously this does not apply to other components.

And even that is only if the bug report is correct.

Post reply on HN