Why does a simple piece of c generate a SIGSEGV on linux as opposed to a SIGBUS on OSX

One of the lads in the office has the following piece of code:

main;

when compiled on linux, and run, it generates a SIGSEGV, but when run on OSX, it generates a SIGBUS,

Why?

The definition of SIGBUS is `Access to an undefined portion of a memory object.`, the definition of `SIGSEGV` is that it’s `Invalid memory reference.`.

The issue is that OSX translates a native MACH exception into a POSIX signal. on OSX, the route is through a translation layer, the code of which indicates:


case EXC_BAD_ACCESS:
if (code == KERN_INVALID_ADDRESS)
*ux_signal = SIGSEGV;
else
*ux_signal = SIGBUS;
break;

This indicates that if you crash with an address that is mapped into the process, but isn’t an invalid address, you’ll get a SIGBUS, however, if you crash with an address that isn’t mapped into the process, you’ll get a SIGSEGV, i.e. all addresses that are unmapped will generate SIGSEGV, while all address that are mapped, but aren’t usable in the way you ask will generate a SIGBUS.

There is some other code:

if (machine_exception(exception, code, subcode, ux_signal, ux_code))
return;

which deals with general protection faults e.g. pages that are simply not mapped.

when you compile the .c file, because you declared the variable main, it gets default storage/allocation which means it goes into the DATA segment of the application, none of which allows the execution of code from there.

When you try to run the program on OSX, it tries to execute the ‘code’ at main, which is data, the exception it gets at this point is bad access. The memory is available, but it isn’t mapped as executable, so you get a SIGBUS.

When you try to run this program on linux, you get a SEGV. The reason is simply because you’re trying to access memory that isn’t mapped for purpose.

When you change the code, to invoke a simple null pointer:


int main(int argc, char **argv) {
void (*crash)(void) = 0;
crash();
}

You get a SEGV, this is caused because there is no 0 mapped page visible to the user (you can use vmmap on processes to see what’s mapped/not mapped in this case).