[PATCH] modpost: Warn about unused module namespace imports

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Symbols can be exported in namespaces and to make use of such symbols,
the namespace has to be explicitly imported. Importing a namespace
without actually using one of its symbols is likely a mistake.

There are a few offenders for an x86_64 allmodconfig build, so the
warning is (for now) only enabled for W=1 builds.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@xxxxxxxxxxxx>
---
Hello,

one of the offenders is drivers/pwm/pwm-raspberrypi-poe.c (

	WARNING: modpost: module pwm-raspberrypi-poe imports namespace PWM, but doesn't use it.

). The issue there is that on x86_64 CONFIG_RASPBERRYPI_FIRMWARE is
always disabled and so devm_rpi_firmware_get() returns always NULL which
makes raspberrypi_pwm_probe return an error before the pwm functions are
used. So the compiler optimizes out all references to pwm functions and
the warning triggers. I didn't look into the other problems to check if
these are similar half-false positives.

Still I think this is a useful check?

Best regards
Uwe

 scripts/mod/modpost.c | 60 +++++++++++++++++++++++++++++++------------
 1 file changed, 44 insertions(+), 16 deletions(-)

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index e18ae7dc8140..ef5a5e9718f3 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -268,13 +268,28 @@ static struct symbol *find_symbol(const char *name)
 
 struct namespace_list {
 	struct list_head list;
+	bool used;
 	char namespace[];
 };
 
+static struct namespace_list *find_namespace_entry(struct list_head *head,
+						   const char *namespace)
+{
+	struct namespace_list *ns_entry;
+
+	if (!namespace[0])
+		return NULL;
+
+	list_for_each_entry(ns_entry, head, list) {
+		if (!strcmp(ns_entry->namespace, namespace))
+			return ns_entry;
+	}
+
+	return NULL;
+}
+
 static bool contains_namespace(struct list_head *head, const char *namespace)
 {
-	struct namespace_list *list;
-
 	/*
 	 * The default namespace is null string "", which is always implicitly
 	 * contained.
@@ -282,21 +297,20 @@ static bool contains_namespace(struct list_head *head, const char *namespace)
 	if (!namespace[0])
 		return true;
 
-	list_for_each_entry(list, head, list) {
-		if (!strcmp(list->namespace, namespace))
-			return true;
-	}
+	if (find_namespace_entry(head, namespace))
+		return true;
 
 	return false;
 }
 
-static void add_namespace(struct list_head *head, const char *namespace)
+static void add_namespace(struct list_head *head, const char *namespace, bool used)
 {
 	struct namespace_list *ns_entry;
 
 	if (!contains_namespace(head, namespace)) {
 		ns_entry = xmalloc(sizeof(*ns_entry) + strlen(namespace) + 1);
 		strcpy(ns_entry->namespace, namespace);
+		ns_entry->used = used;
 		list_add_tail(&ns_entry->list, head);
 	}
 }
@@ -1580,7 +1594,7 @@ static void read_symbols(const char *modname)
 
 		namespace = get_modinfo(&info, "import_ns");
 		while (namespace) {
-			add_namespace(&mod->imported_namespaces, namespace);
+			add_namespace(&mod->imported_namespaces, namespace, false);
 			namespace = get_next_modinfo(&info, "import_ns",
 						     namespace);
 		}
@@ -1670,9 +1684,16 @@ void buf_write(struct buffer *buf, const char *s, int len)
 static void check_exports(struct module *mod)
 {
 	struct symbol *s, *exp;
+	struct namespace_list *ns_entry;
+	const char *basename;
+
+	basename = strrchr(mod->name, '/');
+	if (basename)
+		basename++;
+	else
+		basename = mod->name;
 
 	list_for_each_entry(s, &mod->unresolved_symbols, list) {
-		const char *basename;
 		exp = find_symbol(s->name);
 		if (!exp) {
 			if (!s->weak && nr_unresolved++ < MAX_UNRESOLVED_REPORTS)
@@ -1692,23 +1713,30 @@ static void check_exports(struct module *mod)
 		s->crc_valid = exp->crc_valid;
 		s->crc = exp->crc;
 
-		basename = strrchr(mod->name, '/');
-		if (basename)
-			basename++;
-		else
-			basename = mod->name;
+		ns_entry = find_namespace_entry(&mod->imported_namespaces, exp->namespace);
 
-		if (!contains_namespace(&mod->imported_namespaces, exp->namespace)) {
+		if (exp->namespace[0] && !ns_entry) {
 			modpost_log(!allow_missing_ns_imports,
 				    "module %s uses symbol %s from namespace %s, but does not import it.\n",
 				    basename, exp->name, exp->namespace);
-			add_namespace(&mod->missing_namespaces, exp->namespace);
+			add_namespace(&mod->missing_namespaces, exp->namespace, true);
+		} else if (ns_entry) {
+			ns_entry->used = true;
 		}
 
 		if (!mod->is_gpl_compatible && exp->is_gpl_only)
 			error("GPL-incompatible module %s.ko uses GPL-only symbol '%s'\n",
 			      basename, exp->name);
 	}
+
+	if (extra_warn) {
+		list_for_each_entry(ns_entry, &mod->imported_namespaces, list) {
+			if (!ns_entry->used)
+				modpost_log(false,
+					    "module %s imports namespace %s, but doesn't use it.\n",
+					    basename, ns_entry->namespace);
+		}
+	}
 }
 
 static void handle_white_list_exports(const char *white_list)

base-commit: 232f121837ad8b1c21cc80f2c8842a4090c5a2a0
-- 
2.47.1





[Index of Archives]     [Linux&nblp;USB Development]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite Secrets]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux