


=encoding UTF-8

=head1 NAME

XS::Check - Check XS for some common problems

=head1 SYNOPSIS

    
    use FindBin '$Bin';
    use XS::Check;
    my $check = XS::Check->new ();
    $check->check_file ("$Bin/synopsis.xs");


produces output

    /usr/home/ben/projects/xs-check/examples/synopsis.xs:3: x not a constant type.
    /usr/home/ben/projects/xs-check/examples/synopsis.xs:3: len is not a STRLEN variable (unsigned int ).


(This example is included as L<F<synopsis.pl>|https://fastapi.metacpan.org/source/BKB/XS-Check-0.10/examples/synopsis.pl> in the distribution.)


=head1 VERSION

This documents version 0.10 of XS-Check
corresponding to L<git commit 5dd119e6ab65b7b87be5bb152aeeb5c807347efb|https://github.com/benkasminbullock/xs-check/commit/5dd119e6ab65b7b87be5bb152aeeb5c807347efb> released on Sat Dec 26 15:52:37 2020 +0900.

=head1 DESCRIPTION

This module offers ways to check XS files for some common flaws which
we have tripped over.

=head1 METHODS

=head2 new

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

Make a new XS::Check object. The checks are then run using L</check>
or L</check_file>.

=head3 Changing where the messages go

The messages from L</check> or L</check_file> are usually printed
using Perl's built-in warn function. If you need to have errors
reported some other way, supply a code reference to C<new> with the
key C<reporter> as follows:

    my $usercheck = XS::Check->new (reporter => sub { print "help!" });

The function you supply is then called back when L</check> or
L</check_file> find something to remark on. The function is called
with a hash containing the fields

=over

=item file

the file name of the file where the error occurred, if using
L</check_file> or if set with L</set_file>, otherwise the undefined
value (C<undef>),

=item line

the line number where the error occurred, starting from 1,

=item message

the message from the module, a text string.

=back

The following example demonstrates a user-defined callback using the
C<message> and C<line> fields:

    
    use XS::Check;
    my $rchecker = XS::Check->new (reporter => \& reporter);
    $rchecker->check ("Perl_croak ('croaking');\n");
    sub reporter
    {
        my %rstuff = @_;
        print "$rstuff{message} at $rstuff{line}.\n";
    }
    


produces output

    Remove the 'Perl_' prefix from Perl_croak at 1.


(This example is included as L<F<reporter.pl>|https://fastapi.metacpan.org/source/BKB/XS-Check-0.10/examples/reporter.pl> in the distribution.)


Callback error reporting was added to the module in version 0.07.

=head2 check

    $check->check ($xs);

See L</SUGGESTIONS> for what this reports.

=head2 check_file

    $check->check ($xs_file);

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

This assumes UTF-8 encoding of C<$xs_file>.

=head2 set_file

    $check->set_file ($file);

Set the file name for error reporting. Use any false value to clear
it. For example:

    
    use XS::Check;
    my $check = XS::Check->new ();
    my $xs = "Perl_croak (\"frog\")\n";
    $check->check ($xs);
    $check->set_file ('Yabadabado');
    $check->check ($xs);
    $check->set_file ('');
    $check->check ($xs);


produces output

    1: Remove the 'Perl_' prefix from Perl_croak.
    Yabadabado:1: Remove the 'Perl_' prefix from Perl_croak.
    1: Remove the 'Perl_' prefix from Perl_croak.


(This example is included as L<F<set-file.pl>|https://fastapi.metacpan.org/source/BKB/XS-Check-0.10/examples/set-file.pl> in the distribution.)


This method was added in version 0.08.

=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 due to taking the address of the variable and then
sending it to functions.

=head2 Use const char * for return value of SvPV

SvPV returns the actual Perl buffer, not a copy, so it's better to use
C<const char *> to make sure one does not overwrite it.

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

The C standard library functions should usually be replaced with Newx,
Newxz, and Safefree respectively in Perl XS code, because the C
standard library functions may cause "free to wrong pool" errors on
multithreaded Windows Perls.

=head2 Don't use the Perl_ prefix

Functions of the form C<Perl_croak> should usually not be used, just
C<croak>. This is because the C<Perl_> prefix functions take different
arguments, which are hidden in the macros like C<croak>. (The hidden
arguments are the C<pTHX_> and similar things seen in the Perl source
code.)

This check was added in version 0.04.

=head2 Don't use (void) in arguments

XS functions cannot use the ANSI C C<(void)> to indicate that they do
not take any arguments, instead this results in a variable called
"void" being created.

This check was added in version 0.06.

=head2 Dereferencing av_fetch or hv_fetch

One should not dereference the return value of C<av_fetch> or
C<hv_fetch> without checking for nulls since it is possible to return
C<NULL>, for example if an array is created with only a tenth element.

For an extended discussion, see L<http://blogs.perl.org/users/ben_bullock/2020/02/av-fetch-can-return-null.html>.

Currently this check does not actually check that the returned value
is checked for non-nullness before being dereferenced, only that there
is nothing of the form C<* av_fetch> in your code.

This check was added in version 0.09.

=head2 Put whitespace before hash comments

The XS manual suggests putting whitespace before # comments to
distinguish them from preprocessor statements.

See L<https://perldoc.perl.org/perlxs#Inserting-POD,-Comments-and-C-Preprocessor-Directives>.

=over

Comments can be added to XSUBs by placing a # as the first
non-whitespace of a line. Care should be taken to avoid making the
comment look like a C preprocessor directive, lest it be interpreted
as such. The simplest way to prevent this is to put whitespace in
front of the #.

=back

This check was added in version 0.09.

=head1 LIMITATIONS

As of 0.10, the module has the following limitations.

=over

=item Struct members

The module is not very good at parsing struct members, so XS code like
the following doesn't get dealt with properly:

    s.txt = SvPV (sv, s.len);

=item UTF-8 only

L</check_file> uses L<File::Slurper/read_text> to read the text, which
means it only takes UTF-8.

=item Variable declarations rely on a simplistic hack

The current method of parsing variable declarations uses a very
simplistic hack, and it is likely to produce false results if a
variable name is used twice for two different things in the same file.

=item Variables declared within function definitions are not parsed

The following variable C<length> is not dealt with correctly:

    static void
    sv_to_text_fuzzy (SV * text, STRLEN length)
    {
        const unsigned char * stuff;
        /* Copy the string in "text" into "text_fuzzy". */
        stuff = (unsigned char *) SvPV (text, length);

=item Add one to av_len

The C<av_len> function returns the length of an C<AV *> minus one, so
if it is used as-is, one element of the array will be missed. The
module does a simplistic check of adding one to C<av_len>.

=back

=head1 DEPENDENCIES

=over

=item L<C::Tokenize>

This supplies the regular expressions used to parse C by the module.

=item L<File::Slurper/read_text>

This is used by L</check_file>.

=item L<Text::LineNumber>

This is used to get the line numbers.

=item L<Carp>

=back

=head1 COMMAND-LINE TOOL

A command line tool called C<checkxs> is installed with the module. It
runs the L</check_file> method on each file named on the command line.

    checkxs Some.xs

As of 0.10, there are no options to the script. Its
output goes to standard error.

=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



=head1 AUTHOR

Ben Bullock, <bkb@cpan.org>

=head1 COPYRIGHT & LICENCE

This package and associated files are copyright (C) 
2017-2020
Ben Bullock.

You can use, copy, modify and redistribute this package and associated
files under the Perl Artistic Licence or the GNU General Public
Licence.



