Here is my next attempt at this check. Back in 2009, I used to write Smatch checks which were too complicated. Ideally, each Smatch check should only print one warning. The state engine should only have one custom state, and &undefined and &merged. That check I sent violated all those rules. The other thing which might be interesting is if you pass a NULL to IS_ERR() and then dereference the NULL then print a warning about that. This has a lot of overlaps with some of my existing checks, but it's still a new idea so it belongs in a separate check. It's fine and good even if one bug triggers a lot of different warnings. I'll write that, hang on, brb. regards, dan carpenter /* * Copyright (C) 2021 Oracle. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt */ #include "smatch.h" #include "smatch_extra.h" static int my_id; static void match_is_err(const char *fn, struct expression *expr, void *unused) { struct expression *arg, *call; struct range_list *rl; char *name; arg = get_argument_from_call_expr(expr->args, 0); /* ignore unknown values */ if (!get_implied_rl(arg, &rl)) return; /* error pointers are what we expect */ if (rl_max(rl).uvalue >= (unsigned long long)-4095) return; /* ignore valid pointers */ if (rl_min(rl).uvalue != 0) return; /* * Don't warn if people are using IS_ERR() to sanity check their * parameters. */ call = get_assigned_expr(arg); call = strip_expr(call); if (!call || call->type != EXPR_CALL) return; name = expr_to_str(arg); sm_warning("'%s' is not an error pointer", name); free_string(name); } void check_not_an_err_ptr(int id) { my_id = id; if (option_project != PROJ_KERNEL) return; add_function_hook("IS_ERR", &match_is_err, NULL); }