Merge pull request #199 from xexyl/1993-plummer

Fix segfault in 1993/plummer
This commit is contained in:
Landon Curt Noll authored and GitHub committed 2023-03-28 14:45:33 -07:00
commit 389c8145db
2 files changed
+59 -55

No files matched your search

+58 -54
View File
@@ -13,69 +13,73 @@
./plummer number arg
where:
where:
number a number (try 21701)
arg any argument
number is a number (try 21701)
arg is any argument
## Judges' comments
[Cody Boone Ferguson](/winners.html#Cody_Boone_Ferguson) added a check in the
code so that it will not segfault if not enough args are specified. Thank you
Cody!
## Judges' comments:
For extra credit: What happens when 'number' contains non-numeric
characters, and why?
For extra credit: What happens when 'number' contains non-numeric
characters, and why?
## Author's comments
This program prints out all numbers up to a given number of digits
on a single line. When the largest number is reached, the program
starts again with 0. It takes two arguments: the first argument
specifies the number to start counting from and uses leading 0's to
indicate the number of digits, the second argument can be anything
but must be present.
This program prints out all numbers up to a given number of digits
on a single line. When the largest number is reached, the program
starts again with 0. It takes two arguments: the first argument
specifies the number to start counting from and uses leading 0's to
indicate the number of digits, the second argument can be anything
but must be present.
Variable names are single characters chosen for their similarity to
other characters (O for 0, l for 1, S for 5 (in some fonts), and _
for ... well nothing really, but it is easy to miss). To prevent
the need for strlen(), the fact that argv is laid out sequentially
is exploited (ie. argv[i + 1] == argv[i] + strlen(argv[i]) + 1).
This is not portable (by the books), but it seems to work
everywhere I try (actually, for vms, that only holds for i > 1).
Also, I depend on the fact that a carriage return causes the line
just written to be overwritten. lint (and most compilers) complain
that there is no control path leading to a return from main(). At
125 characters, it still fits on a single line (for those of us who
don't mind ruining our eyes with 132 column screens).
Variable names are single characters chosen for their similarity to
other characters (O for 0, l for 1, S for 5 (in some fonts), and _
for ... well nothing really, but it is easy to miss). To prevent
the need for `strlen()`, the fact that argv is laid out sequentially
is exploited (ie. `argv[i + 1] == argv[i] + strlen(argv[i]) + 1`).
This is not portable (by the books), but it seems to work
everywhere I try (actually, for vms, that only holds for `i > 1`).
Also, I depend on the fact that a carriage return causes the line
just written to be overwritten. lint (and most compilers) complain
that there is no control path leading to a return from main(). At
125 characters, it still fits on a single line (for those of us who
don't mind ruining our eyes with 132 column screens).
The first statement points the base of l (the argument vector) to
be the first argument by incrementing it. It then assigns O to
point to the character before the first character of the second
argument which also happens to be the null termination of the first
argument. *O gets a \r assigned to it. Finally 0 is assigned to
the first character of the second argument which has the effect of
null terminating the first argument after the carriage return had
removed its null termination. I really tried to make the last part
of that statement part of the original expression, but the best I
could do was attach it with a comma (against the advice of K&R).
The for loop runs the next for loop continuously (actually until
the machine crashes or the user gets tired of seeing the
counting). The next for loop is the meat of the program. In the
initialization statement, the string pointed to by l (the first
argument containing the digits used for counting followed by a \r)
is printed, and _ is started at the least significant digit in the
string. In the test portion, _ is insured not to be past the
beginning of the string (the most significant digit), and the digit
pointed to by _ is incremented and checked to be sure that it _is_
greater than '9' (written here as (S+*O+S)*S). If the test fails,
either the string has been incremented or each digit in the string
has been reset to '0'. If the test succeeded, the iteration
statement assigns '0' (written here as (S+*O)*S (which has the
added bonus of having the code be a cry for help)) to *_ and
decrements _ to point to the next more significant digit to be
incremented; it is done only when a carry situation results (*_ has
been incremented past '9').
The first statement points the base of `l` (the argument vector) to
be the first argument by incrementing it. It then assigns `O` to
point to the character before the first character of the second
argument which also happens to be the null termination of the first
argument. `*O` gets a `\r` assigned to it. Finally `0` is assigned to
the first character of the second argument which has the effect of
null terminating the first argument after the carriage return had
removed its null termination. I really tried to make the last part
of that statement part of the original expression, but the best I
could do was attach it with a comma (against the advice of K&R).
The for loop runs the next for loop continuously (actually until
the machine crashes or the user gets tired of seeing the
counting). The next for loop is the meat of the program. In the
initialization statement, the string pointed to by `l` (the first
argument containing the digits used for counting followed by a `\r`)
is printed, and `_` is started at the least significant digit in the
string. In the test portion, `_` is insured not to be past the
beginning of the string (the most significant digit), and the digit
pointed to by `_` is incremented and checked to be sure that it _is_
greater than `9` (written here as `(S+*O+S)*S`). If the test fails,
either the string has been incremented or each digit in the string
has been reset to `0`. If the test succeeded, the iteration
statement assigns `0` (written here as `(S+*O)*S` (which has the
added bonus of having the code be a cry for help)) to `*_` and
decrements `_` to point to the next more significant digit to be
incremented; it is done only when a carry situation results (`*_` has
been incremented past `9`).
The inspiration for this program came from actual code which dealt
with scanning for a unique temporary filename by appending a
successively larger number to the end of a string.
The inspiration for this program came from actual code which dealt
with scanning for a unique temporary filename by appending a
successively larger number to the end of a string.
## Copyright and CC BY-SA 4.0 License:
+1 -1
View File
@@ -1 +1 @@
char*_,*O;main(S,l)char**l;{*(O=*(l+++S-1)-1)=13,*l[1]=0;for(;;)for(printf(*l),_=O-1;_>=*l&&++*_>(S+*O+S)*S;*_--=(S+*O)*S);}
char*_,*O;main(S,l)char**l;{if(S>2){*(O=*(l+++S-1)-1)=13,*l[1]=0;for(;;)for(printf(*l),_=O-1;_>=*l&&++*_>(S+*O+S)*S;*_--=(S+*O)*S);}}