util/lint: update checkpatch.pl to latest linux version

Taken from Linux upstream commit ffe075132af8b7967089c361e506d4fa747efd14

Change-Id: I43d09a912fafe896c045df080c0f75fe6d908087
Signed-off-by: Martin Roth <martinroth@google.com>
Reviewed-on: https://review.coreboot.org/28046
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Martin Roth 2018-08-10 21:04:05 -06:00 committed by Patrick Georgi
parent 8da2fa06f8
commit 60915b3157
1 changed files with 279 additions and 189 deletions

View File

@ -1,9 +1,11 @@
#!/usr/bin/env perl #!/usr/bin/env perl
# SPDX-License-Identifier: GPL-2.0
#
# (c) 2001, Dave Jones. (the file handling bit) # (c) 2001, Dave Jones. (the file handling bit)
# (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit) # (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit)
# (c) 2007,2008, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite) # (c) 2007,2008, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite)
# (c) 2008-2010 Andy Whitcroft <apw@canonical.com> # (c) 2008-2010 Andy Whitcroft <apw@canonical.com>
# Licensed under the terms of the GNU GPL License version 2 # (c) 2010-2018 Joe Perches <joe@perches.com>
use strict; use strict;
use warnings; use warnings;
@ -464,6 +466,7 @@ our $zero_initializer = qr{(?:(?:0[xX])?0+$Int_type?|NULL|false)\b};
our $logFunctions = qr{(?x: our $logFunctions = qr{(?x:
printk(?:_ratelimited|_once|_deferred_once|_deferred|)| printk(?:_ratelimited|_once|_deferred_once|_deferred|)|
(?:[a-z0-9]+_){1,2}(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)| (?:[a-z0-9]+_){1,2}(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)|
TP_printk|
WARN(?:_RATELIMIT|_ONCE|)| WARN(?:_RATELIMIT|_ONCE|)|
panic| panic|
MODULE_[A-Z_]+| MODULE_[A-Z_]+|
@ -575,6 +578,7 @@ foreach my $entry (@mode_permission_funcs) {
$mode_perms_search .= '|' if ($mode_perms_search ne ""); $mode_perms_search .= '|' if ($mode_perms_search ne "");
$mode_perms_search .= $entry->[0]; $mode_perms_search .= $entry->[0];
} }
$mode_perms_search = "(?:${mode_perms_search})";
our $mode_perms_world_writable = qr{ our $mode_perms_world_writable = qr{
S_IWUGO | S_IWUGO |
@ -609,6 +613,37 @@ foreach my $entry (keys %mode_permission_string_types) {
$mode_perms_string_search .= '|' if ($mode_perms_string_search ne ""); $mode_perms_string_search .= '|' if ($mode_perms_string_search ne "");
$mode_perms_string_search .= $entry; $mode_perms_string_search .= $entry;
} }
our $single_mode_perms_string_search = "(?:${mode_perms_string_search})";
our $multi_mode_perms_string_search = qr{
${single_mode_perms_string_search}
(?:\s*\|\s*${single_mode_perms_string_search})*
}x;
sub perms_to_octal {
my ($string) = @_;
return trim($string) if ($string =~ /^\s*0[0-7]{3,3}\s*$/);
my $val = "";
my $oval = "";
my $to = 0;
my $curpos = 0;
my $lastpos = 0;
while ($string =~ /\b(($single_mode_perms_string_search)\b(?:\s*\|\s*)?\s*)/g) {
$curpos = pos($string);
my $match = $2;
my $omatch = $1;
last if ($lastpos > 0 && ($curpos - length($omatch) != $lastpos));
$lastpos = $curpos;
$to |= $mode_permission_string_types{$match};
$val .= '\s*\|\s*' if ($val ne "");
$val .= $match;
$oval .= $omatch;
}
$oval =~ s/^\s*\|\s*//;
$oval =~ s/\s*\|\s*$//;
return sprintf("%04o", $to);
}
our $allowed_asm_includes = qr{(?x: our $allowed_asm_includes = qr{(?x:
irq| irq|
@ -768,7 +803,8 @@ our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant|$String)};
our $declaration_macros = qr{(?x: our $declaration_macros = qr{(?x:
(?:$Storage\s+)?(?:[A-Z_][A-Z0-9]*_){0,2}(?:DEFINE|DECLARE)(?:_[A-Z0-9]+){1,6}\s*\(| (?:$Storage\s+)?(?:[A-Z_][A-Z0-9]*_){0,2}(?:DEFINE|DECLARE)(?:_[A-Z0-9]+){1,6}\s*\(|
(?:$Storage\s+)?[HLP]?LIST_HEAD\s*\(| (?:$Storage\s+)?[HLP]?LIST_HEAD\s*\(|
(?:$Storage\s+)?${Type}\s+uninitialized_var\s*\( (?:$Storage\s+)?${Type}\s+uninitialized_var\s*\(|
(?:SKCIPHER_REQUEST|SHASH_DESC|AHASH_REQUEST)_ON_STACK\s*\(
)}; )};
sub deparenthesize { sub deparenthesize {
@ -1056,7 +1092,7 @@ sub parse_email {
} elsif ($formatted_email =~ /(\S+\@\S+)(.*)$/) { } elsif ($formatted_email =~ /(\S+\@\S+)(.*)$/) {
$address = $1; $address = $1;
$comment = $2 if defined $2; $comment = $2 if defined $2;
$formatted_email =~ s/$address.*$//; $formatted_email =~ s/\Q$address\E.*$//;
$name = $formatted_email; $name = $formatted_email;
$name = trim($name); $name = trim($name);
$name =~ s/^\"|\"$//g; $name =~ s/^\"|\"$//g;
@ -1198,7 +1234,7 @@ sub sanitise_line {
for ($off = 1; $off < length($line); $off++) { for ($off = 1; $off < length($line); $off++) {
$c = substr($line, $off, 1); $c = substr($line, $off, 1);
# Comments we are wacking completly including the begin # Comments we are whacking completely including the begin
# and end, all to $;. # and end, all to $;.
if ($sanitise_quote eq '' && substr($line, $off, 2) eq '/*') { if ($sanitise_quote eq '' && substr($line, $off, 2) eq '/*') {
$sanitise_quote = '*/'; $sanitise_quote = '*/';
@ -1278,6 +1314,7 @@ sub sanitise_line {
sub get_quoted_string { sub get_quoted_string {
my ($line, $rawline) = @_; my ($line, $rawline) = @_;
return "" if (!defined($line) || !defined($rawline));
return "" if ($line !~ m/($String)/g); return "" if ($line !~ m/($String)/g);
return substr($rawline, $-[0], $+[0] - $-[0]); return substr($rawline, $-[0], $+[0] - $-[0]);
} }
@ -1631,6 +1668,28 @@ sub raw_line {
} }
} }
sub get_stat_real {
my ($linenr, $lc) = @_;
my $stat_real = raw_line($linenr, 0);
for (my $count = $linenr + 1; $count <= $lc; $count++) {
$stat_real = $stat_real . "\n" . raw_line($count, 0);
}
return $stat_real;
}
sub get_stat_here {
my ($linenr, $cnt, $here) = @_;
my $herectx = $here . "\n";
for (my $n = 0; $n < $cnt; $n++) {
$herectx .= raw_line($linenr, $n) . "\n";
}
return $herectx;
}
sub cat_vet { sub cat_vet {
my ($vet) = @_; my ($vet) = @_;
my ($res, $coded); my ($res, $coded);
@ -2244,6 +2303,8 @@ sub process {
my $camelcase_file_seeded = 0; my $camelcase_file_seeded = 0;
my $checklicenseline = 1;
sanitise_line_reset(); sanitise_line_reset();
my $line; my $line;
foreach my $rawline (@rawlines) { foreach my $rawline (@rawlines) {
@ -2336,6 +2397,14 @@ sub process {
my $rawline = $rawlines[$linenr - 1]; my $rawline = $rawlines[$linenr - 1];
# check if it's a mode change, rename or start of a patch
if (!$in_commit_log &&
($line =~ /^ mode change [0-7]+ => [0-7]+ \S+\s*$/ ||
($line =~ /^rename (?:from|to) \S+\s*$/ ||
$line =~ /^diff --git a\/[\w\/\.\_\-]+ b\/\S+\s*$/))) {
$is_patch = 1;
}
#extract the line range in the file after the patch is applied #extract the line range in the file after the patch is applied
if (!$in_commit_log && if (!$in_commit_log &&
$line =~ /^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@(.*)/) { $line =~ /^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@(.*)/) {
@ -2446,6 +2515,7 @@ sub process {
} else { } else {
$check = $check_orig; $check = $check_orig;
} }
$checklicenseline = 1;
next; next;
} }
@ -2567,12 +2637,6 @@ sub process {
"A patch subject line should describe the change not the tool that found it\n" . $herecurr); "A patch subject line should describe the change not the tool that found it\n" . $herecurr);
} }
# Check for old stable address
if ($line =~ /^\s*cc:\s*.*<?\bstable\@kernel\.org\b>?.*$/i) {
ERROR("STABLE_ADDRESS",
"The 'stable' address should be 'stable\@vger.kernel.org'\n" . $herecurr);
}
# Check for unwanted Gerrit info # Check for unwanted Gerrit info
if ($in_commit_log && $line =~ /^\s*change-id:/i) { if ($in_commit_log && $line =~ /^\s*change-id:/i) {
ERROR("GERRIT_CHANGE_ID", ERROR("GERRIT_CHANGE_ID",
@ -2795,7 +2859,10 @@ sub process {
# Only applies when adding the entry originally, after that we do not have # Only applies when adding the entry originally, after that we do not have
# sufficient context to determine whether it is indeed long enough. # sufficient context to determine whether it is indeed long enough.
if ($realfile =~ /Kconfig/ && if ($realfile =~ /Kconfig/ &&
$line =~ /^\+\s*config\s+/) { # 'choice' is usually the last thing on the line (though
# Kconfig supports named choices), so use a word boundary
# (\b) rather than a whitespace character (\s)
$line =~ /^\+\s*(?:config|menuconfig|choice)\b/) {
my $length = 0; my $length = 0;
my $cnt = $realcnt; my $cnt = $realcnt;
my $ln = $linenr + 1; my $ln = $linenr + 1;
@ -2810,9 +2877,13 @@ sub process {
next if ($f =~ /^-/); next if ($f =~ /^-/);
last if (!$file && $f =~ /^\@\@/); last if (!$file && $f =~ /^\@\@/);
if ($lines[$ln - 1] =~ /^\+\s*(?:bool|tristate)\s*\"/) { if ($lines[$ln - 1] =~ /^\+\s*(?:bool|tristate|prompt)\s*["']/) {
$is_start = 1; $is_start = 1;
} elsif ($lines[$ln - 1] =~ /^\+\s*(?:---)?help(?:---)?$/) { } elsif ($lines[$ln - 1] =~ /^\+\s*(?:help|---help---)\s*$/) {
if ($lines[$ln - 1] =~ "---help---") {
WARN("CONFIG_DESCRIPTION",
"prefer 'help' over '---help---' for new help texts\n" . $herecurr);
}
$length = -1; $length = -1;
} }
@ -2820,7 +2891,13 @@ sub process {
$f =~ s/#.*//; $f =~ s/#.*//;
$f =~ s/^\s+//; $f =~ s/^\s+//;
next if ($f =~ /^$/); next if ($f =~ /^$/);
if ($f =~ /^\s*config\s/) {
# This only checks context lines in the patch
# and so hopefully shouldn't trigger false
# positives, even though some of these are
# common words in help texts
if ($f =~ /^\s*(?:config|menuconfig|choice|endchoice|
if|endif|menu|endmenu|source)\b/x) {
$is_end = 1; $is_end = 1;
last; last;
} }
@ -2896,6 +2973,30 @@ sub process {
} }
} }
# check for using SPDX license tag at beginning of files
if ($realline == $checklicenseline) {
if ($rawline =~ /^[ \+]\s*\#\!\s*\//) {
$checklicenseline = 2;
} elsif ($rawline =~ /^\+/) {
my $comment = "";
if ($realfile =~ /\.(h|s|S)$/) {
$comment = '/*';
} elsif ($realfile =~ /\.(c|dts|dtsi)$/) {
$comment = '//';
} elsif (($checklicenseline == 2) || $realfile =~ /\.(sh|pl|py|awk|tc)$/) {
$comment = '#';
} elsif ($realfile =~ /\.rst$/) {
$comment = '..';
}
if ($comment !~ /^$/ &&
$rawline !~ /^\+\Q$comment\E SPDX-License-Identifier: /) {
WARN("SPDX_LICENSE_TAG",
"Missing or malformed SPDX-License-Identifier tag in line $checklicenseline\n" . $herecurr);
}
}
}
# check we are in a valid source file if not then ignore this hunk # check we are in a valid source file if not then ignore this hunk
next if ($realfile !~ /\.(h|c|s|S|sh|dtsi|dts)$/); next if ($realfile !~ /\.(h|c|s|S|sh|dtsi|dts)$/);
@ -2905,6 +3006,7 @@ sub process {
# logging functions like pr_info that end in a string # logging functions like pr_info that end in a string
# lines with a single string # lines with a single string
# #defines that are a single string # #defines that are a single string
# lines with an RFC3986 like URL
# #
# There are 3 different line length message types: # There are 3 different line length message types:
# LONG_LINE_COMMENT a comment starts before but extends beyond $max_line_length # LONG_LINE_COMMENT a comment starts before but extends beyond $max_line_length
@ -2931,8 +3033,13 @@ sub process {
$line =~ /^\+\s*#\s*define\s+\w+\s+$String$/) { $line =~ /^\+\s*#\s*define\s+\w+\s+$String$/) {
$msg_type = ""; $msg_type = "";
# EFI_GUID is another special case # More special cases
} elsif ($line =~ /^\+.*\bEFI_GUID\s*\(/) { } elsif ($line =~ /^\+.*\bEFI_GUID\s*\(/ ||
$line =~ /^\+\s*(?:\w+)?\s*DEFINE_PER_CPU/) {
$msg_type = "";
# URL ($rawline is used in case the URL is in a comment)
} elsif ($rawline =~ /^\+.*\b[a-z][\w\.\+\-]*:\/\/\S+/i) {
$msg_type = ""; $msg_type = "";
# Otherwise set the alternate message types # Otherwise set the alternate message types
@ -2961,20 +3068,6 @@ sub process {
"adding a line without newline at end of file\n" . $herecurr); "adding a line without newline at end of file\n" . $herecurr);
} }
# Blackfin: use hi/lo macros
if ($realfile =~ m@arch/blackfin/.*\.S$@) {
if ($line =~ /\.[lL][[:space:]]*=.*&[[:space:]]*0x[fF][fF][fF][fF]/) {
my $herevet = "$here\n" . cat_vet($line) . "\n";
ERROR("LO_MACRO",
"use the LO() macro, not (... & 0xFFFF)\n" . $herevet);
}
if ($line =~ /\.[hH][[:space:]]*=.*>>[[:space:]]*16/) {
my $herevet = "$here\n" . cat_vet($line) . "\n";
ERROR("HI_MACRO",
"use the HI() macro, not (... >> 16)\n" . $herevet);
}
}
# check we are in a valid source file C or perl if not then ignore this hunk # check we are in a valid source file C or perl if not then ignore this hunk
next if ($realfile !~ /\.(h|c|pl|dtsi|dts)$/); next if ($realfile !~ /\.(h|c|pl|dtsi|dts)$/);
@ -3004,6 +3097,12 @@ sub process {
} }
} }
# check for assignments on the start of a line
if ($sline =~ /^\+\s+($Assignment)[^=]/) {
CHK("ASSIGNMENT_CONTINUATIONS",
"Assignment operator '$1' should be on the previous line\n" . $hereprev);
}
# check for && or || at the start of a line # check for && or || at the start of a line
if ($rawline =~ /^\+\s*(&&|\|\|)/) { if ($rawline =~ /^\+\s*(&&|\|\|)/) {
CHK("LOGICAL_CONTINUATIONS", CHK("LOGICAL_CONTINUATIONS",
@ -3012,7 +3111,7 @@ sub process {
# check indentation starts on a tab stop # check indentation starts on a tab stop
if ($^V && $^V ge 5.10.0 && if ($^V && $^V ge 5.10.0 &&
$sline =~ /^\+\t+( +)(?:$c90_Keywords\b|\{\s*$|\}\s*(?:else\b|while\b|\s*$))/) { $sline =~ /^\+\t+( +)(?:$c90_Keywords\b|\{\s*$|\}\s*(?:else\b|while\b|\s*$)|$Declare\s*$Ident\s*[;=])/) {
my $indent = length($1); my $indent = length($1);
if ($indent % 8) { if ($indent % 8) {
if (WARN("TABSTOP", if (WARN("TABSTOP",
@ -3134,6 +3233,7 @@ sub process {
$line =~ /^\+[a-z_]*init/ || $line =~ /^\+[a-z_]*init/ ||
$line =~ /^\+\s*(?:static\s+)?[A-Z_]*ATTR/ || $line =~ /^\+\s*(?:static\s+)?[A-Z_]*ATTR/ ||
$line =~ /^\+\s*DECLARE/ || $line =~ /^\+\s*DECLARE/ ||
$line =~ /^\+\s*builtin_[\w_]*driver/ ||
$line =~ /^\+\s*__setup/)) { $line =~ /^\+\s*__setup/)) {
if (CHK("LINE_SPACING", if (CHK("LINE_SPACING",
"Please use a blank line after function/struct/union/enum declarations\n" . $hereprev) && "Please use a blank line after function/struct/union/enum declarations\n" . $hereprev) &&
@ -3213,6 +3313,12 @@ sub process {
# check we are in a valid C source file if not then ignore this hunk # check we are in a valid C source file if not then ignore this hunk
next if ($realfile !~ /\.(h|c)$/); next if ($realfile !~ /\.(h|c)$/);
# check for unusual line ending [ or (
if ($line =~ /^\+.*([\[\(])\s*$/) {
CHK("OPEN_ENDED_LINE",
"Lines should not end with a '$1'\n" . $herecurr);
}
# check if this appears to be the start function declaration, save the name # check if this appears to be the start function declaration, save the name
if ($sline =~ /^\+\{\s*$/ && if ($sline =~ /^\+\{\s*$/ &&
$prevline =~ /^\+(?:(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*)?($Ident)\(/) { $prevline =~ /^\+(?:(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*)?($Ident)\(/) {
@ -3254,18 +3360,6 @@ sub process {
"CVS style keyword markers, these will _not_ be updated\n". $herecurr); "CVS style keyword markers, these will _not_ be updated\n". $herecurr);
} }
# Blackfin: don't use __builtin_bfin_[cs]sync
if ($line =~ /__builtin_bfin_csync/) {
my $herevet = "$here\n" . cat_vet($line) . "\n";
ERROR("CSYNC",
"use the CSYNC() macro in asm/blackfin.h\n" . $herevet);
}
if ($line =~ /__builtin_bfin_ssync/) {
my $herevet = "$here\n" . cat_vet($line) . "\n";
ERROR("SSYNC",
"use the SSYNC() macro in asm/blackfin.h\n" . $herevet);
}
# check for old HOTPLUG __dev<foo> section markings # check for old HOTPLUG __dev<foo> section markings
if ($line =~ /\b(__dev(init|exit)(data|const|))\b/) { if ($line =~ /\b(__dev(init|exit)(data|const|))\b/) {
WARN("HOTPLUG_SECTION", WARN("HOTPLUG_SECTION",
@ -3860,28 +3954,10 @@ sub process {
"Prefer printk_ratelimited or pr_<level>_ratelimited to printk_ratelimit\n" . $herecurr); "Prefer printk_ratelimited or pr_<level>_ratelimited to printk_ratelimit\n" . $herecurr);
} }
# printk should use KERN_* levels. Note that follow on printk's on the # printk should use KERN_* levels
# same line do not need a level, so we use the current block context if ($line =~ /\bprintk\s*\(\s*(?!KERN_[A-Z]+\b)/) {
# to try and find and validate the current printk. In summary the current WARN("PRINTK_WITHOUT_KERN_LEVEL",
# printk includes all preceding printk's which have no newline on the end. "printk() should include KERN_<LEVEL> facility level\n" . $herecurr);
# we assume the first bad printk is the one to report.
if ($line =~ /\bprintk\((?!KERN_)\s*"/) {
my $ok = 0;
for (my $ln = $linenr - 1; $ln >= $first_line; $ln--) {
#print "CHECK<$lines[$ln - 1]\n";
# we have a preceding printk if it ends
# with "\n" ignore it, else it is to blame
if ($lines[$ln - 1] =~ m{\bprintk\(}) {
if ($rawlines[$ln - 1] !~ m{\\n"}) {
$ok = 1;
}
last;
}
}
if ($ok == 0) {
WARN("PRINTK_WITHOUT_KERN_LEVEL",
"printk() should include KERN_ facility level\n" . $herecurr);
}
} }
if ($line =~ /\bprintk\s*\(\s*KERN_([A-Z]+)/) { if ($line =~ /\bprintk\s*\(\s*KERN_([A-Z]+)/) {
@ -3922,12 +3998,12 @@ sub process {
# function brace can't be on same line, except for #defines of do while, # function brace can't be on same line, except for #defines of do while,
# or if closed on same line # or if closed on same line
if (($line=~/$Type\s*$Ident\(.*\).*\s*{/) and if ($^V && $^V ge 5.10.0 &&
#coreboot - Ignore struct lines with attributes - they're not functions $sline =~ /$Type\s*$Ident\s*$balanced_parens\s*\{/ &&
($line!~/struct.*__attribute__\(\(.*\)\)/) and $sline !~ /\#\s*define\b.*do\s*\{/ &&
!($line=~/\#\s*define.*do\s\{/) and !($line=~/}/)) { $sline !~ /}/) {
if (ERROR("OPEN_BRACE", if (ERROR("OPEN_BRACE",
"open brace '{' following function declarations go on the next line\n" . $herecurr) && "open brace '{' following function definitions go on the next line\n" . $herecurr) &&
$fix) { $fix) {
fix_delete_line($fixlinenr, $rawline); fix_delete_line($fixlinenr, $rawline);
my $fixed_line = $rawline; my $fixed_line = $rawline;
@ -4533,7 +4609,9 @@ sub process {
} }
# check for unnecessary parentheses around comparisons in if uses # check for unnecessary parentheses around comparisons in if uses
if ($^V && $^V ge 5.10.0 && defined($stat) && # when !drivers/staging or command-line uses --strict
if (($realfile !~ m@^(?:drivers/staging/)@ || $check_orig) &&
$^V && $^V ge 5.10.0 && defined($stat) &&
$stat =~ /(^.\s*if\s*($balanced_parens))/) { $stat =~ /(^.\s*if\s*($balanced_parens))/) {
my $if_stat = $1; my $if_stat = $1;
my $test = substr($2, 1, -1); my $test = substr($2, 1, -1);
@ -4944,12 +5022,8 @@ sub process {
#print "REST<$rest> dstat<$dstat> ctx<$ctx>\n"; #print "REST<$rest> dstat<$dstat> ctx<$ctx>\n";
$ctx =~ s/\n*$//; $ctx =~ s/\n*$//;
my $herectx = $here . "\n";
my $stmt_cnt = statement_rawlines($ctx); my $stmt_cnt = statement_rawlines($ctx);
my $herectx = get_stat_here($linenr, $stmt_cnt, $here);
for (my $n = 0; $n < $stmt_cnt; $n++) {
$herectx .= raw_line($linenr, $n) . "\n";
}
if ($dstat ne '' && if ($dstat ne '' &&
$dstat !~ /^(?:$Ident|-?$Constant),$/ && # 10, // foo(), $dstat !~ /^(?:$Ident|-?$Constant),$/ && # 10, // foo(),
@ -5004,7 +5078,7 @@ sub process {
$tmp_stmt =~ s/\b(typeof|__typeof__|__builtin\w+|typecheck\s*\(\s*$Type\s*,|\#+)\s*\(*\s*$arg\s*\)*\b//g; $tmp_stmt =~ s/\b(typeof|__typeof__|__builtin\w+|typecheck\s*\(\s*$Type\s*,|\#+)\s*\(*\s*$arg\s*\)*\b//g;
$tmp_stmt =~ s/\#+\s*$arg\b//g; $tmp_stmt =~ s/\#+\s*$arg\b//g;
$tmp_stmt =~ s/\b$arg\s*\#\#//g; $tmp_stmt =~ s/\b$arg\s*\#\#//g;
my $use_cnt = $tmp_stmt =~ s/\b$arg\b//g; my $use_cnt = () = $tmp_stmt =~ /\b$arg\b/g;
if ($use_cnt > 1) { if ($use_cnt > 1) {
CHK("MACRO_ARG_REUSE", CHK("MACRO_ARG_REUSE",
"Macro argument reuse '$arg' - possible side-effects?\n" . "$herectx"); "Macro argument reuse '$arg' - possible side-effects?\n" . "$herectx");
@ -5021,12 +5095,9 @@ sub process {
# check for macros with flow control, but without ## concatenation # check for macros with flow control, but without ## concatenation
# ## concatenation is commonly a macro that defines a function so ignore those # ## concatenation is commonly a macro that defines a function so ignore those
if ($has_flow_statement && !$has_arg_concat) { if ($has_flow_statement && !$has_arg_concat) {
my $herectx = $here . "\n";
my $cnt = statement_rawlines($ctx); my $cnt = statement_rawlines($ctx);
my $herectx = get_stat_here($linenr, $cnt, $here);
for (my $n = 0; $n < $cnt; $n++) {
$herectx .= raw_line($linenr, $n) . "\n";
}
WARN("MACRO_WITH_FLOW_CONTROL", WARN("MACRO_WITH_FLOW_CONTROL",
"Macros with flow control statements should be avoided\n" . "$herectx"); "Macros with flow control statements should be avoided\n" . "$herectx");
} }
@ -5066,11 +5137,7 @@ sub process {
$ctx =~ s/\n*$//; $ctx =~ s/\n*$//;
my $cnt = statement_rawlines($ctx); my $cnt = statement_rawlines($ctx);
my $herectx = $here . "\n"; my $herectx = get_stat_here($linenr, $cnt, $here);
for (my $n = 0; $n < $cnt; $n++) {
$herectx .= raw_line($linenr, $n) . "\n";
}
if (($stmts =~ tr/;/;/) == 1 && if (($stmts =~ tr/;/;/) == 1 &&
$stmts !~ /^\s*(if|while|for|switch)\b/) { $stmts !~ /^\s*(if|while|for|switch)\b/) {
@ -5084,27 +5151,13 @@ sub process {
} elsif ($dstat =~ /^\+\s*#\s*define\s+$Ident.*;\s*$/) { } elsif ($dstat =~ /^\+\s*#\s*define\s+$Ident.*;\s*$/) {
$ctx =~ s/\n*$//; $ctx =~ s/\n*$//;
my $cnt = statement_rawlines($ctx); my $cnt = statement_rawlines($ctx);
my $herectx = $here . "\n"; my $herectx = get_stat_here($linenr, $cnt, $here);
for (my $n = 0; $n < $cnt; $n++) {
$herectx .= raw_line($linenr, $n) . "\n";
}
WARN("TRAILING_SEMICOLON", WARN("TRAILING_SEMICOLON",
"macros should not use a trailing semicolon\n" . "$herectx"); "macros should not use a trailing semicolon\n" . "$herectx");
} }
} }
# make sure symbols are always wrapped with VMLINUX_SYMBOL() ...
# all assignments may have only one of the following with an assignment:
# .
# ALIGN(...)
# VMLINUX_SYMBOL(...)
if ($realfile eq 'vmlinux.lds.h' && $line =~ /(?:(?:^|\s)$Ident\s*=|=\s*$Ident(?:\s|$))/) {
WARN("MISSING_VMLINUX_SYMBOL",
"vmlinux.lds.h needs VMLINUX_SYMBOL() around C-visible symbols\n" . $herecurr);
}
# check for redundant bracing round if etc # check for redundant bracing round if etc
if ($line =~ /(^.*)\bif\b/ && $1 !~ /else\s*$/) { if ($line =~ /(^.*)\bif\b/ && $1 !~ /else\s*$/) {
my ($level, $endln, @chunks) = my ($level, $endln, @chunks) =
@ -5211,12 +5264,8 @@ sub process {
} }
} }
if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) { if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) {
my $herectx = $here . "\n";
my $cnt = statement_rawlines($block); my $cnt = statement_rawlines($block);
my $herectx = get_stat_here($linenr, $cnt, $here);
for (my $n = 0; $n < $cnt; $n++) {
$herectx .= raw_line($linenr, $n) . "\n";
}
WARN("BRACES", WARN("BRACES",
"braces {} are not necessary for single statement blocks\n" . $herectx); "braces {} are not necessary for single statement blocks\n" . $herectx);
@ -5351,7 +5400,7 @@ sub process {
} }
# check for line continuations in quoted strings with odd counts of " # check for line continuations in quoted strings with odd counts of "
if ($rawline =~ /\\$/ && $rawline =~ tr/"/"/ % 2) { if ($rawline =~ /\\$/ && $sline =~ tr/"/"/ % 2) {
WARN("LINE_CONTINUATIONS", WARN("LINE_CONTINUATIONS",
"Avoid line continuations in quoted strings\n" . $herecurr); "Avoid line continuations in quoted strings\n" . $herecurr);
} }
@ -5630,6 +5679,12 @@ sub process {
} }
} }
# check for smp_read_barrier_depends and read_barrier_depends
if (!$file && $line =~ /\b(smp_|)read_barrier_depends\s*\(/) {
WARN("READ_BARRIER_DEPENDS",
"$1read_barrier_depends should only be used in READ_ONCE or DEC Alpha code\n" . $herecurr);
}
# check of hardware specific defines # check of hardware specific defines
if ($line =~ m@^.\s*\#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $realfile !~ m@include/asm-@) { if ($line =~ m@^.\s*\#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $realfile !~ m@include/asm-@) {
CHK("ARCH_DEFINES", CHK("ARCH_DEFINES",
@ -5786,29 +5841,50 @@ sub process {
} }
} }
# check for vsprintf extension %p<foo> misuses # check for vsprintf extension %p<foo> misuses
if ($^V && $^V ge 5.10.0 && if ($^V && $^V ge 5.10.0 &&
defined $stat && defined $stat &&
$stat =~ /^\+(?![^\{]*\{\s*).*\b(\w+)\s*\(.*$String\s*,/s && $stat =~ /^\+(?![^\{]*\{\s*).*\b(\w+)\s*\(.*$String\s*,/s &&
$1 !~ /^_*volatile_*$/) { $1 !~ /^_*volatile_*$/) {
my $bad_extension = ""; my $stat_real;
my $lc = $stat =~ tr@\n@@; my $lc = $stat =~ tr@\n@@;
$lc = $lc + $linenr; $lc = $lc + $linenr;
for (my $count = $linenr; $count <= $lc; $count++) { for (my $count = $linenr; $count <= $lc; $count++) {
my $specifier;
my $extension;
my $bad_specifier = "";
my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0)); my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0));
$fmt =~ s/%%//g; $fmt =~ s/%%//g;
if ($fmt =~ /(\%[\*\d\.]*p(?![\WFfSsBKRraEhMmIiUDdgVCbGNO]).)/) {
$bad_extension = $1; while ($fmt =~ /(\%[\*\d\.]*p(\w))/g) {
last; $specifier = $1;
$extension = $2;
if ($extension !~ /[SsBKRraEhMmIiUDdgVCbGNOx]/) {
$bad_specifier = $specifier;
last;
}
if ($extension eq "x" && !defined($stat_real)) {
if (!defined($stat_real)) {
$stat_real = get_stat_real($linenr, $lc);
}
WARN("VSPRINTF_SPECIFIER_PX",
"Using vsprintf specifier '\%px' potentially exposes the kernel memory layout, if you don't really need the address please consider using '\%p'.\n" . "$here\n$stat_real\n");
}
} }
} if ($bad_specifier ne "") {
if ($bad_extension ne "") { my $stat_real = get_stat_real($linenr, $lc);
my $stat_real = raw_line($linenr, 0); my $ext_type = "Invalid";
for (my $count = $linenr + 1; $count <= $lc; $count++) { my $use = "";
$stat_real = $stat_real . "\n" . raw_line($count, 0); if ($bad_specifier =~ /p[Ff]/) {
$ext_type = "Deprecated";
$use = " - use %pS instead";
$use =~ s/pS/ps/ if ($bad_specifier =~ /pf/);
}
WARN("VSPRINTF_POINTER_EXTENSION",
"$ext_type vsprintf pointer extension '$bad_specifier'$use\n" . "$here\n$stat_real\n");
} }
WARN("VSPRINTF_POINTER_EXTENSION",
"Invalid vsprintf pointer extension '$bad_extension'\n" . "$here\n$stat_real\n");
} }
} }
@ -5921,10 +5997,7 @@ sub process {
$stat !~ /(?:$Compare)\s*\bsscanf\s*$balanced_parens/)) { $stat !~ /(?:$Compare)\s*\bsscanf\s*$balanced_parens/)) {
my $lc = $stat =~ tr@\n@@; my $lc = $stat =~ tr@\n@@;
$lc = $lc + $linenr; $lc = $lc + $linenr;
my $stat_real = raw_line($linenr, 0); my $stat_real = get_stat_real($linenr, $lc);
for (my $count = $linenr + 1; $count <= $lc; $count++) {
$stat_real = $stat_real . "\n" . raw_line($count, 0);
}
WARN("NAKED_SSCANF", WARN("NAKED_SSCANF",
"unchecked sscanf return value\n" . "$here\n$stat_real\n"); "unchecked sscanf return value\n" . "$here\n$stat_real\n");
} }
@ -5935,10 +6008,7 @@ sub process {
$line =~ /\bsscanf\b/) { $line =~ /\bsscanf\b/) {
my $lc = $stat =~ tr@\n@@; my $lc = $stat =~ tr@\n@@;
$lc = $lc + $linenr; $lc = $lc + $linenr;
my $stat_real = raw_line($linenr, 0); my $stat_real = get_stat_real($linenr, $lc);
for (my $count = $linenr + 1; $count <= $lc; $count++) {
$stat_real = $stat_real . "\n" . raw_line($count, 0);
}
if ($stat_real =~ /\bsscanf\b\s*\(\s*$FuncArg\s*,\s*("[^"]+")/) { if ($stat_real =~ /\bsscanf\b\s*\(\s*$FuncArg\s*,\s*("[^"]+")/) {
my $format = $6; my $format = $6;
my $count = $format =~ tr@%@%@; my $count = $format =~ tr@%@%@;
@ -5992,7 +6062,7 @@ sub process {
# check for function declarations that have arguments without identifier names # check for function declarations that have arguments without identifier names
if (defined $stat && if (defined $stat &&
$stat =~ /^.\s*(?:extern\s+)?$Type\s*$Ident\s*\(\s*([^{]+)\s*\)\s*;/s && $stat =~ /^.\s*(?:extern\s+)?$Type\s*(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*\(\s*([^{]+)\s*\)\s*;/s &&
$1 ne "void") { $1 ne "void") {
my $args = trim($1); my $args = trim($1);
while ($args =~ m/\s*($Type\s*(?:$Ident|\(\s*\*\s*$Ident?\s*\)\s*$balanced_parens)?)/g) { while ($args =~ m/\s*($Type\s*(?:$Ident|\(\s*\*\s*$Ident?\s*\)\s*$balanced_parens)?)/g) {
@ -6068,12 +6138,9 @@ sub process {
} }
if ($r1 !~ /^sizeof\b/ && $r2 =~ /^sizeof\s*\S/ && if ($r1 !~ /^sizeof\b/ && $r2 =~ /^sizeof\s*\S/ &&
!($r1 =~ /^$Constant$/ || $r1 =~ /^[A-Z_][A-Z0-9_]*$/)) { !($r1 =~ /^$Constant$/ || $r1 =~ /^[A-Z_][A-Z0-9_]*$/)) {
my $ctx = '';
my $herectx = $here . "\n";
my $cnt = statement_rawlines($stat); my $cnt = statement_rawlines($stat);
for (my $n = 0; $n < $cnt; $n++) { my $herectx = get_stat_here($linenr, $cnt, $here);
$herectx .= raw_line($linenr, $n) . "\n";
}
if (WARN("ALLOC_WITH_MULTIPLY", if (WARN("ALLOC_WITH_MULTIPLY",
"Prefer $newfunc over $oldfunc with multiply\n" . $herectx) && "Prefer $newfunc over $oldfunc with multiply\n" . $herectx) &&
$cnt == 1 && $cnt == 1 &&
@ -6144,7 +6211,7 @@ sub process {
next if ($fline =~ /^.[\s$;]*$/); next if ($fline =~ /^.[\s$;]*$/);
$has_statement = 1; $has_statement = 1;
$count++; $count++;
$has_break = 1 if ($fline =~ /\bswitch\b|\b(?:break\s*;[\s$;]*$|return\b|goto\b|continue\b)/); $has_break = 1 if ($fline =~ /\bswitch\b|\b(?:break\s*;[\s$;]*$|exit\s*\(\b|return\b|goto\b|continue\b)/);
} }
if (!$has_break && $has_statement) { if (!$has_break && $has_statement) {
WARN("MISSING_BREAK", WARN("MISSING_BREAK",
@ -6156,12 +6223,9 @@ sub process {
if ($^V && $^V ge 5.10.0 && if ($^V && $^V ge 5.10.0 &&
defined $stat && defined $stat &&
$stat =~ /^\+[$;\s]*(?:case[$;\s]+\w+[$;\s]*:[$;\s]*|)*[$;\s]*\bdefault[$;\s]*:[$;\s]*;/g) { $stat =~ /^\+[$;\s]*(?:case[$;\s]+\w+[$;\s]*:[$;\s]*|)*[$;\s]*\bdefault[$;\s]*:[$;\s]*;/g) {
my $ctx = '';
my $herectx = $here . "\n";
my $cnt = statement_rawlines($stat); my $cnt = statement_rawlines($stat);
for (my $n = 0; $n < $cnt; $n++) { my $herectx = get_stat_here($linenr, $cnt, $here);
$herectx .= raw_line($linenr, $n) . "\n";
}
WARN("DEFAULT_NO_BREAK", WARN("DEFAULT_NO_BREAK",
"switch default: should use break\n" . $herectx); "switch default: should use break\n" . $herectx);
} }
@ -6214,6 +6278,12 @@ sub process {
} }
} }
# check for bool bitfields
if ($sline =~ /^.\s+bool\s*$Ident\s*:\s*\d+\s*;/) {
WARN("BOOL_BITFIELD",
"Avoid using bool as bitfield. Prefer bool bitfields as unsigned int or u<8|16|32>\n" . $herecurr);
}
# check for semaphores initialized locked # check for semaphores initialized locked
if ($line =~ /^.\s*sema_init.+,\W?0\W?\)/) { if ($line =~ /^.\s*sema_init.+,\W?0\W?\)/) {
WARN("CONSIDER_COMPLETION", WARN("CONSIDER_COMPLETION",
@ -6277,28 +6347,6 @@ sub process {
} }
} }
# whine about ACCESS_ONCE
if ($^V && $^V ge 5.10.0 &&
$line =~ /\bACCESS_ONCE\s*$balanced_parens\s*(=(?!=))?\s*($FuncArg)?/) {
my $par = $1;
my $eq = $2;
my $fun = $3;
$par =~ s/^\(\s*(.*)\s*\)$/$1/;
if (defined($eq)) {
if (WARN("PREFER_WRITE_ONCE",
"Prefer WRITE_ONCE(<FOO>, <BAR>) over ACCESS_ONCE(<FOO>) = <BAR>\n" . $herecurr) &&
$fix) {
$fixed[$fixlinenr] =~ s/\bACCESS_ONCE\s*\(\s*\Q$par\E\s*\)\s*$eq\s*\Q$fun\E/WRITE_ONCE($par, $fun)/;
}
} else {
if (WARN("PREFER_READ_ONCE",
"Prefer READ_ONCE(<FOO>) over ACCESS_ONCE(<FOO>)\n" . $herecurr) &&
$fix) {
$fixed[$fixlinenr] =~ s/\bACCESS_ONCE\s*\(\s*\Q$par\E\s*\)/READ_ONCE($par)/;
}
}
}
# check for mutex_trylock_recursive usage # check for mutex_trylock_recursive usage
if ($line =~ /mutex_trylock_recursive/) { if ($line =~ /mutex_trylock_recursive/) {
ERROR("LOCKING", ERROR("LOCKING",
@ -6322,8 +6370,69 @@ sub process {
"Exporting world writable files is usually an error. Consider more restrictive permissions.\n" . $herecurr); "Exporting world writable files is usually an error. Consider more restrictive permissions.\n" . $herecurr);
} }
# check for DEVICE_ATTR uses that could be DEVICE_ATTR_<FOO>
# and whether or not function naming is typical and if
# DEVICE_ATTR permissions uses are unusual too
if ($^V && $^V ge 5.10.0 &&
defined $stat &&
$stat =~ /\bDEVICE_ATTR\s*\(\s*(\w+)\s*,\s*\(?\s*(\s*(?:${multi_mode_perms_string_search}|0[0-7]{3,3})\s*)\s*\)?\s*,\s*(\w+)\s*,\s*(\w+)\s*\)/) {
my $var = $1;
my $perms = $2;
my $show = $3;
my $store = $4;
my $octal_perms = perms_to_octal($perms);
if ($show =~ /^${var}_show$/ &&
$store =~ /^${var}_store$/ &&
$octal_perms eq "0644") {
if (WARN("DEVICE_ATTR_RW",
"Use DEVICE_ATTR_RW\n" . $herecurr) &&
$fix) {
$fixed[$fixlinenr] =~ s/\bDEVICE_ATTR\s*\(\s*$var\s*,\s*\Q$perms\E\s*,\s*$show\s*,\s*$store\s*\)/DEVICE_ATTR_RW(${var})/;
}
} elsif ($show =~ /^${var}_show$/ &&
$store =~ /^NULL$/ &&
$octal_perms eq "0444") {
if (WARN("DEVICE_ATTR_RO",
"Use DEVICE_ATTR_RO\n" . $herecurr) &&
$fix) {
$fixed[$fixlinenr] =~ s/\bDEVICE_ATTR\s*\(\s*$var\s*,\s*\Q$perms\E\s*,\s*$show\s*,\s*NULL\s*\)/DEVICE_ATTR_RO(${var})/;
}
} elsif ($show =~ /^NULL$/ &&
$store =~ /^${var}_store$/ &&
$octal_perms eq "0200") {
if (WARN("DEVICE_ATTR_WO",
"Use DEVICE_ATTR_WO\n" . $herecurr) &&
$fix) {
$fixed[$fixlinenr] =~ s/\bDEVICE_ATTR\s*\(\s*$var\s*,\s*\Q$perms\E\s*,\s*NULL\s*,\s*$store\s*\)/DEVICE_ATTR_WO(${var})/;
}
} elsif ($octal_perms eq "0644" ||
$octal_perms eq "0444" ||
$octal_perms eq "0200") {
my $newshow = "$show";
$newshow = "${var}_show" if ($show ne "NULL" && $show ne "${var}_show");
my $newstore = $store;
$newstore = "${var}_store" if ($store ne "NULL" && $store ne "${var}_store");
my $rename = "";
if ($show ne $newshow) {
$rename .= " '$show' to '$newshow'";
}
if ($store ne $newstore) {
$rename .= " '$store' to '$newstore'";
}
WARN("DEVICE_ATTR_FUNCTIONS",
"Consider renaming function(s)$rename\n" . $herecurr);
} else {
WARN("DEVICE_ATTR_PERMS",
"DEVICE_ATTR unusual permissions '$perms' used\n" . $herecurr);
}
}
# Mode permission misuses where it seems decimal should be octal # Mode permission misuses where it seems decimal should be octal
# This uses a shortcut match to avoid unnecessary uses of a slow foreach loop # This uses a shortcut match to avoid unnecessary uses of a slow foreach loop
# o Ignore module_param*(...) uses with a decimal 0 permission as that has a
# specific definition of not visible in sysfs.
# o Ignore proc_create*(...) uses with a decimal 0 permission as that means
# use the default permissions
if ($^V && $^V ge 5.10.0 && if ($^V && $^V ge 5.10.0 &&
defined $stat && defined $stat &&
$line =~ /$mode_perms_search/) { $line =~ /$mode_perms_search/) {
@ -6333,10 +6442,7 @@ sub process {
my $lc = $stat =~ tr@\n@@; my $lc = $stat =~ tr@\n@@;
$lc = $lc + $linenr; $lc = $lc + $linenr;
my $stat_real = raw_line($linenr, 0); my $stat_real = get_stat_real($linenr, $lc);
for (my $count = $linenr + 1; $count <= $lc; $count++) {
$stat_real = $stat_real . "\n" . raw_line($count, 0);
}
my $skip_args = ""; my $skip_args = "";
if ($arg_pos > 1) { if ($arg_pos > 1) {
@ -6347,8 +6453,9 @@ sub process {
if ($stat =~ /$test/) { if ($stat =~ /$test/) {
my $val = $1; my $val = $1;
$val = $6 if ($skip_args ne ""); $val = $6 if ($skip_args ne "");
if (($val =~ /^$Int$/ && $val !~ /^$Octal$/) || if (!($func =~ /^(?:module_param|proc_create)/ && $val eq "0") &&
($val =~ /^$Octal$/ && length($val) ne 4)) { (($val =~ /^$Int$/ && $val !~ /^$Octal$/) ||
($val =~ /^$Octal$/ && length($val) ne 4))) {
ERROR("NON_OCTAL_PERMISSIONS", ERROR("NON_OCTAL_PERMISSIONS",
"Use 4 digit octal (0777) not decimal permissions\n" . "$here\n" . $stat_real); "Use 4 digit octal (0777) not decimal permissions\n" . "$here\n" . $stat_real);
} }
@ -6361,30 +6468,13 @@ sub process {
} }
# check for uses of S_<PERMS> that could be octal for readability # check for uses of S_<PERMS> that could be octal for readability
if ($line =~ /\b$mode_perms_string_search\b/) { while ($line =~ m{\b($multi_mode_perms_string_search)\b}g) {
my $val = ""; my $oval = $1;
my $oval = ""; my $octal = perms_to_octal($oval);
my $to = 0;
my $curpos = 0;
my $lastpos = 0;
while ($line =~ /\b(($mode_perms_string_search)\b(?:\s*\|\s*)?\s*)/g) {
$curpos = pos($line);
my $match = $2;
my $omatch = $1;
last if ($lastpos > 0 && ($curpos - length($omatch) != $lastpos));
$lastpos = $curpos;
$to |= $mode_permission_string_types{$match};
$val .= '\s*\|\s*' if ($val ne "");
$val .= $match;
$oval .= $omatch;
}
$oval =~ s/^\s*\|\s*//;
$oval =~ s/\s*\|\s*$//;
my $octal = sprintf("%04o", $to);
if (WARN("SYMBOLIC_PERMS", if (WARN("SYMBOLIC_PERMS",
"Symbolic permissions '$oval' are not preferred. Consider using octal permissions '$octal'.\n" . $herecurr) && "Symbolic permissions '$oval' are not preferred. Consider using octal permissions '$octal'.\n" . $herecurr) &&
$fix) { $fix) {
$fixed[$fixlinenr] =~ s/$val/$octal/; $fixed[$fixlinenr] =~ s/\Q$oval\E/$octal/;
} }
} }
@ -6425,7 +6515,7 @@ sub process {
exit(0); exit(0);
} }
if (!$is_patch && $file !~ /cover-letter\.patch$/) { if (!$is_patch && $filename !~ /cover-letter\.patch$/) {
ERROR("NOT_UNIFIED_DIFF", ERROR("NOT_UNIFIED_DIFF",
"Does not appear to be a unified-diff format patch\n"); "Does not appear to be a unified-diff format patch\n");
} }