[Toybox] fun with vfork

Rob Landley rob at landley.net
Tue Oct 11 04:23:39 PDT 2016


While doing the rest of nommu support in netcat -L, I had some variant of:

  function()
  {
    int child, blah = 3;

    for (;;) {
      crunch(blah);
      child = vfork();
      if (child<1) break;
    }
    thingy();

    execlp(stuff);
  }

And gcc's optimizer went "blah isn't used anymore after the for loop,
I'll trim the stack frame down so the return address in the call to
thingy() in the child overwrites it, and then when vfork returns it's
corrupted in the parent and the next call to crunch() goes bye-bye".
Because gcc's optimizer does not understand vfork()'s impact on
"liveness analysis". (You can think of vfork() as a setjmp that will
fork() when it hits the next exec or exit, and then the parent process
longjmp()s back to the stack until the child. But gcc's optimizer doesn't.)

The fix is to add an unnecessary use of blah to the end of the function
to let it know it's still %*#(%&& used, but then I need a GREAT BIG
COMMENT to explain why so it isn't removed in future cleanup passes. And
every other variable potentially has that same problem.

As usual, I want to punch gcc's optimizer in the face and go "DO WHAT I
TOLD YOU TO DO, DON'T MAKE STUFF UP!" but it never listens. (Do I have
to start building everything with -O0? What optimization level gives me
dead code elimination and nothing else?)

Rob

P.S. I'm always amused by the go/rust/swift developers who haven't hit
their language with anything like the range of use cases you get in C,
confidently stating that they have yet to see such strange corner cases
in _their_ language yet. Uh-huh. There's a reason for that and it's
probably not the one you think.


More information about the Toybox mailing list