if (("$test" eq "==" && "$type" eq "true") || ("$test" eq "!=" && "$type" eq "false")) { $op = ""; } CHK("BOOL_COMPARISON", "Using comparison to $otype is error prone\n" . $herecurr); ## maybe suggesting a correct construct would better## "Using comparison to $otype is error prone. Perhaps use '${lead}${op}${arg}${trail}'\n" . $herecurr); } } # check for semaphores initialized locked if ($line =~ /^.\s*sema_init.+,\W?0\W?\)/) { WARN("CONSIDER_COMPLETION", "consider using a completion\n" . $herecurr); } # recommend kstrto* over simple_strto* and strict_strto* if ($line =~ /\b((simple|strict)_(strto(l|ll|ul|ull)))\s*\(/) { WARN("CONSIDER_KSTRTO", "$1 is obsolete, use k$3 instead\n" . $herecurr); } # check for __initcall(), use device_initcall() explicitly or more appropriate function please if ($line =~ /^.\s*__initcall\s*\(/) { WARN("USE_DEVICE_INITCALL", "please use device_initcall() or more appropriate function instead of __initcall() (see include/linux/init.h)\n" . $herecurr); } # check for spin_is_locked(), suggest lockdep instead if ($line =~ /\bspin_is_locked\(/) { WARN("USE_LOCKDEP", "Where possible, use lockdep_assert_held instead of assertions based on spin_is_locked\n" . $herecurr); } # check for deprecated apis if ($line =~ /\b($deprecated_apis_search)\b\s*\(/) { my $deprecated_api = $1; my $new_api = $deprecated_apis{$deprecated_api}; WARN("DEPRECATED_API", "Deprecated use of '$deprecated_api', prefer '$new_api' instead\n" . $herecurr); } # check for various structs that are normally const (ops, kgdb, device_tree)# and avoid what seem like struct definitions 'struct foo {' or forward declarations 'struct foo;' if (defined($const_structs) && $line !~ /\bconst\b/ && $line =~ /\bstruct\s+($const_structs)\b(?!\s*[\{;])/) { WARN("CONST_STRUCT", "struct $1 should normally be const\n" . $herecurr); } # use of NR_CPUS is usually wrong# ignore definitions of NR_CPUS and usage to define arrays as likely right# ignore designated initializers using NR_CPUS if ($line =~ /\bNR_CPUS\b/ && $line !~ /^.\s*\s*#\s*if\b.*\bNR_CPUS\b/ && $line !~ /^.\s*\s*#\s*define\b.*\bNR_CPUS\b/ && $line !~ /^.\s*$Declare\s.*\[[^\]]*NR_CPUS[^\]]*\]/ && $line !~ /\[[^\]]*\.\.\.[^\]]*NR_CPUS[^\]]*\]/ && $line !~ /\[[^\]]*NR_CPUS[^\]]*\.\.\.[^\]]*\]/ && $line !~ /^.\s*\.\w+\s*=\s*.*\bNR_CPUS\b/) { WARN("NR_CPUS", "usage of NR_CPUS is often wrong - consider using cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . $herecurr); } # Use of __ARCH_HAS_<FOO> or ARCH_HAVE_<BAR> is wrong. if ($line =~ /\+\s*#\s*define\s+((?:__)?ARCH_(?:HAS|HAVE)\w*)\b/) { ERROR("DEFINE_ARCH_HAS", "#define of '$1' is wrong - use Kconfig variables or standard guards instead\n" . $herecurr); } # likely/unlikely comparisons similar to "(likely(foo) > 0)" if ($perl_version_ok && $line =~ /\b((?:un)?likely)\s*\(\s*$FuncArg\s*\)\s*$Compare/) { WARN("LIKELY_MISUSE", "Using $1 should generally have parentheses around the comparison\n" . $herecurr); } # return sysfs_emit(foo, fmt, ...) fmt without newline if ($line =~ /\breturn\s+sysfs_emit\s*\(\s*$FuncArg\s*,\s*($String)/ && substr($rawline, $-[6], $+[6] - $-[6]) !~ /\\n"$/) { my $offset = $+[6] - 1; if (WARN("SYSFS_EMIT", "return sysfs_emit(...) formats should include a terminating newline\n" . $herecurr) && $fix) { substr($fixed[$fixlinenr], $offset, 0) = '\\n'; } } # check for array definition/declarations that should use flexible arrays instead if ($sline =~ /^[\+ ]\s*\}(?:\s*__packed)?\s*;\s*$/ && $prevline =~ /^\+\s*(?:\}(?:\s*__packed\s*)?|$Type)\s*$Ident\s*\[\s*(0|1)\s*\]\s*;\s*$/) { if (ERROR("FLEXIBLE_ARRAY", "Use C99 flexible arrays - see https://docs.kernel.org/process/deprecated.html#zero-length-and-one-element-arrays\n" . $hereprev) && $1 == '0' && $fix) { $fixed[$fixlinenr - 1] =~ s/\[\s*0\s*\]/[]/; } } # nested likely/unlikely calls if ($line =~ /\b(?:(?:un)?likely)\s*\(\s*!?\s*(IS_ERR(?:_OR_NULL|_VALUE)?|WARN)/) { WARN("LIKELY_MISUSE", "nested (un)?likely() calls, $1 already uses unlikely() internally\n" . $herecurr); } # whine mightly about in_atomic if ($line =~ /\bin_atomic\s*\(/) { if ($realfile =~ m@^drivers/@) { ERROR("IN_ATOMIC", "do not use in_atomic in drivers\n" . $herecurr); } elsif ($realfile !~ m@^kernel/@) { WARN("IN_ATOMIC", "use of in_atomic() is incorrect outside core kernel code\n" . $herecurr); } } # Complain about RCU Tasks Trace used outside of BPF (and of course, RCU). our $rcu_trace_funcs = qr{(?x: rcu_read_lock_tasks_trace | rcu_read_lock_trace | rcu_read_lock_trace_held | rcu_read_unlock_trace | rcu_read_unlock_tasks_trace | call_rcu_tasks_trace | synchronize_rcu_tasks_trace | rcu_barrier_tasks_trace | rcu_tasks_trace_expedite_current | rcu_request_urgent_qs_task )}; our $rcu_trace_paths = qr{(?x: kernel/bpf/ | include/linux/bpf | net/bpf/ | kernel/rcu/ | include/linux/rcu )}; if ($line =~ /\b($rcu_trace_funcs)\s*\(/) { if ($realfile !~ m{^$rcu_trace_paths}) { WARN("RCU_TASKS_TRACE", "use of RCU tasks trace is incorrect outside BPF or core RCU code\n" . $herecurr); } } # check for lockdep_set_novalidate_class if ($line =~ /^.\s*lockdep_set_novalidate_class\s*\(/ || $line =~ /__lockdep_no_validate__\s*\)/ ) { if ($realfile !~ m@^kernel/lockdep@ && $realfile !~ m@^include/linux/lockdep@ && $realfile !~ m@^drivers/base/core@) { ERROR("LOCKDEP", "lockdep_no_validate class is reserved for device->mutex.\n" . $herecurr); } } if ($line =~ /debugfs_create_\w+.*\b$mode_perms_world_writable\b/ || $line =~ /DEVICE_ATTR.*\b$mode_perms_world_writable\b/) { WARN("EXPORTED_WORLD_WRITABLE", "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 ($perl_version_ok && 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# 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 ($perl_version_ok && 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 = get_stat_real($linenr, $lc); 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}($FuncArg(?:\\|\\s*$FuncArg)*)\\s*[,\\)]"; if ($stat =~ /$test/) { my $val = $1; $val = $6 if ($skip_args ne ""); if (!($func =~ /^(?:module_param|proc_create)/ && $val eq "0") && (($val =~ /^$Int$/ && $val !~ /^$Octal$/) || ($val =~ /^$Octal$/ && length($val) ne 4))) { ERROR("NON_OCTAL_PERMISSIONS", "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" . "$here\n" . $stat_real); } } } } # check for uses of S_<PERMS> that could be octal for readability while ($line =~ m{\b($multi_mode_perms_string_search)\b}g) { my $oval = $1; my $octal = perms_to_octal($oval); if (WARN("SYMBOLIC_PERMS", "Symbolic permissions '$oval' are not preferred. Consider using octal permissions '$octal'.\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\Q$oval\E/$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); my $valid_licenses = qr{ GPL| GPL\ v2| GPL\ and\ additional\ rights| Dual\ BSD/GPL| Dual\ MIT/GPL| Dual\ MPL/GPL| Proprietary }x; if ($extracted_string !~ /^"(?:$valid_licenses)"$/x) { WARN("MODULE_LICENSE", "unknown module license " . $extracted_string . "\n" . $herecurr); } if (!$file && $extracted_string eq '"GPL v2"') { if (WARN("MODULE_LICENSE", "Prefer \"GPL\" over \"GPL v2\" - see commit bf7fbeeae6db (\"module: Cure the MODULE_LICENSE \"GPL\" vs. \"GPL v2\" bogosity\")\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\bMODULE_LICENSE\s*\(\s*"GPL v2"\s*\)/MODULE_LICENSE("GPL")/; } } } # check for sysctl duplicate constants if ($line =~ /\.extra[12]\s*=\s*&(zero|one|int_max)\b/) { WARN("DUPLICATED_SYSCTL_CONST", "duplicated sysctl range checking value '$1', consider using the shared one in include/linux/sysctl.h\n" . $herecurr); } # Check that *_device_id tables have sentinel entries. if (defined $stat && $line =~ /struct\s+$dev_id_types\s+\w+\s*\[\s*\]\s*=\s*\{/) { my $stripped = $stat; # Strip diff line prefixes. $stripped =~ s/(^|\n)./$1/g; # Line continuations. $stripped =~ s/\\\n/\n/g; # Strip whitespace, empty strings, zeroes, and commas. $stripped =~ s/""//g; $stripped =~ s/0x0//g; $stripped =~ s/[\s$;,0]//g; # Strip field assignments. $stripped =~ s/\.$Ident=//g; if (!(substr($stripped, -4) eq "{}};" || substr($stripped, -6) eq "{{}}};" || $stripped =~ /ISAPNP_DEVICE_SINGLE_END}};$/ || $stripped =~ /ISAPNP_CARD_END}};$/ || $stripped =~ /NULL};$/ || $stripped =~ /PCMCIA_DEVICE_NULL};$/)) { ERROR("MISSING_SENTINEL", "missing sentinel in ID array\n" . "$here\n$stat\n"); } } # check for uninitialized pointers with __free attribute while ($line =~ /\*\s*($Ident)\s+__free\s*\(\s*$Ident\s*\)\s*[,;]/g) { ERROR("UNINITIALIZED_PTR_WITH_FREE", "pointer '$1' with __free attribute should be initialized\n" . $herecurr); } } # If we have no input at all, then there is nothing to report on # so just keep quiet. if ($#rawlines == -1) { exit(0); } # In mailback mode only produce a report in the negative, for # things that appear to be patches. if ($mailback && ($clean == 1 || !$is_patch)) { exit(0); } # This is not a patch, and we are in 'no-patch' mode so # just keep quiet. if (!$chk_patch && !$is_patch) { exit(0); } if (!$is_patch && $filename !~ /cover-letter\.patch$/) { ERROR("NOT_UNIFIED_DIFF", "Does not appear to be a unified-diff format patch\n"); } if ($is_patch && $has_commit_log && $chk_fixes_tag) { if ($needs_fixes_tag ne "" && !$is_revert && !$fixes_tag) { WARN("MISSING_FIXES_TAG", "The commit message has '$needs_fixes_tag', perhaps it also needs a 'Fixes:' tag?\n"); } } if ($is_patch && $has_commit_log && $chk_signoff) { if ($signoff == 0) { ERROR("MISSING_SIGN_OFF", "Missing Signed-off-by: line(s)\n"); } elsif ($authorsignoff != 1) { # authorsignoff values: # 0 -> missing sign off # 1 -> sign off identical # 2 -> names and addresses match, comments mismatch # 3 -> addresses match, names different # 4 -> names match, addresses different # 5 -> names match, addresses excluding subaddress details (refer RFC 5233) match my $sob_msg = "'From: $author' != 'Signed-off-by: $author_sob'"; if ($authorsignoff == 0) { ERROR("NO_AUTHOR_SIGN_OFF", "Missing Signed-off-by: line by nominal patch author '$author'\n"); } elsif ($authorsignoff == 2) { CHK("FROM_SIGN_OFF_MISMATCH", "From:/Signed-off-by: email comments mismatch: $sob_msg\n"); } elsif ($authorsignoff == 3) { WARN("FROM_SIGN_OFF_MISMATCH", "From:/Signed-off-by: email name mismatch: $sob_msg\n"); } elsif ($authorsignoff == 4) { WARN("FROM_SIGN_OFF_MISMATCH", "From:/Signed-off-by: email address mismatch: $sob_msg\n"); } elsif ($authorsignoff == 5) { WARN("FROM_SIGN_OFF_MISMATCH", "From:/Signed-off-by: email subaddress mismatch: $sob_msg\n"); } } } print report_dump(); if ($summary && !($clean == 1 && $quiet == 1)) { print "$filename " if ($summary_file); print "total: $cnt_error errors, $cnt_warn warnings, " . (($check)? "$cnt_chk checks, " : "") . "$cnt_lines lines checked\n"; } if ($quiet == 0) { # If there were any defects found and not already fixing them if (!$clean and !$fix) { print << "EOM" NOTE: For some of the reported defects, checkpatch may be able to mechanically convert to the typical style using --fix or --fix-inplace.EOM } # If there were whitespace errors which cleanpatch can fix # then suggest that. if ($rpt_cleaners) { $rpt_cleaners = 0; print << "EOM" NOTE: Whitespace errors detected. You may wish to use scripts/cleanpatch or scripts/cleanfileEOM } } if ($clean == 0 && $fix && ("@rawlines" ne "@fixed" || $#fixed_inserted >= 0 || $#fixed_deleted >= 0)) { my $newfile = $filename; $newfile .= ".EXPERIMENTAL-checkpatch-fixes" if (!$fix_inplace); my $linecount = 0; my $f; @fixed = fix_inserted_deleted_lines(\@fixed, \@fixed_inserted, \@fixed_deleted); open($f, '>', $newfile) or die "$P: Can't open $newfile for write\n"; foreach my $fixed_line (@fixed) { $linecount++; if ($file) { if ($linecount > 3) { $fixed_line =~ s/^\+//; print $f $fixed_line . "\n"; } } else { print $f $fixed_line . "\n"; } } close($f); if (!$quiet) { print << "EOM"; Wrote EXPERIMENTAL --fix correction(s) to '$newfile' Do _NOT_ trust the results written to this file.Do _NOT_ submit these changes without inspecting them for correctness. This EXPERIMENTAL file is simply a convenience to help rewrite patches.No warranties, expressed or implied...EOM } } if ($quiet == 0) { print "\n"; if ($clean == 1) { print "$vname has no obvious style problems and is ready for submission.\n"; } else { print "$vname has style problems, please review.\n"; } } return $clean;}Lines 7501–7976 of 7976. Previous lines
if (("$test" eq "==" && "$type" eq "true") || ("$test" eq "!=" && "$type" eq "false")) { $op = ""; } CHK("BOOL_COMPARISON", "Using comparison to $otype is error prone\n" . $herecurr); ## maybe suggesting a correct construct would better ## "Using comparison to $otype is error prone. Perhaps use '${lead}${op}${arg}${trail}'\n" . $herecurr); } } # check for semaphores initialized locked if ($line =~ /^.\s*sema_init.+,\W?0\W?\)/) { WARN("CONSIDER_COMPLETION", "consider using a completion\n" . $herecurr); } # recommend kstrto* over simple_strto* and strict_strto* if ($line =~ /\b((simple|strict)_(strto(l|ll|ul|ull)))\s*\(/) { WARN("CONSIDER_KSTRTO", "$1 is obsolete, use k$3 instead\n" . $herecurr); } # check for __initcall(), use device_initcall() explicitly or more appropriate function please if ($line =~ /^.\s*__initcall\s*\(/) { WARN("USE_DEVICE_INITCALL", "please use device_initcall() or more appropriate function instead of __initcall() (see include/linux/init.h)\n" . $herecurr); } # check for spin_is_locked(), suggest lockdep instead if ($line =~ /\bspin_is_locked\(/) { WARN("USE_LOCKDEP", "Where possible, use lockdep_assert_held instead of assertions based on spin_is_locked\n" . $herecurr); } # check for deprecated apis if ($line =~ /\b($deprecated_apis_search)\b\s*\(/) { my $deprecated_api = $1; my $new_api = $deprecated_apis{$deprecated_api}; WARN("DEPRECATED_API", "Deprecated use of '$deprecated_api', prefer '$new_api' instead\n" . $herecurr); } # check for various structs that are normally const (ops, kgdb, device_tree) # and avoid what seem like struct definitions 'struct foo {' or forward declarations 'struct foo;' if (defined($const_structs) && $line !~ /\bconst\b/ && $line =~ /\bstruct\s+($const_structs)\b(?!\s*[\{;])/) { WARN("CONST_STRUCT", "struct $1 should normally be const\n" . $herecurr); } # use of NR_CPUS is usually wrong # ignore definitions of NR_CPUS and usage to define arrays as likely right # ignore designated initializers using NR_CPUS if ($line =~ /\bNR_CPUS\b/ && $line !~ /^.\s*\s*#\s*if\b.*\bNR_CPUS\b/ && $line !~ /^.\s*\s*#\s*define\b.*\bNR_CPUS\b/ && $line !~ /^.\s*$Declare\s.*\[[^\]]*NR_CPUS[^\]]*\]/ && $line !~ /\[[^\]]*\.\.\.[^\]]*NR_CPUS[^\]]*\]/ && $line !~ /\[[^\]]*NR_CPUS[^\]]*\.\.\.[^\]]*\]/ && $line !~ /^.\s*\.\w+\s*=\s*.*\bNR_CPUS\b/) { WARN("NR_CPUS", "usage of NR_CPUS is often wrong - consider using cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . $herecurr); } # Use of __ARCH_HAS_<FOO> or ARCH_HAVE_<BAR> is wrong. if ($line =~ /\+\s*#\s*define\s+((?:__)?ARCH_(?:HAS|HAVE)\w*)\b/) { ERROR("DEFINE_ARCH_HAS", "#define of '$1' is wrong - use Kconfig variables or standard guards instead\n" . $herecurr); } # likely/unlikely comparisons similar to "(likely(foo) > 0)" if ($perl_version_ok && $line =~ /\b((?:un)?likely)\s*\(\s*$FuncArg\s*\)\s*$Compare/) { WARN("LIKELY_MISUSE", "Using $1 should generally have parentheses around the comparison\n" . $herecurr); } # return sysfs_emit(foo, fmt, ...) fmt without newline if ($line =~ /\breturn\s+sysfs_emit\s*\(\s*$FuncArg\s*,\s*($String)/ && substr($rawline, $-[6], $+[6] - $-[6]) !~ /\\n"$/) { my $offset = $+[6] - 1; if (WARN("SYSFS_EMIT", "return sysfs_emit(...) formats should include a terminating newline\n" . $herecurr) && $fix) { substr($fixed[$fixlinenr], $offset, 0) = '\\n'; } } # check for array definition/declarations that should use flexible arrays instead if ($sline =~ /^[\+ ]\s*\}(?:\s*__packed)?\s*;\s*$/ && $prevline =~ /^\+\s*(?:\}(?:\s*__packed\s*)?|$Type)\s*$Ident\s*\[\s*(0|1)\s*\]\s*;\s*$/) { if (ERROR("FLEXIBLE_ARRAY", "Use C99 flexible arrays - see https://docs.kernel.org/process/deprecated.html#zero-length-and-one-element-arrays\n" . $hereprev) && $1 == '0' && $fix) { $fixed[$fixlinenr - 1] =~ s/\[\s*0\s*\]/[]/; } } # nested likely/unlikely calls if ($line =~ /\b(?:(?:un)?likely)\s*\(\s*!?\s*(IS_ERR(?:_OR_NULL|_VALUE)?|WARN)/) { WARN("LIKELY_MISUSE", "nested (un)?likely() calls, $1 already uses unlikely() internally\n" . $herecurr); } # whine mightly about in_atomic if ($line =~ /\bin_atomic\s*\(/) { if ($realfile =~ m@^drivers/@) { ERROR("IN_ATOMIC", "do not use in_atomic in drivers\n" . $herecurr); } elsif ($realfile !~ m@^kernel/@) { WARN("IN_ATOMIC", "use of in_atomic() is incorrect outside core kernel code\n" . $herecurr); } } # Complain about RCU Tasks Trace used outside of BPF (and of course, RCU). our $rcu_trace_funcs = qr{(?x: rcu_read_lock_tasks_trace | rcu_read_lock_trace | rcu_read_lock_trace_held | rcu_read_unlock_trace | rcu_read_unlock_tasks_trace | call_rcu_tasks_trace | synchronize_rcu_tasks_trace | rcu_barrier_tasks_trace | rcu_tasks_trace_expedite_current | rcu_request_urgent_qs_task )}; our $rcu_trace_paths = qr{(?x: kernel/bpf/ | include/linux/bpf | net/bpf/ | kernel/rcu/ | include/linux/rcu )}; if ($line =~ /\b($rcu_trace_funcs)\s*\(/) { if ($realfile !~ m{^$rcu_trace_paths}) { WARN("RCU_TASKS_TRACE", "use of RCU tasks trace is incorrect outside BPF or core RCU code\n" . $herecurr); } } # check for lockdep_set_novalidate_class if ($line =~ /^.\s*lockdep_set_novalidate_class\s*\(/ || $line =~ /__lockdep_no_validate__\s*\)/ ) { if ($realfile !~ m@^kernel/lockdep@ && $realfile !~ m@^include/linux/lockdep@ && $realfile !~ m@^drivers/base/core@) { ERROR("LOCKDEP", "lockdep_no_validate class is reserved for device->mutex.\n" . $herecurr); } } if ($line =~ /debugfs_create_\w+.*\b$mode_perms_world_writable\b/ || $line =~ /DEVICE_ATTR.*\b$mode_perms_world_writable\b/) { WARN("EXPORTED_WORLD_WRITABLE", "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 ($perl_version_ok && 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 # 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 ($perl_version_ok && 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 = get_stat_real($linenr, $lc); 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}($FuncArg(?:\\|\\s*$FuncArg)*)\\s*[,\\)]"; if ($stat =~ /$test/) { my $val = $1; $val = $6 if ($skip_args ne ""); if (!($func =~ /^(?:module_param|proc_create)/ && $val eq "0") && (($val =~ /^$Int$/ && $val !~ /^$Octal$/) || ($val =~ /^$Octal$/ && length($val) ne 4))) { ERROR("NON_OCTAL_PERMISSIONS", "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" . "$here\n" . $stat_real); } } } } # check for uses of S_<PERMS> that could be octal for readability while ($line =~ m{\b($multi_mode_perms_string_search)\b}g) { my $oval = $1; my $octal = perms_to_octal($oval); if (WARN("SYMBOLIC_PERMS", "Symbolic permissions '$oval' are not preferred. Consider using octal permissions '$octal'.\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\Q$oval\E/$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); my $valid_licenses = qr{ GPL| GPL\ v2| GPL\ and\ additional\ rights| Dual\ BSD/GPL| Dual\ MIT/GPL| Dual\ MPL/GPL| Proprietary }x; if ($extracted_string !~ /^"(?:$valid_licenses)"$/x) { WARN("MODULE_LICENSE", "unknown module license " . $extracted_string . "\n" . $herecurr); } if (!$file && $extracted_string eq '"GPL v2"') { if (WARN("MODULE_LICENSE", "Prefer \"GPL\" over \"GPL v2\" - see commit bf7fbeeae6db (\"module: Cure the MODULE_LICENSE \"GPL\" vs. \"GPL v2\" bogosity\")\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\bMODULE_LICENSE\s*\(\s*"GPL v2"\s*\)/MODULE_LICENSE("GPL")/; } } } # check for sysctl duplicate constants if ($line =~ /\.extra[12]\s*=\s*&(zero|one|int_max)\b/) { WARN("DUPLICATED_SYSCTL_CONST", "duplicated sysctl range checking value '$1', consider using the shared one in include/linux/sysctl.h\n" . $herecurr); } # Check that *_device_id tables have sentinel entries. if (defined $stat && $line =~ /struct\s+$dev_id_types\s+\w+\s*\[\s*\]\s*=\s*\{/) { my $stripped = $stat; # Strip diff line prefixes. $stripped =~ s/(^|\n)./$1/g; # Line continuations. $stripped =~ s/\\\n/\n/g; # Strip whitespace, empty strings, zeroes, and commas. $stripped =~ s/""//g; $stripped =~ s/0x0//g; $stripped =~ s/[\s$;,0]//g; # Strip field assignments. $stripped =~ s/\.$Ident=//g; if (!(substr($stripped, -4) eq "{}};" || substr($stripped, -6) eq "{{}}};" || $stripped =~ /ISAPNP_DEVICE_SINGLE_END}};$/ || $stripped =~ /ISAPNP_CARD_END}};$/ || $stripped =~ /NULL};$/ || $stripped =~ /PCMCIA_DEVICE_NULL};$/)) { ERROR("MISSING_SENTINEL", "missing sentinel in ID array\n" . "$here\n$stat\n"); } } # check for uninitialized pointers with __free attribute while ($line =~ /\*\s*($Ident)\s+__free\s*\(\s*$Ident\s*\)\s*[,;]/g) { ERROR("UNINITIALIZED_PTR_WITH_FREE", "pointer '$1' with __free attribute should be initialized\n" . $herecurr); } } # If we have no input at all, then there is nothing to report on # so just keep quiet. if ($#rawlines == -1) { exit(0); } # In mailback mode only produce a report in the negative, for # things that appear to be patches. if ($mailback && ($clean == 1 || !$is_patch)) { exit(0); } # This is not a patch, and we are in 'no-patch' mode so # just keep quiet. if (!$chk_patch && !$is_patch) { exit(0); } if (!$is_patch && $filename !~ /cover-letter\.patch$/) { ERROR("NOT_UNIFIED_DIFF", "Does not appear to be a unified-diff format patch\n"); } if ($is_patch && $has_commit_log && $chk_fixes_tag) { if ($needs_fixes_tag ne "" && !$is_revert && !$fixes_tag) { WARN("MISSING_FIXES_TAG", "The commit message has '$needs_fixes_tag', perhaps it also needs a 'Fixes:' tag?\n"); } } if ($is_patch && $has_commit_log && $chk_signoff) { if ($signoff == 0) { ERROR("MISSING_SIGN_OFF", "Missing Signed-off-by: line(s)\n"); } elsif ($authorsignoff != 1) { # authorsignoff values: # 0 -> missing sign off # 1 -> sign off identical # 2 -> names and addresses match, comments mismatch # 3 -> addresses match, names different # 4 -> names match, addresses different # 5 -> names match, addresses excluding subaddress details (refer RFC 5233) match my $sob_msg = "'From: $author' != 'Signed-off-by: $author_sob'"; if ($authorsignoff == 0) { ERROR("NO_AUTHOR_SIGN_OFF", "Missing Signed-off-by: line by nominal patch author '$author'\n"); } elsif ($authorsignoff == 2) { CHK("FROM_SIGN_OFF_MISMATCH", "From:/Signed-off-by: email comments mismatch: $sob_msg\n"); } elsif ($authorsignoff == 3) { WARN("FROM_SIGN_OFF_MISMATCH", "From:/Signed-off-by: email name mismatch: $sob_msg\n"); } elsif ($authorsignoff == 4) { WARN("FROM_SIGN_OFF_MISMATCH", "From:/Signed-off-by: email address mismatch: $sob_msg\n"); } elsif ($authorsignoff == 5) { WARN("FROM_SIGN_OFF_MISMATCH", "From:/Signed-off-by: email subaddress mismatch: $sob_msg\n"); } } } print report_dump(); if ($summary && !($clean == 1 && $quiet == 1)) { print "$filename " if ($summary_file); print "total: $cnt_error errors, $cnt_warn warnings, " . (($check)? "$cnt_chk checks, " : "") . "$cnt_lines lines checked\n"; } if ($quiet == 0) { # If there were any defects found and not already fixing them if (!$clean and !$fix) { print << "EOM" NOTE: For some of the reported defects, checkpatch may be able to mechanically convert to the typical style using --fix or --fix-inplace. EOM } # If there were whitespace errors which cleanpatch can fix # then suggest that. if ($rpt_cleaners) { $rpt_cleaners = 0; print << "EOM" NOTE: Whitespace errors detected. You may wish to use scripts/cleanpatch or scripts/cleanfile EOM } } if ($clean == 0 && $fix && ("@rawlines" ne "@fixed" || $#fixed_inserted >= 0 || $#fixed_deleted >= 0)) { my $newfile = $filename; $newfile .= ".EXPERIMENTAL-checkpatch-fixes" if (!$fix_inplace); my $linecount = 0; my $f; @fixed = fix_inserted_deleted_lines(\@fixed, \@fixed_inserted, \@fixed_deleted); open($f, '>', $newfile) or die "$P: Can't open $newfile for write\n"; foreach my $fixed_line (@fixed) { $linecount++; if ($file) { if ($linecount > 3) { $fixed_line =~ s/^\+//; print $f $fixed_line . "\n"; } } else { print $f $fixed_line . "\n"; } } close($f); if (!$quiet) { print << "EOM"; Wrote EXPERIMENTAL --fix correction(s) to '$newfile' Do _NOT_ trust the results written to this file. Do _NOT_ submit these changes without inspecting them for correctness. This EXPERIMENTAL file is simply a convenience to help rewrite patches. No warranties, expressed or implied... EOM } } if ($quiet == 0) { print "\n"; if ($clean == 1) { print "$vname has no obvious style problems and is ready for submission.\n"; } else { print "$vname has style problems, please review.\n"; } } return $clean; }