Date: Wed, 16 Apr 1997 18:07:19 +1000 From: Bruce Evans <bde@zeta.org.au> To: current@FreeBSD.org, toor@dyson.iquest.net Subject: Re: You will need to recompile your libc and apps!!! Message-ID: <199704160807.SAA03190@godzilla.zeta.org.au>
next in thread | raw e-mail | index | archive | help
>There is a serious bug in popen that has gone undetected until now. I The bug came from Lite2, so it has not gone undetected for long :-). >have just committed a fix that makes the shared address space vfork >problem go away (which was due to the popen boo-boo.) I will not The fix is far too complicated. It is sufficient to remove one (unused except for its corruption of of the parent) assignment to pdes[1]. Function calls do not use call by reference in C. I think vfork() is still broken as designed. It makes unwarranted assumptions about the C implementation. Look at what happens if a (very reasonable) implementation preserves caller-saved registers in a natural way: main() { asm(" xorl %esi,%esi # 0 pushl %esi # save %esi call _vfork popl %esi # attempt to restore %esi testl %eax,%eax jge 1f call _abort # fork failed 1: jne 2f incl %eax # child, set %eax = 1 pushl %eax # corrupt stack as part of exiting call __exit # exit code doesn't matter 2: pushl %esi # parent call __exit # exit code 1 iff %esi was corrupted "); } When the parent gains control, its `popl %esi' restores garbage instead of the saved %esi. Worse things may happen for unreasonable implementations. There may be no stack... I wrote the following about system() before I understood the full brokenness of vfork(). Calling sigaction(), etc., should be no worse than calling execve(). Both depend on the C implementation not changing the stack level significantly before making the call making the call. Just returning to the parent depends on the vfork() implementation not doing too much with the stack (another layer of function calls would corrupt return addresses) :-(. popen.c happens to be the only place in libc that uses vfork. I think that system() should also use it. The child in system() does only sigaction() and sigprocmask() calls. This is a good example of where it is critical to know the difference between system calls and library functions - it is hard to tell whether a library function has any side effects. OTOH, all the functions that are safe to call in signal handlers are probably safe to call in vfork()ed children, since any side effects would make them unsafe to call in signal handlers. Unfortunately, _no_ syscalls are safe to call from signal handlers in FreeBSD, since all syscalls may have the side effect of clobbering errno. Fortunately, clobbering errno probably is not a problem for vfork() - after a successful vfork(), the parent has no reason to check errno, and usually has reasons to distrust it (I forget if successful syscalls can clobber errno - what happens for { errno = 0; susccessful_syscall(); assert(errno == 0); } ?). Bruce
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199704160807.SAA03190>