static void match_dma_func(const char *fn, struct expression *expr, void *param) { struct expression *arg; struct symbol *sym; char *name; arg = get_argument_from_call_expr(expr->args, PTR_INT(param)); arg = strip_expr(arg); if (!arg) return; if (arg->type == EXPR_PREOP && arg->op == '&') { if (arg->unop->type != EXPR_SYMBOL) return; name = expr_to_str(arg); sm_msg("error: doing dma on the stack (%s)", name); free_string(name); return; } if (arg->type != EXPR_SYMBOL) return; sym = get_type(arg); if (!sym || sym->type != SYM_ARRAY) return; name = expr_to_var(arg); sm_msg("error: doing dma on the stack (%s)", name); free_string(name); }
static void match_return(struct expression *ret_value) { struct expression *expr; char *macro; if (!ret_value) return; expr = ret_value; if (ret_value->type != EXPR_PREOP || ret_value->op != '-') return; macro = get_macro_name(expr->unop->pos); if (macro && !strcmp(macro, "PTR_ERR")) { sm_msg("warn: returning -%s()", macro); return; } if (!option_spammy) return; expr = get_assigned_expr(ret_value->unop); if (!expr) return; if (expr->type != EXPR_CALL) return; sm_msg("warn: should this return really be negated?"); }
static void match_loop(struct statement *stmt) { struct expression *iterator; char *iter_set; char *iter_tested; if (get_macro_name(stmt->pos)) return; iterator = get_iterator_set(stmt->iterator_pre_statement); iter_set = expr_to_var(iterator); iterator = get_iterator_tested(stmt->iterator_pre_condition); iter_tested = expr_to_var(iterator); if (!iter_set || !iter_tested) goto free; if (strcmp(iter_set, iter_tested)) goto free; /* smatch doesn't handle loops correctly so this silences some * false positives. */ if (right_side_changes(stmt->iterator_pre_condition)) goto free; if (implied_condition_false(stmt->iterator_pre_condition)) sm_msg("warn: we never enter this loop"); free: free_string(iter_set); free_string(iter_tested); }
static void print_missing_break(struct expression *expr) { char *name; if (get_switch_expr() == last_print_expr) return; last_print_expr = get_switch_expr(); name = expr_to_var(expr); sm_msg("warn: missing break? reassigning '%s'", name); free_string(name); }
static void check_size_matches(int data_size, struct expression *size_expr) { sval_t sval; if (data_size == 1) /* this is generic a buffer */ return; if (!get_implied_value(size_expr, &sval)) return; if (sval_cmp_val(sval, data_size) != 0) sm_msg("warn: double check that we're allocating correct size: %d vs %s", data_size, sval_to_str(sval)); }
static void verify_size_expr(struct expression *expr) { if (expr->type != EXPR_BINOP) return; if (expr->op != '-') return; if (is_probably_ok(expr->left)) return; if (is_probably_ok(expr->right)) return; sm_msg("warn: consider using resource_size() here"); }
static void match_strcpy(const char *fn, struct expression *expr, void *unused) { struct expression *dest; struct expression *data; char *dest_name = NULL; char *data_name = NULL; int dest_size; int data_size; dest = get_argument_from_call_expr(expr->args, 0); data = get_argument_from_call_expr(expr->args, 1); dest_size = get_array_size_bytes(dest); if (!dest_size) return; data_size = get_size_from_strlen(data); if (!data_size) data_size = get_array_size_bytes(data); /* If the size of both arrays is known and the destination * buffer is larger than the source buffer, we're okay. */ if (data_size && dest_size >= data_size) return; dest_name = expr_to_str(dest); data_name = expr_to_str(data); if (data_size) sm_msg("error: %s() '%s' too large for '%s' (%d vs %d)", fn, data_name, dest_name, data_size, dest_size); else if (option_spammy) sm_msg("warn: %s() '%s' of unknown size might be too large for '%s'", fn, data_name, dest_name); free_string(dest_name); free_string(data_name); }
static void match_condition(struct expression *expr) { if (expr->type == EXPR_ASSIGNMENT) match_condition(expr->left); if (get_state_expr(my_id, expr) == &filehandle) { char *name; name = expr_to_var(expr); sm_msg("error: comparing a filehandle against zero '%s'", name); set_state_expr(my_id, expr, &oktocheck); free_string(name); } }
static void check_for_held(void) { struct state_list *slist; struct sm_state *tmp; slist = get_all_states(my_id); FOR_EACH_PTR(slist, tmp) { if (slist_has_state(tmp->possible, &held)) { sm_msg("warn: '%s' held on error path.", tmp->name); } } END_FOR_EACH_PTR(tmp); free_slist(&slist); }
static void match_binop(struct expression *expr) { sval_t left, right, sval; if (expr->op != '&') return; if (!get_value(expr, &sval) || sval.value != 0) return; if (get_macro_name(expr->pos)) return; if (!get_value(expr->left, &left) || !get_value(expr->right, &right)) return; sm_msg("warn: odd binop '0x%llx & 0x%llx'", left.uvalue, right.uvalue); }
static void check_expr(struct expression *expr) { struct sm_state *sm; sval_t max; sval_t sval; char *name; int overflow = 0; int underflow = 0; sm = get_sm_state_expr(my_max_id, expr); if (sm && slist_has_state(sm->possible, &user_data)) { if (!get_absolute_max(expr, &max) || sval_cmp_val(max, 20000) > 0) overflow = 1; } sm = get_sm_state_expr(my_min_id, expr); if (sm && slist_has_state(sm->possible, &user_data)) { if (!get_absolute_min(expr, &sval) || (sval_is_negative(sval) && sval_cmp_val(sval, -20000) < 0)) underflow = 1; } if (!overflow && !underflow) return; name = expr_to_var_sym(expr, NULL); if (overflow && underflow) sm_msg("warn: check for integer over/underflow '%s'", name); else if (underflow) sm_msg("warn: check for integer underflow '%s'", name); else sm_msg("warn: check for integer overflow '%s'", name); free_string(name); set_state_expr(my_max_id, expr, &capped); set_state_expr(my_min_id, expr, &capped); }
static void match_condition(struct expression *expr) { sval_t sval; if (expr->type != EXPR_BINOP) return; if (expr->op == '|') { if (get_value(expr->left, &sval) || get_value(expr->right, &sval)) sm_msg("warn: suspicious bitop condition"); return; } if (expr->op != '&') return; if (get_macro_name(expr->pos)) return; if (is_unconstant_macro(expr->left) || is_unconstant_macro(expr->right)) return; if ((get_value(expr->left, &sval) && sval.value == 0) || (get_value(expr->right, &sval) && sval.value == 0)) sm_msg("warn: bitwise AND condition is false here"); }
static void match_free(const char *fn, struct expression *expr, void *data) { struct expression *arg_expr; char *name; sval_t sval; arg_expr = get_argument_from_call_expr(expr->args, 0); if (!get_implied_value(arg_expr, &sval)) return; if (sval.value != 0) return; name = expr_to_var(arg_expr); sm_msg("warn: calling %s() when '%s' is always NULL.", fn, name); free_string(name); }
static void match_binop(struct expression *expr) { const char *name; if (positions_eq(expr->pos, expr->right->pos)) return; if (expr->op != '&') return; name = get_shifter(expr->right); if (!name) return; sm_msg("warn: bit shifter '%s' used for logical '%s'", name, show_special(expr->op)); }
static void match_assign(struct expression *expr) { const char *name; if (expr->op != SPECIAL_OR_ASSIGN) return; if (positions_eq(expr->pos, expr->right->pos)) return; name = get_shifter(expr->right); if (!name) return; sm_msg("warn: '%s' is a shifter (not for '%s').", name, show_special(expr->op)); }
static void match_inside(struct expression *expr, struct position pos) { char *name; int matched = 0; if (positions_eq(expr->pos, pos)) matched++; if (positions_eq(expr->unop->pos, pos)) matched++; if (matched != 1) return; name = get_macro_name(pos); if (!name) return; sm_msg("warn: the '%s' macro might need parens", name); }
static void match_condition(struct expression *expr) { struct symbol *type; char *str; if (expr->type != EXPR_DEREF) return; type = get_type(expr); if (!type || type->type != SYM_ARRAY) return; if (get_macro_name(expr->pos)) return; str = expr_to_str(expr); sm_msg("warn: this array is probably non-NULL. '%s'", str); free_string(str); }
static void match_call(const char *fn, struct expression *expr, void *_arg_no) { struct expression *arg_expr; int arg_no = PTR_INT(_arg_no); sval_t sval; char *name; arg_expr = get_argument_from_call_expr(expr->args, arg_no); if (positions_eq(expr->pos, arg_expr->pos)) return; name = pos_ident(arg_expr->pos); if (!name) return; if (!get_value(arg_expr, &sval)) return; sm_msg("info: bit shifter '%s' '%s'", name, sval_to_str(sval)); }
static void check_and(struct expression *expr) { struct expression *left, *right; left = strip_expr(expr->left); right = strip_expr(expr->right); if (left->type != EXPR_COMPARE || left->op != SPECIAL_EQUAL) return; if (right->type != EXPR_COMPARE || right->op != SPECIAL_EQUAL) return; if (!inconsistent_check(left, right)) return; sm_msg("warn: was || intended here instead of &&?"); }
static void match_binop_info(struct expression *expr) { char *name; sval_t sval; if (positions_eq(expr->pos, expr->right->pos)) return; if (expr->op != SPECIAL_LEFTSHIFT) return; if (expr->right->type != EXPR_VALUE) return; name = pos_ident(expr->right->pos); if (!name) return; if (!get_value(expr->right, &sval)) return; sm_msg("info: bit shifter '%s' '%s'", name, sval_to_str(sval)); }
static void match_return(struct expression *ret_value) { sval_t rval; sval_t lret; char *name; if (!get_value(ret_value, &rval) || rval.value >= 0) return; if (get_implied_value(last_return, &lret)) return; if (!get_implied_max(last_return, &lret) || lret.value >= 0) return; if (get_implied_min(last_return, &lret) && !sval_is_min(lret)) return; name = expr_to_var(last_return); sm_msg("info: why not propagate '%s' from %s() instead of %s?", name, get_fn_name(last_func), sval_to_str(rval)); free_string(name); }
static void match_one_side(struct expression *expr, struct position pos, int op) { char *name; int matched = 0; if ((op == '+' || op == '*' || op == '|' || op == '&') && expr->op == op) return; if (positions_eq(expr->right->pos, pos)) matched++; if (positions_eq(expr->left->pos, pos)) matched++; if (matched != 1) return; name = get_macro_name(pos); if (!name) return; if (option_project == PROJ_WINE && !strcmp("BEGIN", name)) return; sm_msg("warn: the '%s' macro might need parens", name); }