NAME

XS::Check - check XS for problems

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 synopsis.pl in the distribution.)

VERSION

This documents version 0.09 of XS-Check corresponding to git commit c6331ab3c58f68861f564cf1b41e0c8e279b62db released on Fri Dec 25 21:54:39 2020 +0900.

DESCRIPTION

This module offers ways to check XS files for common flaws.

METHODS

new

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

Make a new XS::Check object. The checks are then run using "check" or "check_file".

Changing where the messages go

The messages from "check" or "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 new with the key reporter as follows:

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

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

file

the file name of the file where the error occurred, if using "check_file" or if set with "set_file", otherwise the undefined value (undef),

line

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

message

the message from the module, a text string.

The following example demonstrates a user-defined callback using the message and 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 reporter.pl in the distribution.)

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

check

$check->check ($xs);

See "SUGGESTIONS" for what this reports.

check_file

$check->check ($xs_file);

Convenience method to read in $xs_file then run "check" on it.

This assumes UTF-8 encoding of $xs_file.

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 set-file.pl in the distribution.)

This method was added in version 0.08.

SUGGESTIONS

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

Use STRLEN in SvPV

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

Use const char * for return value of SvPV

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

Don't use malloc/calloc/realloc/free

Replace with Newx etc.

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

Don't use the Perl_ prefix

Functions like Perl_croak should not be used, just croak. The Perl_ prefix functions may take arguments which are hidden in the macros like croak. These are the pTHX_ style things of the Perl source code.

This check was added in version 0.04.

Don't use (void) in arguments

XS functions cannot use the ANSI 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.

Dereferencing av_fetch or hv_fetch

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

This check was added in version 0.09.

Put whitespace before hash comments

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

This check was added in version 0.09.

LIMITATIONS

As of 0.09, the module has the following limitations.

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);
UTF-8 only

"check_file" uses "read_text" in File::Slurper to read the text, which means it only takes UTF-8.

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.

Variables declared within function definitions are not parsed

The following variable 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);

DEPENDENCIES

C::Tokenize

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

"read_text" in File::Slurper

This is used by "check_file".

Text::LineNumber

This is used to get the line numbers.

Carp

COMMAND-LINE TOOL

A command line tool called checkxs is installed with the module. It runs the "check_file" method on each file named on the command line.

checkxs Some.xs

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

SEE ALSO

Perl XS modules and CPAN testers

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

AUTHOR

Ben Bullock, <bkb@cpan.org>

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.