summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rw-r--r--scripts/Kconfig.toolchain3
-rw-r--r--scripts/Makefile.autofdo2
-rw-r--r--scripts/Makefile.build8
-rw-r--r--scripts/Makefile.kcsan13
-rw-r--r--scripts/Makefile.lib9
-rw-r--r--scripts/Makefile.warn1
-rw-r--r--scripts/coccinelle/api/devm_kmalloc_objs.cocci136
-rw-r--r--scripts/coccinelle/api/kmalloc_objs.cocci114
-rw-r--r--scripts/coccinelle/free/cleanup-free.cocci112
-rw-r--r--scripts/coccinelle/misc/array_end.cocci73
-rwxr-xr-xscripts/decode_stacktrace.sh2
-rw-r--r--scripts/generate_rust_target.rs2
-rw-r--r--scripts/kconfig/lkc_proto.h2
-rw-r--r--scripts/kconfig/mconf.c11
-rw-r--r--scripts/kconfig/menu.c49
-rw-r--r--scripts/kconfig/nconf.c11
-rw-r--r--scripts/kconfig/nconf.gui.c2
-rw-r--r--scripts/kconfig/preprocess.c21
-rw-r--r--scripts/kconfig/qconf.cc2
-rw-r--r--scripts/kconfig/symbol.c7
-rw-r--r--scripts/kconfig/tests/err_num_reverse_range/Kconfig111
-rw-r--r--scripts/kconfig/tests/err_num_reverse_range/__init__.py8
-rw-r--r--scripts/kconfig/tests/err_num_reverse_range/expected_stderr11
-rw-r--r--scripts/kconfig/tests/err_transitional/expected_stderr2
-rw-r--r--scripts/kconfig/tests/preprocess/variable/Kconfig5
-rw-r--r--scripts/kconfig/tests/preprocess/variable/expected_stderr1
-rw-r--r--scripts/mod/devicetable-offsets.c60
-rw-r--r--scripts/mod/file2alias.c57
-rwxr-xr-xscripts/modules-check.sh13
29 files changed, 756 insertions, 92 deletions
diff --git a/scripts/Kconfig.toolchain b/scripts/Kconfig.toolchain
index 2acbd40a38f1..1d68075f0469 100644
--- a/scripts/Kconfig.toolchain
+++ b/scripts/Kconfig.toolchain
@@ -233,6 +233,9 @@ config CC_OPT_WNO_FORMAT_OVERFLOW
config CC_OPT_WNO_STRINGOP_TRUNCATION
def_string "$(cc-option-str,-Wno-stringop-truncation)"
+config CC_OPT_WNO_CONSTANT_LOGICAL_OPERAND
+ def_string "$(cc-option-str,-Wno-constant-logical-operand)"
+
config CC_HAS_COUNTED_BY
bool
# clang needs to be at least 20.1.0 to avoid potential crashes
diff --git a/scripts/Makefile.autofdo b/scripts/Makefile.autofdo
index 57a3aba6ffc2..32c18df237f1 100644
--- a/scripts/Makefile.autofdo
+++ b/scripts/Makefile.autofdo
@@ -13,7 +13,7 @@ endif
ifdef CLANG_AUTOFDO_PROFILE
CFLAGS_AUTOFDO_CLANG += -fprofile-sample-use=$(CLANG_AUTOFDO_PROFILE) -ffunction-sections
CFLAGS_AUTOFDO_CLANG += -fsplit-machine-functions
- RUSTFLAGS_AUTOFDO_CLANG += -Zprofile-sample-use=$(CLANG_AUTOFDO_PROFILE) -Zfunction-sections=y
+ RUSTFLAGS_AUTOFDO_CLANG += $(if $(call rustc-min-version,110000),-Cprofile-sample-use,-Zprofile-sample-use)=$(CLANG_AUTOFDO_PROFILE) -Zfunction-sections=y
RUSTFLAGS_AUTOFDO_CLANG += -Cllvm-args=-split-machine-functions
endif
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 33d7f92b2491..9bb4dace669b 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -589,7 +589,10 @@ endif
# Single targets
# ---------------------------------------------------------------------------
-single-subdirs := $(foreach d, $(subdir-ym), $(if $(filter $d/%, $(MAKECMDGOALS)), $d))
+# A single target may match nested entries in subdir-ym. Descend through only
+# the deepest match so that two recursive makes do not build the same target.
+single-subdir = $(lastword $(sort $(foreach d, $(subdir-ym), $(if $(filter $d/%, $(1)), $d))))
+single-subdirs := $(sort $(foreach g, $(MAKECMDGOALS), $(call single-subdir, $g)))
single-subdir-goals := $(filter $(addsuffix /%, $(single-subdirs)), $(MAKECMDGOALS))
$(single-subdir-goals): $(single-subdirs)
@@ -603,7 +606,8 @@ $(subdir-ym):
$(Q)$(MAKE) $(build)=$@ \
need-builtin=$(if $(filter $@/built-in.a, $(subdir-builtin)),1) \
need-modorder=$(if $(filter $@/modules.order, $(subdir-modorder)),1) \
- $(filter $@/%, $(single-subdir-goals))
+ $(filter-out $(addsuffix /%, $(filter $@/%, $(single-subdirs))), \
+ $(filter $@/%, $(single-subdir-goals)))
# Add FORCE to the prerequisites of a target to force it to be always rebuilt.
# ---------------------------------------------------------------------------
diff --git a/scripts/Makefile.kcsan b/scripts/Makefile.kcsan
index 19f693b68a96..01af6fd71006 100644
--- a/scripts/Makefile.kcsan
+++ b/scripts/Makefile.kcsan
@@ -24,3 +24,16 @@ kcsan-cflags += $(call cc-option,$(call cc-param,tsan-instrument-func-entry-exit
endif
export CFLAGS_KCSAN := $(kcsan-cflags)
+
+ifdef CONFIG_HAVE_KCSAN_RUSTC
+# The minimum supported rustc's LLVM supports all of these options.
+rustc-param = -Cllvm-args=-$(1)
+kcsan-rustflags := -Zsanitizer=thread \
+ $(call rustc-param,tsan-compound-read-before-write=1) \
+ $(call rustc-param,tsan-distinguish-volatile=1)
+ifndef CONFIG_KCSAN_WEAK_MEMORY
+kcsan-rustflags += $(call rustc-param,tsan-instrument-func-entry-exit=0)
+endif
+endif
+
+export RUSTFLAGS_KCSAN := $(kcsan-rustflags)
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 19e96b30a122..1749d16c3363 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -98,6 +98,9 @@ ifeq ($(CONFIG_KCSAN),y)
_c_flags += $(if $(patsubst n%,, \
$(KCSAN_SANITIZE_$(target-stem).o)$(KCSAN_SANITIZE)$(is-kernel-object)), \
$(CFLAGS_KCSAN))
+_rust_flags += $(if $(patsubst n%,, \
+ $(KCSAN_SANITIZE_$(target-stem).o)$(KCSAN_SANITIZE)$(is-kernel-object)), \
+ $(RUSTFLAGS_KCSAN))
# Some uninstrumented files provide implied barriers required to avoid false
# positives: set KCSAN_INSTRUMENT_BARRIERS for barrier instrumentation only.
_c_flags += $(if $(patsubst n%,, \
@@ -493,9 +496,9 @@ quiet_cmd_zstd22_with_size = ZSTD22 $@
# the .ascii directive whereas GCC keeps the <space> as-is.
define sed-offsets
's:^[[:space:]]*\.ascii[[:space:]]*"\(.*\)".*:\1:; \
- /^->/{s:->#\(.*\):/* \1 */:; \
- s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
- s:->::; p;}'
+ /^->/{s:->#\(.*\):/* \1 */:p; \
+ s:^->\([[:alnum:]_]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:p; \
+ s:^->BLANK()::p;}'
endef
# Use filechk to avoid rebuilds when a header changes, but the resulting file
diff --git a/scripts/Makefile.warn b/scripts/Makefile.warn
index 556fa249ca07..03b677bdbb0a 100644
--- a/scripts/Makefile.warn
+++ b/scripts/Makefile.warn
@@ -167,6 +167,7 @@ endif
ifdef CONFIG_CC_IS_GCC
KBUILD_CFLAGS += -Wno-maybe-uninitialized
+KBUILD_CFLAGS += $(CONFIG_CC_OPT_WNO_CONSTANT_LOGICAL_OPERAND)
endif
endif
diff --git a/scripts/coccinelle/api/devm_kmalloc_objs.cocci b/scripts/coccinelle/api/devm_kmalloc_objs.cocci
new file mode 100644
index 000000000000..322f79a2d965
--- /dev/null
+++ b/scripts/coccinelle/api/devm_kmalloc_objs.cocci
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/// Use devm_kmalloc_obj family of macros for allocations
+///
+// Confidence: High
+// Options: --include-headers-for-types --all-includes --include-headers --keep-comments
+
+virtual patch
+
+@initialize:python@
+@@
+import sys
+
+def alloc_array(name):
+ func = "FAILED_RENAME"
+ if name == "devm_kmalloc_array":
+ func = "devm_kmalloc_objs"
+ elif name == "devm_kvmalloc_array":
+ func = "devm_kvmalloc_objs"
+ elif name == "devm_kcalloc":
+ func = "devm_kzalloc_objs"
+ elif name == "devm_kvcalloc":
+ func = "devm_kvzalloc_objs"
+ else:
+ print(f"Unknown transform for {name}", file=sys.stderr)
+ return func
+
+// This excludes anything that is assigning to or from integral types or
+// string literals. Everything else gets the sizeof() extracted for the
+// kmalloc_obj() type/var argument. sizeof(void *) is also excluded because
+// it will need case-by-case double-checking to make sure the right type is
+// being assigned.
+@direct depends on patch && !(file in "tools") && !(file in "samples")@
+typedef u8, u16, u32, u64;
+typedef __u8, __u16, __u32, __u64;
+typedef uint8_t, uint16_t, uint32_t, uint64_t;
+typedef uchar, ushort, uint, ulong;
+typedef __le16, __le32, __le64;
+typedef __be16, __be32, __be64;
+typedef wchar_t;
+type INTEGRAL = {u8,__u8,uint8_t,char,unsigned char,uchar,wchar_t,
+ u16,__u16,uint16_t,unsigned short,ushort,
+ u32,__u32,uint32_t,unsigned int,uint,
+ u64,__u64,uint64_t,unsigned long,ulong,
+ __le16,__le32,__le64,__be16,__be32,__be64};
+char [] STRING;
+INTEGRAL *BYTES;
+INTEGRAL **BYTES_PTRS;
+type TYPE;
+expression VAR;
+expression GFP;
+expression COUNT;
+expression FLEX;
+expression E;
+expression DEV;
+identifier ALLOC =~ "^devm_kv?[mz]alloc$";
+fresh identifier ALLOC_OBJ = ALLOC ## "_obj";
+fresh identifier ALLOC_FLEX = ALLOC ## "_flex";
+identifier ALLOC_ARRAY = {devm_kmalloc_array,devm_kvmalloc_array,devm_kcalloc,devm_kvcalloc};
+fresh identifier ALLOC_OBJS = script:python(ALLOC_ARRAY) { alloc_array(ALLOC_ARRAY) };
+@@
+
+(
+- VAR = ALLOC(DEV,(sizeof(*VAR)), GFP)
++ VAR = ALLOC_OBJ(DEV,*VAR, GFP)
+|
+ ALLOC(DEV,(\(sizeof(STRING)\|sizeof(INTEGRAL)\|sizeof(INTEGRAL *)\)), GFP)
+|
+ BYTES = ALLOC(DEV,(sizeof(E)), GFP)
+|
+ BYTES = ALLOC(DEV,(sizeof(TYPE)), GFP)
+|
+ BYTES_PTRS = ALLOC(DEV,(sizeof(E)), GFP)
+|
+ BYTES_PTRS = ALLOC(DEV,(sizeof(TYPE)), GFP)
+|
+ ALLOC(DEV,(sizeof(void *)), GFP)
+|
+- ALLOC(DEV,(sizeof(E)), GFP)
++ ALLOC_OBJ(DEV, E, GFP)
+|
+- ALLOC(DEV,(sizeof(TYPE)), GFP)
++ ALLOC_OBJ(DEV,TYPE, GFP)
+|
+ ALLOC_ARRAY(DEV,COUNT, (\(sizeof(STRING)\|sizeof(INTEGRAL)\|sizeof(INTEGRAL *)\)), GFP)
+|
+ BYTES = ALLOC_ARRAY(DEV, COUNT, (sizeof(E)), GFP)
+|
+ BYTES = ALLOC_ARRAY(DEV,COUNT, (sizeof(TYPE)), GFP)
+|
+ BYTES_PTRS = ALLOC_ARRAY(DEV, COUNT, (sizeof(E)), GFP)
+|
+ BYTES_PTRS = ALLOC_ARRAY(DEV, COUNT, (sizeof(TYPE)), GFP)
+|
+ ALLOC_ARRAY(DEV, (\(sizeof(STRING)\|sizeof(INTEGRAL)\|sizeof(INTEGRAL *)\)), COUNT, GFP)
+|
+ BYTES = ALLOC_ARRAY(DEV, (sizeof(E)), COUNT, GFP)
+|
+ BYTES = ALLOC_ARRAY(DEV, (sizeof(TYPE)), COUNT, GFP)
+|
+ BYTES_PTRS = ALLOC_ARRAY(DEV, (sizeof(E)), COUNT, GFP)
+|
+ BYTES_PTRS = ALLOC_ARRAY(DEV, (sizeof(TYPE)), COUNT, GFP)
+|
+ ALLOC_ARRAY(DEV, COUNT, (sizeof(void *)), GFP)
+|
+ ALLOC_ARRAY(DEV, (sizeof(void *)), COUNT, GFP)
+|
+- ALLOC_ARRAY(DEV, COUNT, (sizeof(E)), GFP)
++ ALLOC_OBJS(DEV, E, COUNT, GFP)
+|
+- ALLOC_ARRAY(DEV, COUNT, (sizeof(TYPE)), GFP)
++ ALLOC_OBJS(DEV, TYPE, COUNT, GFP)
+|
+- ALLOC_ARRAY(DEV, (sizeof(E)), COUNT, GFP)
++ ALLOC_OBJS(DEV, E, COUNT, GFP)
+|
+- ALLOC_ARRAY(DEV, (sizeof(TYPE)), COUNT, GFP)
++ ALLOC_OBJS(DEV, TYPE, COUNT, GFP)
+|
+- ALLOC(DEV, struct_size(VAR, FLEX, COUNT), GFP)
++ ALLOC_FLEX(DEV, *VAR, FLEX, COUNT, GFP)
+|
+- ALLOC(DEV, struct_size_t(TYPE, FLEX, COUNT), GFP)
++ ALLOC_FLEX(DEV, TYPE, FLEX, COUNT, GFP)
+)
+
+@drop_gfp_kernel depends on patch && !(file in "tools") && !(file in "samples")@
+identifier ALLOC = {devm_kmalloc_obj,devm_kmalloc_objs,devm_kmalloc_flex,
+ devm_kzalloc_obj,devm_kzalloc_objs,devm_kzalloc_flex,
+ devm_kvmalloc_obj,devm_kvmalloc_objs,devm_kvmalloc_flex,
+ devm_kvzalloc_obj,devm_kvzalloc_objs,devm_kvzalloc_flex};
+@@
+
+ ALLOC(...
+- , GFP_KERNEL
+ )
diff --git a/scripts/coccinelle/api/kmalloc_objs.cocci b/scripts/coccinelle/api/kmalloc_objs.cocci
index 0a98ddf03eca..e47604f7a1a6 100644
--- a/scripts/coccinelle/api/kmalloc_objs.cocci
+++ b/scripts/coccinelle/api/kmalloc_objs.cocci
@@ -20,6 +20,10 @@ def alloc_array(name):
func = "kzalloc_objs"
elif name == "kvcalloc":
func = "kvzalloc_objs"
+ elif name == "devm_kmalloc_array":
+ func = "devm_kmalloc_objs"
+ elif name == "devm_kcalloc":
+ func = "devm_kzalloc_objs"
else:
print(f"Unknown transform for {name}", file=sys.stderr)
return func
@@ -42,6 +46,15 @@ def alloc_array(name):
// Everything else gets the sizeof() extracted for the kmalloc_obj()
// type/var argument.
//
+// The device-managed allocators differ from the plain ones only by taking
+// the managing "struct device *" as a leading argument, so rather than
+// repeating every pattern for them, the leading arguments are captured in
+// an "expression list" metavariable and replayed on the replacement side.
+// ARGS is empty for the plain allocators, in which case Coccinelle drops
+// the separating comma as well. Note that there is no devm_kvmalloc
+// family, and that the devm array helpers only exist as
+// (dev, count, size, gfp).
+//
// The first matching alternative below wins, so the exclusions must come
// before the more general conversions.
@direct depends on patch && !(file in "tools") && !(file in "samples")@
@@ -81,150 +94,155 @@ expression GFP;
expression COUNT;
expression FLEX;
expression E;
-identifier ALLOC =~ "^kv?[mz]alloc$";
+expression list ARGS;
+identifier ALLOC = {kmalloc,kzalloc,kvmalloc,kvzalloc,
+ devm_kmalloc,devm_kzalloc};
fresh identifier ALLOC_OBJ = ALLOC ## "_obj";
fresh identifier ALLOC_FLEX = ALLOC ## "_flex";
-identifier ALLOC_ARRAY = {kmalloc_array,kvmalloc_array,kcalloc,kvcalloc};
+identifier ALLOC_ARRAY = {kmalloc_array,kvmalloc_array,kcalloc,kvcalloc,
+ devm_kmalloc_array,devm_kcalloc};
fresh identifier ALLOC_OBJS = script:python(ALLOC_ARRAY) { alloc_array(ALLOC_ARRAY) };
@@
(
// Convert a single object sized by its target: p = kmalloc(sizeof(*p), gfp)
-- VAR = ALLOC((sizeof(*VAR)), GFP)
-+ VAR = ALLOC_OBJ(*VAR, GFP)
+- VAR = ALLOC(ARGS, (sizeof(*VAR)), GFP)
++ VAR = ALLOC_OBJ(ARGS, *VAR, GFP)
|
// Exclude byte buffers and integral pointers: kmalloc(sizeof(u8), gfp),
// kmalloc(sizeof("str"), gfp), kmalloc(sizeof(char *), gfp)
- ALLOC((\(sizeof(STRING)\|sizeof(BYTE_TYPES)\|
+ ALLOC(ARGS, (\(sizeof(STRING)\|sizeof(BYTE_TYPES)\|
sizeof(BYTE_TYPES *)\|sizeof(MULTIBYTE_TYPES *)\)), GFP)
|
// Exclude anything assigned to a byte pointer:
// u8 *buf = kmalloc(sizeof(*hdr), gfp)
- BYTES = ALLOC((\(sizeof(E)\|sizeof(TYPE)\)), GFP)
+ BYTES = ALLOC(ARGS, (\(sizeof(E)\|sizeof(TYPE)\)), GFP)
|
// Convert a multi-byte type to a pointer to it:
// u32 *p = kmalloc(sizeof(u32), gfp)
\(MULTIBYTES\|CONST_MULTIBYTES\) =
-- ALLOC((sizeof(MULTIBYTE_TYPES)), GFP)
-+ ALLOC_OBJ(MULTIBYTE_TYPES, GFP)
+- ALLOC(ARGS, (sizeof(MULTIBYTE_TYPES)), GFP)
++ ALLOC_OBJ(ARGS, MULTIBYTE_TYPES, GFP)
|
// Same by expression: u32 *p = kmalloc(sizeof(p[0]), gfp)
\(MULTIBYTES\|CONST_MULTIBYTES\) =
-- ALLOC((sizeof(MULTIBYTE)), GFP)
-+ ALLOC_OBJ(MULTIBYTE, GFP)
+- ALLOC(ARGS, (sizeof(MULTIBYTE)), GFP)
++ ALLOC_OBJ(ARGS, MULTIBYTE, GFP)
|
// Exclude other multi-byte sizes, e.g. to pointers to arrays: s16 (*p)[2] = ...
- ALLOC((\(sizeof(MULTIBYTE_TYPES)\|sizeof(MULTIBYTE)\)), GFP)
+ ALLOC(ARGS, (\(sizeof(MULTIBYTE_TYPES)\|sizeof(MULTIBYTE)\)), GFP)
|
// Exclude anything else assigned to a multi-byte pointer:
// u32 *p = kmalloc(sizeof(*hdr), gfp)
- \(MULTIBYTES\|CONST_MULTIBYTES\) = ALLOC((\(sizeof(E)\|sizeof(TYPE)\)), GFP)
+ \(MULTIBYTES\|CONST_MULTIBYTES\) = ALLOC(ARGS, (\(sizeof(E)\|sizeof(TYPE)\)), GFP)
|
// Exclude void pointers, to be checked by hand: kmalloc(sizeof(void *), gfp)
- ALLOC((sizeof(void *)), GFP)
+ ALLOC(ARGS, (sizeof(void *)), GFP)
|
// Convert any other expression: p = kmalloc(sizeof(s->item), gfp)
-- ALLOC((sizeof(E)), GFP)
-+ ALLOC_OBJ(E, GFP)
+- ALLOC(ARGS, (sizeof(E)), GFP)
++ ALLOC_OBJ(ARGS, E, GFP)
|
// Convert any other type: p = kmalloc(sizeof(struct item), gfp)
-- ALLOC((sizeof(TYPE)), GFP)
-+ ALLOC_OBJ(TYPE, GFP)
+- ALLOC(ARGS, (sizeof(TYPE)), GFP)
++ ALLOC_OBJ(ARGS, TYPE, GFP)
|
// The same, for arrays allocated as (count, size):
// Exclude byte buffers and integral pointers: kcalloc(n, sizeof(u8), gfp),
// kcalloc(n, sizeof(char *), gfp)
- ALLOC_ARRAY(COUNT, (\(sizeof(STRING)\|sizeof(BYTE_TYPES)\|
+ ALLOC_ARRAY(ARGS, COUNT, (\(sizeof(STRING)\|sizeof(BYTE_TYPES)\|
sizeof(BYTE_TYPES *)\|sizeof(MULTIBYTE_TYPES *)\)), GFP)
|
// Exclude arrays assigned to a byte pointer:
// u8 *buf = kcalloc(n, sizeof(*hdr), gfp)
- BYTES = ALLOC_ARRAY(COUNT, (\(sizeof(E)\|sizeof(TYPE)\)), GFP)
+ BYTES = ALLOC_ARRAY(ARGS, COUNT, (\(sizeof(E)\|sizeof(TYPE)\)), GFP)
|
// Convert a multi-byte array to a pointer to it:
// u32 *p = kcalloc(n, sizeof(u32), gfp)
\(MULTIBYTES\|CONST_MULTIBYTES\) =
-- ALLOC_ARRAY(COUNT, (sizeof(MULTIBYTE_TYPES)), GFP)
-+ ALLOC_OBJS(MULTIBYTE_TYPES, COUNT, GFP)
+- ALLOC_ARRAY(ARGS, COUNT, (sizeof(MULTIBYTE_TYPES)), GFP)
++ ALLOC_OBJS(ARGS, MULTIBYTE_TYPES, COUNT, GFP)
|
// Same by expression: u32 *p = kcalloc(n, sizeof(*p), gfp)
\(MULTIBYTES\|CONST_MULTIBYTES\) =
-- ALLOC_ARRAY(COUNT, (sizeof(MULTIBYTE)), GFP)
-+ ALLOC_OBJS(MULTIBYTE, COUNT, GFP)
+- ALLOC_ARRAY(ARGS, COUNT, (sizeof(MULTIBYTE)), GFP)
++ ALLOC_OBJS(ARGS, MULTIBYTE, COUNT, GFP)
|
// Exclude other multi-byte arrays:
// s16 (*pairs)[2] = kcalloc(n, sizeof(s16), gfp)
- ALLOC_ARRAY(COUNT, (\(sizeof(MULTIBYTE_TYPES)\|sizeof(MULTIBYTE)\)), GFP)
+ ALLOC_ARRAY(ARGS, COUNT, (\(sizeof(MULTIBYTE_TYPES)\|sizeof(MULTIBYTE)\)), GFP)
|
// Exclude other arrays assigned to a multi-byte pointer:
// u32 *p = kcalloc(n, sizeof(*hdr), gfp)
- \(MULTIBYTES\|CONST_MULTIBYTES\) = ALLOC_ARRAY(COUNT, (\(sizeof(E)\|sizeof(TYPE)\)), GFP)
+ \(MULTIBYTES\|CONST_MULTIBYTES\) = ALLOC_ARRAY(ARGS, COUNT, (\(sizeof(E)\|sizeof(TYPE)\)), GFP)
|
// Exclude arrays of void pointers: kcalloc(n, sizeof(void *), gfp)
- ALLOC_ARRAY(COUNT, (sizeof(void *)), GFP)
+ ALLOC_ARRAY(ARGS, COUNT, (sizeof(void *)), GFP)
|
// Convert any other expression: p = kcalloc(n, sizeof(*p), gfp)
-- ALLOC_ARRAY(COUNT, (sizeof(E)), GFP)
-+ ALLOC_OBJS(E, COUNT, GFP)
+- ALLOC_ARRAY(ARGS, COUNT, (sizeof(E)), GFP)
++ ALLOC_OBJS(ARGS, E, COUNT, GFP)
|
// Convert any other type: p = kcalloc(n, sizeof(struct item), gfp)
-- ALLOC_ARRAY(COUNT, (sizeof(TYPE)), GFP)
-+ ALLOC_OBJS(TYPE, COUNT, GFP)
+- ALLOC_ARRAY(ARGS, COUNT, (sizeof(TYPE)), GFP)
++ ALLOC_OBJS(ARGS, TYPE, COUNT, GFP)
|
// The same, for arrays allocated as (size, count):
// Exclude byte buffers and integral pointers: kcalloc(sizeof(u8), n, gfp),
// kcalloc(sizeof(char *), n, gfp)
- ALLOC_ARRAY((\(sizeof(STRING)\|sizeof(BYTE_TYPES)\|
+ ALLOC_ARRAY(ARGS, (\(sizeof(STRING)\|sizeof(BYTE_TYPES)\|
sizeof(BYTE_TYPES *)\|sizeof(MULTIBYTE_TYPES *)\)), COUNT, GFP)
|
// Exclude arrays assigned to a byte pointer:
// u8 *buf = kcalloc(sizeof(*hdr), n, gfp)
- BYTES = ALLOC_ARRAY((\(sizeof(E)\|sizeof(TYPE)\)), COUNT, GFP)
+ BYTES = ALLOC_ARRAY(ARGS, (\(sizeof(E)\|sizeof(TYPE)\)), COUNT, GFP)
|
// Convert a multi-byte array to a pointer to it:
// u32 *p = kcalloc(sizeof(u32), n, gfp)
\(MULTIBYTES\|CONST_MULTIBYTES\) =
-- ALLOC_ARRAY((sizeof(MULTIBYTE_TYPES)), COUNT, GFP)
-+ ALLOC_OBJS(MULTIBYTE_TYPES, COUNT, GFP)
+- ALLOC_ARRAY(ARGS, (sizeof(MULTIBYTE_TYPES)), COUNT, GFP)
++ ALLOC_OBJS(ARGS, MULTIBYTE_TYPES, COUNT, GFP)
|
// Same by expression: u32 *p = kcalloc(sizeof(*p), n, gfp)
\(MULTIBYTES\|CONST_MULTIBYTES\) =
-- ALLOC_ARRAY((sizeof(MULTIBYTE)), COUNT, GFP)
-+ ALLOC_OBJS(MULTIBYTE, COUNT, GFP)
+- ALLOC_ARRAY(ARGS, (sizeof(MULTIBYTE)), COUNT, GFP)
++ ALLOC_OBJS(ARGS, MULTIBYTE, COUNT, GFP)
|
// Exclude other multi-byte arrays:
// s16 (*pairs)[2] = kcalloc(sizeof(s16), n, gfp)
- ALLOC_ARRAY((\(sizeof(MULTIBYTE_TYPES)\|sizeof(MULTIBYTE)\)), COUNT, GFP)
+ ALLOC_ARRAY(ARGS, (\(sizeof(MULTIBYTE_TYPES)\|sizeof(MULTIBYTE)\)), COUNT, GFP)
|
// Exclude other arrays assigned to a multi-byte pointer:
// u32 *p = kcalloc(sizeof(*hdr), n, gfp)
- \(MULTIBYTES\|CONST_MULTIBYTES\) = ALLOC_ARRAY((\(sizeof(E)\|sizeof(TYPE)\)), COUNT, GFP)
+ \(MULTIBYTES\|CONST_MULTIBYTES\) = ALLOC_ARRAY(ARGS, (\(sizeof(E)\|sizeof(TYPE)\)), COUNT, GFP)
|
// Exclude arrays of void pointers: kcalloc(sizeof(void *), n, gfp)
- ALLOC_ARRAY((sizeof(void *)), COUNT, GFP)
+ ALLOC_ARRAY(ARGS, (sizeof(void *)), COUNT, GFP)
|
// Convert any other expression: p = kcalloc(sizeof(*p), n, gfp)
-- ALLOC_ARRAY((sizeof(E)), COUNT, GFP)
-+ ALLOC_OBJS(E, COUNT, GFP)
+- ALLOC_ARRAY(ARGS, (sizeof(E)), COUNT, GFP)
++ ALLOC_OBJS(ARGS, E, COUNT, GFP)
|
// Convert any other type: p = kcalloc(sizeof(struct item), n, gfp)
-- ALLOC_ARRAY((sizeof(TYPE)), COUNT, GFP)
-+ ALLOC_OBJS(TYPE, COUNT, GFP)
+- ALLOC_ARRAY(ARGS, (sizeof(TYPE)), COUNT, GFP)
++ ALLOC_OBJS(ARGS, TYPE, COUNT, GFP)
|
// Convert flexible array structures: p = kmalloc(struct_size(p, data, n), gfp)
-- ALLOC(struct_size(VAR, FLEX, COUNT), GFP)
-+ ALLOC_FLEX(*VAR, FLEX, COUNT, GFP)
+- ALLOC(ARGS, struct_size(VAR, FLEX, COUNT), GFP)
++ ALLOC_FLEX(ARGS, *VAR, FLEX, COUNT, GFP)
|
// Same by type: kmalloc(struct_size_t(struct item, data, n), gfp)
-- ALLOC(struct_size_t(TYPE, FLEX, COUNT), GFP)
-+ ALLOC_FLEX(TYPE, FLEX, COUNT, GFP)
+- ALLOC(ARGS, struct_size_t(TYPE, FLEX, COUNT), GFP)
++ ALLOC_FLEX(ARGS, TYPE, FLEX, COUNT, GFP)
)
@drop_gfp_kernel depends on patch && !(file in "tools") && !(file in "samples")@
identifier ALLOC = {kmalloc_obj,kmalloc_objs,kmalloc_flex,
kzalloc_obj,kzalloc_objs,kzalloc_flex,
kvmalloc_obj,kvmalloc_objs,kvmalloc_flex,
- kvzalloc_obj,kvzalloc_objs,kvzalloc_flex};
+ kvzalloc_obj,kvzalloc_objs,kvzalloc_flex,
+ devm_kmalloc_obj,devm_kmalloc_objs,devm_kmalloc_flex,
+ devm_kzalloc_obj,devm_kzalloc_objs,devm_kzalloc_flex};
@@
ALLOC(...
diff --git a/scripts/coccinelle/free/cleanup-free.cocci b/scripts/coccinelle/free/cleanup-free.cocci
new file mode 100644
index 000000000000..2aba766b5bbb
--- /dev/null
+++ b/scripts/coccinelle/free/cleanup-free.cocci
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Find __cleanup(kfree)
+/// Using __cleanup(kfree) will pass the stack address of the annotated
+/// local variable to kfree, causing an invalid free.
+/// I.e., `T v __cleanup(kfree);` --> `kfree(&v);`
+/// Such usage is impossible to be correct.
+///
+// Confidence: High
+// Copyright: (C) 2026 Ella Ma
+// Options: --no-includes --include-headers
+
+virtual report
+virtual org
+
+// Suggesting using __free for the functions with a DEFINE_FREE definition.
+// Update this list when new DEFINE_FREE definitions are added.
+@free@
+attribute name __cleanup;
+symbol kfree, kfree_sensitive, kvfree, kvfree_atomic, free_percpu;
+type T;
+identifier v, n;
+position p;
+@@
+
+(
+ T v __cleanup@p(
+(
+ n
+&
+(
+ kfree \| kfree_sensitive \| kvfree \| kvfree_atomic \| free_percpu
+)
+)
+ );
+|
+ T v __cleanup@p(
+(
+ n
+&
+(
+ kfree \| kfree_sensitive \| kvfree \| kvfree_atomic \| free_percpu
+)
+)
+ ) = ...;
+)
+
+@script:python depends on report@
+p << free.p;
+n << free.n;
+@@
+
+msg = f"ERROR: __cleanup({n}) will cause an invalid free: the stack address of the annotated variable will be passed to {n}; declare the variable using __free({n}) to cause the pointee to be freed"
+coccilib.report.print_report(p[0], msg)
+
+@script:python depends on org@
+p << free.p;
+n << free.n;
+@@
+
+msg = f"ERROR: __cleanup({n}) will cause an invalid free: the stack address of the annotated variable will be passed to {n}; declare the variable using __free({n}) to cause the pointee to be freed"
+coccilib.org.print_todo(p[0], msg)
+
+
+// Reporting __cleanup usage for the functions without a DEFINE_FREE definition.
+// The following list only contains frequently used functions. Supplement it if
+// necessary.
+@cleanup@
+attribute name __cleanup;
+symbol vfree, vfree_atomic, kfree_const;
+type T;
+identifier v, n;
+position p;
+@@
+
+(
+ T v __cleanup@p(
+(
+ n
+&
+(
+ vfree \| vfree_atomic \| kfree_const
+)
+)
+ );
+|
+ T v __cleanup@p(
+(
+ n
+&
+(
+ vfree \| vfree_atomic \| kfree_const
+)
+)
+ ) = ...;
+)
+
+@script:python depends on report@
+p << cleanup.p;
+n << cleanup.n;
+@@
+
+msg = f"ERROR: __cleanup({n}) will cause an invalid free: the stack address of the annotated variable will be passed to {n}"
+coccilib.report.print_report(p[0], msg)
+
+@script:python depends on org@
+p << cleanup.p;
+n << cleanup.n;
+@@
+
+msg = f"ERROR: __cleanup({n}) will cause an invalid free: the stack address of the annotated variable will be passed to {n}"
+coccilib.org.print_todo(p[0], msg)
diff --git a/scripts/coccinelle/misc/array_end.cocci b/scripts/coccinelle/misc/array_end.cocci
new file mode 100644
index 000000000000..2f0bbc4ce17d
--- /dev/null
+++ b/scripts/coccinelle/misc/array_end.cocci
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/// Use ARRAY_END instead of an expression derived from ARRAY_SIZE
+//
+// Confidence: High
+// Copyright: 2026, Alejandro Colomar <alx@kernel.org>
+// Options: --no-includes --include-headers
+
+virtual patch
+virtual context
+virtual org
+virtual report
+
+@depends on context disable zero_multiple_format@
+type T;
+T[] a;
+expression b;
+@@
+(
+* a + ARRAY_SIZE(a)
+|
+* &a[0] + ARRAY_SIZE(a)
+|
+* &a[ARRAY_SIZE(a)]
+|
+* &a[ARRAY_SIZE(a) - b]
+)
+
+@depends on patch disable zero_multiple_format@
+type T;
+T[] a;
+expression b;
+@@
+(
+- (a + ARRAY_SIZE(a))
++ ARRAY_END(a)
+|
+- (&a[0] + ARRAY_SIZE(a))
++ ARRAY_END(a)
+|
+- (&a[ARRAY_SIZE(a)])
++ ARRAY_END(a)
+|
+- (&a[ARRAY_SIZE(a) - b])
++ ARRAY_END(a) - b
+)
+
+@r depends on org || report disable zero_multiple_format@
+type T;
+T[] a;
+expression b;
+position p;
+@@
+(
+ a@p + ARRAY_SIZE(a)
+|
+ &a[0]@p + ARRAY_SIZE(a)
+|
+ &a[ARRAY_SIZE(a)]@p
+|
+ &a[ARRAY_SIZE(a)@p - b]
+)
+
+@script:python depends on org@
+p << r.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING should use ARRAY_END")
+
+@script:python depends on report@
+p << r.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING: opportunity for ARRAY_END")
diff --git a/scripts/decode_stacktrace.sh b/scripts/decode_stacktrace.sh
index 39d60d477bf3..8b06810d463a 100755
--- a/scripts/decode_stacktrace.sh
+++ b/scripts/decode_stacktrace.sh
@@ -346,7 +346,7 @@ handle_line() {
echo "${spaces[$last]}${symbol}${module:+ ${module}}${info_str:+ ${info_str}}"
}
-while read line; do
+while IFS= read -r line || [[ -n $line ]]; do
# Strip unexpected carriage return at end of line
line=${line%$'\r'}
diff --git a/scripts/generate_rust_target.rs b/scripts/generate_rust_target.rs
index 7687b0dd5474..4b02bffa6b46 100644
--- a/scripts/generate_rust_target.rs
+++ b/scripts/generate_rust_target.rs
@@ -231,7 +231,7 @@ fn main() {
}
ts.push("features", features);
ts.push("llvm-target", "x86_64-linux-gnu");
- ts.push("supported-sanitizers", ["kcfi", "kernel-address"]);
+ ts.push("supported-sanitizers", ["kcfi", "kernel-address", "thread"]);
if cfg.rustc_version_atleast(1, 91, 0) {
ts.push("target-pointer-width", 64);
} else {
diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h
index 8b436c87ba4a..2e736434b924 100644
--- a/scripts/kconfig/lkc_proto.h
+++ b/scripts/kconfig/lkc_proto.h
@@ -21,7 +21,7 @@ bool conf_errors(void);
struct symbol * sym_lookup(const char *name, int flags);
struct symbol * sym_find(const char *name);
void print_symbol_for_listconfig(struct symbol *sym);
-struct symbol ** sym_re_search(const char *pattern);
+struct symbol ** sym_re_search(const char *pattern, int *sym_cnt);
const char * sym_type_name(enum symbol_type type);
void sym_calc_value(struct symbol *sym);
bool sym_dep_errors(void);
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index b8b7bba84a65..ebfc5bd09c1c 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -384,8 +384,10 @@ static void show_help(struct menu *menu)
static void search_conf(void)
{
struct symbol **sym_arr;
+ int sym_cnt = 0;
struct gstr res;
struct gstr title;
+ struct gstr res_title;
char *dialog_input;
int dres, vscroll = 0, hscroll = 0;
bool again;
@@ -422,7 +424,7 @@ again:
stpart.text = str_get(&sttext);
list_add_tail(&stpart.entries, &trail);
- sym_arr = sym_re_search(dialog_input);
+ sym_arr = sym_re_search(dialog_input, &sym_cnt);
do {
LIST_HEAD(head);
struct search_data data = {
@@ -433,9 +435,14 @@ again:
jump_key_char = 0;
res = get_relations_str(sym_arr, &head);
set_subtitle();
- dres = show_textbox_ext("Search Results", str_get(&res), 0, 0,
+
+ res_title = str_new();
+ str_printf(&res_title, "Search Results (%d)", sym_cnt);
+ dres = show_textbox_ext(str_get(&res_title), str_get(&res), 0, 0,
&vscroll, &hscroll,
handle_search_keys, &data);
+ str_free(&res_title);
+
again = false;
if (dres >= '1' && dres <= '9') {
assert(data.target != NULL);
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index bda3e2650216..1a3ad09a92d2 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -43,7 +43,7 @@ void menu_warn(const struct menu *menu, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
- fprintf(stderr, "%s:%d:warning: ", menu->filename, menu->lineno);
+ fprintf(stderr, "%s:%d: warning: ", menu->filename, menu->lineno);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
@@ -53,7 +53,17 @@ static void prop_warn(const struct property *prop, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
- fprintf(stderr, "%s:%d:warning: ", prop->filename, prop->lineno);
+ fprintf(stderr, "%s:%d: warning: ", prop->filename, prop->lineno);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+}
+
+static void prop_err(const struct property *prop, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "%s:%d: error: ", prop->filename, prop->lineno);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
@@ -246,18 +256,15 @@ static int menu_validate_number(struct symbol *sym, struct symbol *sym2,
if (sym2->type != S_UNKNOWN ||
!sym_string_valid(sym, sym2->name)) {
- fprintf(stderr, "%s:%d: error: '%s' is an invalid value for '%s'\n",
- prop->filename, prop->lineno, sym2->name,
- sym_type_name(sym->type));
+ prop_err(prop, "'%s' is an invalid value for '%s'",
+ sym2->name, sym_type_name(sym->type));
return 1;
}
if (!sym_string_check_bounds(sym, sym2->name)) {
- fprintf(stderr,
- "%s:%d: error: %s constant '%s' is outside the 64-bit %s bounds\n",
- prop->filename, prop->lineno, sym_type_name(sym->type),
- sym2->name, sym->type == S_INT ? "signed" : "unsigned");
-
+ prop_err(prop, "%s constant '%s' is outside the 64-bit %s bounds",
+ sym_type_name(sym->type), sym2->name,
+ sym->type == S_INT ? "signed" : "unsigned");
return 1;
}
@@ -267,9 +274,9 @@ static int menu_validate_number(struct symbol *sym, struct symbol *sym2,
static int sym_check_prop(struct symbol *sym)
{
struct property *prop;
- struct symbol *sym2;
+ struct symbol *sym2, *lower, *upper;
char *use;
- int errors = 0;
+ int errors = 0, numeric_errors;
for (prop = sym->prop; prop; prop = prop->next) {
switch (prop->type) {
@@ -318,8 +325,22 @@ static int sym_check_prop(struct symbol *sym)
if (sym->type != S_INT && sym->type != S_HEX)
prop_warn(prop, "range is only allowed "
"for int or hex symbols");
- errors += menu_validate_number(sym, prop->expr->left.sym, prop);
- errors += menu_validate_number(sym, prop->expr->right.sym, prop);
+ lower = prop->expr->left.sym;
+ upper = prop->expr->right.sym;
+ numeric_errors = menu_validate_number(sym, lower, prop);
+ numeric_errors += menu_validate_number(sym, upper, prop);
+ errors += numeric_errors;
+ if (numeric_errors || lower->type != S_UNKNOWN || upper->type != S_UNKNOWN)
+ break;
+
+ if ((sym->type == S_INT &&
+ strtoll(lower->name, NULL, 10) > strtoll(upper->name, NULL, 10)) ||
+ (sym->type == S_HEX &&
+ strtoull(lower->name, NULL, 16) > strtoull(upper->name, NULL, 16))) {
+ prop_err(prop, "range lower limit '%s' is greater than upper limit '%s'",
+ lower->name, upper->name);
+ errors++;
+ }
break;
default:
;
diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c
index 521700ed7152..4c9c4ee7c3a7 100644
--- a/scripts/kconfig/nconf.c
+++ b/scripts/kconfig/nconf.c
@@ -700,8 +700,10 @@ static int do_exit(void)
static void search_conf(void)
{
struct symbol **sym_arr;
+ int sym_cnt = 0;
struct gstr res;
struct gstr title;
+ struct gstr res_title;
char *dialog_input;
int dres, vscroll = 0, hscroll = 0;
bool again;
@@ -732,7 +734,7 @@ again:
if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
dialog_input += strlen(CONFIG_);
- sym_arr = sym_re_search(dialog_input);
+ sym_arr = sym_re_search(dialog_input, &sym_cnt);
do {
LIST_HEAD(head);
@@ -742,10 +744,15 @@ again:
};
jump_key_char = 0;
res = get_relations_str(sym_arr, &head);
+
+ res_title = str_new();
+ str_printf(&res_title, "Search Results (%d)", sym_cnt);
dres = show_scroll_win_ext(main_window,
- "Search Results", str_get(&res),
+ str_get(&res_title), str_get(&res),
&vscroll, &hscroll,
handle_search_keys, &data);
+ str_free(&res_title);
+
again = false;
if (dres >= '1' && dres <= '9') {
assert(data.target != NULL);
diff --git a/scripts/kconfig/nconf.gui.c b/scripts/kconfig/nconf.gui.c
index 2d097bc7ef1a..5900eba0a512 100644
--- a/scripts/kconfig/nconf.gui.c
+++ b/scripts/kconfig/nconf.gui.c
@@ -523,7 +523,7 @@ int show_scroll_win_ext(WINDOW *main_window, const char *title, char *text,
int x, y, lines, columns;
int start_x = 0, start_y = 0;
int text_lines = 0, text_cols = 0;
- int total_cols = 0;
+ int total_cols = get_line_length(title) + 4;
int win_cols = 0;
int win_lines = 0;
int i = 0;
diff --git a/scripts/kconfig/preprocess.c b/scripts/kconfig/preprocess.c
index 783abcaa5cc5..db226898c988 100644
--- a/scripts/kconfig/preprocess.c
+++ b/scripts/kconfig/preprocess.c
@@ -293,27 +293,33 @@ void variable_add(const char *name, const char *value,
if (flavor == VAR_APPEND) {
flavor = v->flavor;
append = true;
- } else {
- free(v->value);
}
} else {
/* For undefined variables, += assumes the recursive flavor */
if (flavor == VAR_APPEND)
flavor = VAR_RECURSIVE;
+ }
+ /*
+ * Expand the value before touching the variable because the
+ * right-hand side may refer to the variable itself, like
+ * "X := $(X) foo".
+ */
+ if (flavor == VAR_SIMPLE)
+ new_value = expand_string(value);
+ else
+ new_value = xstrdup(value);
+
+ if (!v) {
v = xmalloc(sizeof(*v));
v->name = xstrdup(name);
+ v->value = NULL;
v->exp_count = 0;
list_add_tail(&v->node, &variable_list);
}
v->flavor = flavor;
- if (flavor == VAR_SIMPLE)
- new_value = expand_string(value);
- else
- new_value = xstrdup(value);
-
if (append) {
v->value = xrealloc(v->value,
strlen(v->value) + strlen(new_value) + 2);
@@ -321,6 +327,7 @@ void variable_add(const char *name, const char *value,
strcat(v->value, new_value);
free(new_value);
} else {
+ free(v->value);
v->value = new_value;
}
}
diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc
index b02ead7a3f98..8f51dc55226d 100644
--- a/scripts/kconfig/qconf.cc
+++ b/scripts/kconfig/qconf.cc
@@ -1245,7 +1245,7 @@ void ConfigSearchWindow::search(void)
list->clear();
info->clear();
- result = sym_re_search(editField->text().toLatin1());
+ result = sym_re_search(editField->text().toLatin1(), nullptr);
if (!result)
return;
for (p = result; *p; p++) {
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index 4ced4dd6485b..27138252c667 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -1077,7 +1077,7 @@ static int sym_rel_comp(const void *sym1, const void *sym2)
return strcmp(s1->sym->name, s2->sym->name);
}
-struct symbol **sym_re_search(const char *pattern)
+struct symbol **sym_re_search(const char *pattern, int *sym_cnt)
{
struct symbol *sym, **sym_arr = NULL;
struct sym_match *sym_match_arr = NULL;
@@ -1122,6 +1122,8 @@ struct symbol **sym_re_search(const char *pattern)
sym_arr[i] = sym_match_arr[i].sym;
sym_arr[cnt] = NULL;
}
+ if (sym_cnt)
+ *sym_cnt = cnt;
sym_re_search_free:
/* sym_match_arr can be NULL if no match, but free(NULL) is OK */
free(sym_match_arr);
@@ -1184,7 +1186,7 @@ static void sym_check_print_recursive(struct symbol *last_sym)
break;
if (!stack) {
fprintf(stderr, "unexpected recursive dependency error\n");
- return;
+ goto out;
}
for (; stack; stack = stack->next) {
@@ -1229,6 +1231,7 @@ static void sym_check_print_recursive(struct symbol *last_sym)
"subsection \"Kconfig recursive dependency limitations\"\n"
"\n");
+out:
if (check_top == &cv_stack)
dep_stack_remove();
}
diff --git a/scripts/kconfig/tests/err_num_reverse_range/Kconfig b/scripts/kconfig/tests/err_num_reverse_range/Kconfig
new file mode 100644
index 000000000000..c55091aca274
--- /dev/null
+++ b/scripts/kconfig/tests/err_num_reverse_range/Kconfig
@@ -0,0 +1,111 @@
+# SPDX-License-Identifier: GPL-2.0
+# Check constant range bounds.
+
+config INT_ORDERED
+ int
+ range -10 10
+
+config INT_EQUAL
+ int
+ range 5 5
+
+config HEX_ORDERED
+ hex
+ range 0x7fffffffffffffff 0xffffffffffffffff
+
+config HEX_EQUAL
+ hex
+ range 0xffffffffffffffff 0xffffffffffffffff
+
+# Skip ranges with symbolic bounds.
+
+config INT_LOWER
+ int
+
+config INT_UPPER
+ int
+
+config INT_SYMBOL_LOWER
+ int
+ range INT_LOWER 0
+
+config INT_SYMBOL_UPPER
+ int
+ range 0 INT_UPPER
+
+config INT_SYMBOL_BOTH
+ int
+ range INT_LOWER INT_UPPER
+
+config HEX_LOWER
+ hex
+
+config HEX_UPPER
+ hex
+
+config HEX_SYMBOL_LOWER
+ hex
+ range HEX_LOWER 0x0
+
+config HEX_SYMBOL_UPPER
+ hex
+ range 0x0 HEX_UPPER
+
+config HEX_SYMBOL_BOTH
+ hex
+ range HEX_LOWER HEX_UPPER
+
+# Reject reversed constant bounds.
+
+config INT_REVERSED
+ int
+ range 10 2
+
+config INT_REVERSED_NEGATIVE
+ int
+ range -1 -10
+
+config INT_REVERSED_SIGNED
+ int
+ range 1 -1
+
+config INT_REVERSED_QUOTED
+ int
+ range "8" "2"
+
+config HEX_REVERSED
+ hex
+ range 0x10 0xf
+
+config HEX_REVERSED_HIGH
+ hex
+ range 0xffffffffffffffff 0x8000000000000000
+
+config HEX_REVERSED_UNPREFIXED
+ hex
+ range f a
+
+# Check each conditional range independently.
+
+config RANGE_CONDITION
+ bool
+
+config INT_REVERSED_FIRST
+ int
+ range 10 2 if RANGE_CONDITION
+ range -10 10 if !RANGE_CONDITION
+
+config INT_REVERSED_SECOND
+ int
+ range -10 10 if RANGE_CONDITION
+ range 10 2 if !RANGE_CONDITION
+
+config HEX_REVERSED_FIRST
+ hex
+ range 0x10 0xf if RANGE_CONDITION
+ range 0x0 0x10 if !RANGE_CONDITION
+
+config HEX_REVERSED_SECOND
+ hex
+ range 0x0 0x10 if RANGE_CONDITION
+ range 0x10 0xf if !RANGE_CONDITION
diff --git a/scripts/kconfig/tests/err_num_reverse_range/__init__.py b/scripts/kconfig/tests/err_num_reverse_range/__init__.py
new file mode 100644
index 000000000000..4a7219bbe49e
--- /dev/null
+++ b/scripts/kconfig/tests/err_num_reverse_range/__init__.py
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+"""
+Reject constant range bounds when the lower bound is greater than the upper.
+"""
+
+def test(conf):
+ assert conf.olddefconfig() == 1
+ assert conf.stderr_matches('expected_stderr')
diff --git a/scripts/kconfig/tests/err_num_reverse_range/expected_stderr b/scripts/kconfig/tests/err_num_reverse_range/expected_stderr
new file mode 100644
index 000000000000..8742f3f46469
--- /dev/null
+++ b/scripts/kconfig/tests/err_num_reverse_range/expected_stderr
@@ -0,0 +1,11 @@
+Kconfig:62: error: range lower limit '10' is greater than upper limit '2'
+Kconfig:66: error: range lower limit '-1' is greater than upper limit '-10'
+Kconfig:70: error: range lower limit '1' is greater than upper limit '-1'
+Kconfig:74: error: range lower limit '8' is greater than upper limit '2'
+Kconfig:78: error: range lower limit '0x10' is greater than upper limit '0xf'
+Kconfig:82: error: range lower limit '0xffffffffffffffff' is greater than upper limit '0x8000000000000000'
+Kconfig:86: error: range lower limit 'f' is greater than upper limit 'a'
+Kconfig:95: error: range lower limit '10' is greater than upper limit '2'
+Kconfig:101: error: range lower limit '10' is greater than upper limit '2'
+Kconfig:105: error: range lower limit '0x10' is greater than upper limit '0xf'
+Kconfig:111: error: range lower limit '0x10' is greater than upper limit '0xf'
diff --git a/scripts/kconfig/tests/err_transitional/expected_stderr b/scripts/kconfig/tests/err_transitional/expected_stderr
index b52db4f680f4..ba317850c043 100644
--- a/scripts/kconfig/tests/err_transitional/expected_stderr
+++ b/scripts/kconfig/tests/err_transitional/expected_stderr
@@ -1,4 +1,4 @@
-Kconfig:46:warning: config symbol defined without type
+Kconfig:46: warning: config symbol defined without type
Kconfig:7: error: transitional symbols can only have help sections
Kconfig:14: error: transitional symbols can only have help sections
Kconfig:21: error: transitional symbols can only have help sections
diff --git a/scripts/kconfig/tests/preprocess/variable/Kconfig b/scripts/kconfig/tests/preprocess/variable/Kconfig
index 9ce2f95cbd24..226114e86a28 100644
--- a/scripts/kconfig/tests/preprocess/variable/Kconfig
+++ b/scripts/kconfig/tests/preprocess/variable/Kconfig
@@ -51,3 +51,8 @@ $(warning,$(greeting,Hello))
# Unreferenced parameters are just ignored.
$(warning,$(greeting,Hello,John,ignored,ignored))
+
+# Simply expanded variable referring to itself.
+X := 1
+X := $(X) 2
+$(warning,X = $(X))
diff --git a/scripts/kconfig/tests/preprocess/variable/expected_stderr b/scripts/kconfig/tests/preprocess/variable/expected_stderr
index a4841c3fdff5..7008e3b1771c 100644
--- a/scripts/kconfig/tests/preprocess/variable/expected_stderr
+++ b/scripts/kconfig/tests/preprocess/variable/expected_stderr
@@ -7,3 +7,4 @@ Kconfig:41: AB = 5
Kconfig:45: Hello, my name is John.
Kconfig:50: Hello, my name is .
Kconfig:53: Hello, my name is John.
+Kconfig:58: X = 1 2
diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c
index 92596bfa6aec..875eafeb743d 100644
--- a/scripts/mod/devicetable-offsets.c
+++ b/scripts/mod/devicetable-offsets.c
@@ -1,8 +1,64 @@
// SPDX-License-Identifier: GPL-2.0
#define COMPILE_OFFSETS
-#include <linux/device-id/scmi.h>
+#include <linux/cpufeature.h>
#include <linux/kbuild.h>
-#include <linux/mod_devicetable.h>
+
+#include <linux/device-id/acpi.h>
+#include <linux/device-id/amba.h>
+#include <linux/device-id/ap.h>
+#include <linux/device-id/arm_smccc.h>
+#include <linux/device-id/auxiliary.h>
+#include <linux/device-id/bcma.h>
+#include <linux/device-id/ccw.h>
+#include <linux/device-id/cdx.h>
+#include <linux/device-id/coreboot.h>
+#include <linux/device-id/css.h>
+#include <linux/device-id/dfl.h>
+#include <linux/device-id/dmi.h>
+#include <linux/device-id/eisa.h>
+#include <linux/device-id/fsl_mc.h>
+#include <linux/device-id/hda.h>
+#include <linux/device-id/hid.h>
+#include <linux/device-id/hv_vmbus.h>
+#include <linux/device-id/i2c.h>
+#include <linux/device-id/i3c.h>
+#include <linux/device-id/ieee1394.h>
+#include <linux/device-id/input.h>
+#include <linux/device-id/ipack.h>
+#include <linux/device-id/isapnp.h>
+#include <linux/device-id/ishtp.h>
+#include <linux/device-id/mcb.h>
+#include <linux/device-id/mdio.h>
+#include <linux/device-id/mei_cl.h>
+#include <linux/device-id/mhi.h>
+#include <linux/device-id/mips_cdmm.h>
+#include <linux/device-id/of.h>
+#include <linux/device-id/parisc.h>
+#include <linux/device-id/pci.h>
+#include <linux/device-id/pcmcia.h>
+#include <linux/device-id/platform.h>
+#include <linux/device-id/pnp.h>
+#include <linux/device-id/rio.h>
+#include <linux/device-id/rpmsg.h>
+#include <linux/device-id/scmi.h>
+#include <linux/device-id/sdio.h>
+#include <linux/device-id/sdw.h>
+#include <linux/device-id/serio.h>
+#include <linux/device-id/slim.h>
+#include <linux/device-id/spi.h>
+#include <linux/device-id/ssam.h>
+#include <linux/device-id/ssb.h>
+#include <linux/device-id/tb.h>
+#include <linux/device-id/tee_client.h>
+#include <linux/device-id/typec.h>
+#include <linux/device-id/ulpi.h>
+#include <linux/device-id/usb.h>
+#include <linux/device-id/vchiq.h>
+#include <linux/device-id/vio.h>
+#include <linux/device-id/virtio.h>
+#include <linux/device-id/wmi.h>
+#include <linux/device-id/x86_cpu.h>
+#include <linux/device-id/zorro.h>
#define DEVID(devid) DEFINE(SIZE_##devid, sizeof(struct devid))
#define DEVID_FIELD(devid, field) \
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 61a831c18721..f848b39145d9 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -121,8 +121,63 @@ typedef struct {
/* Big exception to the "don't include kernel headers into userspace, which
* even potentially has different endianness and word sizes, since
* we handle those differences explicitly below */
+#include "../../include/linux/cpufeature.h"
+#include "../../include/linux/device-id/acpi.h"
+#include "../../include/linux/device-id/amba.h"
+#include "../../include/linux/device-id/ap.h"
+#include "../../include/linux/device-id/arm_smccc.h"
+#include "../../include/linux/device-id/auxiliary.h"
+#include "../../include/linux/device-id/bcma.h"
+#include "../../include/linux/device-id/ccw.h"
+#include "../../include/linux/device-id/cdx.h"
+#include "../../include/linux/device-id/coreboot.h"
+#include "../../include/linux/device-id/css.h"
+#include "../../include/linux/device-id/dfl.h"
+#include "../../include/linux/device-id/dmi.h"
+#include "../../include/linux/device-id/eisa.h"
+#include "../../include/linux/device-id/fsl_mc.h"
+#include "../../include/linux/device-id/hda.h"
+#include "../../include/linux/device-id/hid.h"
+#include "../../include/linux/device-id/hv_vmbus.h"
+#include "../../include/linux/device-id/i2c.h"
+#include "../../include/linux/device-id/i3c.h"
+#include "../../include/linux/device-id/ieee1394.h"
+#include "../../include/linux/device-id/input.h"
+#include "../../include/linux/device-id/ipack.h"
+#include "../../include/linux/device-id/isapnp.h"
+#include "../../include/linux/device-id/ishtp.h"
+#include "../../include/linux/device-id/mcb.h"
+#include "../../include/linux/device-id/mdio.h"
+#include "../../include/linux/device-id/mei_cl.h"
+#include "../../include/linux/device-id/mhi.h"
+#include "../../include/linux/device-id/mips_cdmm.h"
+#include "../../include/linux/device-id/of.h"
+#include "../../include/linux/device-id/parisc.h"
+#include "../../include/linux/device-id/pci.h"
+#include "../../include/linux/device-id/pcmcia.h"
+#include "../../include/linux/device-id/platform.h"
+#include "../../include/linux/device-id/pnp.h"
+#include "../../include/linux/device-id/rio.h"
+#include "../../include/linux/device-id/rpmsg.h"
#include "../../include/linux/device-id/scmi.h"
-#include "../../include/linux/mod_devicetable.h"
+#include "../../include/linux/device-id/sdio.h"
+#include "../../include/linux/device-id/sdw.h"
+#include "../../include/linux/device-id/serio.h"
+#include "../../include/linux/device-id/slim.h"
+#include "../../include/linux/device-id/spi.h"
+#include "../../include/linux/device-id/ssam.h"
+#include "../../include/linux/device-id/ssb.h"
+#include "../../include/linux/device-id/tb.h"
+#include "../../include/linux/device-id/tee_client.h"
+#include "../../include/linux/device-id/typec.h"
+#include "../../include/linux/device-id/ulpi.h"
+#include "../../include/linux/device-id/usb.h"
+#include "../../include/linux/device-id/vchiq.h"
+#include "../../include/linux/device-id/vio.h"
+#include "../../include/linux/device-id/virtio.h"
+#include "../../include/linux/device-id/wmi.h"
+#include "../../include/linux/device-id/x86_cpu.h"
+#include "../../include/linux/device-id/zorro.h"
struct devtable {
const char *device_id;
diff --git a/scripts/modules-check.sh b/scripts/modules-check.sh
index 4c8da90de78e..3d12dc53b202 100755
--- a/scripts/modules-check.sh
+++ b/scripts/modules-check.sh
@@ -13,10 +13,19 @@ exit_code=0
# Check uniqueness of module names
check_same_name_modules()
{
- for m in $(sed 's:.*/::' "$1" | sort | uniq -d)
+ for m in $(sed 's:.*/::; s/-/_/g' "$1" | sort | uniq -d)
do
echo "error: the following would cause module name conflict:" >&2
- sed -n "/\/$m/s:^\(.*\)\.o\$: \1.ko:p" "$1" >&2
+ awk -v name="$m" '
+ {
+ basename = $0
+ sub(/^.*\//, "", basename)
+ gsub(/-/, "_", basename)
+ if (basename == name) {
+ sub(/\.o$/, ".ko")
+ print " " $0
+ }
+ }' "$1" >&2
exit_code=1
done
}