checkpatch: update with latest checkpatch from the linux kernel

Update with commit 577f12c07e4edd54730dc559a9c7bc44d22bf7dc from
the Linux kernel.

Change-Id: Ie2cabbfea415d26ffacef340d9497342b496dc29
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
This commit is contained in:
Anas Nashif 2016-11-07 15:57:57 -05:00 committed by Anas Nashif
parent 302d23d1a6
commit 0f3d5478a8

View file

@ -27,12 +27,15 @@ my $emacs = 0;
my $terse = 0;
my $showfile = 0;
my $file = 0;
my $git = 0;
my %git_commits = ();
my $check = 0;
my $check_orig = 0;
my $summary = 1;
my $mailback = 0;
my $summary_file = 0;
my $show_types = 0;
my $list_types = 0;
my $fix = 0;
my $fix_inplace = 0;
my $root;
@ -42,8 +45,8 @@ my %use_type = ();
my @use = ();
my %ignore_type = ();
my @ignore = ();
my @exclude = ();
my $help = 0;
my @exclude = ();
my $configuration_file = ".checkpatch.conf";
my $max_line_length = 80;
my $ignore_perl_version = 0;
@ -52,7 +55,9 @@ my $min_conf_desc_length = 4;
my $spelling_file = "$D/spelling.txt";
my $codespell = 0;
my $codespellfile = "/usr/share/codespell/dictionary.txt";
my $conststructsfile = "$D/const_structs.checkpatch";
my $color = 1;
my $allow_c99_comments = 1;
sub help {
my ($exitcode) = @_;
@ -69,14 +74,25 @@ Options:
--emacs emacs compile window format
--terse one line per report
--showfile emit diffed file position, not input file position
-g, --git treat FILE as a single commit or git revision range
single git commit with:
<rev>
<rev>^
<rev>~n
multiple git commits with:
<rev1>..<rev2>
<rev1>...<rev2>
<rev>-<count>
git merges are ignored
-f, --file treat FILE as regular source file
--subjective, --strict enable more subjective tests
--list-types list the possible message types
--types TYPE(,TYPE2...) show only these comma separated message types
--ignore TYPE(,TYPE2...) ignore various comma separated message types
--show-types show the specific message type in the output
--exclude DIR(,DIR22...) exclude directories
--max-line-length=n set the maximum line length, if exceeded, warn
--min-conf-desc-length=n set the min description length, if shorter, warn
--show-types show the message "types" in the output
--root=PATH PATH to the kernel tree root
--no-summary suppress the per-file summary
--mailback only produce a report in case of warnings/errors
@ -108,6 +124,37 @@ EOM
exit($exitcode);
}
sub uniq {
my %seen;
return grep { !$seen{$_}++ } @_;
}
sub list_types {
my ($exitcode) = @_;
my $count = 0;
local $/ = undef;
open(my $script, '<', abs_path($P)) or
die "$P: Can't read '$P' $!\n";
my $text = <$script>;
close($script);
my @types = ();
for ($text =~ /\b(?:(?:CHK|WARN|ERROR)\s*\(\s*"([^"]+)")/g) {
push (@types, $_);
}
@types = sort(uniq(@types));
print("#\tMessage type\n\n");
foreach my $type (@types) {
print(++$count . "\t" . $type . "\n");
}
exit($exitcode);
}
my $conf = which_conf($configuration_file);
if (-f $conf) {
my @conf_args;
@ -143,12 +190,14 @@ GetOptions(
'terse!' => \$terse,
'showfile!' => \$showfile,
'f|file!' => \$file,
'g|git!' => \$git,
'subjective!' => \$check,
'strict!' => \$check,
'ignore=s' => \@ignore,
'exclude=s' => \@exclude,
'exclude=s' => \@exclude,
'types=s' => \@use,
'show-types!' => \$show_types,
'list-types!' => \$list_types,
'max-line-length=i' => \$max_line_length,
'min-conf-desc-length=i' => \$min_conf_desc_length,
'root=s' => \$root,
@ -169,6 +218,8 @@ GetOptions(
help(0) if ($help);
list_types(0) if ($list_types);
$fix = 1 if ($fix_inplace);
$check_orig = $check;
@ -181,9 +232,9 @@ if ($^V && $^V lt $minimum_perl_version) {
}
}
#if no filenames are given, push '-' to read patch from stdin
if ($#ARGV < 0) {
print "$P: no input files\n";
exit(1);
push(@ARGV, '-');
}
sub hash_save_array_words {
@ -267,12 +318,12 @@ our $Sparse = qr{
__kernel|
__force|
__iomem|
__pmem|
__must_check|
__init_refok|
__kprobes|
__ref|
__rcu
__rcu|
__private
}x;
our $InitAttributePrefix = qr{__(?:mem|cpu|dev|net_|)};
our $InitAttributeData = qr{$InitAttributePrefix(?:initdata\b)};
@ -476,7 +527,11 @@ our @mode_permission_funcs = (
["module_param_array_named", 5],
["debugfs_create_(?:file|u8|u16|u32|u64|x8|x16|x32|x64|size_t|atomic_t|bool|blob|regset32|u32_array)", 2],
["proc_create(?:_data|)", 2],
["(?:CLASS|DEVICE|SENSOR)_ATTR", 2],
["(?:CLASS|DEVICE|SENSOR|SENSOR_DEVICE|IIO_DEVICE)_ATTR", 2],
["IIO_DEV_ATTR_[A-Z_]+", 1],
["SENSOR_(?:DEVICE_|)ATTR_2", 2],
["SENSOR_TEMPLATE(?:_2|)", 3],
["__ATTR", 2],
);
#Create a search pattern for all these functions to speed up a loop below
@ -494,6 +549,32 @@ our $mode_perms_world_writable = qr{
0[0-7][0-7][2367]
}x;
our %mode_permission_string_types = (
"S_IRWXU" => 0700,
"S_IRUSR" => 0400,
"S_IWUSR" => 0200,
"S_IXUSR" => 0100,
"S_IRWXG" => 0070,
"S_IRGRP" => 0040,
"S_IWGRP" => 0020,
"S_IXGRP" => 0010,
"S_IRWXO" => 0007,
"S_IROTH" => 0004,
"S_IWOTH" => 0002,
"S_IXOTH" => 0001,
"S_IRWXUGO" => 0777,
"S_IRUGO" => 0444,
"S_IWUGO" => 0222,
"S_IXUGO" => 0111,
);
#Create a search pattern for all these strings to speed up a loop below
our $mode_perms_string_search = "";
foreach my $entry (keys %mode_permission_string_types) {
$mode_perms_string_search .= '|' if ($mode_perms_string_search ne "");
$mode_perms_string_search .= $entry;
}
our $allowed_asm_includes = qr{(?x:
irq|
memory|
@ -551,6 +632,29 @@ if ($codespell) {
$misspellings = join("|", sort keys %spelling_fix) if keys %spelling_fix;
my $const_structs = "";
if (open(my $conststructs, '<', $conststructsfile)) {
while (<$conststructs>) {
my $line = $_;
$line =~ s/\s*\n?$//g;
$line =~ s/^\s*//g;
next if ($line =~ m/^\s*#/);
next if ($line =~ m/^\s*$/);
if ($line =~ /\s/) {
print("$conststructsfile: '$line' invalid - ignored\n");
next;
}
$const_structs .= '|' if ($const_structs ne "");
$const_structs .= $line;
}
close($conststructsfile);
#} else {
# warn "No structs that should be const will be found - file '$conststructsfile': $!\n";
}
sub build_types {
my $mods = "(?x: \n" . join("|\n ", (@modifierList, @modifierListFile)) . "\n)";
my $all = "(?x: \n" . join("|\n ", (@typeList, @typeListFile)) . "\n)";
@ -754,10 +858,42 @@ my @fixed_inserted = ();
my @fixed_deleted = ();
my $fixlinenr = -1;
# If input is git commits, extract all commits from the commit expressions.
# For example, HEAD-3 means we need check 'HEAD, HEAD~1, HEAD~2'.
die "$P: No git repository found\n" if ($git && !-e ".git");
if ($git) {
my @commits = ();
foreach my $commit_expr (@ARGV) {
my $git_range;
if ($commit_expr =~ m/^(.*)-(\d+)$/) {
$git_range = "-$2 $1";
} elsif ($commit_expr =~ m/\.\./) {
$git_range = "$commit_expr";
} else {
$git_range = "-1 $commit_expr";
}
my $lines = `git log --no-color --no-merges --pretty=format:'%H %s' $git_range`;
foreach my $line (split(/\n/, $lines)) {
$line =~ /^([0-9a-fA-F]{40,40}) (.*)$/;
next if (!defined($1) || !defined($2));
my $sha1 = $1;
my $subject = $2;
unshift(@commits, $sha1);
$git_commits{$sha1} = $subject;
}
}
die "$P: no git commits after extraction!\n" if (@commits == 0);
@ARGV = @commits;
}
my $vname;
for my $filename (@ARGV) {
my $FILE;
if ($file) {
if ($git) {
open($FILE, '-|', "git format-patch -M --stdout -1 $filename") ||
die "$P: $filename: git format-patch failed - $!\n";
} elsif ($file) {
open($FILE, '-|', "diff -u /dev/null $filename") ||
die "$P: $filename: diff failed - $!\n";
} elsif ($filename eq '-') {
@ -768,6 +904,8 @@ for my $filename (@ARGV) {
}
if ($filename eq '-') {
$vname = 'Your patch';
} elsif ($git) {
$vname = "Commit " . substr($filename, 0, 12) . ' ("' . $git_commits{$filename} . '")';
} else {
$vname = $filename;
}
@ -812,7 +950,7 @@ EOM
print << "EOM"
NOTE: If any of the errors are false positives, please report
them to the maintainer.
them to the maintainer, see CHECKPATCH in MAINTAINERS.
EOM
}
}
@ -1064,6 +1202,11 @@ sub sanitise_line {
$res =~ s@(\#\s*(?:error|warning)\s+).*@$1$clean@;
}
if ($allow_c99_comments && $res =~ m@(//.*$)@) {
my $match = $1;
$res =~ s/\Q$match\E/"$;" x length($match)/e;
}
return $res;
}
@ -1983,6 +2126,7 @@ sub process {
my $is_patch = 0;
my $in_header_lines = $file ? 0 : 1;
my $in_commit_log = 0; #Scanning lines before patch
my $has_commit_log = 0; #Encountered lines before patch
my $commit_log_possible_stack_dump = 0;
my $commit_log_long_line = 0;
my $commit_log_has_diff = 0;
@ -2256,7 +2400,7 @@ sub process {
# Check if MAINTAINERS is being updated. If so, there's probably no need to
# emit the "does MAINTAINERS need updating?" message on file add/move/delete
if ($realfile =~ /MAINTAINERS/) {
if ($line =~ /^\s*MAINTAINERS\s*\|/) {
$reported_maintainer_file = 1;
}
@ -2376,8 +2520,9 @@ sub process {
# Check for git id commit length and improperly formed commit descriptions
if ($in_commit_log && !$commit_log_possible_stack_dump &&
$line !~ /^\s*(?:Link|Patchwork|http|https|BugLink):/i &&
($line =~ /\bcommit\s+[0-9a-f]{5,}\b/i ||
($line =~ /\b[0-9a-f]{12,40}\b/i &&
($line =~ /(?:\s|^)[0-9a-f]{12,40}(?:[\s"'\(\[]|$)/i &&
$line !~ /[\<\[][0-9a-f]{12,40}[\>\]]/i &&
$line !~ /\bfixes:\s*[0-9a-f]{12,40}/i))) {
my $init_char = "c";
@ -2482,6 +2627,7 @@ sub process {
$rawline =~ /^(commit\b|from\b|[\w-]+:).*$/i)) {
$in_header_lines = 0;
$in_commit_log = 1;
$has_commit_log = 1;
}
# Check if there is UTF-8 in a commit log when a mail header has explicitly
@ -2691,6 +2837,10 @@ sub process {
$line =~ /^\+\s*#\s*define\s+\w+\s+$String$/) {
$msg_type = "";
# EFI_GUID is another special case
} elsif ($line =~ /^\+.*\bEFI_GUID\s*\(/) {
$msg_type = "";
# Otherwise set the alternate message types
# a comment starts before $max_line_length
@ -2766,6 +2916,19 @@ sub process {
"Logical continuations should be on the previous line\n" . $hereprev);
}
# check indentation starts on a tab stop
if ($^V && $^V ge 5.10.0 &&
$sline =~ /^\+\t+( +)(?:$c90_Keywords\b|\{\s*$|\}\s*(?:else\b|while\b|\s*$))/) {
my $indent = length($1);
if ($indent % 8) {
if (WARN("TABSTOP",
"Statements should start on a tabstop\n" . $herecurr) &&
$fix) {
$fixed[$fixlinenr] =~ s@(^\+\t+) +@$1 . "\t" x ($indent/8)@e;
}
}
}
# check multi-line statement indentation matches previous line
if ($^V && $^V ge 5.10.0 &&
$prevline =~ /^\+([ \t]*)((?:$c90_Keywords(?:\s+if)\s*)|(?:$Declare\s*)?(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*|$Ident\s*=\s*$Ident\s*)\(.*(\&\&|\|\||,)\s*$/) {
@ -2842,6 +3005,30 @@ sub process {
"Block comments use a trailing */ on a separate line\n" . $herecurr);
}
# Block comment * alignment
if ($prevline =~ /$;[ \t]*$/ && #ends in comment
$line =~ /^\+[ \t]*$;/ && #leading comment
$rawline =~ /^\+[ \t]*\*/ && #leading *
(($prevrawline =~ /^\+.*?\/\*/ && #leading /*
$prevrawline !~ /\*\/[ \t]*$/) || #no trailing */
$prevrawline =~ /^\+[ \t]*\*/)) { #leading *
my $oldindent;
$prevrawline =~ m@^\+([ \t]*/?)\*@;
if (defined($1)) {
$oldindent = expand_tabs($1);
} else {
$prevrawline =~ m@^\+(.*/?)\*@;
$oldindent = expand_tabs($1);
}
$rawline =~ m@^\+([ \t]*)\*@;
my $newindent = $1;
$newindent = expand_tabs($newindent);
if (length($oldindent) ne length($newindent)) {
WARN("BLOCK_COMMENT_STYLE",
"Block comments should align the * on each line\n" . $hereprev);
}
}
# check for missing blank lines after struct/union declarations
# with exceptions for various attributes and macros
if ($prevline =~ /^[\+ ]};?\s*$/ &&
@ -3251,6 +3438,30 @@ sub process {
#ignore lines not being added
next if ($line =~ /^[^\+]/);
# check for declarations of signed or unsigned without int
while ($line =~ m{\b($Declare)\s*(?!char\b|short\b|int\b|long\b)\s*($Ident)?\s*[=,;\[\)\(]}g) {
my $type = $1;
my $var = $2;
$var = "" if (!defined $var);
if ($type =~ /^(?:(?:$Storage|$Inline|$Attribute)\s+)*((?:un)?signed)((?:\s*\*)*)\s*$/) {
my $sign = $1;
my $pointer = $2;
$pointer = "" if (!defined $pointer);
if (WARN("UNSPECIFIED_INT",
"Prefer '" . trim($sign) . " int" . rtrim($pointer) . "' to bare use of '$sign" . rtrim($pointer) . "'\n" . $herecurr) &&
$fix) {
my $decl = trim($sign) . " int ";
my $comp_pointer = $pointer;
$comp_pointer =~ s/\s//g;
$decl .= $comp_pointer;
$decl = rtrim($decl) if ($var eq "");
$fixed[$fixlinenr] =~ s@\b$sign\s*\Q$pointer\E\s*$var\b@$decl$var@;
}
}
}
# TEST: allow direct testing of the type matcher.
if ($dbg_type) {
if ($line =~ /^.\s*$Declare\s*$/) {
@ -3449,15 +3660,6 @@ sub process {
}
}
# check for uses of DEFINE_PCI_DEVICE_TABLE
if ($line =~ /\bDEFINE_PCI_DEVICE_TABLE\s*\(\s*(\w+)\s*\)\s*=/) {
if (WARN("DEFINE_PCI_DEVICE_TABLE",
"Prefer struct pci_device_id over deprecated DEFINE_PCI_DEVICE_TABLE\n" . $herecurr) &&
$fix) {
$fixed[$fixlinenr] =~ s/\b(?:static\s+|)DEFINE_PCI_DEVICE_TABLE\s*\(\s*(\w+)\s*\)\s*=\s*/static const struct pci_device_id $1\[\] = /;
}
}
# check for new typedefs, only function parameters and sparse annotations
# make sense.
if ($line =~ /\btypedef\s/ &&
@ -4121,7 +4323,7 @@ sub process {
## }
#need space before brace following if, while, etc
if (($line =~ /\(.*\)\{/ && $line !~ /\($Type\){/) ||
if (($line =~ /\(.*\)\{/ && $line !~ /\($Type\)\{/) ||
$line =~ /do\{/) {
if (ERROR("SPACING",
"space required before the open brace '{'\n" . $herecurr) &&
@ -4279,7 +4481,7 @@ sub process {
my $comp = $3;
my $to = $4;
my $newcomp = $comp;
if ($lead !~ /$Operators\s*$/ &&
if ($lead !~ /(?:$Operators|\.)\s*$/ &&
$to !~ /^(?:Constant|[A-Z_][A-Z0-9_]*)$/ &&
WARN("CONSTANT_COMPARISON",
"Comparisons should place the constant on the right side of the test\n" . $herecurr) &&
@ -4554,7 +4756,17 @@ sub process {
$has_flow_statement = 1 if ($ctx =~ /\b(goto|return)\b/);
$has_arg_concat = 1 if ($ctx =~ /\#\#/ && $ctx !~ /\#\#\s*(?:__VA_ARGS__|args)\b/);
$dstat =~ s/^.\s*\#\s*define\s+$Ident(?:\([^\)]*\))?\s*//;
$dstat =~ s/^.\s*\#\s*define\s+$Ident(\([^\)]*\))?\s*//;
my $define_args = $1;
my $define_stmt = $dstat;
my @def_args = ();
if (defined $define_args && $define_args ne "") {
$define_args = substr($define_args, 1, length($define_args) - 2);
$define_args =~ s/\s*//g;
@def_args = split(",", $define_args);
}
$dstat =~ s/$;//g;
$dstat =~ s/\\\n.//g;
$dstat =~ s/^\s*//s;
@ -4573,6 +4785,9 @@ sub process {
{
}
# Make asm volatile uses seem like a generic function
$dstat =~ s/\b_*asm_*\s+_*volatile_*\b/asm_volatile/g;
my $exceptions = qr{
$Declare|
module_param_named|
@ -4587,6 +4802,15 @@ sub process {
^\[
}x;
#print "REST<$rest> dstat<$dstat> ctx<$ctx>\n";
$ctx =~ s/\n*$//;
my $herectx = $here . "\n";
my $stmt_cnt = statement_rawlines($ctx);
for (my $n = 0; $n < $stmt_cnt; $n++) {
$herectx .= raw_line($linenr, $n) . "\n";
}
if ($dstat ne '' &&
$dstat !~ /^(?:$Ident|-?$Constant),$/ && # 10, // foo(),
$dstat !~ /^(?:$Ident|-?$Constant);$/ && # foo();
@ -4602,13 +4826,6 @@ sub process {
$dstat !~ /^\(\{/ && # ({...
$ctx !~ /^.\s*#\s*define\s+TRACE_(?:SYSTEM|INCLUDE_FILE|INCLUDE_PATH)\b/)
{
$ctx =~ s/\n*$//;
my $herectx = $here . "\n";
my $cnt = statement_rawlines($ctx);
for (my $n = 0; $n < $cnt; $n++) {
$herectx .= raw_line($linenr, $n) . "\n";
}
if ($dstat =~ /;/) {
WARN("MULTISTATEMENT_MACRO_USE_DO_WHILE",
@ -4617,6 +4834,46 @@ sub process {
WARN("COMPLEX_MACRO",
"Macros with complex values should be enclosed in parentheses\n" . "$herectx");
}
}
# Make $define_stmt single line, comment-free, etc
my @stmt_array = split('\n', $define_stmt);
my $first = 1;
$define_stmt = "";
foreach my $l (@stmt_array) {
$l =~ s/\\$//;
if ($first) {
$define_stmt = $l;
$first = 0;
} elsif ($l =~ /^[\+ ]/) {
$define_stmt .= substr($l, 1);
}
}
$define_stmt =~ s/$;//g;
$define_stmt =~ s/\s+/ /g;
$define_stmt = trim($define_stmt);
# check if any macro arguments are reused (ignore '...' and 'type')
foreach my $arg (@def_args) {
next if ($arg =~ /\.\.\./);
next if ($arg =~ /^type$/i);
my $tmp = $define_stmt;
$tmp =~ s/\b(typeof|__typeof__|__builtin\w+|typecheck\s*\(\s*$Type\s*,|\#+)\s*\(*\s*$arg\s*\)*\b//g;
$tmp =~ s/\#+\s*$arg\b//g;
$tmp =~ s/\b$arg\s*\#\#//g;
my $use_cnt = $tmp =~ s/\b$arg\b//g;
if ($use_cnt > 1) {
CHK("MACRO_ARG_REUSE",
"Macro argument reuse '$arg' - possible side-effects?\n" . "$herectx");
}
# check if any macro arguments may have other precedence issues
if ($define_stmt =~ m/($Operators)?\s*\b$arg\b\s*($Operators)?/m &&
((defined($1) && $1 ne ',') ||
(defined($2) && $2 ne ','))) {
CHK("MACRO_ARG_PRECEDENCE",
"Macro argument '$arg' may be better as '($arg)' to avoid precedence issues\n" . "$herectx");
}
}
# check for macros with flow control, but without ## concatenation
@ -5381,46 +5638,46 @@ sub process {
}
# Check for memcpy(foo, bar, ETH_ALEN) that could be ether_addr_copy(foo, bar)
if ($^V && $^V ge 5.10.0 &&
defined $stat &&
$stat =~ /^\+(?:.*?)\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
if (WARN("PREFER_ETHER_ADDR_COPY",
"Prefer ether_addr_copy() over memcpy() if the Ethernet addresses are __aligned(2)\n" . "$here\n$stat\n") &&
$fix) {
$fixed[$fixlinenr] =~ s/\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/ether_addr_copy($2, $7)/;
}
}
# if ($^V && $^V ge 5.10.0 &&
# defined $stat &&
# $stat =~ /^\+(?:.*?)\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
# if (WARN("PREFER_ETHER_ADDR_COPY",
# "Prefer ether_addr_copy() over memcpy() if the Ethernet addresses are __aligned(2)\n" . "$here\n$stat\n") &&
# $fix) {
# $fixed[$fixlinenr] =~ s/\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/ether_addr_copy($2, $7)/;
# }
# }
# Check for memcmp(foo, bar, ETH_ALEN) that could be ether_addr_equal*(foo, bar)
if ($^V && $^V ge 5.10.0 &&
defined $stat &&
$stat =~ /^\+(?:.*?)\bmemcmp\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
WARN("PREFER_ETHER_ADDR_EQUAL",
"Prefer ether_addr_equal() or ether_addr_equal_unaligned() over memcmp()\n" . "$here\n$stat\n")
}
# if ($^V && $^V ge 5.10.0 &&
# defined $stat &&
# $stat =~ /^\+(?:.*?)\bmemcmp\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
# WARN("PREFER_ETHER_ADDR_EQUAL",
# "Prefer ether_addr_equal() or ether_addr_equal_unaligned() over memcmp()\n" . "$here\n$stat\n")
# }
# check for memset(foo, 0x0, ETH_ALEN) that could be eth_zero_addr
# check for memset(foo, 0xFF, ETH_ALEN) that could be eth_broadcast_addr
if ($^V && $^V ge 5.10.0 &&
defined $stat &&
$stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
my $ms_val = $7;
if ($ms_val =~ /^(?:0x|)0+$/i) {
if (WARN("PREFER_ETH_ZERO_ADDR",
"Prefer eth_zero_addr over memset()\n" . "$here\n$stat\n") &&
$fix) {
$fixed[$fixlinenr] =~ s/\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*,\s*ETH_ALEN\s*\)/eth_zero_addr($2)/;
}
} elsif ($ms_val =~ /^(?:0xff|255)$/i) {
if (WARN("PREFER_ETH_BROADCAST_ADDR",
"Prefer eth_broadcast_addr() over memset()\n" . "$here\n$stat\n") &&
$fix) {
$fixed[$fixlinenr] =~ s/\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*,\s*ETH_ALEN\s*\)/eth_broadcast_addr($2)/;
}
}
}
# if ($^V && $^V ge 5.10.0 &&
# defined $stat &&
# $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
#
# my $ms_val = $7;
#
# if ($ms_val =~ /^(?:0x|)0+$/i) {
# if (WARN("PREFER_ETH_ZERO_ADDR",
# "Prefer eth_zero_addr over memset()\n" . "$here\n$stat\n") &&
# $fix) {
# $fixed[$fixlinenr] =~ s/\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*,\s*ETH_ALEN\s*\)/eth_zero_addr($2)/;
# }
# } elsif ($ms_val =~ /^(?:0xff|255)$/i) {
# if (WARN("PREFER_ETH_BROADCAST_ADDR",
# "Prefer eth_broadcast_addr() over memset()\n" . "$here\n$stat\n") &&
# $fix) {
# $fixed[$fixlinenr] =~ s/\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*,\s*ETH_ALEN\s*\)/eth_broadcast_addr($2)/;
# }
# }
# }
# typecasts on min/max could be min_t/max_t
if ($^V && $^V ge 5.10.0 &&
@ -5540,6 +5797,19 @@ sub process {
"externs should be avoided in .c files\n" . $herecurr);
}
if ($realfile =~ /\.[ch]$/ && defined $stat &&
$stat =~ /^.\s*(?:extern\s+)?$Type\s*$Ident\s*\(\s*([^{]+)\s*\)\s*;/s &&
$1 ne "void") {
my $args = trim($1);
while ($args =~ m/\s*($Type\s*(?:$Ident|\(\s*\*\s*$Ident?\s*\)\s*$balanced_parens)?)/g) {
my $arg = trim($1);
if ($arg =~ /^$Type$/ && $arg !~ /enum\s+$Ident$/) {
WARN("FUNCTION_ARGUMENTS",
"function definition argument '$arg' should also have an identifier name\n" . $herecurr);
}
}
}
# checks for new __setup's
if ($rawline =~ /\b__setup\("([^"]*)"/) {
my $name = $1;
@ -5611,8 +5881,9 @@ sub process {
}
}
# check for #defines like: 1 << <digit> that could be BIT(digit)
if ($line =~ /#\s*define\s+\w+\s+\(?\s*1\s*([ulUL]*)\s*\<\<\s*(?:\d+|$Ident)\s*\)?/) {
# check for #defines like: 1 << <digit> that could be BIT(digit), it is not exported to uapi
if ($realfile !~ m@^include/uapi/@ &&
$line =~ /#\s*define\s+\w+\s+\(?\s*1\s*([ulUL]*)\s*\<\<\s*(?:\d+|$Ident)\s*\)?/) {
my $ull = "";
$ull = "_ULL" if (defined($1) && $1 =~ /ll/i);
if (CHK("BIT_MACRO",
@ -5622,6 +5893,16 @@ sub process {
}
}
# check for #if defined CONFIG_<FOO> || defined CONFIG_<FOO>_MODULE
if ($line =~ /^\+\s*#\s*if\s+defined(?:\s*\(?\s*|\s+)(CONFIG_[A-Z_]+)\s*\)?\s*\|\|\s*defined(?:\s*\(?\s*|\s+)\1_MODULE\s*\)?\s*$/) {
my $config = $1;
if (WARN("PREFER_IS_ENABLED",
"Prefer IS_ENABLED(<FOO>) to CONFIG_<FOO> || CONFIG_<FOO>_MODULE\n" . $herecurr) &&
$fix) {
$fixed[$fixlinenr] = "\+#if IS_ENABLED($config)";
}
}
# check for case / default statements not preceded by break/fallthrough/switch
if ($line =~ /^.\s*(?:case\s+(?:$Ident|$Constant)\s*|default):/) {
my $has_break = 0;
@ -5728,46 +6009,6 @@ sub process {
}
# check for various structs that are normally const (ops, kgdb, device_tree)
my $const_structs = qr{
acpi_dock_ops|
address_space_operations|
backlight_ops|
block_device_operations|
dentry_operations|
dev_pm_ops|
dma_map_ops|
extent_io_ops|
file_lock_operations|
file_operations|
hv_ops|
ide_dma_ops|
intel_dvo_dev_ops|
item_operations|
iwl_ops|
kgdb_arch|
kgdb_io|
kset_uevent_ops|
lock_manager_operations|
microcode_ops|
mtrr_ops|
neigh_ops|
nlmsvc_binding|
of_device_id|
pci_raw_ops|
pipe_buf_operations|
platform_hibernation_ops|
platform_suspend_ops|
proto_ops|
rpc_pipe_ops|
seq_operations|
snd_ac97_build_ops|
soc_pcmcia_socket_ops|
stacktrace_ops|
sysfs_ops|
tty_operations|
uart_ops|
usb_mon_operations|
wd_ops}x;
if ($line !~ /\bconst\b/ &&
$line =~ /\bstruct\s+($const_structs)\b/) {
WARN("CONST_STRUCT",
@ -5812,6 +6053,28 @@ 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 lockdep_set_novalidate_class
if ($line =~ /^.\s*lockdep_set_novalidate_class\s*\(/ ||
$line =~ /__lockdep_no_validate__\s*\)/ ) {
@ -5832,34 +6095,69 @@ sub process {
# Mode permission misuses where it seems decimal should be octal
# This uses a shortcut match to avoid unnecessary uses of a slow foreach loop
if ($^V && $^V ge 5.10.0 &&
defined $stat &&
$line =~ /$mode_perms_search/) {
foreach my $entry (@mode_permission_funcs) {
my $func = $entry->[0];
my $arg_pos = $entry->[1];
my $lc = $stat =~ tr@\n@@;
$lc = $lc + $linenr;
my $stat_real = raw_line($linenr, 0);
for (my $count = $linenr + 1; $count <= $lc; $count++) {
$stat_real = $stat_real . "\n" . raw_line($count, 0);
}
my $skip_args = "";
if ($arg_pos > 1) {
$arg_pos--;
$skip_args = "(?:\\s*$FuncArg\\s*,\\s*){$arg_pos,$arg_pos}";
}
my $test = "\\b$func\\s*\\(${skip_args}([\\d]+)\\s*[,\\)]";
if ($line =~ /$test/) {
my $test = "\\b$func\\s*\\(${skip_args}($FuncArg(?:\\|\\s*$FuncArg)*)\\s*[,\\)]";
if ($stat =~ /$test/) {
my $val = $1;
$val = $6 if ($skip_args ne "");
if ($val !~ /^0$/ &&
(($val =~ /^$Int$/ && $val !~ /^$Octal$/) ||
length($val) ne 4)) {
if (($val =~ /^$Int$/ && $val !~ /^$Octal$/) ||
($val =~ /^$Octal$/ && length($val) ne 4)) {
ERROR("NON_OCTAL_PERMISSIONS",
"Use 4 digit octal (0777) not decimal permissions\n" . $herecurr);
} elsif ($val =~ /^$Octal$/ && (oct($val) & 02)) {
"Use 4 digit octal (0777) not decimal permissions\n" . "$here\n" . $stat_real);
}
if ($val =~ /^$Octal$/ && (oct($val) & 02)) {
ERROR("EXPORTED_WORLD_WRITABLE",
"Exporting writable files is usually an error. Consider more restrictive permissions.\n" . $herecurr);
"Exporting writable files is usually an error. Consider more restrictive permissions.\n" . "$here\n" . $stat_real);
}
}
}
}
# check for uses of S_<PERMS> that could be octal for readability
if ($line =~ /\b$mode_perms_string_search\b/) {
my $val = "";
my $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",
"Symbolic permissions '$oval' are not preferred. Consider using octal permissions '$octal'.\n" . $herecurr) &&
$fix) {
$fixed[$fixlinenr] =~ s/$val/$octal/;
}
}
# validate content of MODULE_LICENSE against list from include/linux/module.h
if ($line =~ /\bMODULE_LICENSE\s*\(\s*($String)\s*\)/) {
my $extracted_string = get_quoted_string($line, $rawline);
@ -5901,7 +6199,7 @@ sub process {
ERROR("NOT_UNIFIED_DIFF",
"Does not appear to be a unified-diff format patch\n");
}
if ($is_patch && $filename ne '-' && $chk_signoff && $signoff == 0) {
if ($is_patch && $has_commit_log && $chk_signoff && $signoff == 0) {
ERROR("MISSING_SIGN_OFF",
"Missing Signed-off-by: line(s)\n");
}
@ -5915,14 +6213,12 @@ sub process {
}
if ($quiet == 0) {
# If there were whitespace errors which cleanpatch can fix
# then suggest that.
if ($rpt_cleaners) {
$rpt_cleaners = 0;
# If there were any defects found and not already fixing them
if (!$clean and !$fix) {
print << "EOM"
NOTE: Whitespace errors detected.
You may wish to use scripts/cleanpatch or scripts/cleanfile
NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.
EOM
}
}