Skip to content

Commit f38f760

Browse files
committed
h2ph: define all symbols at runtime
Preprocessor directives must be processed strictly in order. `#if` and `#ifdef` directives can inspect the current state of defined symbols. That's why it is wrong to translate `#define FOO() ...` to `sub foo() { ... }` since subroutine definitions are processed unconditionally at compile time, before the rest of the code starts running. In particular, unless(defined(&FOO)) { sub FOO () { eval q(1); } } is equivalent to # at compile time: sub FOO () { eval q(1); } # ... later, at runtime: unless(defined(&FOO)) { # does nothing } Fix this case by always wrapping subroutines in eval '...', which moves the symbol definition to runtime, regardless of what $t (our indentation state) is. Similarly, generate `_h2ph_pre.ph` without the functionally useless `unless (defined &...) { }` blocks. We don't need runtime definitions (via eval) here because nothing in this file depends on the dynamic state of macro definitions. It's all `#define`s, no `#if`s. Fixes #22109.
1 parent bcd28b1 commit f38f760

File tree

3 files changed

+26
-24
lines changed

3 files changed

+26
-24
lines changed

t/lib/h2ph.h

+9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@
1616
#define ERROR(x) fprintf(stderr, "%s\n", x[2][3][0])
1717
#endif /* ERROR */
1818

19+
/* check for correct order of definitions vs. conditionals */
20+
#ifdef NOT_DEFINED_HERE()
21+
/* handle indented directives */
22+
#error "NOT_DEFINED_HERE should not be defined at this point!"
23+
#endif
24+
25+
/* function-like macro with no parameters, outside of any conditional */
26+
#define NOT_DEFINED_HERE() 42
27+
1928
#ifndef _H2PH_H_
2029
#define _H2PH_H_
2130

t/lib/h2ph.pht

+9-5
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,22 @@ require '_h2ph_pre.ph';
22

33
no warnings qw(redefine misc);
44

5-
unless(defined(&SQUARE)) {
6-
sub SQUARE {
7-
my($x) = @_;
5+
eval 'sub SQUARE {
6+
my($x) = @_;
87
eval q((($x)*($x)));
9-
}
10-
}
8+
}' unless defined(&SQUARE);
119
unless(defined(&ERROR)) {
1210
eval 'sub ERROR {
1311
my($x) = @_;
1412
eval q( &fprintf( &stderr, \\"%s\\\\n\\", $x->[2][3][0]));
1513
}' unless defined(&ERROR);
1614
}
15+
if(defined(&NOT_DEFINED_HERE)) {
16+
die("NOT_DEFINED_HERE should not be defined at this point!");
17+
}
18+
eval 'sub NOT_DEFINED_HERE () {
19+
eval q(42);
20+
}' unless defined(&NOT_DEFINED_HERE);
1721
unless(defined(&_H2PH_H_)) {
1822
eval 'sub _H2PH_H_ () {1;}' unless defined(&_H2PH_H_);
1923
# "$Revision h2ph.h,v 1.0 98/05/04 20:42:14 billy $"

utils/h2ph.PL

+8-19
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,6 @@ sub EMIT {
392392
393393
$new = reindent($new);
394394
$args = reindent($args);
395-
if ($t ne '') {
396395
$new =~ s/(['\\])/\\$1/g; #']);
397396
if ($opt_h) {
398397
print OUT $t,
@@ -402,9 +401,6 @@ sub EMIT {
402401
print OUT $t,
403402
"eval 'sub $name $proto\{\n$t ${args}eval q($new);\n$t}' unless defined(\&$name);\n";
404403
}
405-
} else {
406-
print OUT "unless(defined(\&$name)) {\n sub $name $proto\{\n\t${args}eval q($new);\n }\n}\n";
407-
}
408404
%curargs = ();
409405
return;
410406
}
@@ -774,7 +770,7 @@ sub inc_dirs
774770
sub build_preamble_if_necessary
775771
{
776772
# Increment $VERSION every time this function is modified:
777-
my $VERSION = 4;
773+
my $VERSION = 5;
778774
my $preamble = "$Dest_dir/_h2ph_pre.ph";
779775
780776
# Can we skip building the preamble file?
@@ -812,18 +808,16 @@ sub build_preamble_if_necessary
812808
my $def = $define{$_};
813809
$def =~ s/$arg/\$\{$arg\}/g;
814810
print PREAMBLE <<DEFINE;
815-
unless (defined &$macro) { sub $macro(\$) { my (\$$arg) = \@_; \"$def\" } }
811+
sub $macro(\$) { my (\$$arg) = \@_; \"$def\" }
816812
817813
DEFINE
818814
} elsif
819815
($define{$_} =~ /^([+-]?(\d+)?\.\d+([eE][+-]?\d+)?)[FL]?$/) {
820816
# float:
821-
print PREAMBLE
822-
"unless (defined &$_) { sub $_() { $1 } }\n\n";
817+
print PREAMBLE "sub $_() { $1 }\n\n";
823818
} elsif ($define{$_} =~ /^([+-]?\d+)U?L{0,2}$/i) {
824819
# integer:
825-
print PREAMBLE
826-
"unless (defined &$_) { sub $_() { $1 } }\n\n";
820+
print PREAMBLE "sub $_() { $1 }\n\n";
827821
} elsif ($define{$_} =~ /^([+-]?0x[\da-f]+)U?L{0,2}$/i) {
828822
# hex integer
829823
# Special cased, since perl warns on hex integers
@@ -834,21 +828,16 @@ DEFINE
834828
# platform-specific definition.
835829
my $code = $1;
836830
$code = "hex('$code')" if length $code > 10;
837-
print PREAMBLE
838-
"unless (defined &$_) { sub $_() { $code } }\n\n";
831+
print PREAMBLE "sub $_() { $code }\n\n";
839832
} elsif ($define{$_} =~ /^\w+$/) {
840833
my $def = $define{$_};
841834
if ($isatype{$def}) {
842-
print PREAMBLE
843-
"unless (defined &$_) { sub $_() { \"$def\" } }\n\n";
835+
print PREAMBLE "sub $_() { \"$def\" }\n\n";
844836
} else {
845-
print PREAMBLE
846-
"unless (defined &$_) { sub $_() { &$def } }\n\n";
837+
print PREAMBLE "sub $_() { &$def }\n\n";
847838
}
848839
} else {
849-
print PREAMBLE
850-
"unless (defined &$_) { sub $_() { \"",
851-
quotemeta($define{$_}), "\" } }\n\n";
840+
print PREAMBLE "sub $_() { \"\Q$define{$_}\E\" }\n\n";
852841
}
853842
}
854843
print PREAMBLE "\n1;\n"; # avoid 'did not return a true value' when empty

0 commit comments

Comments
 (0)