IOCCC remarks

In the future, I'll be adding some remarks about my favorite winners of the contests that I've watched, participated in, and judged.

Now, due to the limited write-accessibility of the main IOCCC page, here is a quick update on the IOCCC judging process of the 2006 contest:

March 13, 2007: We're using a 64-bit machine to compile and run the entries this year!
Guess what? Saving pointer values in integers is now passé...

February 20: The winners have been posted, and the hint files for easy reading are here.

November 6: The winners have been announced.

October 18: The winners have been selected. We will announce the winners and will demonstrate the winning entries at the Vintage Computer Festival hosted by the Computer History Museum in Mountain View, California on Saturday, November 5, at some time between 10 am and 1 pm (check the latest schedule for the exact time). E-mail will be sent to the winners shortly afterwards.

October 11: We're in the final round. It's hard to part with some entries...

May 26: The web-only submission interface definitely helps: there is no more need to cross-match the updates.


A little teaser (what could have won the hypothetical first obfuscated C++ contest):

#include <iostream>

#define t template
#define S struct
#define i int
#define s static const int

#define T(x,y,z)t<i n,i a>S x<n,a,y>{z;};

t<i n,i a,i d>S c:c<n,a-1,n%a>{};
t<i n,i a,i d>S N{s v=N<n,(2*a+d)/2,n/(a+d/2)-(2*a+d)/2>::v;};
T(c,0,)T(N,0,s v=a)T(N,1,s v=a)T(N,-1,s v=a-1)
t<i n>S c<n,1,1>{c(){std::cout<<n<<std::endl;}};
t<i n>S C:C<n-1>,c<n,N<n,2,n/2-2>::v,1>{};
t<>S C<1>{};C<125>a;

main() {}

The category would have been, most likely, Best abuse of the C++ template engine. Also see how to compute the square root.


How to make some older entries work

Write me if you have problems what an entry that is not mentioned here.

The contests I judged

x86 OS

The winner of the 2004 contest is quite dependent on the environment. Please see Askar Safin's deobfuscation and reconstruction.


Binary translator

One of my favorite entries, Most likely to amaze-2001 needs some preparation before you can be amazed. The provided small C program, after compilation, has to use a particular subset of x86 instructions (can you figure out what instructions are in that subset?); otherwise the binary translator will dump core. Here is how to achieve this using a fairly fresh GCC (3.2):

gcc -mpreferred-stack-boundary=2 -S ten.c
echo '#define leave .byte 0x89,0xec,0x5d' | cat - ten.s > ten.S
gcc -o ten ten.S
Apparently, the version of GCC used by the author did not generate a leave instruction by default. (And using -fomit-frame-pointer does not help because stack-relative memory references (offset(%esp)) do not work - only frame-relative (offset(%ebp)) and some %eax-relative.)

As the translator modifies the binary that it translates, in case it fails midpoint for whatever reason, the binary can be rendered unusable. Keep a backup copy and do cp ten.clean ten after the translator has not terminated cleanly.

The next step is to ensure that the translator is able to parse the (unaligned) x86 code.
If your host architecture does not support unaligned word access, you need to add a flag to the host C compiler invocation line that turns on the misaligned access feature (-misalign for the Sun C compiler); or, lacking that (GCC), to add a way to intercept and to interpret the faulting memory accesses.

Luckily, Sun Solaris OS provides that feature in the kernel: just add asm("ta 6"); as the first statement in main().

This should get you going; do not be alarmed if the program does not produce any output for 5-10 seconds.

If the execution halts mid-way with a failure to open some file or the other, increase the number of available file descriptors (1024 should be plenty), or, better, modify the code to store the file descriptor returned by open() and to close it just before execv().

After a failed run, do not forget to remove all files that start with .ten and to update the ten executable from a backup copy.

If you have a big-endian machine (PowerPC, SPARC), can you spot a bug (look closely at the output)? Which is the offending instruction?

If you have a big-endian machine and the execution fails with

10 green bottles, standing on the wall.
10 green bottles, standing on the wall.
And if one green bottle should accidently fall,
There'd be Segmentation Fault                 Hmm...  What if it falls but does not break?
can you find which is the offending instruction and to modify the assembly code to make it work?

I have a prime number printing program that can be run by the translator. Can you write such a program?


C compiler/linker/execution environment

Another favorite entry of mine is Best abuse of the rules-2001. Most of the code is quite portable, if you allow for unaligned word access, but at the very end the program jumps to the x86 code it had generated, thus bringing back memories of the winner of the very first IOCCC in 1984.

Fabrice Bellard has a version of his entry on his website that produces ELF files. The (Linux) kernel is able to load and to execute them, but the GNU binutils tools do not recognize them as ELF.

You can disassemble these files with objdump -b binary -m i386 -D <filename>. The compiler is also endianness-dependent, so if your host architecture is big-endian, all multibyte literal constants in the assembly output will be wrong. This makes the assembly code slightly less readable, but it is still possible to observe the tricks played by the author to minimize the number of necessary instruction patterns.


The contests I watched

The Periodic table of elements

The Best visuals-1988 entry had to be modified to conform to the ANSI C preprocessor syntax, but on some platforms, even isaak.ansi.c does not work - it returns without printing anything.
What is the problem and how to fix it without changing a single character in the source (if you're lazy and want to see the output ASAP, go change the source, but that's cheating)?
Why did it work before and what exactly happened that caused it to stop working?


The Game of Life

The Best X11 graphics-1991 entry was the first one that used X11 graphics, and how! Somewhat unfortunately, over the years the computers got so fast that it takes a fraction of a minute for a 1280x1024 or even a bigger screen to settle to a trivial state, but nevertheless it is quite entertaining to watch.

Most newer desktop environments obscure the root window completely; due to that, and due to the fact that you do not want to disable access control on your primary X server, it is better to start a separate X server to run this entry:

 
X -ac -depth 8 :1 & sleep 5 ; davidguy 127.0.0.1:1.0

This starts an X server with 8-bit color (make sure you have the appropriate section in your configuration file that allows the 8-bit mode) without access control on screen 1, makes it active, waits 5 seconds for the server to initialize, then starts the application on that screen. After 5 seconds you should see some action. If you don't, or after you've seen enough, press Ctrl-Alt-Backspace to kill the server and return to where you were.

Alternatively, if the default X server configuration does not include an 8-bit mode and you do not want to edit it, you'll have to modify the fixed version of the entry to work with non-default screens, as it is done in the presented entry, but this is too tedious. Just change one character (which one to what?) to make it open screen 1 when called without arguments (UNIX sockets are ubiquitous nowadays), and enjoy:

X -ac :1 & sleep 5; davidguy.fix


Copyright © 2004 Leonid A. Broukhis