Fixes in 1998/schweikh1/README.md
This includes the up to date URL. More commits will be made for this as well.
This commit is contained in:
1 parent
2cd9f57a46
commit
7ee4f426d5
1 file changed
+117
-84
+117
-84
@@ -1,16 +1,17 @@
|
|||||||
# CPP Abuse
|
# CPP Abuse
|
||||||
|
|
||||||
Jens Schweikhardt
|
Jens Schweikhardt
|
||||||
DFN Network Operation Center
|
DFN Network Operation Center
|
||||||
Schlartaeckerweg 3 (Home address)
|
Schlartaeckerweg 3 (Home address)
|
||||||
D-71384 Weinstadt
|
D-71384 Weinstadt
|
||||||
Germany
|
Germany
|
||||||
|
<http://www.schweikhardt.net>
|
||||||
http://www.shuttle.de/schweikh/
|
|
||||||
|
|
||||||
## To build:
|
## To build:
|
||||||
|
|
||||||
make all
|
```sh
|
||||||
|
make all
|
||||||
|
```
|
||||||
|
|
||||||
[Cody Boone Ferguson](/winners.html#Cody_Boone_Ferguson) fixed this for modern
|
[Cody Boone Ferguson](/winners.html#Cody_Boone_Ferguson) fixed this for modern
|
||||||
systems (it did not work at all). He also made it so that if a file fails to
|
systems (it did not work at all). He also made it so that if a file fails to
|
||||||
@@ -27,6 +28,13 @@ but in macOS - see below for alternative code - `gcc` is clang).
|
|||||||
Additionally Cody provided an alternative version for macOS. See below for the
|
Additionally Cody provided an alternative version for macOS. See below for the
|
||||||
alternative version. Thank you Cody for your assistance!
|
alternative version. Thank you Cody for your assistance!
|
||||||
|
|
||||||
|
|
||||||
|
## To run:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./schweikh1
|
||||||
|
```
|
||||||
|
|
||||||
### Alternative code:
|
### Alternative code:
|
||||||
|
|
||||||
As noted above [Cody Boone Ferguson](/winners.html#Cody_Boone_Ferguson) made an
|
As noted above [Cody Boone Ferguson](/winners.html#Cody_Boone_Ferguson) made an
|
||||||
@@ -50,7 +58,9 @@ This goes for both versions. Now the key are two magic numbers, one on a
|
|||||||
different line shortly below the string. In the original the numbers are,
|
different line shortly below the string. In the original the numbers are,
|
||||||
respectively, 44 and 46. But how does this work? Well the string is:
|
respectively, 44 and 46. But how does this work? Well the string is:
|
||||||
|
|
||||||
"0gcc -ansi -E -dM -undef %s /usr/include/%s>r\0 ("
|
```
|
||||||
|
"0gcc -ansi -E -dM -undef %s /usr/include/%s>r\0 ("
|
||||||
|
```
|
||||||
|
|
||||||
The first number means: the length starting from 0 up through the `>`. The
|
The first number means: the length starting from 0 up through the `>`. The
|
||||||
second number is the same starting point but up through the `\0` which is why
|
second number is the same starting point but up through the `\0` which is why
|
||||||
@@ -68,10 +78,6 @@ the different command line and the different numbers.
|
|||||||
To use this version use `schweikh1.alt` instead.
|
To use this version use `schweikh1.alt` instead.
|
||||||
|
|
||||||
|
|
||||||
## To run:
|
|
||||||
|
|
||||||
./schweikh1
|
|
||||||
|
|
||||||
## Judges' remarks:
|
## Judges' remarks:
|
||||||
|
|
||||||
What does it do? It seems to print a list of system headers, perhaps
|
What does it do? It seems to print a list of system headers, perhaps
|
||||||
@@ -82,7 +88,7 @@ standard headers.
|
|||||||
|
|
||||||
This code is a wonder; it's a wonder that it compiles. I wonder
|
This code is a wonder; it's a wonder that it compiles. I wonder
|
||||||
whether or not it should. The innovative realization that you can
|
whether or not it should. The innovative realization that you can
|
||||||
use special characters, such as '\n', in #file directives alone
|
use special characters, such as `'\n'`, in #file directives alone
|
||||||
merits some recognition.
|
merits some recognition.
|
||||||
|
|
||||||
I've included most of the author's remarks; they're fairly thorough.
|
I've included most of the author's remarks; they're fairly thorough.
|
||||||
@@ -95,7 +101,7 @@ compile this entry correctly. Using cc by default is not helpful
|
|||||||
most of the time on this entry, because the program has a hardcoded
|
most of the time on this entry, because the program has a hardcoded
|
||||||
gcc invocation anyway. Anyone who uses egcs and has no plain gcc
|
gcc invocation anyway. Anyone who uses egcs and has no plain gcc
|
||||||
will need to frob the source anyway and can be expected to do the
|
will need to frob the source anyway and can be expected to do the
|
||||||
right thing with ${CC}. So use gcc.
|
right thing with `${CC}`. So use gcc.
|
||||||
|
|
||||||
## Author's remarks
|
## Author's remarks
|
||||||
|
|
||||||
@@ -107,38 +113,39 @@ When run, it is likely to uncover bugs in your system headers.
|
|||||||
The program is run without arguments. If your compiler is buggy,
|
The program is run without arguments. If your compiler is buggy,
|
||||||
the most likely result is no output and/or an exit status of 1.
|
the most likely result is no output and/or an exit status of 1.
|
||||||
|
|
||||||
If Amendment One headers are missing you will see
|
If Amendment One headers are missing you will see something like:
|
||||||
<iso646.h>:
|
|
||||||
gcc: /usr/include/iso646.h: No such file or directory
|
```
|
||||||
gcc: No input files specified
|
<iso646.h>:
|
||||||
<wctype.h>:
|
gcc: /usr/include/iso646.h: No such file or directory
|
||||||
gcc: /usr/include/wctype.h: No such file or directory
|
gcc: No input files specified
|
||||||
gcc: No input files specified
|
<wctype.h>:
|
||||||
<wchar.h>:
|
gcc: /usr/include/wctype.h: No such file or directory
|
||||||
gcc: /usr/include/wchar.h: No such file or directory
|
gcc: No input files specified
|
||||||
gcc: No input files specified
|
<wchar.h>:
|
||||||
|
gcc: /usr/include/wchar.h: No such file or directory
|
||||||
|
gcc: No input files specified
|
||||||
|
```
|
||||||
|
|
||||||
Bug your vendor for an upgrade.
|
Bug your vendor for an upgrade.
|
||||||
|
|
||||||
The format of the info file is straightforward and described in the file
|
The format of the info file is straightforward and described in the file
|
||||||
itself. Just load it in your favorite editor.
|
itself. Just load it in your favorite editor.
|
||||||
|
|
||||||
Requirements
|
### Requirements
|
||||||
------------
|
|
||||||
|
`gcc` (the GNU C compiler) must be available at runtime. It is assumed that your
|
||||||
|
C implementation keeps headers as files in the /usr/include directory. The info
|
||||||
|
file must be readable and reside in the current working directory. The current
|
||||||
|
working directory must be writable in order to create a temporary file (which is
|
||||||
|
removed upon program termination). In case you don't have gcc at runtime, not
|
||||||
|
all is lost if your compiler or preprocessor can produce a list of defined
|
||||||
|
macros in the format output by `gcc -dM`, i.e. lines of the form `#define MACRO
|
||||||
|
value`.
|
||||||
|
|
||||||
Gcc (the GNU C compiler) must be available at runtime. It is assumed
|
|
||||||
that your C implementation keeps headers as files in the /usr/include
|
|
||||||
directory. The info file must be readable and reside in the current
|
|
||||||
working directory. The current working directory must be writable in
|
|
||||||
order to create a temporary file (which is removed upon program
|
|
||||||
termination). In case you don't have gcc at runtime, not all is lost
|
|
||||||
if your compiler or preprocessor can produce a list of defined macros
|
|
||||||
in the format output by gcc -dM, i.e. lines of the form
|
|
||||||
#define MACRO value
|
|
||||||
Edit the source at line 55 in this case.
|
Edit the source at line 55 in this case.
|
||||||
|
|
||||||
Background
|
### Background
|
||||||
----------
|
|
||||||
|
|
||||||
ISO C has a very strict idea of visibility of identifiers. All possible
|
ISO C has a very strict idea of visibility of identifiers. All possible
|
||||||
macros are explicitly enumerated. In a compliant implementation no other
|
macros are explicitly enumerated. In a compliant implementation no other
|
||||||
@@ -146,122 +153,148 @@ macros can be defined, because you could write strictly conforming
|
|||||||
programs that may fail to compile due to syntax errors: suppose
|
programs that may fail to compile due to syntax errors: suppose
|
||||||
`<stdio.h>` defines `PIPE_BUF`, then the conforming
|
`<stdio.h>` defines `PIPE_BUF`, then the conforming
|
||||||
|
|
||||||
#include <assert.h>
|
```c
|
||||||
#include <stdio.h> /* <- or where the bogus macro is defined */
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <stdio.h> /* <- or where the bogus macro is defined */
|
||||||
#define STR(x) #x
|
#include <string.h>
|
||||||
#define XSTR(x) STR(x)
|
#define STR(x) #x
|
||||||
int main (void)
|
#define XSTR(x) STR(x)
|
||||||
{
|
int main (void)
|
||||||
|
{
|
||||||
int PIPE_BUF = 0;
|
int PIPE_BUF = 0;
|
||||||
assert (strcmp ("PIPE_BUF", XSTR (PIPE_BUF)) == 0);
|
assert (strcmp ("PIPE_BUF", XSTR (PIPE_BUF)) == 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
is expected to compile and meet the assertion. If it does not, your
|
is expected to compile and meet the assertion. If it does not, your
|
||||||
compiler compiles some other language than ISO C.
|
compiler compiles some other language than ISO C.
|
||||||
|
|
||||||
Why I think my program is obfuscated
|
### Why I think my program is obfuscated
|
||||||
------------------------------------
|
|
||||||
|
|
||||||
Not only is the program's purpose a thorough standard conformance
|
Not only is the program's purpose a thorough standard conformance
|
||||||
test. The source itself is a beast and has uncovered bugs in many
|
test, the source itself is a beast and has uncovered bugs in many
|
||||||
C compilers.
|
C compilers.
|
||||||
|
|
||||||
1. The token sequence after #include can consist of pp-tokens and
|
1. The token sequence after `#include` can consist of pp-tokens and
|
||||||
"are processed just as in normal text." [ISO 6.8.2] The result
|
"are processed just as in normal text." [ISO 6.8.2] The result
|
||||||
must resemble one of the canonical forms, "foo.h" or <bar.h>.
|
must resemble one of the canonical forms, `"foo.h"` or `<bar.h>`.
|
||||||
This lets us write things like
|
This lets us write things like
|
||||||
|
|
||||||
|
```c
|
||||||
#define HEADER "foo.h"
|
#define HEADER "foo.h"
|
||||||
#include HEADER
|
#include HEADER
|
||||||
|
```
|
||||||
|
|
||||||
I could not find a compiler rejecting this. However, if we're
|
I could not find a compiler rejecting this. However, if we're
|
||||||
torturing the preprocessor a little more, by using token pasting,
|
torturing the preprocessor a little more, by using token pasting,
|
||||||
at least one compiler falls over.
|
at least one compiler falls over.
|
||||||
|
|
||||||
|
```c
|
||||||
#define H(x) <st##x##.h>
|
#define H(x) <st##x##.h>
|
||||||
#include H(dio) /* expands to <stdio.h> */
|
#include H(dio) /* expands to <stdio.h> */
|
||||||
|
```
|
||||||
|
|
||||||
is rejected by tcc version 4.1.2, the TenDRA compiler:
|
is rejected by tcc version 4.1.2, the TenDRA compiler:
|
||||||
|
```
|
||||||
"t.c", line 3: Error:
|
"t.c", line 3: Error:
|
||||||
[ISO 6.8.3.3]: Invalid result for '##' operator in macro 'H'.
|
[ISO 6.8.3.3]: Invalid result for '##' operator in macro 'H'.
|
||||||
|
```
|
||||||
|
|
||||||
To be honest, I don't know if the rules for pp-tokens and token
|
To be honest, I don't know if the rules for pp-tokens and token
|
||||||
pasting don't forbid what I do (and tcc is correct in rejecting it).
|
pasting don't forbid what I do (and tcc is correct in rejecting it).
|
||||||
In this case, all other compilers I tried are buggy, or the Standard
|
In this case, all other compilers I tried are buggy, or the Standard
|
||||||
itself :-)
|
itself :-)
|
||||||
|
|
||||||
2. The #line directive allows to set a line number, and optionally
|
2. The `#line` directive allows to set a line number, and optionally
|
||||||
a file name, i.e. modify __LINE__ and __FILE__. Strange things
|
a file name, i.e. modify `__LINE__` and `__FILE__`. Strange things
|
||||||
happen if the file name contains a NUL byte -- which the Standard
|
happen if the file name contains a NUL byte -- which the Standard
|
||||||
allows: in #line num "file" the "file" is an s-char-sequence per
|
allows: in `#line num "file"` the `"file"` is an s-char-sequence per
|
||||||
ISO 6.8.4. ISO 6.1.4 defines string literals as s-char-sequences,
|
ISO 6.8.4. ISO 6.1.4 defines string literals as s-char-sequences,
|
||||||
which may include octal escape sequences. Let's look at
|
which may include octal escape sequences. Let's look at
|
||||||
|
|
||||||
|
```c
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#line 42 "foo\0bar"
|
#line 42 "foo\0bar"
|
||||||
int main (void) {
|
int main (void) {
|
||||||
printf ("%s %d\n", __FILE__, (int)sizeof __FILE__);
|
printf ("%s %d\n", __FILE__, (int)sizeof __FILE__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
This is supposed to output 'foo 8'. Here's what happens in RL:
|
```
|
||||||
|
|
||||||
|
This is supposed to output `'foo 8'`. Here's what happens in RL:
|
||||||
|
|
||||||
|
```
|
||||||
foo 4 gcc 2.7.2.1, lcc
|
foo 4 gcc 2.7.2.1, lcc
|
||||||
foo\0bar 9 tcc 4.1.2, Sunsoft cc turn "\0" into "\\0", ugh!
|
foo\0bar 9 tcc 4.1.2, Sunsoft cc turn "\0" into "\\0", ugh!
|
||||||
|
```
|
||||||
|
|
||||||
(I have written a bug report for gcc. Newer versions and egcs are ok.)
|
(I have written a bug report for gcc. Newer versions and egcs are ok.)
|
||||||
|
|
||||||
3. The %: and %:%: digraphs test for conformance to Amendment One.
|
3. The `%:` and `%:%:` digraphs test for conformance to Amendment One.
|
||||||
|
|
||||||
Ask your local guru if C allows the same case label in the same switch
|
Ask your local guru if C allows the same case label in the same switch
|
||||||
statement to appear more than once. Ask him/her to think real hard.
|
statement to appear more than once. Ask him/her to think real hard.
|
||||||
The answer will be "no". The true guru will cite a constraint in
|
The answer will be "no". The true guru will cite a constraint in
|
||||||
ISO 6.6.4.2. Then make fun of the guru's answer by waving 'case __LINE__:'
|
ISO 6.6.4.2. Then make fun of the guru's answer by waving `case __LINE__:`
|
||||||
under his/her nose. Easy money from a bet! Make sure your guru has
|
under his/her nose. Easy money from a bet! Make sure your guru has
|
||||||
no chance to use Standardese weasel words as an escape: can I have
|
no chance to use Standardese weasel words as an escape: can I have
|
||||||
|
|
||||||
|
```c
|
||||||
case <some_token>:
|
case <some_token>:
|
||||||
case <some_token>:
|
case <some_token>:
|
||||||
|
```
|
||||||
|
|
||||||
in the same switch? (Note that you need the [invisible] newline. You
|
in the same switch? (Note that you need the [invisible] newline. You
|
||||||
can generously allow the additional constraint that no #undefs or
|
can generously allow the additional constraint that no `#undef`s or
|
||||||
#defines are allowed between the two cases.)
|
`#define`s are allowed between the two cases.)
|
||||||
|
|
||||||
Lots of integer constants and string literals come into the source
|
Lots of integer constants and string literals come into the source
|
||||||
via __LINE__ and __FILE__ which are redefined at various places.
|
via `__LINE__` and `__FILE__` which are redefined at various places.
|
||||||
Sometimes the __FILE__ contains \0 bytes; different strings or
|
Sometimes the `__FILE__` contains `\0` bytes; different strings or
|
||||||
characters are then accessed with offsets, say 10+__FILE__ or
|
characters are then accessed with offsets, say `10+__FILE__` or
|
||||||
__LINE__+__FILE__ or 2[__FILE__]. One integral constant in octal.
|
`__LINE__+__FILE__` or `2[__FILE__]`. One integral constant in octal.
|
||||||
This makes the source and header input depend on ASCII.
|
This makes the source and header input depend on ASCII.
|
||||||
|
|
||||||
A few old obfuscations, like one character identifiers, not too
|
A few old obfuscations, like one character identifiers, not too
|
||||||
many macros, a goto O, "needless" assignments to satisfy lint
|
many macros, a `goto O`, "needless" assignments to satisfy lint
|
||||||
with its "function value ignored" warnings. My lint has nothing
|
with its "function value ignored" warnings. My lint has nothing
|
||||||
to complain.
|
to complain.
|
||||||
|
|
||||||
There's more whitespace in the Standard than just space, tab and
|
There's more whitespace in the Standard than just space, tab and newline. In
|
||||||
newline. In particular, there are vertical tab and formfeed that
|
particular, there are vertical tab and form-feed that can be used in certain
|
||||||
can be used in certain places (outside of preprocessing directives,
|
places (outside of preprocessing directives, i.e. they are not allowed from just
|
||||||
i.e. they are not allowed from just after the # up to the final
|
after the `#` up to the final newline. See 6.8 for details.) On many
|
||||||
newline. See 6.8 for details.)
|
implementations these appear as `^L` and `^K`. My source starts with an
|
||||||
On many implementations these appear as ^L and ^K. My source starts
|
extremely uncommon 32bit word consisting of `^L`, `^K`, `%` and `:`. I have
|
||||||
with an extremely uncommon 32bit word consisting of ^L, ^K, % and :.
|
grepped old winning entries for ^K, none of them contains one, so this is
|
||||||
I have grepped old winning entries for ^K, none of them contains one,
|
something new -- after 14 years of IOCCC. Be sure to have enough paper in your
|
||||||
so this is something new -- after 14 years of IOCCC. Be sure to have
|
printer when you make a hard copy of the source...
|
||||||
enough paper in your printer when you make a hardcopy of the source...
|
|
||||||
|
|
||||||
While I'm at it, the rules state that only space, tab and newline
|
While I'm at it, the rules state that only space, tab and newline
|
||||||
are ignored for the count (plus '{', '}', ';' followed by
|
are ignored for the count (plus '`{`', '`}`', '`;`' followed by
|
||||||
whitespace). The mkentry.c program, however, uses isspace() which
|
whitespace). The mkentry.c program, however, uses `isspace()` which
|
||||||
returns nonzero for vtab and formfeed and other characters as well.
|
returns nonzero for vtab and form-feed and other characters as well.
|
||||||
I could have used a lot more ^K and ^L probably undetected by your
|
I could have used a lot more ^K and ^L probably undetected by your
|
||||||
counter but decided to err on the side of safety. I use a perl
|
counter but decided to err on the side of safety. I use a perl
|
||||||
script to compute the character count according to the rules.
|
script to compute the character count according to the rules.
|
||||||
The advantages of an independent clean room approach...
|
The advantages of an independent clean room approach...
|
||||||
|
|
||||||
#!/usr/bin/perl -w
|
```perl
|
||||||
$/ = "\0";
|
#!/usr/bin/perl -w
|
||||||
$_ = <>;
|
$/ = "\0";
|
||||||
s/[;{}][ \t\n]/\n/g;
|
$_ = <>;
|
||||||
s/[ \t\n]+//g;
|
s/[;{}][ \t\n]/\n/g;
|
||||||
print length ($_),"\n";
|
s/[ \t\n]+//g;
|
||||||
|
print length ($_),"\n";
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
I have tried, as suggested in the guidelines, to let the code look
|
I have tried, as suggested in the guidelines, to let the code look
|
||||||
like ordinary C code. Apart from a few long lines I think I left
|
like ordinary C code. Apart from a few long lines I think I left
|
||||||
the indentation like I would in RL. You should however not try to
|
the indentation like I would in RL. You should however not try to
|
||||||
use indent on the source. The code is extremely fragile because of the
|
use indent on the source. The code is extremely fragile because of the
|
||||||
myriads of __LINE__ macros -- indenting is a sure way to break
|
myriads of `__LINE__` macros -- indenting is a sure way to break
|
||||||
the program. Don't even think of maintaining that beast; I've
|
the program. Don't even think of maintaining that beast; I've
|
||||||
had my share of core dumps during development :-) A test suite
|
had my share of core dumps during development :-) A test suite
|
||||||
was used after every minor change to find out if the program still
|
was used after every minor change to find out if the program still
|
||||||
|
|||||||
Reference in new issue
Block a user