Powered by Linux
[RFC PATCH] check_freeing_devm: Also track erroneous usage of kfree when the pointer has been re-assigned — Semantic Matching Tool

[RFC PATCH] check_freeing_devm: Also track erroneous usage of kfree when the pointer has been re-assigned

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

 



When some memory is allocated, a common pattern is to use a tmp variable
to check if the allocation has succeeded or not. This tmp variable is then
stored in another variable for future use.

   ptr = devm_kmalloc(...);
   if (!ptr)
      return -ENOMEM;
   another_val = ptr;

So trying to see if this 'alias' is incorrectly freed with kfree makes
sense.

To do that, add a new hook that check, when an assignment is detected if
the right part of the expression is already recorded.
If so, also record the right part, so that bogus kfree can check both
reference.

Signed-off-by: Christophe JAILLET <christophe.jaillet@xxxxxxxxxx>
---
This is my first 'real' code proposal for smatch.
It is likely to be wrong/incomplete/imperfect. Maybe this functionality
is already implemented somewhere else and I just try to duplicate it.

All I know is that it seams to work for me, even if it has not detected any
issue yet :) (compiling takes SO MUCH time on my machine)
---
 check_freeing_devm.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/check_freeing_devm.c b/check_freeing_devm.c
index 11e8d8bc30b6..51fa990f1b4a 100644
--- a/check_freeing_devm.c
+++ b/check_freeing_devm.c
@@ -26,6 +26,29 @@ static void match_assign(const char *fn, struct expression *expr, void *unused)
 	set_state_expr(my_id, expr->left, &devm);
 }
 
+/*
+ * This hook deals with things like:
+ * ptr = devm_kmalloc(...);
+ * if (!ptr)
+ * 	return -ENOMEM;
+ * another_val = ptr;			<==
+ */
+static void match_reassign(struct expression *expr)
+{
+	struct expression *left, *right;
+
+	if (expr->op != '=')
+		return;
+
+	right = strip_expr(expr->right);
+	if (!get_state_expr(my_id, right))
+		return;
+
+	left = strip_expr(expr->left);
+
+	set_state_expr(my_id, left, &devm);
+}
+
 static void match_free_func(const char *fn, struct expression *expr, void *_arg)
 {
 	struct expression *arg_expr;
@@ -86,4 +109,6 @@ void check_freeing_devm(int id)
 	add_function_hook("kfree", &match_free_func, INT_PTR(0));
 	add_function_hook("krealloc", &match_free_func, INT_PTR(0));
 	register_funcs_from_file();
+
+	add_hook(&match_reassign, ASSIGNMENT_HOOK);
 }
-- 
2.34.1




[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux