Live data from Hacker News

The Shortest Crashing C Program

llbit.se

61–70 of 94 posts

Re: The Shortest Crashing C Program

#61
post #55
post #47

Earlier quoted context omitted.

Originally I thought I'd skip mentioning compiling empty files because doing so without linking separately `gcc` will refuse to link it. I updated the article with a reference to your comment.

Actually you don't have to link it separately if you don't link against stdlib. See my comment here: https://news.ycombinator.com/item?id=5762578

Cool!

Re: The Shortest Crashing C Program

#63
post #31
post #28

Earlier quoted context omitted.

I find it interesting that displays the error from exec, but not bash: zsh: exec format error: ./a

Why? The file is marked as executable, so the shell very reasonably tries to execute it by calling some well-chosen member of the exec() family ( http://linux.die.net/man/3/exec ). The exec() function then needs to open and parse the file according to the formats it supports, which of course fails since the file is empty. Do you simply mean that you expected the shell to validate this, and not try to execute empty fi…

Traditionally, if the kernel cannot execute the file, then it is treated as a shell (/bin/sh) script. (Somewhere along the line, #! got added to specify an interpreter other than the shell.) I read POSIX as requiring this " rel="nofollow">http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu..., so if zsh claims to be a POSIX compatible shell, that's probably a bug.

In Seventh Edition UNIX, /bin/true is an empty file; it is a shell script that succeeds at does nothing.

Some later commercial UNIXes are noted to have /bin/true contain nothing but comments containing a copyright notice for that nothing.

Re: The Shortest Crashing C Program

#65
post #59
post #20

The explanation is not quite correct - execution starts at &main rather than the address given by the value of main. On VC++, at least - well, on my PC anyway - the process halts because the data segment doesn't have the execute bit set. It isn't trying to run code at address 0. (If execution of bytes in the data segment were possible, which I'm sure it used to be, then you'd still likely get a crash, but it's not gu…

No, a ret instruction would probably segfault, depending on the content of the stack. To terminate a program you have to use the corresponding system call. On linux : mov $1, %eax int $0x80

to3m is correct. On my GNU/Linux machine main() is called from __libc_start_main(). A ret instruction in main() returns to __libc_start_main(), which in turn calls exit().

Re: The Shortest Crashing C Program

#66
post #59
post #20

The explanation is not quite correct - execution starts at &main rather than the address given by the value of main. On VC++, at least - well, on my PC anyway - the process halts because the data segment doesn't have the execute bit set. It isn't trying to run code at address 0. (If execution of bytes in the data segment were possible, which I'm sure it used to be, then you'd still likely get a crash, but it's not gu…

No, a ret instruction would probably segfault, depending on the content of the stack. To terminate a program you have to use the corresponding system call. On linux : mov $1, %eax int $0x80

That (or something like it) is true for the process as a whole, but not necessarily for main. It's usual to call main from a library-provided function, so it returns just like any other function. This removes the need to special-case main in any way, and provides a space for any system-specific startup and shutdown code.

If you've got VS2012, you can see this code in the file at something like "c:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\crt\src\crt0.c" (it should be easy to find for other versions - it's been in pretty much in that place, with that name, probably with those contents, since VC5 I think).

For glibc, see http://sourceware.org/git/?p=glibc.git;a=blob;f=csu/libc-sta....

My post was a bit x86/VC++-specific but the principles have been common to all the C environments I've used. I don't think I've ever used one that by default called your startup function directly, bypassing C runtime initialisation. (Though it's very easy to set this up with Visual Studio.)

Re: The Shortest Crashing C Program

#69
post #31
post #28

Earlier quoted context omitted.

I find it interesting that displays the error from exec, but not bash: zsh: exec format error: ./a

Why? The file is marked as executable, so the shell very reasonably tries to execute it by calling some well-chosen member of the exec() family ( http://linux.die.net/man/3/exec ). The exec() function then needs to open and parse the file according to the formats it supports, which of course fails since the file is empty. Do you simply mean that you expected the shell to validate this, and not try to execute empty fi…

> Do you simply mean that you expected the shell to validate this, and not try to execute empty files?

I understand what happens here and why there is an error message in zsh, but I'm surprised by the fact that bash does not signal the error (exec returns -1, after all).

Bash includes logic to parse ELF[1], so I guess that after exec fails it tries to parse the file and has a special case for empty files.

    [1]: http://utcc.utoronto.ca/~cks/space/blog/unix/BashSuperintelligentExec

Re: The Shortest Crashing C Program

#70
post #20

The explanation is not quite correct - execution starts at &main rather than the address given by the value of main. On VC++, at least - well, on my PC anyway - the process halts because the data segment doesn't have the execute bit set. It isn't trying to run code at address 0. (If execution of bytes in the data segment were possible, which I'm sure it used to be, then you'd still likely get a crash, but it's not gu…

You're right about this. On my GNU/Linux machine, main is in the data segment. The process receives a segfault for trying to execute from a page marked as not executable.

    (gdb) print &main
    $1 = (int *) 0x600864 
    (gdb) run
    Starting program: /tmp/s 
    Program received signal SIGSEGV, Segmentation fault.
    0x0000000000600864 in main ()

If we are to mark the data segment as executable (quite easy for ELF), we can see execution starting at &main and continuing until end of the page and then segfaulting for trying to execute from an unmapped virtual address.

    (gdb) print &main
    $1 = (int *) 0x600864 
    (gdb) run
    Starting program: /tmp/s 
    Program received signal SIGSEGV, Segmentation fault.
    0x0000000000601000 in ?? ()

If we change the source to main=0xC3; as per your suggestion and we mark the data segment as executable, the program exits correctly (but with an exit status we don't control).

    (gdb) x/i &main
    0x600860 :	retq   
    (gdb) run
    Starting program: /tmp/s_ret 
    [Inferior 1 (process 10588) exited with code 0140]
Post reply on HN