Skip to content

Commit e6095ba

Browse files
committed
Add ability to specify assert() calls in embed.fnc
This allows the removal of the G flag, and the removal of three customized PERL_ARGS_ASSERT macros. One of these showed the brittleness of the old scheme, as after it was written, code was added to improve the generic versions of these macros, but no one realized to update the custom one. This can no longer happen. These commits also improve the error checking of embed.fnc entries; adds comments and white space
2 parents 8971586 + c70e28c commit e6095ba

File tree

8 files changed

+184
-93
lines changed

8 files changed

+184
-93
lines changed

embed.fnc

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
: Supported at least since perl-5.23.8, with or without ppport.h.
3636
:
3737
: Lines in this file are of the form:
38-
: flags|return_type|name|arg1|arg2|...|argN
38+
: flags|return_type|name|arg1|arg2|...|argN ( assert(...) )*
3939
:
4040
: 'flags' is a string of single letters. Most of the flags are meaningful only
4141
: to embed.pl; some only to autodoc.pl, and others only to makedef.pl. The
@@ -46,6 +46,9 @@
4646
: A line may be continued onto the next by ending it with a backslash.
4747
: Leading and trailing whitespace will be ignored in each component.
4848
:
49+
: The optional list of asserts is used to customize the generated
50+
: PERL_ARGS_ASSERT macro. See AUTOMATIC PARAMETER SANITY CHECKING below
51+
:
4952
: Most entries here have a macro created with the entry name. This presents
5053
: name space collision potentials which haven't been well thought out, but are
5154
: now documented here. In practice this has rarely been an issue. At least,
@@ -172,6 +175,14 @@
172175
: may not be of the correct type. As already mentioned, NOCHECK
173176
: suppresses this check.
174177
:
178+
: You can specify your own checking beyond these by adding any number of
179+
: assert() calls to any given entry after its final argument. Whatever you
180+
: specify will be added to the ARGS_ASSERT macro for the entry in the order
181+
: you've specified, and after all the assertions that already have been
182+
: described in this section. When adding yours, weigh that doing it here
183+
: will make it less visible to a maintainer than keeping it in the function
184+
: it applies to
185+
:
175186
: Currently, it is optional to include an empty ARGS_ASSERT macro in your
176187
: functions. But a porting test enforces that a non-empty one is included.
177188
: The call should be at the top of your function so that the sanity checks
@@ -442,13 +453,6 @@
442453
: flag even on a format function is if the format would generate error:
443454
: format string argument is not a string type
444455
:
445-
: 'G' Suppress empty PERL_ARGS_ASSERT_foo macro. Normally such a macro is
446-
: generated for all entries for functions 'foo' in this file. The macro
447-
: is empty unless regen/embed.pl deems that there should be assert()
448-
: calls to verify the sanity of some or all of foo's arguments.
449-
:
450-
: proto.h: An empty PERL_ARGS_ASSERT macro is not defined
451-
:
452456
: 'h' Hide any documentation that would normally go into perlapi or
453457
: perlintern. This is typically used when the documentation is actually
454458
: in another pod. If you don't use the 'h', that documentation is
@@ -750,7 +754,8 @@ ARdp |SSize_t|av_len |NN AV *av
750754
ARdp |AV * |av_make |SSize_t size \
751755
|NN SV **strp
752756
CRdip |AV * |av_new_alloc |SSize_t size \
753-
|bool zeroflag
757+
|bool zeroflag \
758+
assert(size > 0)
754759
p |SV * |av_nonelem |NN AV *av \
755760
|SSize_t ix
756761
Adp |SV * |av_pop |NN AV *av
@@ -2410,7 +2415,7 @@ p |void |no_bareword_filehandle \
24102415
|NN const char *fhname
24112416
Tefprv |void |noperl_die |NN const char *pat \
24122417
|...
2413-
CGTdp |void |noshutdownhook
2418+
CTdp |void |noshutdownhook
24142419
Adp |int |nothreadhook
24152420
p |void |notify_parser_that_encoding_changed
24162421
: Used in perly.y
@@ -4526,11 +4531,12 @@ op |void |sv_add_backref |NN SV * const tsv \
45264531
|NN SV * const sv
45274532
#endif
45284533
#if defined(PERL_IN_GV_C) || defined(PERL_IN_UNIVERSAL_C)
4529-
EGdp |HV * |gv_stashsvpvn_cached \
4530-
|SV *namesv \
4531-
|const char *name \
4534+
Edp |HV * |gv_stashsvpvn_cached \
4535+
|NULLOK SV *namesv \
4536+
|NULLOK const char *name \
45324537
|U32 namelen \
4533-
|I32 flags
4538+
|I32 flags \
4539+
assert(namesv || name)
45344540
#endif
45354541
#if defined(PERL_IN_HV_C)
45364542
Sx |void |clear_placeholders \
@@ -6109,17 +6115,19 @@ S |I32 |utf16_textfilter \
61096115
# endif
61106116
#endif /* defined(PERL_IN_TOKE_C) */
61116117
#if defined(PERL_IN_UNIVERSAL_C)
6112-
GS |bool |isa_lookup |NULLOK NOCHECK HV *stash \
6118+
S |bool |isa_lookup |NN HV *stash \
61136119
|NULLOK SV *namesv \
61146120
|NULLOK const char *name \
61156121
|STRLEN len \
6116-
|U32 flags
6117-
GS |bool |sv_derived_from_svpvn \
6118-
|NULLOK SV *sv \
6122+
|U32 flags \
6123+
assert(namesv || name)
6124+
S |bool |sv_derived_from_svpvn \
6125+
|NN SV *sv \
61196126
|NULLOK SV *namesv \
61206127
|NULLOK const char *name \
61216128
|const STRLEN len \
6122-
|U32 flags
6129+
|U32 flags \
6130+
assert(namesv || name)
61236131
#endif
61246132
#if defined(PERL_IN_UTF8_C)
61256133
RS |UV |check_locale_boundary_crossing \

gv.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1691,17 +1691,14 @@ reasons.
16911691
=cut
16921692
*/
16931693

1694-
#define PERL_ARGS_ASSERT_GV_STASHSVPVN_CACHED \
1695-
assert(namesv || name)
1696-
16971694
HV*
16981695
Perl_gv_stashsvpvn_cached(pTHX_ SV *namesv, const char *name, U32 namelen, I32 flags)
16991696
{
1697+
PERL_ARGS_ASSERT_GV_STASHSVPVN_CACHED;
1698+
17001699
HV* stash;
17011700
HE* he;
17021701

1703-
PERL_ARGS_ASSERT_GV_STASHSVPVN_CACHED;
1704-
17051702
he = (HE *)hv_common(
17061703
PL_stashcache, namesv, name, namelen,
17071704
(flags & SVf_UTF8) ? HVhek_UTF8 : 0, 0, NULL, 0

inline.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,10 +191,10 @@ initialized.
191191
PERL_STATIC_INLINE AV *
192192
Perl_av_new_alloc(pTHX_ SSize_t size, bool zeroflag)
193193
{
194+
PERL_ARGS_ASSERT_AV_NEW_ALLOC;
195+
194196
AV * const av = newAV();
195197
SV** ary;
196-
PERL_ARGS_ASSERT_AV_NEW_ALLOC;
197-
assert(size > 0);
198198

199199
Newx(ary, size, SV*); /* Newx performs the memwrap check */
200200
AvALLOC(av) = ary;

pod/perldelta.pod

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,19 @@ memory saving is unrealistic.
434434
C<sv_vcatpvfn_flags()> now substitutes the Unicode REPLACEMENT CHARACTER
435435
for malformed input. Previously it used the NUL character.
436436

437+
=item *
438+
439+
For core Perl maintainers, the syntax of F<embed.fnc> has been extended.
440+
Every function, C<foo()>, named in this file has generated for it a
441+
macro named C<PERL_ARGS_ASSERT_FOO>. The macro expands to C<assert()>
442+
calls that do basic sanity checking for each argument to C<foo()> that
443+
we currently deem as being appropriate to have such checking. (That
444+
means that many arguments are not checked, and that the generated macro
445+
may currently expand to nothing.) With this release, you can add
446+
C<assert()> statements yourself to F<embed.fnc> that will be
447+
incorporated into the generated macro, beyond the system-generated ones.
448+
Comments and examples in F<embed.fnc> give details.
449+
437450
=back
438451

439452
=head1 Selected Bug Fixes

proto.h

Lines changed: 11 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

regen/HeaderParser.pm

Lines changed: 63 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -737,46 +737,94 @@ sub lines { $_[0]->{lines} }
737737
sub tidy_embed_fnc_entry {
738738
my ($self, $line_data)= @_;
739739
my $line= $line_data->{line};
740-
return $line if $line =~ /^\s*:/;
741-
return $line unless $line_data->{type} eq "content";
742-
return $line unless $line =~ /\|/;
743740

744-
$line =~ s/\s*\\\n/ /g;
745-
$line =~ s/\s+\z//;
746-
($line)= expand($line);
741+
return $line if $line =~ /^\s*:/; # Don't tidy comments
742+
return $line unless $line_data->{type} eq "content"; # Nor #if-like
743+
return $line unless $line =~ /\|/; # Nor non-entries
744+
745+
$line =~ s/\s*\\\n/ /g; # Embedded \n to blank
746+
$line =~ s/\s+\z//; # No trailing white space
747+
($line)= expand($line); # No tabs
748+
749+
# Remove any assertions, and save them. This must be done before the
750+
# split because the assertions can contain '|'
751+
$line =~ s/ \b ( assert \s* \( .* ) \z //x;
752+
my $assertions = $1;
753+
754+
# Split into fields
747755
my ($flags, $ret, $name, @args)= split /\s*\|\s*/, $line;
756+
757+
# Sort and remove duplicate flags. Alpha flags are sorted first
748758
my %flag_seen;
749-
$flags= join "", grep !$flag_seen{$_}++, sort split //, $flags;
750-
if ($flags =~ s/^#//) {
751-
$flags .= "#";
752-
}
753-
if ($flags eq "#") {
759+
$flags = join "", grep !$flag_seen{$_}++,
760+
sort {
761+
my $a_is_word = $a =~ /\w/;
762+
my $b_is_word = $b =~ /\w/;
763+
return $a cmp $b if $a_is_word == $b_is_word;
764+
return -1 if $a_is_word;
765+
return 1;
766+
} split //, $flags;
767+
768+
if ($flags eq "#") { # Could be an attempt at a conditional
754769
die "Not allowed to use only '#' for flags"
755770
. "in 'embed.fnc' at line $line_data->{start_line_num}";
756771
}
772+
757773
if (!$flags) {
758774
die "Missing flags in function definition"
759775
. " in 'embed.fnc' at line $line_data->{start_line_num}\n"
760776
. "Did you a forget a line continuation on the previous line?\n";
761777
}
778+
779+
# Normalize the return type and arguments
762780
for ($ret, @args) {
763781
s/(\w)\*/$1 */g;
764782
s/\*\s+(\w)/*$1/g;
765783
s/\*const/* const/g;
766784
}
785+
786+
# Start the output; right justify
767787
my $head= sprintf "%-8s|%-7s", $flags, $ret;
768788
$head .= sprintf "|%*s", -(31 - length($head)), $name;
789+
790+
# Start first argument on next line if $head already extends too far to
791+
# the right
769792
if (@args and length($head) > 32) {
770793
$head .= "\\\n";
771794
$head .= " " x 32;
772795
}
796+
797+
# Add each argument on a separate line
773798
foreach my $ix (0 .. $#args) {
774799
my $arg= $args[$ix];
775800
$head .= "|$arg";
776801
$head .= "\\\n" . (" " x 32) if $ix < $#args;
777802
}
803+
804+
my @assertions;
805+
if ($assertions) {
806+
# Put each assertion into a separate array element
807+
@assertions = split / \s* assert \s* \( /x, $assertions;
808+
shift @assertions; # The split leaves an empty first element
809+
810+
# Trim each assertion, including any trailing semicolon
811+
foreach my $this_assertion (@assertions) {
812+
$this_assertion =~ s/ ^ \s+ //x;
813+
$this_assertion =~ s/ \s+ \z //x;
814+
$this_assertion =~ s/ ; \z //x;
815+
816+
# Restore split delimitter
817+
$this_assertion = "assert($this_assertion";
818+
819+
# Each assertion is on a separate line (for now, anyway)
820+
$head .= "\\\n" . (" " x 32);
821+
$head .= $this_assertion;
822+
}
823+
}
824+
778825
$line= $head . "\n";
779826
827+
# Make all lines in this entry the same length; minimum 72
780828
if ($line =~ /\\\n/) {
781829
my @lines= split /\s*\\\n/, $line;
782830
my $len= length($lines[0]);
@@ -787,15 +835,18 @@ sub tidy_embed_fnc_entry {
787835
(map { sprintf "%*s", -$len, $_ } @lines[ 0 .. $#lines - 1 ]),
788836
$lines[-1]);
789837
}
790-
($line)= unexpand($line);
838+
839+
($line)= unexpand($line); # Back to using tabs
791840
792841
$line_data->{embed}= EmbedLine->new(
793842
flags => $flags,
794843
return_type => $ret,
795844
name => $name,
796845
args => \@args,
846+
assertions => \@assertions,
797847
start_line_num => $line_data->{start_line_num},
798848
);
849+
799850
$line =~ s/\s+\z/\n/;
800851
$line_data->{line}= $line;
801852
return $line;

0 commit comments

Comments
 (0)