/* * Copyright (C) 2015 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 */ /* * Sometimes people do: "if (err == ENOMEM) {" when the intent was to do: * "if (err == -ENOMEM) {" */ #include "smatch.h" #include "smatch_extra.h" static int my_id; const char *error_codes[] = { "EPERM", "ENOENT", "ESRCH", "EINTR", "EIO", "ENXIO", "E2BIG", "ENOEXEC", "EBADF", "ECHILD", "EAGAIN", "ENOMEM", "EACCES", "EFAULT", "ENOTBLK", "EBUSY", "EEXIST", "EXDEV", "ENODEV", "ENOTDIR", "EISDIR", "EINVAL", "ENFILE", "EMFILE", "ENOTTY", "ETXTBSY", "EFBIG", "ENOSPC", "ESPIPE", "EROFS", "EMLINK", "EPIPE", "EDOM", "ERANGE", "EDEADLK", "ENAMETOOLONG", "ENOLCK", "ENOSYS", "ENOTEMPTY", "ELOOP", "EWOULDBLOCK", "ENOMSG", "EIDRM", "ECHRNG", "EL2NSYNC", "EL3HLT", "EL3RST", "ELNRNG", "EUNATCH", "ENOCSI", "EL2HLT", "EBADE", "EBADR", "EXFULL", "ENOANO", "EBADRQC", "EBADSLT", "EDEADLOCK", "EBFONT", "ENOSTR", "ENODATA", "ETIME", "ENOSR", "ENONET", "ENOPKG", "EREMOTE", "ENOLINK", "EADV", "ESRMNT", "ECOMM", "EPROTO", "EMULTIHOP", "EDOTDOT", "EBADMSG", "EOVERFLOW", "ENOTUNIQ", "EBADFD", "EREMCHG", "ELIBACC", "ELIBBAD", "ELIBSCN", "ELIBMAX", "ELIBEXEC", "EILSEQ", "ERESTART", "ESTRPIPE", "EUSERS", "ENOTSOCK", "EDESTADDRREQ", "EMSGSIZE", "EPROTOTYPE", "ENOPROTOOPT", "EPROTONOSUPPORT", "ESOCKTNOSUPPORT", "EOPNOTSUPP", "EPFNOSUPPORT", "EAFNOSUPPORT", "EADDRINUSE", "EADDRNOTAVAIL", "ENETDOWN", "ENETUNREACH", "ENETRESET", "ECONNABORTED", "ECONNRESET", "ENOBUFS", "EISCONN", "ENOTCONN", "ESHUTDOWN", "ETOOMANYREFS", "ETIMEDOUT", "ECONNREFUSED", "EHOSTDOWN", "EHOSTUNREACH", "EALREADY", "EINPROGRESS", "ESTALE", "EUCLEAN", "ENOTNAM", "ENAVAIL", "EISNAM", "EREMOTEIO", "EDQUOT", "ENOMEDIUM", "EMEDIUMTYPE", "ECANCELED", "ENOKEY", "EKEYEXPIRED", "EKEYREVOKED", "EKEYREJECTED", "EOWNERDEAD", "ENOTRECOVERABLE", "ERFKILL", "EHWPOISON", "ERESTARTSYS", "ERESTARTNOINTR", "ERESTARTNOHAND", "ENOIOCTLCMD", "ERESTART_RESTARTBLOCK", "EPROBE_DEFER", "EOPENSTALE", "EBADHANDLE", "ENOTSYNC", "EBADCOOKIE", "ENOTSUPP", "ETOOSMALL", "ESERVERFAULT", "EBADTYPE", "EJUKEBOX", "EIOCBQUEUED", }; static void warn_on_positive_error(struct expression *expr) { sval_t sval; char *name; int found = 0; int i; if (!expr) return; if (!get_value(expr, &sval)) return; if (sval_is_negative(sval) || sval.value > 4095) return; name = get_macro_name(expr->pos); if (!name) return; if (name[0] != 'E') return; for (i = 0; i < ARRAY_SIZE(error_codes); i++) { if (strcmp(name, error_codes[i]) == 0) { found = 1; break; } } if (!found) return; sm_msg("warn: was negative '-%s' intended?", name); } static void match_condition(struct expression *expr) { if (expr->type != EXPR_COMPARE || expr->op != SPECIAL_EQUAL) return; /* check that the condition is known false */ // if (!get_implied_value(expr, &sval) || sval.value == 1) // return; warn_on_positive_error(expr->right); } static void match_assign(struct expression *expr) { warn_on_positive_error(expr->right); } static void match_return(struct expression *expr) { warn_on_positive_error(expr); } void check_positive_error_code(int id) { if (option_project != PROJ_KERNEL) return; my_id = id; add_hook(&match_condition, CONDITION_HOOK); add_hook(&match_assign, ASSIGNMENT_HOOK); add_hook(&match_return, RETURN_HOOK); }