Skip to content

Commit

Permalink
Add more documentation; check for malloc/free etc
Browse files Browse the repository at this point in the history
  • Loading branch information
benkasminbullock committed Aug 16, 2017
1 parent 44fc6b2 commit bb1e5bd
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 8 deletions.
28 changes: 23 additions & 5 deletions lib/XS/Check.pm
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ sub new
return bless {};
}

# Report an error $message in $var

sub report
{
my ($o, $var, $message) = @_;
my $file = $o->get_file ();
my $line = $o->get_line_number ($var);
warn "$file$line: $message";
}

# Match a call to SvPV

my $svpv_re = qr/
Expand All @@ -38,24 +48,31 @@ my $svpv_re = qr/
sub check_svpv
{
my ($o, $xs) = @_;
my $file = $o->get_file ();
while ($xs =~ /($svpv_re)/g) {
my $match = $1;
my $lvar = $2;
my $arg2 = $4;
my $lvar_type = $o->get_type ($lvar);
my $arg2_type = $o->get_type ($arg2);
if ($lvar_type && $lvar_type !~ /const\s+char\s+\*/) {
my $lineno = $o->get_line_number ($xs);
warn "$file$lineno: $lvar not const char *";
$o->report ($xs, "$lvar not const char *");
}
if ($arg2_type && $arg2_type !~ /STRLEN/) {
my $lineno = $o->get_line_number ($xs);
warn "$file$lineno: $arg2 not STRLEN, type = $arg2_type";
$o->report ($xs, "$lvar not const char *");
}
}
}

# Look for malloc/calloc/realloc/free and suggest replacing them.

sub check_malloc
{
my ($o, $xs) = @_;
while ($xs =~ /((?:m|c|re)alloc|free)/g) {
$o->report ("Change $1 to Newx/Newz/Safefree");
}
}

# Regular expression to match a C declaration.

my $declare_re = qr/
Expand Down Expand Up @@ -138,6 +155,7 @@ sub check
$o->line_numbers ($xs);
$o->read_declarations ($xs);
$o->check_svpv ($xs);
$o->check_malloc ($xs);
}

sub check_file
Expand Down
56 changes: 53 additions & 3 deletions lib/XS/Check.pod.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,74 @@ commit.commit %]> released on [% commit.date %].

=head1 DESCRIPTION

Check XS files for errors.

=head1 METHODS

=head2 new

my $check = XS::Check->new ();

=head2 check

=head2 new
$check->check ($xs);

See L</SUGGESTIONS> for what this reports.

=head2 check_file

$check->check ($xs_file);

Convenience method to read in $xs_file then run L</check> on it.

This assumes UTF-8 encoding of $xs_file.

=head1 SUGGESTIONS

This section details the possible suggestions made by the module and
the motivations behind them.

=head2 Use STRLEN in SvPV

Using an int type for the second argument to SvPV may cause errors on
64-bit Perls.

=head2 Use const char * for return value of SvPV

Be careful to not overwrite Perl's own buffer, which SvPV returns.

=head2 Don't use malloc/calloc/realloc/free

Replace with Newx etc.

These cause "free to wrong pool" errors on multithreaded Windows
Perls.

=head1 DEPENDENCIES

=over

=item L<File::Slurper>
=item L<File::Slurper/read_text>

This is used by L</check_file>.

=item L<Text::LineNumber>

=item L<Text::LineNumbers>
This is used to get the line numbers.

=item L<Carp>

=back

=head1 SEE ALSO

=over

=item L<Perl XS modules and CPAN testers|https://www.lemoda.net/perl/perl-xs-cpan-testers/index.html>

A collection of more or less obscure bugs found by CPAN testers, the
original inspiration for this module.

=back

[% INCLUDE "author" %]
6 changes: 6 additions & 0 deletions t/xs-check.t
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ STRLEN len;
x = SvPV (sv, len);
EOF
ok ($warning, "Warning with not const char *");
$warning = undef;
$checker->check (<<EOF);
const char * x;
x = malloc (100);
EOF
ok ($warning, "Warning with malloc");

done_testing ();
# Local variables:
Expand Down

0 comments on commit bb1e5bd

Please sign in to comment.