Open llvmbot opened 9 years ago
Can you explain why you think noclone is important in this example? As far as I can see, you're violating the rules for using vfork:
"the behavior is undefined if the process created by vfork() [...] calls any other function before successfully calling _exit(2) or one of the exec(3) family of functions"
Your call to 'f' here is breaking this rule.
You are correct that this does not obey the version of the POSIX standard that mentions vfork. However, the next version of the POSIX standard removed vfork from the standard as it was too finicky too use and difficult for compilers to work around. Clang itself miscompiles code that uses vfork in a conformant way to that version of the POSIX standard. Because Clang miscompiles conformant code using vfork, I don't expect Clang to change that and many other compilers could miscompile the code anyways so I wrote my little wrapper that tries to carefully isolate away some of the unsafety of vfork. I don't feel bad about breaking that outdated version of the POSIX standard because following that version of the standard does not work.
Can you explain why you think noclone is important in this example? As far as I can see, you're violating the rules for using vfork:
"the behavior is undefined if the process created by vfork() [...] calls any other function before successfully calling _exit(2) or one of the exec(3) family of functions"
Your call to 'f' here is breaking this rule.
Nevermind the volatile workaround does work. I am still cautious of it because the semantics are unclear though.
Extended Description
noclone is a companion attribute to the noinline attribute that GCC implements. It prevents constant propagation from happening. If one is doing magic low level hackery then it is a necessity. A specific use case I have for this is creating a safe wrapper for vfork (which most compilers understandably mess up on).
The wrapper:
attribute((noinline)) attribute((noclone)) attribute((no_sanitize_address)) static pid_t safe_vfork(int (f)(void ), void * arg) { atomic_signal_fence(ATOMIC_SEQ_CST);
}
Some workarounds:
Use assembly: This is annoying but would work. Put safe_vfork in a separate module: This doesn't work with link-time optimization but is the typical workaround. Use volatile on the function arguments as follows: Strangely, this doesn't actually work. I can further work around this with more indirection but I am hesitant to do so because the semantics of volatile are very unclear and compiler specific.
attribute((noinline)) attribute((noclone)) attribute((no_sanitize_address)) static pid_t safe_vfork(int (volatile f)(void ), void * volatile arg) { atomic_signal_fence(ATOMIC_SEQ_CST);
}