What happens if a program is compiled while another instance is already running?

c++

Solution

This really depends on how `ld` (invoked by `g++`) goes about creating the new executable. If it just does an `open` (with the proper flags for creation if the file doesn't exist), then what happens to the running process depends on paging, but there's a good chance of a crash. If it does an `unlink` first, before creating the new file, the running process will continue to use the old image, which will only be freed when the process ends.

Traditionally, the original Unix linkers used the first strategy, which has the advantage of keeping the access rights on an existing executable. This was, however, before the days of virtual memory, when an executable was loaded in one shot, in the call to `exec`, and what happened to the file afterwards was irrelevant. Today, if I were writing a linker, I'd use the second, but first read the mode of the original file, and create the new file with the same mode.

You can easily see which strategy is being used by creating an executable, then changing the mode, doing `ls -il` on it, then recompiling, and doing `ls -il` again. If the inode number has changed, the linker is doing an `unlink` before opening the output. And if the mode has changed (back to whatever the default is in your environment), the linker is failing to read the orginal mode before doing the `unlink`.

In the case of g++ under Linux, both the inode number and the mode change. (I'd consider the fact that the mode changes a bug.) IIRC, on the other hand, `ld` under Solaris did not delete the file—I don't recall doing the above test, but I do have vague memories of programs crashing when we recompiled one of the DLL's they were using.

Finally, FWIW, why deleting the file doesn't crash the application: files under Unix (represented by inodes) are reference counted, and are deleted automatically when the reference count goes to 0. (Very much like `shared_ptr`.) There is a reference count for each directory entry pointing to the file (each hard link), and for each open file descriptor referring to the file. "Deleting" a file under Unix doesn't actually touch the file, it just removes the directory entry pointing to it (which decrements the use count, which may result in the file being deleted). A loaded executable contains an open file descriptor for its executable and all of the `.so`s it has loaded, which counts as a reference to the file, so deleting the last directory entry pointing to it will still leave the reference count greater than 0.

EDIT: I might add that unlinking will also break hard links (which will remain pointing to the old version). This is probably not an issue today, since everyone only uses soft links (which are references to a file name, and not to a file itself), but I can remember back in the early days, before soft links existed, we took pains to avoid breaking links: in the editor I worked on, we wrote the output to a totally new file, then either moved that to the original file (if the inode count was 1), or copied it (if the inode count was greater than 1; i.e. if there were other hard links to the file we didn't know about).

Problem

`$ g++ program.cpp` `$ ./a.out &` (program.cpp is modified.) `$ g++ program.cpp` How can the running process still produce accurate results if the executable is overwritten?

Original source