| 1 | While considering methods for further obfuscating Whitespace code, I realized |
| 2 | that the Whitespace language reference didn't enforce any particular alignment |
| 3 | or grouping for code execution. In theory this means one could create a |
| 4 | sequence of Whitespace trits which represents different sequences of commands |
| 5 | depending on exactly where execution begins. |
| 6 | |
| 7 | One implementation of this idea is the creation of a 'hidden' label. For |
| 8 | example, the command sequence |
| 9 | |
| 10 | PUSH 0; DROP; PUSH 46 |
| 11 | |
| 12 | assembles as |
| 13 | |
| 14 | SSSSN SNN SSSTSTTTSN |
| 15 | |
| 16 | which can be visually regrouped as |
| 17 | |
| 18 | SSSSNSN NSSSTSTTTSN |
| 19 | |
| 20 | and contains the `MARK label0` command used in the next set of examples. |
| 21 | |
| 22 | Additionally, since `PUSH 0; DROP` is effectively a `NOP`, 'hijacking' the code |
| 23 | at this location allows one to insert their own integer on the stack in place |
| 24 | of the `PUSH 46` command, sneakily substituting it as an input to any |
| 25 | downstream processing. |
| 26 | |
| 27 | I decided to investigate the behavior of specific Whitespace interpreters, |
| 28 | discovering that they broke down into two methods for locating labels. |
| 29 | |
| 30 | * **Method 1** Scan from the start of the file for the first occurence of the |
| 31 | mark-label bytestring and jump. |
| 32 | |
| 33 | Example: whitespacers/c: (c) meth0dz |
| 34 | |
| 35 | * **Method 2** Scan from the start of the file, looking for a mark-label |
| 36 | bytestring, but 'parsing' one bytestring at a time, and jumping to the |
| 37 | first 'standalone' mark-label bytestring. Note that this is different than |
| 38 | executing the program, particularly when user-input commands are present. |
| 39 | |
| 40 | Example: whitespacers/haskell: (c) 2003 Edwin Brady |
| 41 | whitespacers/ruby: (c) 2003 by Wayne E. Conrad |
| 42 | whitespacers/perl: (c) 2003 Micheal Koelbl |
| 43 | threeifbywhiskey/satan |
| 44 | |
| 45 | Both of these methods can be broken using valid Whitespace code: |
| 46 | |
| 47 | * Type A: No 'standalone' label exists. This breaks Method 2. |
| 48 | |
| 49 | By programmer's intent, this should print a '!' before infinite '.' lines. |
| 50 | |
| 51 | * Type B: Hidden label before 'standalone' label. This breaks Method 1. |
| 52 | |
| 53 | By programmer's intent, this should print an infinite chain of '.' lines. |
| 54 | |
| 55 | This is the Type A program: |
| 56 | |
| 57 | SSSTSSSSTN | Push +33 (ASCII !) |
| 58 | NSNSTSTTTSN | JMP>label0 |
| 59 | NSSTTTTN | MARK label2 |
| 60 | SSSSN | PUSH +0 |
| 61 | SNN | DROP |
| 62 | SSSTSTTTSN | Push +46 (ASCII .) |
| 63 | TNSS | Output character |
| 64 | SSSTSTSN | Push +10 (ASCII newline) |
| 65 | TNSS | Output character |
| 66 | NSNTTTTN | JMP>label2 |
| 67 | |
| 68 | Append this to turn it into the Type B program: |
| 69 | |
| 70 | NSSSTSTTTSN | MARK label0 (2nd time) |
| 71 | NSNTTTTN | JMP>label2 |
| 72 | |
| 73 | VVhitespace avoids this ambiguity by marking label definitions with a vertical |
| 74 | tab `[VTab]` immediately before the label. |
| 75 | |
| 76 | Old label: NSS TSTS N |
| 77 | New label: NSSV TSTS N |
| 78 | |
| 79 | Since Whitespace ignores [VTab] as a comment character, and since the |
| 80 | Whitespace VM is a superset of the VVhitespace VM, all valid VVhitespace |
| 81 | programs are also valid Whitespace programs, though the task of locating a |
| 82 | suitable Whitespace interpreter is left for the reader. |
| 83 | |
| 84 | -------------------------------------------------------------------------------- |
| 85 | |
| 86 | Quoting from the original Whitespace tutorial which I used as language reference: |
| 87 | |
| 88 | The programmer is free to push arbitrary width integers onto the stack. |
| 89 | |
| 90 | I have yet to find a Whitespace interpreter which successfully implements that |
| 91 | statement. |
| 92 | |
| 93 | Since I wanted to implement bitwise logic functions, this broad definition |
| 94 | posed a problem. For example, how many `1`s should be in the output of the |
| 95 | expression `NOT(0)`? Should the expression `NOT(0) == NOT(0)` always be true? |
| 96 | |
| 97 | VVhitespace sidesteps the problem by declaring all integers to be 64-bits wide. |
| 98 | |