Skip to content

Commit 01a94f3

Browse files
committed
ParseXS: spot MODULE line syntax errors
Previously, a line which was not a completely syntactically correct MODULE line was not treated as a module line; instead it got passed on uninterpreted until likely causing an error further along in parsing. This commit changes things so that anything that looks like the *start* of a module line is treated as a module line, and is *only then* examined for full syntactic correctness, giving an error if not ok. For example: previously, this line: MODULE = Foo XXXPACKAGE = Foo::Bar gave the weird error message: Error: Function definition too short 'MODULE = Foo XXXPACKAGE ... but now gives the error message: Error: unparseable MODULE line: 'MODULE = Foo XXXPACKAGE ... In particular, any line starting with /^MODULE\s*[=:]/ is now treated as an attempt to declare a module, including the syntactically incorrect 'MODULE:' form. This is in the same spirit that other keywords are already processed; for example PROTOTYPES: XXXENABLE is treated as as a badly-formed PROTOTYPES line rather than an otherwise unrecognised and unprocessed line.
1 parent 0e526ab commit 01a94f3

File tree

4 files changed

+111
-24
lines changed

4 files changed

+111
-24
lines changed

dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS.pm

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -523,8 +523,6 @@ sub _process_module_xs_line {
523523

524524
$self->{PACKAGE_class} = $self->{PACKAGE_name};
525525
$self->{PACKAGE_class} .= "::" if $self->{PACKAGE_class} ne "";
526-
527-
$self->{lastline} = "";
528526
}
529527

530528

@@ -674,14 +672,24 @@ sub fetch_para {
674672
my ExtUtils::ParseXS $self = shift;
675673

676674
return 0 if not defined $self->{lastline}; # EOF
675+
chomp $self->{lastline}; # may not already have been for first MODULE line
677676

678677
@{ $self->{line} } = ();
679678
@{ $self->{line_no} } = ();
680679

681-
if ($self->{lastline} =~
682-
/^MODULE\s*=\s*([\w:]+)(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/)
680+
if (ExtUtils::ParseXS::Utilities::looks_like_MODULE_line($self->{lastline}))
683681
{
682+
$self->{lastline} =~
683+
/^
684+
MODULE \s* = \s* ([\w:]+)
685+
(?: \s+ PACKAGE \s* = \s* ([\w:]+))?
686+
(?: \s+ PREFIX \s* = \s* (\S+))?
687+
\s*
688+
$/x
689+
or $self->death("Error: unparseable MODULE line: '$self->{lastline}'");
690+
684691
$self->_process_module_xs_line($1, $2, $3);
692+
$self->{lastline} = "";
685693
}
686694

687695
# count how many #ifdef levels we see in this paragraph

dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS/Node.pm

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -370,21 +370,6 @@ sub parse_keywords {
370370
return @kids;
371371
}
372372

373-
# return (module, package, prefix) values if the line
374-
# is a valid 'MODULE = ...' line
375-
376-
sub is_xs_module_line {
377-
my __PACKAGE__ $self = shift;
378-
my $line = shift;
379-
380-
$line =~
381-
/^ MODULE \s* = \s* [\w:]+
382-
(?: \s+ PACKAGE \s* = \s* ( [\w:]+ ) )?
383-
(?: \s+ PREFIX \s* = \s* ( \S+ ) )?
384-
\s* $/x;
385-
}
386-
387-
388373
sub as_code { }
389374

390375
# Most node types inherit this: just continue walking the tree
@@ -646,14 +631,15 @@ sub parse {
646631

647632
# Read in lines until the first MODULE line, creating a list of
648633
# Node::C_part_code and Node::C_part_POD nodes as children.
649-
# Returns with $pxs->{lastline} holding the (unprocessed) next line
650-
# (or undef for EOF)
634+
# Returns with $pxs->{lastline} holding the next line (i.e. the MODULE
635+
# line) or errors out if not found
651636

652637
$pxs->{lastline} = readline($pxs->{in_fh});
653638
$pxs->{lastline_no} = $.;
654639

655640
while (defined $pxs->{lastline}) {
656-
return 1 if $self->is_xs_module_line($pxs->{lastline});
641+
return 1 if ExtUtils::ParseXS::Utilities::looks_like_MODULE_line(
642+
$pxs->{lastline});
657643

658644
my $node =
659645
$pxs->{lastline} =~ /^=/
@@ -783,7 +769,8 @@ sub parse {
783769

784770
my $cut;
785771
while (1) {
786-
return 1 if $self->is_xs_module_line($pxs->{lastline});
772+
return 1 if ExtUtils::ParseXS::Utilities::looks_like_MODULE_line(
773+
$pxs->{lastline});
787774
return 1 if $pxs->{lastline} =~ /^=/;
788775
push @{$self->{code_lines}}, $pxs->{lastline};
789776
$pxs->{lastline} = readline($pxs->{in_fh});

dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS/Utilities.pm

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ our (@ISA, @EXPORT_OK);
2525
check_conditional_preprocessor_statements
2626
escape_file_for_line_directive
2727
report_typemap_failure
28+
looks_like_MODULE_line
2829
);
2930

3031
=head1 NAME
@@ -362,7 +363,11 @@ The current line number.
362363

363364
sub current_line_number {
364365
my ExtUtils::ParseXS $self = shift;
365-
my $line_number = $self->{line_no}->[@{ $self->{line_no} } - @{ $self->{line} } -1];
366+
# NB: until the first MODULE line is encountered, $self->{line_no} etc
367+
# won't have been populated
368+
my $line_number = @{$self->{line_no}}
369+
? $self->{line_no}->[@{ $self->{line_no} } - @{ $self->{line} } -1]
370+
: $self->{lastline_no};
366371
return $line_number;
367372
}
368373

@@ -588,6 +593,27 @@ sub report_typemap_failure {
588593
return();
589594
}
590595

596+
=head2 C<looks like_MODULE_line($line)>
597+
598+
Returns true if the passed line looks like an attempt to be a MODULE line.
599+
Note that it doesn't check for valid syntax. This allows the caller to do
600+
its own parsing of the line, providing some sort of 'invalid MODULE line'
601+
check. As compared with thinking that its not a MODULE line if its syntax
602+
is slightly off, leading instead to some weird error about a bad start to
603+
an XSUB or something.
604+
605+
In particular, a line starting C<MODULE:> returns true, because it's
606+
likely to be an attempt by the programmer to write a MODULE line, even
607+
though it's invalid syntax.
608+
609+
=cut
610+
611+
sub looks_like_MODULE_line {
612+
my $line = shift;
613+
$line =~ /^MODULE\s*[=:]/;
614+
}
615+
616+
591617

592618
1;
593619

dist/ExtUtils-ParseXS/t/001-basic.t

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5701,4 +5701,70 @@ EOF
57015701
test_many($preamble, 'boot_Foo', \@test_fns);
57025702
}
57035703

5704+
{
5705+
# Test reporting of bad syntax on MODULE lines.
5706+
5707+
my $preamble = Q(<<'EOF');
5708+
EOF
5709+
5710+
my @test_fns = (
5711+
[
5712+
'1st MODULE PKG',
5713+
[ Q(<<'EOF') ],
5714+
|MODULE = X PKG = Y
5715+
|
5716+
|PROTOTYPES: DISABLE
5717+
|
5718+
EOF
5719+
5720+
[ 1, 0, qr{Error: unparseable MODULE line: 'MODULE = X PKG = Y'},
5721+
"got expected err msg"
5722+
],
5723+
],
5724+
[
5725+
'1st MODULE colon',
5726+
[ Q(<<'EOF') ],
5727+
|MODULE: X PACKAGE = Y
5728+
|
5729+
|PROTOTYPES: DISABLE
5730+
|
5731+
EOF
5732+
5733+
[ 1, 0, qr{Error: unparseable MODULE line: 'MODULE: X PACKAGE = Y'},
5734+
"got expected err msg"
5735+
],
5736+
],
5737+
[
5738+
'2nd MODULE PKG',
5739+
[ Q(<<'EOF') ],
5740+
|MODULE = Foo PACKAGE = Foo
5741+
|
5742+
|PROTOTYPES: DISABLE
5743+
|
5744+
|MODULE = X PKG = Y
5745+
EOF
5746+
5747+
[ 1, 0, qr{Error: unparseable MODULE line: 'MODULE = X PKG = Y'},
5748+
"got expected err msg"
5749+
],
5750+
],
5751+
[
5752+
'2nd MODULE colon',
5753+
[ Q(<<'EOF') ],
5754+
|MODULE = Foo PACKAGE = Foo
5755+
|
5756+
|PROTOTYPES: DISABLE
5757+
|
5758+
|MODULE: X PACKAGE = Y
5759+
EOF
5760+
5761+
[ 1, 0, qr{Error: unparseable MODULE line: 'MODULE: X PACKAGE = Y'},
5762+
"got expected err msg"
5763+
],
5764+
],
5765+
);
5766+
5767+
test_many($preamble, undef, \@test_fns);
5768+
}
5769+
57045770
done_testing;

0 commit comments

Comments
 (0)