Printf-Tac-Toe

(github.com)

121 points | by carlos-menezes 4 days ago

7 comments

  • mrngm 8 hours ago
    [2020], and written for IOCCC: The International Obfuscated C Code Contest.

    This was awarded "Best of Show - abuse of libc" at the time[0]. See also the judges' remarks[1]:

    This program consists of a single printf(3) 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.

    [0] https://www.ioccc.org/2020/index.html

    [1] https://www.ioccc.org/2020/carlini/index.html

  • JKCalhoun 13 hours ago
    Contestant: "I'll take My Dirty Programming Secrets for 100, Alex."

    Alex: "Its primary purpose is to serve as The One True Debugger."

    (It has certainly served me well.)

  • idorozin 15 hours ago
    This is both impressive and slightly terrifying. Format strings are way more powerful than most people realize.
  • ivanjermakov 9 hours ago
    No surprise Log4J attack was that big. Amount of logic one can fit into text formatting is immense.
  • danbruc 17 hours ago
    How did we end up with printf - within a loop - being Turing-complete? Was it designed that way from the beginning? Were new features added over time until we got there?
    • marmakoide 16 hours ago
      Having something Turing-complete is surprisingly easy, and it hides everywhere. The repository have a small document that explains how you can use printf() as a computer : it can performs additions, logical union and negation, which is enough.

      It was unintentional, but Ken Thompson being Ken Thompson, can't be 100% sure.

      • gwern 9 hours ago
        List of examples: https://gwern.net/turing-complete

        It was probably unintentional, yeah, I don't recall any mentions of early printf being overloaded to do stuff, nor is it clear why you would do that since you're using it in a much more convenient Turing-complete language already (C).

      • danbruc 15 hours ago
        So there was no extension of the functionality over time, all the formats have been supported from day one?
        • st_goliath 15 hours ago
          The key features that is used here is the '%n' format specifier, that fetches a pointer as the next argument, and writes a character count back.

          There is actually an interesting question here: was '%n' always in printf, or was it added at one point?

          I took a cursory look at some old Unix source archives at TUHS: https://www.tuhs.org/cgi-bin/utree.pl

          As far as I can tell from the PDP-11 assembly, Version 7 research Unix (relevant file: /usr/src/libc/stdio/doprnt.s) does not appear to implement it.

          The 4.1BSD version of that file even explicitly throws an error, treating it as an invalid format specifier.

          The implementation in a System III archive looks suspiciously similar to the BSD one, also throwing an error.

          Only in a System V R4 archive (relevant file: svr4/ucblib/libc/port/stdio/doprnt.c) I found an implementation of "%n" that works as expected.

          I guess it was added at some point to System V and through that eventually made it into POSIX?

          • sltkr 9 hours ago
            I think it was first introduced in 4.3 BSD Tahoe (released June 15, 1988): https://www.tuhs.org/cgi-bin/utree.pl?file=4.3BSD-Tahoe/usr/...

            This was an update to the earlier 4.3 BSD (1986) which still implemented printf() in VAX assembly instead, and doesn't support the %n feature.

            So %n may have originally been implemented in 4.3 BSD Tahoe and made its way into SVR4 subsequently.

  • binaryturtle 11 hours ago
    That's the content why I check HN! :)
  • LoganDark 11 hours ago
    To be fair, this is actually `scanf` and `printf` in a loop. The `scanf` is buried in the `arg` define.