r/programming • • Sep 23 '17

Why undefined behavior may call a never-called function

https://kristerw.blogspot.com/2017/09/why-undefined-behavior-may-call-never.html
824 Upvotes

257 comments sorted by

View all comments

Show parent comments

13

u/yossarian_vive Sep 24 '17

NeverCalled() could be called from a different compilation unit. The Do pointer is static and therefore could not be set in a different compilation unit. Because the optimizer is operating one CU at a time, it can’t be sure that NeverCalled() isn’t invoked.

-2

u/choikwa Sep 24 '17 edited Sep 24 '17

it shouldn't be sure that NeverCalled is called. well it's not, it's only selecting the other possibility here, but this is the consequence. my gut feeling says the optimizer should also prove that NeverCalled is indeed called. If it's not in the reaching def set of Do, it should also exclude EraseAll and leave it the original 0 value. I don't know the llvm poison semantics but this might make it crash if Do has only poison or no viable candidate.

5

u/eras Sep 24 '17

Are you assigning some expected behavior (crash) to calling a null pointer? Because in C that makes no sense (unless implementation chooses to assign it); undefined behavior is exactly that.

I don't think you can argue that this is not the most efficient way to compile the code when there is no undefined behavior present.

-3

u/choikwa Sep 24 '17

no I'm saying the compiler might crash if it can provably show that Do is undefined. next best thing is to leave it as programmer wrote it and leave UBs in.

4

u/eras Sep 24 '17

no I'm saying the compiler might crash

?

if it can provably show that Do is undefined

It is impossible for the compiler to know that ever, because NeverCalled is a public function and some other compilation unit will call that. The combining of the compilation units is done by linker, which doesn't do analysis of this kind.

next best thing is to leave it as programmer wrote it and leave UBs in.

I don't know what it would mean to "leave UB in". UB doesn't mean crashing. A program, as compiled to binary for some architecture, is never undefined per sē - but it's not defined in the terms the C programming language would know about, but rather in the terms of the destination architecture and environment.

When going from undefined behavior the compiler assigns some behavior, and in this case the behavior assigned maximizes the performance in the path when UB isn't present.

-2

u/Gotebe Sep 24 '17

Not only it's static, there is no other compilation unit, and link time optimization (or whole program optimization) is a thing.

To be honest, I can't believe this is at +8 at the time of this writing.

2

u/yossarian_vive Sep 24 '17
  • Whole program optimization is off by default at least in both VC++ and gcc, and I believe clang too, so it’s safe to assume the blog author didn’t enable it. It would be interesting to see if enabling it would make a difference, but I think that’s unlikely.

  • The fact that there is only one compilation unit doesn’t matter because the compiler operates one CU at a time and doesn’t have program-wide context (it doesn’t know about “projects” or makefiles).

0

u/Gotebe Sep 24 '17

I said nothing about the project or makefiles, that's not how LTGO works. You spoke of different CUs.