/* * Copyright (C) 2010 Dan Carpenter. * * 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 "symbol.h" #include "smatch.h" #include "smatch_slist.h" #include "smatch_extra.h" static bool get_rl_sval(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *sval_res); static bool get_rl_internal(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res); static bool handle_variable(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval); static struct range_list *(*custom_handle_variable)(struct expression *expr); static bool get_implied_value_internal(struct expression *expr, int *recurse_cnt, sval_t *res_sval); static int get_absolute_rl_internal(struct expression *expr, struct range_list **rl, int *recurse_cnt); static sval_t zero = {.type = &int_ctype, {.value = 0} }; static sval_t one = {.type = &int_ctype, {.value = 1} }; static int fast_math_only; struct range_list *rl_zero(void) { static struct range_list *zero_perm; if (!zero_perm) zero_perm = clone_rl_permanent(alloc_rl(zero, zero)); return zero_perm; } struct range_list *rl_one(void) { static struct range_list *one_perm; if (!one_perm) one_perm = clone_rl_permanent(alloc_rl(one, one)); return one_perm; } enum { RL_EXACT, RL_HARD, RL_FUZZY, RL_IMPLIED, RL_ABSOLUTE, RL_REAL_ABSOLUTE, }; static bool last_stmt_rl(struct statement *stmt, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval) { struct expression *expr; if (!stmt) return false; stmt = last_ptr_list((struct ptr_list *)stmt->stmts); if (stmt->type == STMT_LABEL) { if (stmt->label_statement && stmt->label_statement->type == STMT_EXPRESSION) expr = stmt->label_statement->expression; else return false; } else if (stmt->type == STMT_EXPRESSION) { expr = stmt->expression; } else { return false; } return get_rl_sval(expr, implied, recurse_cnt, res, res_sval); } static bool handle_expression_statement_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval) { return last_stmt_rl(get_expression_statement(expr), implied, recurse_cnt, res, res_sval); } static bool handle_address(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval) { struct range_list *rl; static int recursed; sval_t sval; if (recursed > 10) return false; if (implied == RL_EXACT) return false; if (custom_handle_variable) { rl = custom_handle_variable(expr); if (rl) { *res = rl; return true; } } recursed++; if (get_mtag_sval(expr, &sval)) { recursed--; *res_sval = sval; return true; } if (get_address_rl(expr, res)) { recursed--; return true; } recursed--; return 0; } static bool handle_ampersand_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval) { return handle_address(expr, implied, recurse_cnt, res, res_sval); } static bool handle_negate_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval) { if (known_condition_true(expr->unop)) { *res_sval = zero; return true; } if (known_condition_false(expr->unop)) { *res_sval = one; return true; } if (implied == RL_EXACT) return false; if (implied_condition_true(expr->unop)) { *res_sval = zero; return true; } if (implied_condition_false(expr->unop)) { *res_sval = one; return true; } *res = alloc_rl(zero, one); return true; } static bool handle_bitwise_negate(struct expression *expr, int implied, int *recurse_cnt, sval_t *res_sval) { struct range_list *rl; sval_t sval = {}; if (!get_rl_sval(expr->unop, implied, recurse_cnt, &rl, &sval)) return false; if (!sval.type && !rl_to_sval(rl, &sval)) return false; sval = sval_preop(sval, '~'); sval_cast(get_type(expr->unop), sval); *res_sval = sval; return true; } static bool untrusted_type_min(struct expression *expr) { struct range_list *rl; rl = var_user_rl(expr); return rl && sval_is_min(rl_min(rl)); } static bool handle_minus_preop(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval) { struct range_list *rl; struct range_list *ret = NULL; struct symbol *type; sval_t neg_one = { 0 }; sval_t zero = { 0 }; sval_t sval = {}; neg_one.value = -1; zero.value = 0; if (!get_rl_sval(expr->unop, implied, recurse_cnt, &rl, &sval)) return false; if (sval.type) { *res_sval = sval_preop(sval, '-'); return true; } /* * One complication is that -INT_MIN is still INT_MIN because of integer * overflows... But how many times do we set a time out to INT_MIN? * So normally when we call abs() then it does return a positive value. * */ type = rl_type(rl); neg_one.type = zero.type = type; if (sval_is_negative(rl_min(rl))) { struct range_list *neg; struct data_range *drange; sval_t new_min, new_max; neg = alloc_rl(sval_type_min(type), neg_one); neg = rl_intersection(rl, neg); if (sval_is_min(rl_min(neg)) && !sval_is_min(rl_max(neg))) neg = remove_range(neg, sval_type_min(type), sval_type_min(type)); FOR_EACH_PTR(neg, drange) { new_min = drange->max; new_min.value = -new_min.value; new_max = drange->min; new_max.value = -new_max.value; add_range(&ret, new_min, new_max); } END_FOR_EACH_PTR(drange); if (untrusted_type_min(expr)) add_range(&ret, sval_type_min(type), sval_type_min(type)); } if (!sval_is_negative(rl_max(rl))) { struct range_list *pos; struct data_range *drange; sval_t new_min, new_max; pos = alloc_rl(zero, sval_type_max(type)); pos = rl_intersection(rl, pos); FOR_EACH_PTR(pos, drange) { new_min = drange->max; new_min.value = -new_min.value; new_max = drange->min; new_max.value = -new_max.value; add_range(&ret, new_min, new_max); } END_FOR_EACH_PTR(drange); } *res = ret; return true; } static bool handle_preop_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval) { switch (expr->op) { case '&': return handle_ampersand_rl(expr, implied, recurse_cnt, res, res_sval); case '!': return handle_negate_rl(expr, implied, recurse_cnt, res, res_sval); case '~': return handle_bitwise_negate(expr, implied, recurse_cnt, res_sval); case '-': return handle_minus_preop(expr, implied, recurse_cnt, res, res_sval); case '*': return handle_variable(expr, implied, recurse_cnt, res, res_sval); case '(': return handle_expression_statement_rl(expr, implied, recurse_cnt, res, res_sval); default: return false; } } static bool handle_divide_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res) { struct range_list *left_rl = NULL; struct range_list *right_rl = NULL; struct symbol *type; type = get_type(expr); get_rl_internal(expr->left, implied, recurse_cnt, &left_rl); left_rl = cast_rl(type, left_rl); get_rl_internal(expr->right, implied, recurse_cnt, &right_rl); right_rl = cast_rl(type, right_rl); if (!left_rl || !right_rl) return false; if (implied != RL_REAL_ABSOLUTE) { if (is_whole_rl(left_rl) || is_whole_rl(right_rl)) return false; } *res = rl_binop(left_rl, '/', right_rl); return true; } static int handle_offset_subtraction(struct expression *expr) { struct expression *left, *right; struct symbol *left_sym, *right_sym; struct symbol *type; int left_offset, right_offset; type = get_type(expr); if (!type || type->type != SYM_PTR) return -1; type = get_real_base_type(type); if (!type || (type_bits(type) != 8 && (type != &void_ctype))) return -1; left = strip_expr(expr->left); right = strip_expr(expr->right); if (left->type != EXPR_PREOP || left->op != '&') return -1; left = strip_expr(left->unop); left_sym = expr_to_sym(left); right_sym = expr_to_sym(right); if (!left_sym || left_sym != right_sym) return -1; left_offset = get_member_offset_from_deref(left); if (right->type == EXPR_SYMBOL) right_offset = 0; else { if (right->type != EXPR_PREOP || right->op != '&') return -1; right = strip_expr(right->unop); right_offset = get_member_offset_from_deref(right); } if (left_offset < 0 || right_offset < 0) return -1; return left_offset - right_offset; } static bool max_is_unknown_max(struct range_list *rl) { /* * The issue with this code is that we had: * if (foo > 1) return 1 - foo; * Ideally we would say that returns s32min-(-1) but what Smatch * was saying was that the lowest possible value was "1 - INT_MAX" * * My solution is to ignore max values for int or larger. I keep * the max for shorts etc, because those might be worthwhile. * * The problem with just returning 1 - INT_MAX is that that is * treated as useful information but s32min is treated as basically * unknown. */ if (type_bits(rl_type(rl)) < 31) return false; return sval_is_max(rl_max(rl)); } static bool handle_subtract_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res) { struct symbol *type; struct range_list *left_orig, *right_orig; struct range_list *left_rl, *right_rl; sval_t min, max, tmp; int comparison; int offset; type = get_type(expr); offset = handle_offset_subtraction(expr); if (offset >= 0) { tmp.type = type; tmp.value = offset; *res = alloc_rl(tmp, tmp); return true; } comparison = get_comparison(expr->left, expr->right); left_orig = NULL; get_rl_internal(expr->left, implied, recurse_cnt, &left_orig); left_rl = cast_rl(type, left_orig); right_orig = NULL; get_rl_internal(expr->right, implied, recurse_cnt, &right_orig); right_rl = cast_rl(type, right_orig); if ((!left_rl || !right_rl) && (implied == RL_EXACT || implied == RL_HARD || implied == RL_FUZZY)) return false; if (!left_rl) left_rl = alloc_whole_rl(type); if (!right_rl) right_rl = alloc_whole_rl(type); /* negative values complicate everything fix this later */ if (sval_is_negative(rl_min(right_rl))) return false; max = rl_max(left_rl); min = sval_type_min(type); switch (comparison) { case '>': case SPECIAL_UNSIGNED_GT: min = sval_type_val(type, 1); max = rl_max(left_rl); break; case SPECIAL_GTE: case SPECIAL_UNSIGNED_GTE: min = sval_type_val(type, 0); max = rl_max(left_rl); break; case SPECIAL_EQUAL: min = sval_type_val(type, 0); max = sval_type_val(type, 0); break; case '<': case SPECIAL_UNSIGNED_LT: max = sval_type_val(type, -1); break; case SPECIAL_LTE: case SPECIAL_UNSIGNED_LTE: max = sval_type_val(type, 0); break; default: if (!left_orig || !right_orig) return false; *res = rl_binop(left_rl, '-', right_rl); return true; } if (!max_is_unknown_max(right_rl) && !sval_binop_overflows(rl_min(left_rl), '-', rl_max(right_rl))) { tmp = sval_binop(rl_min(left_rl), '-', rl_max(right_rl)); if (sval_cmp(tmp, min) > 0) min = tmp; } if (!sval_is_max(rl_max(left_rl))) { tmp = sval_binop(rl_max(left_rl), '-', rl_min(right_rl)); if (sval_cmp(tmp, max) < 0) max = tmp; } if (sval_is_min(min) && sval_is_max(max)) return false; *res = cast_rl(type, alloc_rl(min, max)); return true; } static bool handle_mod_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res) { struct range_list *rl; sval_t left, right, sval; if (implied == RL_EXACT) { if (!get_implied_value(expr->right, &right)) return false; if (!get_implied_value(expr->left, &left)) return false; sval = sval_binop(left, '%', right); *res = alloc_rl(sval, sval); return true; } /* if we can't figure out the right side it's probably hopeless */ if (!get_implied_value_internal(expr->right, recurse_cnt, &right)) return false; right = sval_cast(get_type(expr), right); right.value--; if (get_rl_internal(expr->left, implied, recurse_cnt, &rl) && rl && rl_max(rl).uvalue < right.uvalue) right.uvalue = rl_max(rl).uvalue; *res = alloc_rl(sval_cast(right.type, zero), right); return true; } static bool handle_bitwise_AND(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res) { struct symbol *type; struct range_list *left_rl, *right_rl; int new_recurse; if (implied != RL_IMPLIED && implied != RL_ABSOLUTE && implied != RL_REAL_ABSOLUTE) return false; type = get_type(expr); if (!get_rl_internal(expr->left, implied, recurse_cnt, &left_rl)) left_rl = alloc_whole_rl(type); left_rl = cast_rl(type, left_rl); new_recurse = *recurse_cnt; if (*recurse_cnt >= 200) new_recurse = 100; /* Let's try super hard to get the mask */ if (!get_rl_internal(expr->right, implied, &new_recurse, &right_rl)) right_rl = alloc_whole_rl(type); right_rl = cast_rl(type, right_rl); *recurse_cnt = new_recurse; *res = rl_binop(left_rl, '&', right_rl); return true; } static bool use_rl_binop(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res) { struct symbol *type; struct range_list *left_rl, *right_rl; if (implied != RL_IMPLIED && implied != RL_ABSOLUTE && implied != RL_REAL_ABSOLUTE) return false; type = get_type(expr); get_absolute_rl_internal(expr->left, &left_rl, recurse_cnt); get_absolute_rl_internal(expr->right, &right_rl, recurse_cnt); left_rl = cast_rl(type, left_rl); right_rl = cast_rl(type, right_rl); if (!left_rl || !right_rl) return false; *res = rl_binop(left_rl, expr->op, right_rl); return true; } static bool handle_right_shift(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res) { struct range_list *left_rl, *right_rl; sval_t min, max; if (implied == RL_EXACT || implied == RL_HARD) return false; if (get_rl_internal(expr->left, implied, recurse_cnt, &left_rl)) { max = rl_max(left_rl); min = rl_min(left_rl); } else { if (implied == RL_FUZZY) return false; max = sval_type_max(get_type(expr->left)); min = sval_type_val(get_type(expr->left), 0); } if (get_rl_internal(expr->right, implied, recurse_cnt, &right_rl) && !sval_is_negative(rl_min(right_rl))) { min = sval_binop(min, SPECIAL_RIGHTSHIFT, rl_max(right_rl)); max = sval_binop(max, SPECIAL_RIGHTSHIFT, rl_min(right_rl)); } else if (!sval_is_negative(min)) { min.value = 0; max = sval_type_max(max.type); } else { return false; } *res = alloc_rl(min, max); return true; } static bool handle_left_shift(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res) { struct range_list *left_rl, *rl; sval_t right; if (implied == RL_EXACT || implied == RL_HARD) return false; /* this is hopeless without the right side */ if (!get_implied_value_internal(expr->right, recurse_cnt, &right)) return false; if (!get_rl_internal(expr->left, implied, recurse_cnt, &left_rl)) { if (implied == RL_FUZZY) return false; left_rl = alloc_whole_rl(get_type(expr->left)); } rl = rl_binop(left_rl, SPECIAL_LEFTSHIFT, alloc_rl(right, right)); if (!rl) return false; *res = rl; return true; } static bool handle_known_binop(struct expression *expr, sval_t *res) { sval_t left, right; if (!get_value(expr->left, &left)) return false; if (!get_value(expr->right, &right)) return false; *res = sval_binop(left, expr->op, right); return true; } static int has_actual_ranges(struct range_list *rl) { struct data_range *tmp; FOR_EACH_PTR(rl, tmp) { if (sval_cmp(tmp->min, tmp->max) != 0) return 1; } END_FOR_EACH_PTR(tmp); return 0; } static struct range_list *handle_implied_binop(struct range_list *left_rl, int op, struct range_list *right_rl) { struct range_list *res_rl; struct data_range *left_drange, *right_drange; sval_t res; if (!left_rl || !right_rl) return NULL; if (has_actual_ranges(left_rl)) return NULL; if (has_actual_ranges(right_rl)) return NULL; if (ptr_list_size((struct ptr_list *)left_rl) * ptr_list_size((struct ptr_list *)right_rl) > 20) return NULL; res_rl = NULL; FOR_EACH_PTR(left_rl, left_drange) { FOR_EACH_PTR(right_rl, right_drange) { if ((op == '%' || op == '/') && right_drange->min.value == 0) return NULL; res = sval_binop(left_drange->min, op, right_drange->min); add_range(&res_rl, res, res); } END_FOR_EACH_PTR(right_drange); } END_FOR_EACH_PTR(left_drange); return res_rl; } static bool handle_binop_rl_helper(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval) { struct symbol *type; struct range_list *left_rl = NULL; struct range_list *right_rl = NULL; struct range_list *rl; sval_t min, max; type = get_promoted_type(get_type(expr->left), get_type(expr->right)); get_rl_internal(expr->left, implied, recurse_cnt, &left_rl); left_rl = cast_rl(type, left_rl); get_rl_internal(expr->right, implied, recurse_cnt, &right_rl); right_rl = cast_rl(type, right_rl); if (!left_rl && !right_rl) return false; rl = handle_implied_binop(left_rl, expr->op, right_rl); if (rl) { *res = rl; return true; } switch (expr->op) { case '%': return handle_mod_rl(expr, implied, recurse_cnt, res); case '&': return handle_bitwise_AND(expr, implied, recurse_cnt, res); case '|': case '^': return use_rl_binop(expr, implied, recurse_cnt, res); case SPECIAL_RIGHTSHIFT: return handle_right_shift(expr, implied, recurse_cnt, res); case SPECIAL_LEFTSHIFT: return handle_left_shift(expr, implied, recurse_cnt, res); case '-': return handle_subtract_rl(expr, implied, recurse_cnt, res); case '/': return handle_divide_rl(expr, implied, recurse_cnt, res); } if (!left_rl || !right_rl) return false; if (sval_binop_overflows(rl_min(left_rl), expr->op, rl_min(right_rl))) return false; if (sval_binop_overflows(rl_max(left_rl), expr->op, rl_max(right_rl))) return false; min = sval_binop(rl_min(left_rl), expr->op, rl_min(right_rl)); max = sval_binop(rl_max(left_rl), expr->op, rl_max(right_rl)); *res = alloc_rl(min, max); return true; } static bool handle_binop_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval) { struct smatch_state *state; struct range_list *rl; sval_t val; if (handle_known_binop(expr, &val)) { *res_sval = val; return true; } if (implied == RL_EXACT) return false; if (custom_handle_variable) { rl = custom_handle_variable(expr); if (rl) { *res = rl; return true; } } state = get_extra_state(expr); if (state && !is_whole_rl(estate_rl(state))) { if (implied != RL_HARD || estate_has_hard_max(state)) { *res = clone_rl(estate_rl(state)); return true; } } return handle_binop_rl_helper(expr, implied, recurse_cnt, res, res_sval); } static int do_comparison(struct expression *expr) { struct range_list *left_ranges = NULL; struct range_list *right_ranges = NULL; int poss_true, poss_false; struct symbol *type; type = get_type(expr); get_absolute_rl(expr->left, &left_ranges); get_absolute_rl(expr->right, &right_ranges); left_ranges = cast_rl(type, left_ranges); right_ranges = cast_rl(type, right_ranges); poss_true = possibly_true_rl(left_ranges, expr->op, right_ranges); poss_false = possibly_false_rl(left_ranges, expr->op, right_ranges); if (!poss_true && !poss_false) return 0x0; if (poss_true && !poss_false) return 0x1; if (!poss_true && poss_false) return 0x2; return 0x3; } static bool handle_comparison_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval) { sval_t left, right; int cmp; if (expr->op == SPECIAL_EQUAL && expr->left->type == EXPR_TYPE) { struct symbol *left, *right; if (expr->right->type != EXPR_TYPE) return false; left = get_real_base_type(expr->left->symbol); right = get_real_base_type(expr->right->symbol); if (type_bits(left) == type_bits(right) && type_positive_bits(left) == type_positive_bits(right)) *res_sval = one; else *res_sval = zero; return true; } if (get_value(expr->left, &left) && get_value(expr->right, &right)) { struct data_range tmp_left, tmp_right; tmp_left.min = left; tmp_left.max = left; tmp_right.min = right; tmp_right.max = right; if (true_comparison_range(&tmp_left, expr->op, &tmp_right)) *res_sval = one; else *res_sval = zero; return true; } if (implied == RL_EXACT) return false; cmp = do_comparison(expr); if (cmp == 1) { *res_sval = one; return true; } if (cmp == 2) { *res_sval = zero; return true; } *res = alloc_rl(zero, one); return true; } static bool handle_logical_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval) { sval_t left, right; int left_known = 0; int right_known = 0; if (implied == RL_EXACT) { if (get_value(expr->left, &left)) left_known = 1; if (get_value(expr->right, &right)) right_known = 1; } else { if (get_implied_value_internal(expr->left, recurse_cnt, &left)) left_known = 1; if (get_implied_value_internal(expr->right, recurse_cnt, &right)) right_known = 1; } switch (expr->op) { case SPECIAL_LOGICAL_OR: if (left_known && left.value) goto one; if (right_known && right.value) goto one; if (left_known && right_known) goto zero; break; case SPECIAL_LOGICAL_AND: if (left_known && right_known) { if (left.value && right.value) goto one; goto zero; } break; default: return false; } if (implied == RL_EXACT) return false; *res = alloc_rl(zero, one); return true; zero: *res_sval = zero; return true; one: *res_sval = one; return true; } static bool handle_conditional_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval) { struct expression *cond_true; struct range_list *true_rl, *false_rl; struct symbol *type; int final_pass_orig = final_pass; cond_true = expr->cond_true; if (!cond_true) cond_true = expr->conditional; if (known_condition_true(expr->conditional)) return get_rl_sval(cond_true, implied, recurse_cnt, res, res_sval); if (known_condition_false(expr->conditional)) return get_rl_sval(expr->cond_false, implied, recurse_cnt, res, res_sval); if (implied == RL_EXACT) return false; if (implied_condition_true(expr->conditional)) return get_rl_sval(cond_true, implied, recurse_cnt, res, res_sval); if (implied_condition_false(expr->conditional)) return get_rl_sval(expr->cond_false, implied, recurse_cnt, res, res_sval); /* this becomes a problem with deeply nested conditional statements */ if (fast_math_only || low_on_memory()) return false; type = get_type(expr); __push_fake_cur_stree(); final_pass = 0; __split_whole_condition(expr->conditional); true_rl = NULL; get_rl_internal(cond_true, implied, recurse_cnt, &true_rl); __push_true_states(); __use_false_states(); false_rl = NULL; get_rl_internal(expr->cond_false, implied, recurse_cnt, &false_rl); __merge_true_states(); __free_fake_cur_stree(); final_pass = final_pass_orig; if (!true_rl || !false_rl) return false; true_rl = cast_rl(type, true_rl); false_rl = cast_rl(type, false_rl); *res = rl_union(true_rl, false_rl); return true; } static bool get_fuzzy_max_helper(struct expression *expr, sval_t *max) { struct smatch_state *state; sval_t sval; if (get_hard_max(expr, &sval)) { *max = sval; return true; } state = get_extra_state(expr); if (!state || !estate_has_fuzzy_max(state)) return false; *max = sval_cast(get_type(expr), estate_get_fuzzy_max(state)); return true; } static bool get_fuzzy_min_helper(struct expression *expr, sval_t *min) { struct smatch_state *state; sval_t sval; state = get_extra_state(expr); if (!state || !estate_rl(state)) return false; sval = estate_min(state); if (sval_is_negative(sval) && sval_is_min(sval)) return false; if (sval_is_max(sval)) return false; *min = sval_cast(get_type(expr), sval); return true; } int get_const_value(struct expression *expr, sval_t *sval) { struct symbol *sym; sval_t right; if (expr->type != EXPR_SYMBOL || !expr->symbol) return 0; sym = expr->symbol; if (!(sym->ctype.modifiers & MOD_CONST)) return 0; if (get_value(sym->initializer, &right)) { *sval = sval_cast(get_type(expr), right); return 1; } return 0; } struct range_list *var_to_absolute_rl(struct expression *expr) { struct smatch_state *state; struct range_list *rl; state = get_extra_state(expr); if (!state || is_whole_rl(estate_rl(state))) { state = get_real_absolute_state(expr); if (state && state->data && !estate_is_whole(state)) return clone_rl(estate_rl(state)); if (get_mtag_rl(expr, &rl)) return rl; if (get_db_type_rl(expr, &rl) && !is_whole_rl(rl)) return rl; return alloc_whole_rl(get_type(expr)); } /* err on the side of saying things are possible */ if (!estate_rl(state)) return alloc_whole_rl(get_type(expr)); return clone_rl(estate_rl(state)); } static bool handle_variable(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval) { struct smatch_state *state; struct range_list *rl; sval_t sval, min, max; struct symbol *type; if (get_const_value(expr, &sval)) { *res_sval = sval; return true; } if (implied == RL_EXACT) return false; if (custom_handle_variable) { rl = custom_handle_variable(expr); if (rl) { if (!rl_to_sval(rl, res_sval)) *res = rl; } else { *res = var_to_absolute_rl(expr); } return true; } if (get_mtag_sval(expr, &sval)) { *res_sval = sval; return true; } type = get_type(expr); if (type && (type->type == SYM_ARRAY || type->type == SYM_FN)) return handle_address(expr, implied, recurse_cnt, res, res_sval); /* FIXME: call rl_to_sval() on the results */ switch (implied) { case RL_HARD: case RL_IMPLIED: case RL_ABSOLUTE: state = get_extra_state(expr); if (!state) { if (implied == RL_HARD) return false; if (get_mtag_rl(expr, res)) return true; if (get_db_type_rl(expr, res)) return true; if (is_array(expr) && get_array_rl(expr, res)) return true; return false; } if (implied == RL_HARD && !estate_has_hard_max(state)) return false; *res = clone_rl(estate_rl(state)); return true; case RL_REAL_ABSOLUTE: { struct smatch_state *abs_state; state = get_extra_state(expr); abs_state = get_real_absolute_state(expr); if (estate_rl(state) && estate_rl(abs_state)) { *res = clone_rl(rl_intersection(estate_rl(state), estate_rl(abs_state))); return true; } else if (estate_rl(state)) { *res = clone_rl(estate_rl(state)); return true; } else if (estate_is_empty(state)) { /* * FIXME: we don't handle empty extra states correctly. * * The real abs rl is supposed to be filtered by the * extra state if there is one. We don't bother keeping * the abs state in sync all the time because we know it * will be filtered later. * * It's not totally obvious to me how they should be * handled. Perhaps we should take the whole rl and * filter by the imaginary states. Perhaps we should * just go with the empty state. * * Anyway what we currently do is return NULL here and * that gets translated into the whole range in * get_real_absolute_rl(). * */ return false; } else if (estate_rl(abs_state)) { *res = clone_rl(estate_rl(abs_state)); return true; } if (get_mtag_rl(expr, res)) return true; if (get_db_type_rl(expr, res)) return true; if (is_array(expr) && get_array_rl(expr, res)) return true; return false; } case RL_FUZZY: if (!get_fuzzy_min_helper(expr, &min)) min = sval_type_min(get_type(expr)); if (!get_fuzzy_max_helper(expr, &max)) return false; /* fuzzy ranges are often inverted */ if (sval_cmp(min, max) > 0) { sval = min; min = max; max = sval; } *res = alloc_rl(min, max); return true; } return false; } static sval_t handle_sizeof(struct expression *expr) { struct symbol *sym; sval_t ret; ret = sval_blank(expr); sym = expr->cast_type; if (!sym) { sym = evaluate_expression(expr->cast_expression); if (!sym) { __silence_warnings_for_stmt = true; sym = &int_ctype; } #if 0 /* * Expressions of restricted types will possibly get * promoted - check that here. I'm not sure how this works, * the problem is that sizeof(le16) shouldn't be promoted and * the original code did that... Let's if zero this out and * see what breaks. */ if (is_restricted_type(sym)) { if (type_bits(sym) < bits_in_int) sym = &int_ctype; } #endif if (is_fouled_type(sym)) sym = &int_ctype; } examine_symbol_type(sym); ret.type = size_t_ctype; if (type_bits(sym) <= 0) /* sizeof(void) */ { if (get_real_base_type(sym) == &void_ctype) ret.value = 1; else ret.value = 0; } else ret.value = type_bytes(sym); return ret; } static bool handle_strlen(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval) { struct expression *arg, *tmp; sval_t tag; sval_t ret = { .type = &ulong_ctype }; struct range_list *rl; arg = get_argument_from_call_expr(expr->args, 0); if (!arg) return false; if (arg->type == EXPR_STRING) { ret.value = arg->string->length - 1; *res_sval = ret; return true; } if (implied == RL_EXACT) return false; if (get_implied_value(arg, &tag) && (tmp = fake_string_from_mtag(tag.uvalue))) { ret.value = tmp->string->length - 1; *res_sval = ret; return true; } if (implied == RL_HARD || implied == RL_FUZZY) return false; if (get_implied_return(expr, &rl)) { *res = rl; return true; } return false; } static bool handle_builtin_constant_p(struct expression *expr, int implied, int *recurse_cnt, sval_t *res_sval) { struct expression *arg; struct range_list *rl; arg = get_argument_from_call_expr(expr->args, 0); if (get_rl_internal(arg, RL_EXACT, recurse_cnt, &rl)) *res_sval = one; else *res_sval = zero; return true; } static bool handle__builtin_choose_expr(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval) { struct expression *const_expr, *expr1, *expr2; sval_t sval; const_expr = get_argument_from_call_expr(expr->args, 0); expr1 = get_argument_from_call_expr(expr->args, 1); expr2 = get_argument_from_call_expr(expr->args, 2); if (!get_value(const_expr, &sval) || !expr1 || !expr2) return false; if (sval.value) return get_rl_sval(expr1, implied, recurse_cnt, res, res_sval); else return get_rl_sval(expr2, implied, recurse_cnt, res, res_sval); } static bool handle_call_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval) { struct range_list *rl; if (sym_name_is("__builtin_constant_p", expr->fn)) return handle_builtin_constant_p(expr, implied, recurse_cnt, res_sval); if (sym_name_is("__builtin_choose_expr", expr->fn)) return handle__builtin_choose_expr(expr, implied, recurse_cnt, res, res_sval); if (sym_name_is("__builtin_expect", expr->fn) || sym_name_is("__builtin_bswap16", expr->fn) || sym_name_is("__builtin_bswap32", expr->fn) || sym_name_is("__builtin_bswap64", expr->fn)) { struct expression *arg; arg = get_argument_from_call_expr(expr->args, 0); return get_rl_sval(arg, implied, recurse_cnt, res, res_sval); } if (sym_name_is("strlen", expr->fn)) return handle_strlen(expr, implied, recurse_cnt, res, res_sval); if (implied == RL_EXACT || implied == RL_HARD) return false; if (custom_handle_variable) { rl = custom_handle_variable(expr); if (rl) { *res = rl; return true; } } /* Ugh... get_implied_return() sets *rl to NULL on failure */ if (get_implied_return(expr, &rl)) { *res = rl; return true; } rl = db_return_vals(expr); if (rl) { *res = rl; return true; } return false; } static bool handle_cast(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval) { struct range_list *rl; struct symbol *type; sval_t sval = {}; type = get_type(expr); if (get_rl_sval(expr->cast_expression, implied, recurse_cnt, &rl, &sval)) { if (sval.type) *res_sval = sval_cast(type, sval); else *res = cast_rl(type, rl); return true; } if (implied == RL_ABSOLUTE || implied == RL_REAL_ABSOLUTE) { *res = alloc_whole_rl(type); return true; } if (implied == RL_IMPLIED && type && type_bits(type) > 0 && type_bits(type) < 32) { *res = alloc_whole_rl(type); return true; } return false; } static bool get_offset_from_down(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval) { struct expression *index; struct symbol *type = expr->in; struct range_list *rl; struct symbol *field; int offset = 0; sval_t sval = { .type = ssize_t_ctype }; sval_t tmp_sval = {}; /* * FIXME: I don't really know what I'm doing here. I wish that I * could just get rid of the __builtin_offset() function and use: * "&((struct bpf_prog *)NULL)->insns[fprog->len]" instead... * Anyway, I have done the minimum ammount of work to get that * expression to work. * */ if (expr->op != '.' || !expr->down || expr->down->type != EXPR_OFFSETOF || expr->down->op != '[' || !expr->down->index) return false; index = expr->down->index; examine_symbol_type(type); type = get_real_base_type(type); if (!type) return false; field = find_identifier(expr->ident, type->symbol_list, &offset); if (!field) return false; type = get_real_base_type(field); if (!type || type->type != SYM_ARRAY) return false; type = get_real_base_type(type); if (get_implied_value_internal(index, recurse_cnt, &sval)) { res_sval->type = ssize_t_ctype; res_sval->value = offset + sval.value * type_bytes(type); return true; } if (!get_rl_sval(index, implied, recurse_cnt, &rl, &tmp_sval)) return false; /* * I'm not sure why get_rl_sval() would return an sval when * get_implied_value_internal() failed but it does when I * parse drivers/net/ethernet/mellanox/mlx5/core/en/monitor_stats.c * */ if (tmp_sval.type) { res_sval->type = ssize_t_ctype; res_sval->value = offset + sval.value * type_bytes(type); return true; } sval.value = type_bytes(type); rl = rl_binop(rl, '*', alloc_rl(sval, sval)); sval.value = offset; *res = rl_binop(rl, '+', alloc_rl(sval, sval)); return true; } static bool get_offset_from_in(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval) { struct symbol *type = get_real_base_type(expr->in); struct symbol *field; int offset = 0; if (expr->op != '.' || !type || !expr->ident) return false; field = find_identifier(expr->ident, type->symbol_list, &offset); if (!field) return false; res_sval->type = size_t_ctype; res_sval->value = offset; return true; } static bool handle_offsetof_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval) { if (get_offset_from_down(expr, implied, recurse_cnt, res, res_sval)) return true; if (get_offset_from_in(expr, implied, recurse_cnt, res, res_sval)) return true; evaluate_expression(expr); if (expr->type == EXPR_VALUE) { *res_sval = sval_from_val(expr, expr->value); return true; } return false; } static bool get_rl_sval(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *sval_res) { struct range_list *rl = (void *)-1UL; struct symbol *type; sval_t sval = {}; type = get_type(expr); expr = strip_parens(expr); if (!expr) return false; if (++(*recurse_cnt) >= 200) return false; switch(expr->type) { case EXPR_CAST: case EXPR_FORCE_CAST: case EXPR_IMPLIED_CAST: handle_cast(expr, implied, recurse_cnt, &rl, &sval); goto out_cast; } expr = strip_expr(expr); if (!expr) return false; switch (expr->type) { case EXPR_VALUE: sval = sval_from_val(expr, expr->value); break; case EXPR_FVALUE: sval = sval_from_fval(expr, expr->fvalue); break; case EXPR_PREOP: handle_preop_rl(expr, implied, recurse_cnt, &rl, &sval); break; case EXPR_POSTOP: get_rl_sval(expr->unop, implied, recurse_cnt, &rl, &sval); break; case EXPR_BINOP: handle_binop_rl(expr, implied, recurse_cnt, &rl, &sval); break; case EXPR_COMPARE: handle_comparison_rl(expr, implied, recurse_cnt, &rl, &sval); break; case EXPR_LOGICAL: handle_logical_rl(expr, implied, recurse_cnt, &rl, &sval); break; case EXPR_PTRSIZEOF: case EXPR_SIZEOF: sval = handle_sizeof(expr); break; case EXPR_SELECT: case EXPR_CONDITIONAL: handle_conditional_rl(expr, implied, recurse_cnt, &rl, &sval); break; case EXPR_CALL: handle_call_rl(expr, implied, recurse_cnt, &rl, &sval); break; case EXPR_STRING: if (get_mtag_sval(expr, &sval)) break; if (implied == RL_EXACT) break; rl = alloc_rl(valid_ptr_min_sval, valid_ptr_max_sval); break; case EXPR_OFFSETOF: handle_offsetof_rl(expr, implied, recurse_cnt, &rl, &sval); break; case EXPR_ALIGNOF: evaluate_expression(expr); if (expr->type == EXPR_VALUE) sval = sval_from_val(expr, expr->value); break; default: handle_variable(expr, implied, recurse_cnt, &rl, &sval); } out_cast: if (rl == (void *)-1UL) rl = NULL; if (sval.type || (rl && rl_to_sval(rl, &sval))) { *sval_res = sval; return true; } if (implied == RL_EXACT) return false; if (rl) { *res = rl; return true; } if (type && (implied == RL_ABSOLUTE || implied == RL_REAL_ABSOLUTE)) { *res = alloc_whole_rl(type); return true; } return false; } static bool get_rl_internal(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res) { struct range_list *rl = NULL; sval_t sval = {}; if (!get_rl_sval(expr, implied, recurse_cnt, &rl, &sval)) return false; if (sval.type) *res = alloc_rl(sval, sval); else *res = rl; return true; } static bool get_rl_helper(struct expression *expr, int implied, struct range_list **res) { struct range_list *rl = NULL; sval_t sval = {}; int recurse_cnt = 0; if (get_value(expr, &sval)) { *res = alloc_rl(sval, sval); return true; } if (!get_rl_sval(expr, implied, &recurse_cnt, &rl, &sval)) return false; if (sval.type) *res = alloc_rl(sval, sval); else *res = rl; return true; } struct { struct expression *expr; sval_t sval; } cached_results[24]; static int cache_idx; void clear_math_cache(void) { memset(cached_results, 0, sizeof(cached_results)); } void set_fast_math_only(void) { fast_math_only++; } void clear_fast_math_only(void) { fast_math_only--; } /* * Don't cache EXPR_VALUE because values are fast already. * */ static bool get_value_literal(struct expression *expr, sval_t *res_sval) { struct expression *tmp; int recurse_cnt = 0; tmp = strip_expr(expr); if (!tmp || tmp->type != EXPR_VALUE) return false; return get_rl_sval(expr, RL_EXACT, &recurse_cnt, NULL, res_sval); } /* returns 1 if it can get a value literal or else returns 0 */ int get_value(struct expression *expr, sval_t *res_sval) { struct range_list *(*orig_custom_fn)(struct expression *expr); int recurse_cnt = 0; sval_t sval = {}; int i; if (get_value_literal(expr, res_sval)) return 1; /* * This only handles RL_EXACT because other expr statements can be * different at different points. Like the list iterator, for example. */ for (i = 0; i < ARRAY_SIZE(cached_results); i++) { if (expr == cached_results[i].expr) { if (cached_results[i].sval.type) { *res_sval = cached_results[i].sval; return true; } return false; } } orig_custom_fn = custom_handle_variable; custom_handle_variable = NULL; get_rl_sval(expr, RL_EXACT, &recurse_cnt, NULL, &sval); custom_handle_variable = orig_custom_fn; cached_results[cache_idx].expr = expr; cached_results[cache_idx].sval = sval; cache_idx = (cache_idx + 1) % ARRAY_SIZE(cached_results); if (!sval.type) return 0; *res_sval = sval; return 1; } static bool get_implied_value_internal(struct expression *expr, int *recurse_cnt, sval_t *res_sval) { struct range_list *rl; res_sval->type = NULL; if (!get_rl_sval(expr, RL_IMPLIED, recurse_cnt, &rl, res_sval)) return false; if (!res_sval->type && !rl_to_sval(rl, res_sval)) return false; return true; } int get_implied_value(struct expression *expr, sval_t *sval) { struct range_list *rl; if (!get_rl_helper(expr, RL_IMPLIED, &rl) || !rl_to_sval(rl, sval)) return 0; return 1; } int get_implied_value_fast(struct expression *expr, sval_t *sval) { struct range_list *rl; static int recurse; int ret = 0; if (recurse) return 0; recurse = 1; set_fast_math_only(); if (get_rl_helper(expr, RL_IMPLIED, &rl) && rl_to_sval(rl, sval)) ret = 1; clear_fast_math_only(); recurse = 0; return ret; } int get_implied_min(struct expression *expr, sval_t *sval) { struct range_list *rl; if (!get_rl_helper(expr, RL_IMPLIED, &rl) || !rl) return 0; *sval = rl_min(rl); return 1; } int get_implied_max(struct expression *expr, sval_t *sval) { struct range_list *rl; if (!get_rl_helper(expr, RL_IMPLIED, &rl) || !rl) return 0; *sval = rl_max(rl); return 1; } int get_implied_rl(struct expression *expr, struct range_list **rl) { if (!get_rl_helper(expr, RL_IMPLIED, rl) || !*rl) return 0; return 1; } static int get_absolute_rl_internal(struct expression *expr, struct range_list **rl, int *recurse_cnt) { *rl = NULL; get_rl_internal(expr, RL_ABSOLUTE, recurse_cnt, rl); if (!*rl) *rl = alloc_whole_rl(get_type(expr)); return 1; } int get_absolute_rl(struct expression *expr, struct range_list **rl) { *rl = NULL; get_rl_helper(expr, RL_ABSOLUTE, rl); if (!*rl) *rl = alloc_whole_rl(get_type(expr)); return 1; } int get_real_absolute_rl(struct expression *expr, struct range_list **rl) { *rl = NULL; get_rl_helper(expr, RL_REAL_ABSOLUTE, rl); if (!*rl) *rl = alloc_whole_rl(get_type(expr)); return 1; } int custom_get_absolute_rl(struct expression *expr, struct range_list *(*fn)(struct expression *expr), struct range_list **rl) { int ret; *rl = NULL; custom_handle_variable = fn; ret = get_rl_helper(expr, RL_REAL_ABSOLUTE, rl); custom_handle_variable = NULL; return ret; } int get_implied_rl_var_sym(const char *var, struct symbol *sym, struct range_list **rl) { struct smatch_state *state; state = get_state(SMATCH_EXTRA, var, sym); *rl = estate_rl(state); if (*rl) return 1; return 0; } int get_hard_max(struct expression *expr, sval_t *sval) { struct range_list *rl; if (!get_rl_helper(expr, RL_HARD, &rl) || !rl) return 0; *sval = rl_max(rl); return 1; } int get_fuzzy_min(struct expression *expr, sval_t *sval) { struct range_list *rl; sval_t tmp; if (!get_rl_helper(expr, RL_FUZZY, &rl) || !rl) return 0; tmp = rl_min(rl); if (sval_is_negative(tmp) && sval_is_min(tmp)) return 0; *sval = tmp; return 1; } int get_fuzzy_max(struct expression *expr, sval_t *sval) { struct range_list *rl; sval_t max; if (!get_rl_helper(expr, RL_FUZZY, &rl) || !rl) return 0; max = rl_max(rl); if (max.uvalue > INT_MAX - 10000) return 0; *sval = max; return 1; } int get_absolute_min(struct expression *expr, sval_t *sval) { struct range_list *rl; struct symbol *type; type = get_type(expr); if (!type) type = &llong_ctype; // FIXME: this is wrong but places assume get type can't fail. rl = NULL; get_rl_helper(expr, RL_REAL_ABSOLUTE, &rl); if (rl) *sval = rl_min(rl); else *sval = sval_type_min(type); if (sval_cmp(*sval, sval_type_min(type)) < 0) *sval = sval_type_min(type); return 1; } int get_absolute_max(struct expression *expr, sval_t *sval) { struct range_list *rl; struct symbol *type; type = get_type(expr); if (!type) type = &llong_ctype; rl = NULL; get_rl_helper(expr, RL_REAL_ABSOLUTE, &rl); if (rl) *sval = rl_max(rl); else *sval = sval_type_max(type); if (sval_cmp(sval_type_max(type), *sval) < 0) *sval = sval_type_max(type); return 1; } int known_condition_true(struct expression *expr) { sval_t tmp; if (!expr) return 0; if (__inline_fn && get_param_num(expr) >= 0) { if (get_implied_value(expr, &tmp) && tmp.value) return 1; return 0; } if (get_value(expr, &tmp) && tmp.value) return 1; return 0; } int known_condition_false(struct expression *expr) { sval_t tmp; if (!expr) return 0; if (__inline_fn && get_param_num(expr) >= 0) { if (get_implied_value(expr, &tmp) && tmp.value == 0) return 1; return 0; } if (expr_is_zero(expr)) return 1; return 0; } int implied_condition_true(struct expression *expr) { sval_t tmp; if (!expr) return 0; if (known_condition_true(expr)) return 1; if (get_implied_value(expr, &tmp) && tmp.value) return 1; if (expr->type == EXPR_POSTOP) return implied_condition_true(expr->unop); if (expr->type == EXPR_PREOP && expr->op == SPECIAL_DECREMENT) return implied_not_equal(expr->unop, 1); if (expr->type == EXPR_PREOP && expr->op == SPECIAL_INCREMENT) return implied_not_equal(expr->unop, -1); expr = strip_expr(expr); switch (expr->type) { case EXPR_COMPARE: if (do_comparison(expr) == 1) return 1; break; case EXPR_PREOP: if (expr->op == '!') { if (implied_condition_false(expr->unop)) return 1; break; } break; default: if (implied_not_equal(expr, 0) == 1) return 1; break; } return 0; } int implied_condition_false(struct expression *expr) { struct expression *tmp; sval_t sval; if (!expr) return 0; if (known_condition_false(expr)) return 1; switch (expr->type) { case EXPR_COMPARE: if (do_comparison(expr) == 2) return 1; case EXPR_PREOP: if (expr->op == '!') { if (implied_condition_true(expr->unop)) return 1; break; } tmp = strip_expr(expr); if (tmp != expr) return implied_condition_false(tmp); break; default: if (get_implied_value(expr, &sval) && sval.value == 0) return 1; break; } return 0; }