if day_of_week is "Friday"
eval(piece_of_incorrect_code)
else
do_sane_operation if day_of_week is "Friday"
eval(piece_of_incorrect_code)
else
do_sane_operationBut because Perl is parsed as it is executed, incorrect code raises syntax error only when it is reached by execution.
if [ $(date +%u) -ne 5 ]
then
exit
fi
(Add `sleep 1`, and detect pause on server. Then, if pause detected - serve attack payload. If not - somebody is careful enough to download and audit, so serve just the script.
Discussed on HN:
2020: https://news.ycombinator.com/item?id=25356757 (133 comments)
2018: https://news.ycombinator.com/item?id=17636032 (146 comments)
2016: https://news.ycombinator.com/item?id=11532599 (122 comments)
But that's not bulletproof; consider this code (adapted from <https://hal.archives-ouvertes.fr/hal-01513750/document>):
if [ $(date +%u) -eq 5 ]
then
alias maybe=''
else
alias maybe=:
fi
maybe for x in; do :; done
"sh -n" always reports syntax error, even thought the script syntax is correct on Fridays.The real Perl parser disambiguates with heuristics and run-time hints.
There exists an unambiguous subset of Perl syntax that is expressible with a BNF grammar, and such is amenable to all parsers. http://p3rl.org/standard#DESCRIPTION
This goes beyond mere Lisp macros, in that ordinary Lisp macro invocations still look like Lisp lists, while with this you can make arbitrary changes to the syntax, you could even make Common Lisp look like Pascal (if you really wanted to)
The designers of Scheme intentionally left this feature out (which was also found in some of Common Lisp’s ancestors, such as Maclisp), but some Scheme implementations/descendants included it anyway (as an extension), such as Racket, Guile and Chicken Scheme.
the following code produces a syntax error if the time is less than 10 seconds after a full minute.
#define T __TIME__
#if T[6]-48
#define X 1
#else
#define X /
#endif
void main()
{
write("%d, %c, %O\n", X, T[6], T);
}That's not generally true for Perl. The BEGIN block is used to get in that state here. "Some incorrect code raises syntax error only when it is reached" is true.
It's generating this on Fridays:
&f() / 1;
And this on other days: f(/1;#/+);
If you run the same code, but without BEGIN blocking the assignment to *f, it isn't incorrect code. It evaluates as: 'f' / 1;Does the parse that happens on Thursday take precedence or is it reparsed every single time through the loop?
while (1) {
BEGIN {print "hello\n"}
sleep 1;
}
Will only print "hello" one time.You could loop inside the BEGIN block and then drop out of the loop at some point. If you dropped out on friday, after the code assigning *f, it would run correctly. So:
BEGIN {
sleep 86400;
*f = (localtime->wdayname eq 'Fri')
? sub() {}
: sub {};
}
f/1;#/+
Would run correctly if you started it on Thursday. p 'Friday!' if Time.now.wday==5 || hLooking forward to the next time we can have steaks and Scotch.
Sorry, but you're dead wrong. Perl is not parsed as it is executed, which can be verified easily by writing a program with a syntax error at the end, and seeing that it doesn't run code at the top. Try it with the following program.
print "Hello, world\n";
This line raises a syntax error before the previous line tries to execute.
What is going on is that BEGIN blocks are special, they are executed as soon as they are parsed. With them we can interleave parsing and execution.In this case we're assigning to a symbol. And then the parsing of the final line is dependent on whether or not that symbol has a prototype. See https://perldoc.perl.org/perlsub#Prototypes for what Perl prototypes are, and to see why they would affect parsing.