testhelper: Fix ETXTBSY race when writing executables
On Unix-systems, trying to execve(3P) into an executable which is
currently open in any process as writeable will result in ETXTBSY
errors. We're frequently observing this error in our test suite when
using the WriteExecutable()
testhelper function.
The root cause of this is a race between fork(3P), execve(3P) and us still having the file descriptor open for writing. Suppose the following race where one thread is trying to write an executable and execute it, and a second thread forking to execute any other executable:
Thread 1 Thread 2
fd = open(O_WRONLY)
fork()
close(fd)
fork()
execve(fd)
execve()
We call fork(3P) in the second thread after having opened the file as writeable, which means that the newly created process inherits the writeable file descriptor. And even though we close it in the first thread, execve(3P) will fail with ETXTBSY because it's still open in the second process, which didn't yet call execve(3P) itself and thus hasn't closed the file descriptor until now.
Fix this race by using file locking such that we know that all writeable
file descriptors must have been closed at the time of returning from
WriteExecutable()
. Please refer to 1 for further information about
this issue.
Fixes #4018 (closed)