First Smatch Check

This is a small guide to writing a First Smatch Check. Read about
Smatch Data Types first. This blog will explain how to create a simple Smatch check for dereferencing freed variables.

There is already a better but quite complicated Smatch check for dereferencing freed variables so a simple check like this is not very useful in practice. It’s just an example to show some basic ideas.

The heuristic is that if we call kfree(p) then we want to print a warning if p
is ever dereferenced after that. The check will be called “check_dereferencing_kfreed.c”.

Every check needs to include the header file and declare its unique id.

#include "smatch.h"

static int my_id;

In olden times, Smatch checks were often quite complicated where I tried to
think about the whole life of a pointer. A pointer could be &uninitialized,
&valid, &null or &freed. I created an elaborate chart for how pointers could
transition from &uninitialized to &valid etc and a bunch of cases which would
lead to errors. But these days, I have learned it’s simpler if checks just have one state (besides the shared states of &undefined and &merged).

STATE(freed);

We will use two hooks, one for when kfree is called and one for dereferencing
pointers.

add_function_hook("kfree", &match_kfree, NULL);
add_dereference_hook(&match_deref);

Let’s implement the match_kfree() function. It takes the first argment to
kfree and sets the state to &freed.

static void match_kfree(const char *fn, struct expression *expr, void *_arg_nr)
{
	struct expression *arg;

	arg = get_argument_from_call_expr(expr->args, 0);
	set_state_expr(my_id, arg, &freed);
}

Now let’s implement the match_deref() function. It has to generate a warning
if the pointer is possibly freed.

static void match_deref(struct expression *expr)
{
	char *name;

	if (!expr_has_possible_state(my_id, expr, &freed))
		return;

	name = expr_to_str(expr);
	sm_warning("pointer '%s' was freed", name);
	free_string(name);
}

Now we just have to tie it all together. Since the file name was called
check_dereferencing_kfreed.c then the main function will be called that as
well.

void check_dereferencing_kfreed(int id)
{
	my_id = id;

	add_function_hook("kfree", &match_kfree, NULL);
	add_dereference_hook(&match_deref);
}

And we can add the check to check_list.h:

CK(check_dereferencing_kfreed)

The last step is to test it. I prefer to test the code on a real world
bug instead of a contrived test. Real world bugs are always more subtle than
made up tests. But in this case, we’ll create a test.

// The test will only work if kfree() is declared
void kfree(void *p);
_Bool frob(void);

void test_func(int *p)
{
	if (frob())
		kfree(p);
	*p = 100;
}

Please note that I am too lazy to test this code myself. I have not compiled it. If anyone tests then email me what I did wrong. I will fix it and add your name to the changelog here:

Changelog:

Harshit: Change the name of the function from deref_hook() to match_deref()

2 responses to “First Smatch Check”

  1. […] days the param/key API is the preferred way to write Smatch checks. In my First Smatch Check post I wrote how to implement match_kfree() in the old way which hardcoded that the freed variable […]

    Like

  2. […] my First Smatch Check post I left out an important part of the check. If we kfree(p), then assign “p = […]

    Like

Leave a comment

Design a site like this with WordPress.com
Get started