Add 2020 source files for real
This commit is contained in:
1 parent
a3c1748648
commit
9d61fc0fb4
147 files changed
+32101
No files matched your search
@@ -0,0 +1,326 @@
|
||||
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional //EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta name="GENERATOR" content="mkd2html 2.2.2">
|
||||
<meta http-equiv="Content-Type"
|
||||
content="text/html; charset=utf-8"> <link rel="stylesheet"
|
||||
type="text/css"
|
||||
href="../hint.css" />
|
||||
<title></title>
|
||||
<title>Best of show - abuse of libc</title>
|
||||
</head>
|
||||
<body>
|
||||
<CENTER>
|
||||
<IMG SRC="/png/ioccc.png" ALT="IOCCC" height=78 width=267>
|
||||
<P><FONT size="6"><I>The International Obfuscated C Code Contest</I></FONT></P>
|
||||
<div id="bar">
|
||||
<ul>
|
||||
<li><a href="../index.html">About the 27th IOCCC</a></li>
|
||||
<li><a href="../whowon.html">27th IOCCC Winners</a></li>
|
||||
<li><a href="/index.html">IOCCC home</a></li>
|
||||
<li><a href="/winners.html">List of All Winners</a></li>
|
||||
<li><a href="/judges.html">The Judges</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<P><FONT size="6"><B>A 27<sup>th</sup> IOCCC Winner</B></FONT></P>
|
||||
</CENTER>
|
||||
|
||||
|
||||
<h1>Best of show - abuse of libc</h1>
|
||||
|
||||
<p>Nicholas Carlini <a href="mailto:nicholas@carlini.com">nicholas@carlini.com</a><br/>
|
||||
<a href="https://nicholas.carlini.com">https://nicholas.carlini.com</a></p>
|
||||
|
||||
<p>The code for this entry can be found in <a href="prog.c">prog.c</a></p>
|
||||
|
||||
<h2>Judges' comments:</h2>
|
||||
|
||||
<h3>To use:</h3>
|
||||
|
||||
<pre><code>make
|
||||
./prog
|
||||
</code></pre>
|
||||
|
||||
<h3>Try:</h3>
|
||||
|
||||
<pre><code># Play with a friend, P1 and P2, squares are numbered 1..9
|
||||
./prog
|
||||
</code></pre>
|
||||
|
||||
<h3>Selected Judges Remarks:</h3>
|
||||
|
||||
<p>This program consists of a single print statement wrapped in a while loop. You
|
||||
would not think that this would amount to much, but you would be very, very
|
||||
wrong. A clue to what is happening and how this works is encoded in the
|
||||
ASCII art of the program source.</p>
|
||||
|
||||
<h2>Author’s comments:</h2>
|
||||
|
||||
<p>HOW ABOUT A NICE GAME OF <strike>CHESS</strike>TIC-TAC-TOE?</p>
|
||||
|
||||
<h3>USAGE</h3>
|
||||
|
||||
<pre><code>cc -o prog prog.c
|
||||
./prog
|
||||
</code></pre>
|
||||
|
||||
<p>Alternates between P1 and P2. Enter a digit [1-9] to move:</p>
|
||||
|
||||
<pre><code>1 | 2 | 3
|
||||
---------
|
||||
4 | 5 | 6
|
||||
---------
|
||||
7 | 8 | 9
|
||||
</code></pre>
|
||||
|
||||
<p>The game ends if:</p>
|
||||
|
||||
<ul>
|
||||
<li>A player completes three in a row; that player wins</li>
|
||||
<li>All squares are taken; neither player wins</li>
|
||||
<li>A player makes an illegal move; their opponent wins</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3>LIMITATIONS</h3>
|
||||
|
||||
<p>Bad things may happen if the entered move is outside of the range [1..9]</p>
|
||||
|
||||
<p>While the game will stop if one player tries to overwrite another player’s move,
|
||||
it will happily allow a player to move on top of themself. However, given that
|
||||
this is an effective no-op and guarantees a loss to a competent opponent, if you
|
||||
do this you probably deserve to lose.</p>
|
||||
|
||||
<p>Your terminal may beep at you every turn. We’ll call this a feature that …
|
||||
the program … is hard at work processing your move! That is! Please be
|
||||
patient.</p>
|
||||
|
||||
<p>After macro expansion the format string is roughly 100K. This makes some
|
||||
compilers unhappy, and others slow. (For example, passing GCC the flags -Wall
|
||||
-Wextra -pedantic will result in a warning about oversized strings.)</p>
|
||||
|
||||
<p>Under some terminals the program may exit early. The following should always work:</p>
|
||||
|
||||
<pre><code>echo "1 2 3 4 5 6 7" | ./prog
|
||||
</code></pre>
|
||||
|
||||
<h3>OBFUSCATION</h3>
|
||||
|
||||
<p>The entirety of the program consists of a single iterated call to printf.</p>
|
||||
|
||||
<pre><code>int main() {
|
||||
while(*d) printf(fmt, arg);
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
<p>Here, <code>fmt</code> is a single string, and <code>arg</code> is a series of arguments to printf.</p>
|
||||
|
||||
<p>While its primary purpose is to serve as The One True Debugger, printf also happens
|
||||
to be Turing complete. (See “Control-Flow Bending: On the Effectiveness of Control-Flow
|
||||
Integrity” where we introduced this in an actual, published, academic paper. The
|
||||
things you can get away with sometimes.)</p>
|
||||
|
||||
<p>We <strike>ab</strike>use this fact to implement the logic of tic-tac-toe entirely within
|
||||
this one printf call (and a call to scanf() to read user input).</p>
|
||||
|
||||
<p>Here’s (briefly) how it works.</p>
|
||||
|
||||
<h4>Preliminaries</h4>
|
||||
|
||||
<p>This program uses three printf format specifiers.
|
||||
- <code>%d</code> takes an integer argument and prints it
|
||||
- <code>%s</code> takes a string argument and prints it
|
||||
- <code>%n</code> takes a pointer and writes (!!) the number of bytes printed so far.</p>
|
||||
|
||||
<p>Okay, everyone probably knows this. Let’s get a bit more advanced.</p>
|
||||
|
||||
<p>Format specifiers can take extra “arguments”.
|
||||
- <code>"%hhn"</code>: store the number of bytes written mod 256 to the char pointer
|
||||
- <code>"%2$d"</code>: print argument 2 to printf (and not the sequentially next argument)
|
||||
- <code>"%8d"</code>: pad the printed integer to 8 characters
|
||||
- <code>"%3$.*4$d"</code>: print argument 3 to printf with as many zeros as in argument 4.</p>
|
||||
|
||||
<p>For example, the following expression</p>
|
||||
|
||||
<pre><code>printf("%1$.*2$d%3$hhn", 5, 10, &x)
|
||||
</code></pre>
|
||||
|
||||
<p>will have the same effect as if we had written</p>
|
||||
|
||||
<pre><code>x = 10;
|
||||
</code></pre>
|
||||
|
||||
<p>because it will print out <code>0000000005</code> (5 padded to size 10) and then write the
|
||||
number of bytes written to x.</p>
|
||||
|
||||
<h4>Printf Oriented Programming</h4>
|
||||
|
||||
<p>Alright, now we can get to the real fun.</p>
|
||||
|
||||
<p>We perform arbitrary computation with printf treating memory as a binary
|
||||
array—one bit per pair of bytes:
|
||||
- The zero bit is represented by the sequence <code>00 00</code>
|
||||
- The one-bit is represented by the sequence <code>xx 00</code> where <code>xx</code> is any non-zero byte.</p>
|
||||
|
||||
<p>We can use format strings to compute the OR/NOT of arbitrary “bits”.</p>
|
||||
|
||||
<p>We’ll start with the simplest, OR:</p>
|
||||
|
||||
<pre><code>printf("%1$s%2$s%3$hhn", a, b, c)
|
||||
</code></pre>
|
||||
|
||||
<p>will compute</p>
|
||||
|
||||
<pre><code>*c = strlen(a) + strlen(b)
|
||||
</code></pre>
|
||||
|
||||
<p>but given that <code>strlen(x)</code> is <code>1</code> for a 1-bit and <code>0</code> for a 0-bit, we have</p>
|
||||
|
||||
<pre><code>*c = a | b
|
||||
</code></pre>
|
||||
|
||||
<p>Computing the NOT of a single value is also easy:</p>
|
||||
|
||||
<pre><code>printf("%1$255d%1$s%hhn", a, b)
|
||||
</code></pre>
|
||||
|
||||
<p>will compute</p>
|
||||
|
||||
<pre><code>*b = (strlen(a)+255)%256 = strlen(a)-1
|
||||
</code></pre>
|
||||
|
||||
<p>and again, because <code>strlen(x)</code> is either <code>1</code> or <code>0</code> we have</p>
|
||||
|
||||
<pre><code>*c = !b
|
||||
</code></pre>
|
||||
|
||||
<p>From here we can compute any binary circuit. Doing something efficient,
|
||||
though, still takes work.</p>
|
||||
|
||||
<h4>Tic-Tac-Toe</h4>
|
||||
|
||||
<p>The game itself is represented as a board of 18 bits, 9 bits per player, along
|
||||
with a turn counter that alternates between player 1 and player 2.</p>
|
||||
|
||||
<p>To detect who has won, we implement the following logic. Let A, B, and C be
|
||||
pointers to three squares in a row to test, and D be where to save if there is a
|
||||
win or not.</p>
|
||||
|
||||
<pre><code>"%A$s%B$s%C$s%1$253d%11$hhn" // r11 = !(*A & *B & *C)
|
||||
ZERO
|
||||
"%11$s%1$255d%11hhn" // r11 = !r11
|
||||
ZERO
|
||||
"%11$s%D$s%D$hhn" // *D = *D | r11
|
||||
</code></pre>
|
||||
|
||||
<p>That is, we set <code>*D</code> to <code>1</code> if there is a three-in-a-row. We repeat this for all
|
||||
possible three-in-a-row configurations, for both players.</p>
|
||||
|
||||
<p>The ZERO macro ensures that the number of bytes written out is 0 mod 256 with
|
||||
the following expression</p>
|
||||
|
||||
<pre><code>"%1$hhn%1$s" (repeated 256 times)
|
||||
</code></pre>
|
||||
|
||||
<p>where argument 1 is a pointer to a temporary variable followed by a null byte.</p>
|
||||
|
||||
<p>This works because if the current count is 0 mod 256, then “%1$hhn” will write
|
||||
zero to argument 1 and then “%1$s” will never emit any text. If, on the other
|
||||
hand, the count is not 0 mod 256, a length-1 string will be written to argument
|
||||
1, and then “%1$s” will increment the count by one. By repeating this 256
|
||||
times we’re eventually going to reach 0 mod 256.</p>
|
||||
|
||||
<p>Checking if there has been an invalid move is achieved similarly.</p>
|
||||
|
||||
<p>In order to decide what to print out, we have to cast the “in-memory” array of
|
||||
bits to Xs and Os to print out. This is actually rather straightforward. Given
|
||||
in 1$ the pointer to player 1’s square, and 2$ the pointer to player 2’s, and
|
||||
in 3$ the pointer to the board string, we can compute</p>
|
||||
|
||||
<pre><code>"%1$s" (repeated 47 times) "%2$s" (repeated 56 times) %1$32d%3$hhn"
|
||||
</code></pre>
|
||||
|
||||
<p>which will, in effect, compute</p>
|
||||
|
||||
<pre><code>*r3 = (*r1) * 47 + (*r2) * 56 + 32
|
||||
</code></pre>
|
||||
|
||||
<p>which will output ‘ ’ if neither are true, ‘X’ if r1 is, or ‘O’ if r2 is.</p>
|
||||
|
||||
<h4>Further Obfuscations</h4>
|
||||
|
||||
<p>In order to be able to finally display the board, while still only using one
|
||||
printf statement, we finish the statement with</p>
|
||||
|
||||
<pre><code>"\n\033[2J\n%26$s"
|
||||
</code></pre>
|
||||
|
||||
<p>which is the escape sequence to clear the screen, and then prints argument 26.
|
||||
Argument 26 is a pointer to a char* in memory, that initially is undefined,
|
||||
but within the printf statement we will construct this string to look like a
|
||||
tic-tac-toe board.</p>
|
||||
|
||||
<p>After the board, we need to print one of the following strings:</p>
|
||||
|
||||
<pre><code>P1>_
|
||||
P2>_
|
||||
P1 WINS
|
||||
P2 WINS
|
||||
P1 TIES
|
||||
P2 TIES
|
||||
</code></pre>
|
||||
|
||||
<p>Depending on if it’s P1 or P2’s turn to move, the game is over and someone
|
||||
won, or the game is over and it is a draw.</p>
|
||||
|
||||
<p>This turns out not to be as hard as it might look. Using the same trick as
|
||||
before, we set byte four to be</p>
|
||||
|
||||
<pre><code>*byte4 = is_win * 'W' + is_tie * 'T'
|
||||
</code></pre>
|
||||
|
||||
<p>The byte <code>'I'</code> and <code>'S'</code> can always be the same, and we do the same for <code>'E'</code>/<code>'N'</code>.</p>
|
||||
|
||||
<p>We do this same on-the-fly creation of the <code>scanf()</code> format string, but for a
|
||||
different reason. We first want to run <code>printf()</code> to show the first board, and
|
||||
then alternate between runs to <code>scanf()</code> and <code>printf()</code> reading and then
|
||||
displaying moves. importantly, we <em>do not</em> want a final scanf when the game
|
||||
ends. It should just exit.</p>
|
||||
|
||||
<p>One option would be to implement the logic as</p>
|
||||
|
||||
<pre><code>printf()
|
||||
while (*ok) {
|
||||
scanf();
|
||||
printf();
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
<p>but this would DOUBLE the number of calls to printf we require. So instead we
|
||||
implement it like this</p>
|
||||
|
||||
<pre><code>while (*ok) {
|
||||
scanf();
|
||||
printf();
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
<p>(In reality we actually pass <code>scanf()</code> as an argument to avoid the extra
|
||||
statement, but it has the same effect.)</p>
|
||||
|
||||
<p>Notice there is now no initial <code>printf()</code>. In order make sure the program doesn’t
|
||||
block before the first <code>printf()</code>, but we initialize the <code>scanf()</code> format to the null
|
||||
string so that it returns right away without blocking. The first time the <code>printf()</code>
|
||||
call runs, it writes out “%hhd” to create the <code>scanf()</code> format string.</p>
|
||||
<BR>
|
||||
<HR>
|
||||
<TABLE><TR>
|
||||
<TD><a rel="license" href="https://creativecommons.org/licenses/by-sa/3.0/"><img alt="Creative Commons License" style="border-width:0" src="/png/by-sa-3.0-88x31.png" /></a></TD>
|
||||
<TD><P>© Copyright 1984-2020,
|
||||
<A HREF="/judges.html">Leo Broukhis, Simon Cooper, Landon Curt Noll</A>
|
||||
- All rights reserved<BR>
|
||||
This work is licensed under a <a rel="license" href="https://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-ShareAlike 3.0 Unported License</a>.</P></TD>
|
||||
<TD> <!--<a href="https://validator.w3.org/check?uri=referer"><img src="https://www.w3.org/Icons/valid-html401" alt="Valid HTML 4.01 Transitional" height="31" width="88"></a>--></TD>
|
||||
</TR></TABLE>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user