The Shortest Crashing C Program
llbit.se
llbit.se
[1] http://www.muppetlabs.com/~breadbox/software/tiny/teensy.htm...
$ touch a.c
$ gcc -c a.c
$ ld a.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400078
$ ./a.out
Segmentation fault
gcc -nostdlib ./empty.c -o ./empty
Edit: This one actually runs correctly:
$ touch empty.c
$ gcc -static -nostartfiles ./empty.c -e_exit -o ./empty
$ ./empty && echo $?
> 0$ rm -rf a
$ cp a.c a
$ chmod +x a
$ ./a
$
zsh: exec format error: ./aThe 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 files?
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.
This was altered for 2008[2] to "A file that contains characters organized into zero or more lines."
The 2008 version is actually broken, since it contradicts itself -- a file cannot "contain characters" on zero lines.
[1] http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_...
[2] http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_...
I disagree. To me this doesn't mean that a file "contains at least one character", but that files are containers and their contained values are characters. Like most containers in computer science, the set of contained values can be empty, but it's still meaningful to say that it's a container that "contains characters".
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 $ ld a.o
ld: warning: -macosx_version_min not specified, assuming 10.7
Undefined symbols for architecture x86_64:
"start", referenced from:
implicit entry/start for main executable
ld: symbol(s) not found for inferred architecture x86_64gcc -nostdlib ./empty.c -e0 -o ./empty
$ ld a.o -U _main -U start(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 guaranteed. (uint32_t)0 is a valid sequence of instructions - it's ADD BYTE PTR [EAX],AL - and so if EAX contained a valid value then it would execute without a problem. Then, if the following byte were 0xC3 (RET) then the program would execute. OK, so that's all rather unlikely, but you have to bear these things in mind. So I think 0xCC (INT 3) would be a better choice.)
(gdb) print &main
$1 = (int *) 0x600864 <main>
(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 <main>
(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 <main>: retq
(gdb) run
Starting program: /tmp/s_ret
[Inferior 1 (process 10588) exited with code 0140]mov $1, %eax
int $0x80
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.)
NULL pointers will lead to a crash. It would be more interesting to have it as a random pointer, which could do quite anything.
Not in C. Dereferencing a NULL pointer is undefined behavior, so any of the actions described by the parent would be correct.
Yes. I don't have chapter and verse handy but it is in the standard. The bit pattern of NULL is not required to be zero (so memset(&p, 0, sizeof(p)) is not guaranteed to yield null) but it must compare equally to 0 and assigning 0 must produce NULL.
[Edit: OK, in C99 this is covered in 6.3.2.3: Pointers. "An integer constant expression with the value 0, or such an expression cast to type void * , is called a null pointer constant." Then 7.17.3 says that NULL expands to a null pointer constant.]
> If you actually wanted a pointer to the begging of the memory, you would dereference 0,
Yeah, it's really easy to set up an environment where that happens. At one point I was experimenting with writing a small/toy kernel for x86 and I mapped the virtual address 0 to a valid page, and boom, dereferencing NULL did stuff. Not a great idea to set up the page tables that way for obvious reasons, but I'm going to guess that lots of hardware out there will let you do it...
In the old days of 16-bit x86, linear address 0 had the interrupt vector, so as I recall lots of DOS (maybe even Win9x) environments had dereferencing NULL do meaningful (surely confusing) things.
Maybe the task should have been formulated as the shortest valid C program that invokes undefined behaviour instead. (Or maybe the task isn't very interesting either way.)
As for software, I wrote it for PHP 5.3 (nowadays upgraded to 5.4 though) with MySQL and persistent database connections. The server is Windows 7 with apache 2.4.
You could probably do the same thing in x86 and it'd work on a modern compiler.
EDIT: this is wrong, see below.
That's wrong. 'static' variables are initialized to zero. Non-static variables are un-initialized, so they have a "random" value.
See:
$ valgrind ./a.out
==5118== Memcheck, a memory error detector
==5118== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==5118== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==5118== Command: ./a.out
==5118==
==5118==
==5118== Process terminating with default action of signal 11 (SIGSEGV)
==5118== Bad permissions for mapped region at address 0x600864
==5118== at 0x600864: ??? (in /home/def/a.out)
==5118== by 0x4E54A14: (below main) (in /usr/lib/libc-2.17.so)
main will have a value of zero, and 0x600864 will presumably be &main (it's not the initial arbitrary value of main).
Auto variables are left uninitialized so that they don't have to be given a value when they're allocated. It's for efficiency, and it makes the compiler simpler to have this blanket rule rather than have it try to figure out the minimal initializations necessary (which probably isn't even possible). But this ocnsideration doesn't apply to globals or statics, because the initialization can be done at compile time, or (sometimes, in C++) on program startup.
With ELF binaries for C programs it's done at startup as well. The data segment is created as having memory size SIZEM and file size SIZEF. If SIZEF < SIZEM, memory from SIZEF to SIZEM is set to 0.
Global(variables at file scope) and variables with static linkage (i.e. the static keyword) both of have static storage duration.
"An object whose identifier is declared with external or internal linkage, or with the storage-class specifier `static' has /static storage duration/. Its lifetime is the entire execution of the program and its stored value is initialized only once, prior to program startup."
The default initial value of objects with static storage duration is dealt with in 6.7.8 paragraph 10. Basically: pointers set to NULL, non-pointers have all bits reset, aggregates thus recursively.
Edit, @deweerdt: ok :)
$ cat short.c
M
$ gcc -DM='main;' short.c -o short
$ ./short
Segmentation faultI find it hard to believe that the C89 spec states that an integer called "main" is to be considered the main function, and suspect this is undefined behaviour (though I've not checked).
$ gcc -std=c99 -pedantic /tmp/main.c -o /tmp/main
/tmp/main.c:1:1: warning: data definition has no type
or storage class [enabled by default]
/tmp/main.c:1:1: warning: type defaults to ‘int’ in
declaration of ‘main’ [enabled by default]
/tmp/main.c:1:1: warning: ‘main’ is usually a function
[-Wmain]
$ /tmp/main
Segmentation fault (core dumped) gcc -nostdlib -std=c89 a.c -o a
a.c:1: warning: data definition has no type or storage class
Undefined symbols for architecture x86_64:
"start", referenced from:
-u command line option
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status` main(){*(int*)0=0;}
or: main(){*""=0;}
or: main(){main();}if I'm not mistaken, there are platforms like TI C600 dsps for which 0 is the start of the usable address space
import Unsafe.Coerce;main=unsafeCoerce()1
main=undefinedint a;::a::b();
$ gcc -O0 -c short.c
short.c:1: warning: data definition has no type or storage class
$ ld -e _m -o short short.o
ld: warning: -macosx_version_min not specified, assuming 10.7
$ ./short
[1] 2040 segmentation fault ./short
main(){}
??
main;