checksrc: introduce 'banfunc' to ban specific functions

Use 'banfunc' and 'allowfunc' in .checksrc to specify which functions to
ban or allow to be used. This saves us from having to edit the script
going forward when we want to ban or allow specific functions.

This replaces a set of previous rules and all banned functions are now
checked with the BANNEDFUNC rule.

There is a set of default banned functions, shown by invoking
./checksrc.

Also, -a and -b options are added to specify allowed or banned functions
on the command line.

Closes #15835
This commit is contained in:
Daniel Stenberg 2024-12-27 09:21:56 +01:00
parent 66e5351e0a
commit c445b7426a
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
9 changed files with 92 additions and 80 deletions

View File

@ -1,4 +1,3 @@
disable TYPEDEFSTRUCT
disable SNPRINTF
disable BANNEDFUNC
disable SSCANF

View File

@ -1,2 +1,5 @@
enable STRERROR
enable STRNCPY
banfunc strerror
banfunc strncpy
banfunc sscanf
banfunc snprintf
banfunc vsnprint

View File

@ -891,7 +891,7 @@ const char *Curl_strerror(int err, char *buf, size_t buflen)
}
#else
{
/* !checksrc! disable STRERROR 1 */
/* !checksrc! disable BANNEDFUNC 1 */
const char *msg = strerror(err);
if(msg)
msnprintf(buf, buflen, "%s", msg);

View File

@ -47,10 +47,34 @@ my %ignore_set;
my %ignore_used;
my @ignore_line;
my %banfunc = (
"gmtime" => 1,
"localtime" => 1,
"gets" => 1,
"strtok" => 1,
"sprintf" => 1,
"vsprintf" => 1,
"strcat" => 1,
"strncat" => 1,
"_mbscat" => 1,
"_mbsncat" => 1,
"_tcscat" => 1,
"_tcsncat" => 1,
"_wcscat" => 1,
"_wcsncat" => 1,
"LoadLibrary" => 1,
"LoadLibraryA" => 1,
"LoadLibraryW" => 1,
"LoadLibraryEx" => 1,
"LoadLibraryExA" => 1,
"LoadLibraryExW" => 1,
"_waccess" => 1,
"_access" => 1,
"access" => 1,
);
my %warnings_extended = (
'COPYRIGHTYEAR' => 'copyright year incorrect',
'STRERROR', => 'strerror() detected',
'STRNCPY', => 'strncpy() detected',
'STDERR', => 'stderr detected',
);
@ -92,14 +116,12 @@ my %warnings = (
'RETURNNOSPACE' => 'return without space',
'SEMINOSPACE' => 'semicolon without following space',
'SIZEOFNOPAREN' => 'use of sizeof without parentheses',
'SNPRINTF' => 'use of snprintf',
'SPACEAFTERPAREN' => 'space after open parenthesis',
'SPACEBEFORECLOSE' => 'space before a close parenthesis',
'SPACEBEFORECOMMA' => 'space before a comma',
'SPACEBEFOREPAREN' => 'space before an open parenthesis',
'SPACESEMICOLON' => 'space before semicolon',
'SPACESWITCHCOLON' => 'space before colon of switch label',
"SSCANF" => 'use of sscanf',
'TABS' => 'TAB characters not allowed',
'TRAILINGSPACE' => 'Trailing whitespace on the line',
'TYPEDEFSTRUCT' => 'typedefed struct',
@ -144,14 +166,14 @@ sub readlocalfile {
if (/^\s*(#.*)/) {
next;
}
elsif (/^\s*enable ([A-Z]+)$/) {
elsif (/^enable ([A-Z]+)$/) {
if(!defined($warnings_extended{$1})) {
print STDERR "invalid warning specified in .checksrc: \"$1\"\n";
next;
}
$warnings{$1} = $warnings_extended{$1};
}
elsif (/^\s*disable ([A-Z]+)$/) {
elsif (/^disable ([A-Z]+)$/) {
if(!defined($warnings{$1})) {
print STDERR "invalid warning specified in .checksrc: \"$1\"\n";
next;
@ -159,6 +181,12 @@ sub readlocalfile {
# Accept-list
push @alist, $1;
}
elsif (/^banfunc ([^ ]*)/) {
$banfunc{$1} = $1;
}
elsif (/^allowfunc ([^ ]*)/) {
undef $banfunc{$1};
}
else {
die "Invalid format in $dir/.checksrc on line $i\n";
}
@ -223,27 +251,38 @@ $file = shift @ARGV;
while(defined $file) {
if($file =~ /-D(.*)/) {
if($file =~ /^-D(.*)/) {
$dir = $1;
$file = shift @ARGV;
next;
}
elsif($file =~ /-W(.*)/) {
elsif($file =~ /^-W(.*)/) {
$wlist .= " $1 ";
$file = shift @ARGV;
next;
}
elsif($file =~ /-A(.+)/) {
elsif($file =~ /^-b(.*)/) {
$banfunc{$1} = $1;
print STDERR "ban use of \"$1\"\n";
$file = shift @ARGV;
next;
}
elsif($file =~ /^-a(.*)/) {
undef $banfunc{$1};
$file = shift @ARGV;
next;
}
elsif($file =~ /^-A(.+)/) {
push @alist, $1;
$file = shift @ARGV;
next;
}
elsif($file =~ /-i([1-9])/) {
elsif($file =~ /^-i([1-9])/) {
$indent = $1 + 0;
$file = shift @ARGV;
next;
}
elsif($file =~ /-m([0-9]+)/) {
elsif($file =~ /^-m([0-9]+)/) {
$max_column = $1 + 0;
$file = shift @ARGV;
next;
@ -260,6 +299,8 @@ if(!$file) {
print "checksrc.pl [option] <file1> [file2] ...\n";
print " Options:\n";
print " -A[rule] Accept this violation, can be used multiple times\n";
print " -a[func] Allow use of this function\n";
print " -b[func] Ban use of this function\n";
print " -D[DIR] Directory to prepend file names\n";
print " -h Show help output\n";
print " -W[file] Skip the given file - ignore all its flaws\n";
@ -277,6 +318,11 @@ if(!$file) {
}
}
print " [*] = disabled by default\n";
print "\nDetects and bans use of these functions:\n";
for my $f (sort keys %banfunc) {
printf (" %-18s\n", $f);
}
exit;
}
@ -801,54 +847,23 @@ sub scanfile {
}
# scan for use of banned functions
if($l =~ /^(.*\W)
(gmtime|localtime|
gets|
strtok|
v?sprintf|
(str|_mbs|_tcs|_wcs)n?cat|
LoadLibrary(Ex)?(A|W)?|
_?w?access)
\s*\(
/x) {
my $bl = $l;
again:
if(($l =~ /^(.*?\W)(\w+)(\s*\()/x) && $banfunc{$2}) {
my $bad = $2;
my $prefix = $1;
my $suff = $3;
checkwarn("BANNEDFUNC",
$line, length($1), $file, $ol,
"use of $2 is banned");
}
# scan for use of sscanf. This is not a BANNEDFUNC to allow for
# individual enable/disable of this warning.
if($l =~ /^(.*\W)(sscanf)\s*\(/x) {
if($1 !~ /^ *\#/) {
# skip preprocessor lines
checkwarn("SSCANF",
$line, length($1), $file, $ol,
"use of $2 is banned");
}
}
if($warnings{"STRERROR"}) {
# scan for use of banned strerror. This is not a BANNEDFUNC to
# allow for individual enable/disable of this warning.
if($l =~ /^(.*\W)(strerror)\s*\(/x) {
if($1 !~ /^ *\#/) {
# skip preprocessor lines
checkwarn("STRERROR",
$line, length($1), $file, $ol,
"use of $2 is banned");
}
}
}
if($warnings{"STRNCPY"}) {
# scan for use of banned strncpy. This is not a BANNEDFUNC to
# allow for individual enable/disable of this warning.
if($l =~ /^(.*\W)(strncpy)\s*\(/x) {
if($1 !~ /^ *\#/) {
# skip preprocessor lines
checkwarn("STRNCPY",
$line, length($1), $file, $ol,
"use of $2 is banned");
}
}
}
$line, length($prefix), $file, $ol,
"use of $bad is banned");
my $replace = 'x' x (length($bad) + 1);
$prefix =~ s/\*/\\*/;
$suff =~ s/\(/\\(/;
$l =~ s/$prefix$bad$suff/$prefix$replace/;
goto again;
}
$l = $bl; # restore to pre-bannedfunc content
if($warnings{"STDERR"}) {
# scan for use of banned stderr. This is not a BANNEDFUNC to
# allow for individual enable/disable of this warning.
@ -861,12 +876,6 @@ sub scanfile {
}
}
}
# scan for use of snprintf for curl-internals reasons
if($l =~ /^(.*\W)(v?snprintf)\s*\(/x) {
checkwarn("SNPRINTF",
$line, length($1), $file, $ol,
"use of $2 is banned");
}
# scan for use of non-binary fopen without the macro
if($l =~ /^(.*\W)fopen\s*\([^,]*, *\"([^"]*)/) {

View File

@ -1,2 +1,3 @@
enable STDERR
enable STRNCPY
banfunc strncpy
banfunc sscanf

View File

@ -16,7 +16,7 @@ checksrc
</name>
<command type="perl">
%SRCDIR/../scripts/checksrc.pl %LOGDIR/code%TESTNUMBER.c
%SRCDIR/../scripts/checksrc.pl -bmagicbad -balsobad %LOGDIR/code%TESTNUMBER.c
</command>
<file name="%LOGDIR/code%TESTNUMBER.c">
/* test source code
@ -71,7 +71,7 @@ void startfunc(int a, int b) {
}
int a = sizeof int;
int a = snprintf(buffer, sizeof(buffer), "%d", 99);
int a = magicbad(buffer, alsobad(buffer), "%d", 99);
int moo = hej?wrong:a>b;
int moo2 = wrong2:(a)>(b);
@ -162,9 +162,12 @@ void startfunc(int a, int b) {
./%LOGDIR/code1185.c:52:16: warning: sizeof without parenthesis (SIZEOFNOPAREN)
int a = sizeof int;
^
./%LOGDIR/code1185.c:53:10: warning: use of snprintf is banned (SNPRINTF)
int a = snprintf(buffer, sizeof(buffer), "%d", 99);
./%LOGDIR/code1185.c:53:10: warning: use of magicbad is banned (BANNEDFUNC)
int a = magicbad(buffer, alsobad(buffer), "%d", 99);
^
./%LOGDIR/code1185.c:53:27: warning: use of alsobad is banned (BANNEDFUNC)
int a = magicbad(buffer, alsobad(buffer), "%d", 99);
^
./%LOGDIR/code1185.c:54:21: warning: missing space before colon (NOSPACEC)
int moo = hej?wrong:a>b;
^
@ -201,7 +204,7 @@ void startfunc(int a, int b) {
./%LOGDIR/code1185.c:1:1: error: Missing closing comment (OPENCOMMENT)
^
checksrc: 0 errors and 38 warnings
checksrc: 0 errors and 39 warnings
</stdout>
<errorcode>
5

View File

@ -1,3 +1,3 @@
disable TYPEDEFSTRUCT
disable BANNEDFUNC
disable SSCANF
allowfunc localtime
allowfunc LoadLibrary

View File

@ -30,8 +30,6 @@
#include "stub_gssapi.h"
/* !checksrc! disable SNPRINTF all */
#define MAX_CREDS_LENGTH 250
#define APPROX_TOKEN_LEN 250

View File

@ -1,2 +1 @@
enable STRNCPY
disable SSCANF
banfunc STRNCPY