11f5207b7SJohn Levon /* 21f5207b7SJohn Levon * Copyright (C) 2012 Oracle. 31f5207b7SJohn Levon * 41f5207b7SJohn Levon * This program is free software; you can redistribute it and/or 51f5207b7SJohn Levon * modify it under the terms of the GNU General Public License 61f5207b7SJohn Levon * as published by the Free Software Foundation; either version 2 71f5207b7SJohn Levon * of the License, or (at your option) any later version. 81f5207b7SJohn Levon * 91f5207b7SJohn Levon * This program is distributed in the hope that it will be useful, 101f5207b7SJohn Levon * but WITHOUT ANY WARRANTY; without even the implied warranty of 111f5207b7SJohn Levon * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 121f5207b7SJohn Levon * GNU General Public License for more details. 131f5207b7SJohn Levon * 141f5207b7SJohn Levon * You should have received a copy of the GNU General Public License 151f5207b7SJohn Levon * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt 161f5207b7SJohn Levon */ 171f5207b7SJohn Levon 181f5207b7SJohn Levon /* 191f5207b7SJohn Levon * The point here is to store that a buffer has x bytes even if we don't know 201f5207b7SJohn Levon * the value of x. 211f5207b7SJohn Levon * 221f5207b7SJohn Levon */ 231f5207b7SJohn Levon 241f5207b7SJohn Levon #include "smatch.h" 251f5207b7SJohn Levon #include "smatch_extra.h" 261f5207b7SJohn Levon #include "smatch_slist.h" 271f5207b7SJohn Levon 281f5207b7SJohn Levon static int size_id; 291f5207b7SJohn Levon static int link_id; 301f5207b7SJohn Levon 311f5207b7SJohn Levon /* 32*efe51d0cSJohn Levon * There is a bunch of code which does this: 331f5207b7SJohn Levon * 341f5207b7SJohn Levon * if (size) 351f5207b7SJohn Levon * foo = malloc(size); 361f5207b7SJohn Levon * 37*efe51d0cSJohn Levon * So if "size" is non-zero then the size of "foo" is size. But really it's 38*efe51d0cSJohn Levon * also true if size is zero. It's just better to assume to not trample over 39*efe51d0cSJohn Levon * the data that we have by merging &undefined states. 401f5207b7SJohn Levon * 411f5207b7SJohn Levon */ 421f5207b7SJohn Levon static struct smatch_state *unmatched_state(struct sm_state *sm) 431f5207b7SJohn Levon { 441f5207b7SJohn Levon return sm->state; 451f5207b7SJohn Levon } 461f5207b7SJohn Levon 471f5207b7SJohn Levon static struct smatch_state *merge_links(struct smatch_state *s1, struct smatch_state *s2) 481f5207b7SJohn Levon { 491f5207b7SJohn Levon struct expression *expr1, *expr2; 501f5207b7SJohn Levon 511f5207b7SJohn Levon expr1 = s1->data; 521f5207b7SJohn Levon expr2 = s2->data; 531f5207b7SJohn Levon 541f5207b7SJohn Levon if (expr1 && expr2 && expr_equiv(expr1, expr2)) 551f5207b7SJohn Levon return s1; 561f5207b7SJohn Levon return &merged; 571f5207b7SJohn Levon } 581f5207b7SJohn Levon 591f5207b7SJohn Levon static void match_link_modify(struct sm_state *sm, struct expression *mod_expr) 601f5207b7SJohn Levon { 611f5207b7SJohn Levon struct expression *expr; 621f5207b7SJohn Levon struct sm_state *tmp; 631f5207b7SJohn Levon 641f5207b7SJohn Levon expr = sm->state->data; 651f5207b7SJohn Levon if (expr) { 661f5207b7SJohn Levon set_state_expr(size_id, expr, &undefined); 671f5207b7SJohn Levon set_state(link_id, sm->name, sm->sym, &undefined); 681f5207b7SJohn Levon return; 691f5207b7SJohn Levon } 701f5207b7SJohn Levon 711f5207b7SJohn Levon FOR_EACH_PTR(sm->possible, tmp) { 721f5207b7SJohn Levon expr = tmp->state->data; 731f5207b7SJohn Levon if (expr) 741f5207b7SJohn Levon set_state_expr(size_id, expr, &undefined); 751f5207b7SJohn Levon } END_FOR_EACH_PTR(tmp); 761f5207b7SJohn Levon set_state(link_id, sm->name, sm->sym, &undefined); 771f5207b7SJohn Levon } 781f5207b7SJohn Levon 79*efe51d0cSJohn Levon static const char *limit_map[] = { 80*efe51d0cSJohn Levon "byte_count", 81*efe51d0cSJohn Levon "elem_count", 82*efe51d0cSJohn Levon "elem_last", 83*efe51d0cSJohn Levon "used_count", 84*efe51d0cSJohn Levon "used_last", 85*efe51d0cSJohn Levon }; 86*efe51d0cSJohn Levon 87*efe51d0cSJohn Levon int state_to_limit(struct smatch_state *state) 88*efe51d0cSJohn Levon { 89*efe51d0cSJohn Levon int i; 90*efe51d0cSJohn Levon 91*efe51d0cSJohn Levon if (!state || !state->data) 92*efe51d0cSJohn Levon return -1; 93*efe51d0cSJohn Levon 94*efe51d0cSJohn Levon for (i = 0; i < ARRAY_SIZE(limit_map); i++) { 95*efe51d0cSJohn Levon if (strncmp(state->name, limit_map[i], strlen(limit_map[i])) == 0) 96*efe51d0cSJohn Levon return i + BYTE_COUNT; 97*efe51d0cSJohn Levon } 98*efe51d0cSJohn Levon 99*efe51d0cSJohn Levon return -1; 100*efe51d0cSJohn Levon } 101*efe51d0cSJohn Levon 102*efe51d0cSJohn Levon const char *limit_type_str(unsigned int limit_type) 103*efe51d0cSJohn Levon { 104*efe51d0cSJohn Levon if (limit_type - BYTE_COUNT >= ARRAY_SIZE(limit_map)) { 105*efe51d0cSJohn Levon sm_msg("internal: wrong size type %u", limit_type); 106*efe51d0cSJohn Levon return "unknown"; 107*efe51d0cSJohn Levon } 108*efe51d0cSJohn Levon 109*efe51d0cSJohn Levon return limit_map[limit_type - BYTE_COUNT]; 110*efe51d0cSJohn Levon } 111*efe51d0cSJohn Levon 112*efe51d0cSJohn Levon static struct smatch_state *alloc_compare_size(int limit_type, struct expression *expr) 1131f5207b7SJohn Levon { 1141f5207b7SJohn Levon struct smatch_state *state; 1151f5207b7SJohn Levon char *name; 116*efe51d0cSJohn Levon char buf[256]; 1171f5207b7SJohn Levon 1181f5207b7SJohn Levon state = __alloc_smatch_state(0); 1191f5207b7SJohn Levon expr = strip_expr(expr); 1201f5207b7SJohn Levon name = expr_to_str(expr); 121*efe51d0cSJohn Levon snprintf(buf, sizeof(buf), "%s %s", limit_type_str(limit_type), name); 122*efe51d0cSJohn Levon state->name = alloc_sname(buf); 1231f5207b7SJohn Levon free_string(name); 1241f5207b7SJohn Levon state->data = expr; 1251f5207b7SJohn Levon return state; 1261f5207b7SJohn Levon } 1271f5207b7SJohn Levon 1281f5207b7SJohn Levon static int bytes_per_element(struct expression *expr) 1291f5207b7SJohn Levon { 1301f5207b7SJohn Levon struct symbol *type; 1311f5207b7SJohn Levon 1321f5207b7SJohn Levon type = get_type(expr); 1331f5207b7SJohn Levon if (!type) 1341f5207b7SJohn Levon return 0; 1351f5207b7SJohn Levon 1361f5207b7SJohn Levon if (type->type != SYM_PTR && type->type != SYM_ARRAY) 1371f5207b7SJohn Levon return 0; 1381f5207b7SJohn Levon 1391f5207b7SJohn Levon type = get_base_type(type); 1401f5207b7SJohn Levon return type_bytes(type); 1411f5207b7SJohn Levon } 1421f5207b7SJohn Levon 143*efe51d0cSJohn Levon static void db_save_type_links(struct expression *array, int type_limit, struct expression *size) 1441f5207b7SJohn Levon { 1451f5207b7SJohn Levon const char *array_name; 1461f5207b7SJohn Levon 1471f5207b7SJohn Levon array_name = get_data_info_name(array); 1481f5207b7SJohn Levon if (!array_name) 1491f5207b7SJohn Levon array_name = ""; 150*efe51d0cSJohn Levon sql_insert_data_info(size, type_limit, array_name); 1511f5207b7SJohn Levon } 1521f5207b7SJohn Levon 1531f5207b7SJohn Levon static void match_alloc_helper(struct expression *pointer, struct expression *size) 1541f5207b7SJohn Levon { 1551f5207b7SJohn Levon struct expression *tmp; 1561f5207b7SJohn Levon struct sm_state *sm; 157*efe51d0cSJohn Levon int limit_type = ELEM_COUNT; 1581f5207b7SJohn Levon sval_t sval; 1591f5207b7SJohn Levon int cnt = 0; 1601f5207b7SJohn Levon 1611f5207b7SJohn Levon pointer = strip_expr(pointer); 1621f5207b7SJohn Levon size = strip_expr(size); 1631f5207b7SJohn Levon if (!size || !pointer) 1641f5207b7SJohn Levon return; 1651f5207b7SJohn Levon 1661f5207b7SJohn Levon while ((tmp = get_assigned_expr(size))) { 1671f5207b7SJohn Levon size = strip_expr(tmp); 1681f5207b7SJohn Levon if (cnt++ > 5) 1691f5207b7SJohn Levon break; 1701f5207b7SJohn Levon } 1711f5207b7SJohn Levon 1721f5207b7SJohn Levon if (size->type == EXPR_BINOP && size->op == '*') { 1731f5207b7SJohn Levon struct expression *mult_left, *mult_right; 1741f5207b7SJohn Levon 1751f5207b7SJohn Levon mult_left = strip_expr(size->left); 1761f5207b7SJohn Levon mult_right = strip_expr(size->right); 1771f5207b7SJohn Levon 1781f5207b7SJohn Levon if (get_implied_value(mult_left, &sval) && 1791f5207b7SJohn Levon sval.value == bytes_per_element(pointer)) 1801f5207b7SJohn Levon size = mult_right; 1811f5207b7SJohn Levon else if (get_implied_value(mult_right, &sval) && 1821f5207b7SJohn Levon sval.value == bytes_per_element(pointer)) 1831f5207b7SJohn Levon size = mult_left; 1841f5207b7SJohn Levon else 1851f5207b7SJohn Levon return; 1861f5207b7SJohn Levon } 1871f5207b7SJohn Levon 1881f5207b7SJohn Levon /* Only save links to variables, not fixed sizes */ 1891f5207b7SJohn Levon if (get_value(size, &sval)) 1901f5207b7SJohn Levon return; 1911f5207b7SJohn Levon 192*efe51d0cSJohn Levon if (size->type == EXPR_BINOP && size->op == '+' && 193*efe51d0cSJohn Levon get_value(size->right, &sval) && sval.value == 1) { 194*efe51d0cSJohn Levon size = size->left; 195*efe51d0cSJohn Levon limit_type = ELEM_LAST; 196*efe51d0cSJohn Levon } 197*efe51d0cSJohn Levon 198*efe51d0cSJohn Levon db_save_type_links(pointer, limit_type, size); 199*efe51d0cSJohn Levon sm = set_state_expr(size_id, pointer, alloc_compare_size(limit_type, size)); 2001f5207b7SJohn Levon if (!sm) 2011f5207b7SJohn Levon return; 202*efe51d0cSJohn Levon set_state_expr(link_id, size, alloc_state_expr(pointer)); 2031f5207b7SJohn Levon } 2041f5207b7SJohn Levon 2051f5207b7SJohn Levon static void match_alloc(const char *fn, struct expression *expr, void *_size_arg) 2061f5207b7SJohn Levon { 2071f5207b7SJohn Levon int size_arg = PTR_INT(_size_arg); 2081f5207b7SJohn Levon struct expression *pointer, *call, *arg; 2091f5207b7SJohn Levon 2101f5207b7SJohn Levon pointer = strip_expr(expr->left); 2111f5207b7SJohn Levon call = strip_expr(expr->right); 2121f5207b7SJohn Levon arg = get_argument_from_call_expr(call->args, size_arg); 2131f5207b7SJohn Levon match_alloc_helper(pointer, arg); 2141f5207b7SJohn Levon } 2151f5207b7SJohn Levon 2161f5207b7SJohn Levon static void match_calloc(const char *fn, struct expression *expr, void *_start_arg) 2171f5207b7SJohn Levon { 2181f5207b7SJohn Levon int start_arg = PTR_INT(_start_arg); 2191f5207b7SJohn Levon struct expression *pointer, *call, *arg; 2201f5207b7SJohn Levon struct sm_state *tmp; 221*efe51d0cSJohn Levon int limit_type = ELEM_COUNT; 2221f5207b7SJohn Levon sval_t sval; 2231f5207b7SJohn Levon 2241f5207b7SJohn Levon pointer = strip_expr(expr->left); 2251f5207b7SJohn Levon call = strip_expr(expr->right); 2261f5207b7SJohn Levon arg = get_argument_from_call_expr(call->args, start_arg); 2271f5207b7SJohn Levon if (get_implied_value(arg, &sval) && 2281f5207b7SJohn Levon sval.value == bytes_per_element(pointer)) 2291f5207b7SJohn Levon arg = get_argument_from_call_expr(call->args, start_arg + 1); 2301f5207b7SJohn Levon 231*efe51d0cSJohn Levon if (arg->type == EXPR_BINOP && arg->op == '+' && 232*efe51d0cSJohn Levon get_value(arg->right, &sval) && sval.value == 1) { 233*efe51d0cSJohn Levon arg = arg->left; 234*efe51d0cSJohn Levon limit_type = ELEM_LAST; 235*efe51d0cSJohn Levon } 236*efe51d0cSJohn Levon 237*efe51d0cSJohn Levon db_save_type_links(pointer, limit_type, arg); 238*efe51d0cSJohn Levon tmp = set_state_expr(size_id, pointer, alloc_compare_size(limit_type, arg)); 2391f5207b7SJohn Levon if (!tmp) 2401f5207b7SJohn Levon return; 241*efe51d0cSJohn Levon set_state_expr(link_id, arg, alloc_state_expr(pointer)); 2421f5207b7SJohn Levon } 2431f5207b7SJohn Levon 244*efe51d0cSJohn Levon struct expression *get_size_variable(struct expression *buf, int *limit_type) 2451f5207b7SJohn Levon { 2461f5207b7SJohn Levon struct smatch_state *state; 2471f5207b7SJohn Levon 2481f5207b7SJohn Levon state = get_state_expr(size_id, buf); 249*efe51d0cSJohn Levon if (!state) 250*efe51d0cSJohn Levon return NULL; 251*efe51d0cSJohn Levon *limit_type = state_to_limit(state); 252*efe51d0cSJohn Levon return state->data; 2531f5207b7SJohn Levon } 2541f5207b7SJohn Levon 2551f5207b7SJohn Levon struct expression *get_array_variable(struct expression *size) 2561f5207b7SJohn Levon { 2571f5207b7SJohn Levon struct smatch_state *state; 2581f5207b7SJohn Levon 2591f5207b7SJohn Levon state = get_state_expr(link_id, size); 2601f5207b7SJohn Levon if (state) 2611f5207b7SJohn Levon return state->data; 2621f5207b7SJohn Levon return NULL; 2631f5207b7SJohn Levon } 2641f5207b7SJohn Levon 2651f5207b7SJohn Levon static void array_check(struct expression *expr) 2661f5207b7SJohn Levon { 2671f5207b7SJohn Levon struct expression *array; 2681f5207b7SJohn Levon struct expression *size; 2691f5207b7SJohn Levon struct expression *offset; 2701f5207b7SJohn Levon char *array_str, *offset_str; 271*efe51d0cSJohn Levon int limit_type; 2721f5207b7SJohn Levon 2731f5207b7SJohn Levon expr = strip_expr(expr); 2741f5207b7SJohn Levon if (!is_array(expr)) 2751f5207b7SJohn Levon return; 2761f5207b7SJohn Levon 2771f5207b7SJohn Levon array = get_array_base(expr); 278*efe51d0cSJohn Levon size = get_size_variable(array, &limit_type); 2791f5207b7SJohn Levon if (!size) 2801f5207b7SJohn Levon return; 281*efe51d0cSJohn Levon if (limit_type != ELEM_COUNT) 282*efe51d0cSJohn Levon return; 2831f5207b7SJohn Levon offset = get_array_offset(expr); 2841f5207b7SJohn Levon if (!possible_comparison(size, SPECIAL_EQUAL, offset)) 2851f5207b7SJohn Levon return; 2861f5207b7SJohn Levon 2871f5207b7SJohn Levon array_str = expr_to_str(array); 2881f5207b7SJohn Levon offset_str = expr_to_str(offset); 2891f5207b7SJohn Levon sm_warning("potentially one past the end of array '%s[%s]'", array_str, offset_str); 2901f5207b7SJohn Levon free_string(array_str); 2911f5207b7SJohn Levon free_string(offset_str); 2921f5207b7SJohn Levon } 2931f5207b7SJohn Levon 2941f5207b7SJohn Levon struct db_info { 2951f5207b7SJohn Levon char *name; 2961f5207b7SJohn Levon int ret; 2971f5207b7SJohn Levon }; 2981f5207b7SJohn Levon 2991f5207b7SJohn Levon static int db_limitter_callback(void *_info, int argc, char **argv, char **azColName) 3001f5207b7SJohn Levon { 3011f5207b7SJohn Levon struct db_info *info = _info; 3021f5207b7SJohn Levon 3031f5207b7SJohn Levon /* 3041f5207b7SJohn Levon * If possible the limitters are tied to the struct they limit. If we 3051f5207b7SJohn Levon * aren't sure which struct they limit then we use them as limitters for 3061f5207b7SJohn Levon * everything. 3071f5207b7SJohn Levon */ 3081f5207b7SJohn Levon if (!info->name || argv[0][0] == '\0' || strcmp(info->name, argv[0]) == 0) 3091f5207b7SJohn Levon info->ret = 1; 3101f5207b7SJohn Levon return 0; 3111f5207b7SJohn Levon } 3121f5207b7SJohn Levon 3131f5207b7SJohn Levon static char *vsl_to_data_info_name(const char *name, struct var_sym_list *vsl) 3141f5207b7SJohn Levon { 3151f5207b7SJohn Levon struct var_sym *vs; 3161f5207b7SJohn Levon struct symbol *type; 3171f5207b7SJohn Levon static char buf[80]; 3181f5207b7SJohn Levon const char *p; 3191f5207b7SJohn Levon 3201f5207b7SJohn Levon if (ptr_list_size((struct ptr_list *)vsl) != 1) 3211f5207b7SJohn Levon return NULL; 3221f5207b7SJohn Levon vs = first_ptr_list((struct ptr_list *)vsl); 3231f5207b7SJohn Levon 3241f5207b7SJohn Levon type = get_real_base_type(vs->sym); 3251f5207b7SJohn Levon if (!type || type->type != SYM_PTR) 3261f5207b7SJohn Levon goto top_level_name; 3271f5207b7SJohn Levon type = get_real_base_type(type); 3281f5207b7SJohn Levon if (!type || type->type != SYM_STRUCT) 3291f5207b7SJohn Levon goto top_level_name; 3301f5207b7SJohn Levon if (!type->ident) 3311f5207b7SJohn Levon goto top_level_name; 3321f5207b7SJohn Levon 3331f5207b7SJohn Levon p = name; 3341f5207b7SJohn Levon while ((name = strstr(p, "->"))) 3351f5207b7SJohn Levon p = name + 2; 3361f5207b7SJohn Levon 3371f5207b7SJohn Levon snprintf(buf, sizeof(buf),"(struct %s)->%s", type->ident->name, p); 3381f5207b7SJohn Levon return alloc_sname(buf); 3391f5207b7SJohn Levon 3401f5207b7SJohn Levon top_level_name: 3411f5207b7SJohn Levon if (!(vs->sym->ctype.modifiers & MOD_TOPLEVEL)) 3421f5207b7SJohn Levon return NULL; 3431f5207b7SJohn Levon if (vs->sym->ctype.modifiers & MOD_STATIC) 3441f5207b7SJohn Levon snprintf(buf, sizeof(buf),"static %s", name); 3451f5207b7SJohn Levon else 3461f5207b7SJohn Levon snprintf(buf, sizeof(buf),"global %s", name); 3471f5207b7SJohn Levon return alloc_sname(buf); 3481f5207b7SJohn Levon } 3491f5207b7SJohn Levon 3501f5207b7SJohn Levon int db_var_is_array_limit(struct expression *array, const char *name, struct var_sym_list *vsl) 3511f5207b7SJohn Levon { 3521f5207b7SJohn Levon char *size_name; 3531f5207b7SJohn Levon char *array_name = get_data_info_name(array); 3541f5207b7SJohn Levon struct db_info db_info = {.name = array_name,}; 3551f5207b7SJohn Levon 3561f5207b7SJohn Levon size_name = vsl_to_data_info_name(name, vsl); 3571f5207b7SJohn Levon if (!size_name) 3581f5207b7SJohn Levon return 0; 3591f5207b7SJohn Levon 3601f5207b7SJohn Levon run_sql(db_limitter_callback, &db_info, 3611f5207b7SJohn Levon "select value from data_info where type = %d and data = '%s';", 3621f5207b7SJohn Levon ARRAY_LEN, size_name); 3631f5207b7SJohn Levon 3641f5207b7SJohn Levon return db_info.ret; 3651f5207b7SJohn Levon } 3661f5207b7SJohn Levon 367*efe51d0cSJohn Levon int buf_comparison_index_ok(struct expression *expr) 3681f5207b7SJohn Levon { 3691f5207b7SJohn Levon struct expression *array; 3701f5207b7SJohn Levon struct expression *size; 3711f5207b7SJohn Levon struct expression *offset; 372*efe51d0cSJohn Levon int limit_type; 3731f5207b7SJohn Levon int comparison; 3741f5207b7SJohn Levon 3751f5207b7SJohn Levon array = get_array_base(expr); 376*efe51d0cSJohn Levon size = get_size_variable(array, &limit_type); 3771f5207b7SJohn Levon if (!size) 3781f5207b7SJohn Levon return 0; 3791f5207b7SJohn Levon offset = get_array_offset(expr); 380*efe51d0cSJohn Levon comparison = get_comparison(offset, size); 381*efe51d0cSJohn Levon if (!comparison) 382*efe51d0cSJohn Levon return 0; 383*efe51d0cSJohn Levon 384*efe51d0cSJohn Levon if ((limit_type == ELEM_COUNT || limit_type == ELEM_LAST) && 385*efe51d0cSJohn Levon (comparison == '<' || comparison == SPECIAL_UNSIGNED_LT)) 386*efe51d0cSJohn Levon return 1; 387*efe51d0cSJohn Levon if (limit_type == ELEM_LAST && 388*efe51d0cSJohn Levon (comparison == SPECIAL_LTE || 389*efe51d0cSJohn Levon comparison == SPECIAL_UNSIGNED_LTE || 390*efe51d0cSJohn Levon comparison == SPECIAL_EQUAL)) 3911f5207b7SJohn Levon return 1; 3921f5207b7SJohn Levon 3931f5207b7SJohn Levon return 0; 3941f5207b7SJohn Levon } 3951f5207b7SJohn Levon 3961f5207b7SJohn Levon static int known_access_ok_numbers(struct expression *expr) 3971f5207b7SJohn Levon { 3981f5207b7SJohn Levon struct expression *array; 3991f5207b7SJohn Levon struct expression *offset; 4001f5207b7SJohn Levon sval_t max; 4011f5207b7SJohn Levon int size; 4021f5207b7SJohn Levon 4031f5207b7SJohn Levon array = get_array_base(expr); 4041f5207b7SJohn Levon offset = get_array_offset(expr); 4051f5207b7SJohn Levon 4061f5207b7SJohn Levon size = get_array_size(array); 4071f5207b7SJohn Levon if (size <= 0) 4081f5207b7SJohn Levon return 0; 4091f5207b7SJohn Levon 4101f5207b7SJohn Levon get_absolute_max(offset, &max); 4111f5207b7SJohn Levon if (max.uvalue < size) 4121f5207b7SJohn Levon return 1; 4131f5207b7SJohn Levon return 0; 4141f5207b7SJohn Levon } 4151f5207b7SJohn Levon 4161f5207b7SJohn Levon static void array_check_data_info(struct expression *expr) 4171f5207b7SJohn Levon { 4181f5207b7SJohn Levon struct expression *array; 4191f5207b7SJohn Levon struct expression *offset; 4201f5207b7SJohn Levon struct state_list *slist; 4211f5207b7SJohn Levon struct sm_state *sm; 4221f5207b7SJohn Levon struct compare_data *comp; 4231f5207b7SJohn Levon char *offset_name; 4241f5207b7SJohn Levon const char *equal_name = NULL; 4251f5207b7SJohn Levon 4261f5207b7SJohn Levon expr = strip_expr(expr); 4271f5207b7SJohn Levon if (!is_array(expr)) 4281f5207b7SJohn Levon return; 4291f5207b7SJohn Levon 4301f5207b7SJohn Levon if (known_access_ok_numbers(expr)) 4311f5207b7SJohn Levon return; 432*efe51d0cSJohn Levon if (buf_comparison_index_ok(expr)) 4331f5207b7SJohn Levon return; 4341f5207b7SJohn Levon 4351f5207b7SJohn Levon array = get_array_base(expr); 4361f5207b7SJohn Levon offset = get_array_offset(expr); 4371f5207b7SJohn Levon offset_name = expr_to_var(offset); 4381f5207b7SJohn Levon if (!offset_name) 4391f5207b7SJohn Levon return; 4401f5207b7SJohn Levon slist = get_all_possible_equal_comparisons(offset); 4411f5207b7SJohn Levon if (!slist) 4421f5207b7SJohn Levon goto free; 4431f5207b7SJohn Levon 4441f5207b7SJohn Levon FOR_EACH_PTR(slist, sm) { 4451f5207b7SJohn Levon comp = sm->state->data; 4461f5207b7SJohn Levon if (strcmp(comp->left_var, offset_name) == 0) { 4471f5207b7SJohn Levon if (db_var_is_array_limit(array, comp->right_var, comp->right_vsl)) { 4481f5207b7SJohn Levon equal_name = comp->right_var; 4491f5207b7SJohn Levon break; 4501f5207b7SJohn Levon } 4511f5207b7SJohn Levon } else if (strcmp(comp->right_var, offset_name) == 0) { 4521f5207b7SJohn Levon if (db_var_is_array_limit(array, comp->left_var, comp->left_vsl)) { 4531f5207b7SJohn Levon equal_name = comp->left_var; 4541f5207b7SJohn Levon break; 4551f5207b7SJohn Levon } 4561f5207b7SJohn Levon } 4571f5207b7SJohn Levon } END_FOR_EACH_PTR(sm); 4581f5207b7SJohn Levon 4591f5207b7SJohn Levon if (equal_name) { 4601f5207b7SJohn Levon char *array_name = expr_to_str(array); 4611f5207b7SJohn Levon 4621f5207b7SJohn Levon sm_warning("potential off by one '%s[]' limit '%s'", array_name, equal_name); 4631f5207b7SJohn Levon free_string(array_name); 4641f5207b7SJohn Levon } 4651f5207b7SJohn Levon 4661f5207b7SJohn Levon free: 4671f5207b7SJohn Levon free_slist(&slist); 4681f5207b7SJohn Levon free_string(offset_name); 4691f5207b7SJohn Levon } 4701f5207b7SJohn Levon 4711f5207b7SJohn Levon static void add_allocation_function(const char *func, void *call_back, int param) 4721f5207b7SJohn Levon { 4731f5207b7SJohn Levon add_function_assign_hook(func, call_back, INT_PTR(param)); 4741f5207b7SJohn Levon } 4751f5207b7SJohn Levon 476*efe51d0cSJohn Levon static int is_sizeof(struct expression *expr) 4771f5207b7SJohn Levon { 478*efe51d0cSJohn Levon const char *name; 479*efe51d0cSJohn Levon 480*efe51d0cSJohn Levon if (expr->type == EXPR_SIZEOF) 481*efe51d0cSJohn Levon return 1; 482*efe51d0cSJohn Levon name = pos_ident(expr->pos); 483*efe51d0cSJohn Levon if (name && strcmp(name, "sizeof") == 0) 484*efe51d0cSJohn Levon return 1; 485*efe51d0cSJohn Levon return 0; 486*efe51d0cSJohn Levon } 487*efe51d0cSJohn Levon 488*efe51d0cSJohn Levon static int match_size_binop(struct expression *size, struct expression *expr, int *limit_type) 489*efe51d0cSJohn Levon { 490*efe51d0cSJohn Levon int orig_type = *limit_type; 491*efe51d0cSJohn Levon struct expression *left; 492*efe51d0cSJohn Levon sval_t sval; 493*efe51d0cSJohn Levon 494*efe51d0cSJohn Levon left = expr->left; 495*efe51d0cSJohn Levon if (!expr_equiv(size, left)) 496*efe51d0cSJohn Levon return 0; 497*efe51d0cSJohn Levon 498*efe51d0cSJohn Levon if (expr->op == '-' && 499*efe51d0cSJohn Levon get_value(expr->right, &sval) && 500*efe51d0cSJohn Levon sval.value == 1 && 501*efe51d0cSJohn Levon orig_type == ELEM_COUNT) { 502*efe51d0cSJohn Levon *limit_type = ELEM_LAST; 503*efe51d0cSJohn Levon return 1; 504*efe51d0cSJohn Levon } 505*efe51d0cSJohn Levon 506*efe51d0cSJohn Levon if (expr->op == '+' && 507*efe51d0cSJohn Levon get_value(expr->right, &sval) && 508*efe51d0cSJohn Levon sval.value == 1 && 509*efe51d0cSJohn Levon orig_type == ELEM_LAST) { 510*efe51d0cSJohn Levon *limit_type = ELEM_COUNT; 511*efe51d0cSJohn Levon return 1; 512*efe51d0cSJohn Levon } 513*efe51d0cSJohn Levon 514*efe51d0cSJohn Levon if (expr->op == '*' && 515*efe51d0cSJohn Levon is_sizeof(expr->right) && 516*efe51d0cSJohn Levon orig_type == ELEM_COUNT) { 517*efe51d0cSJohn Levon *limit_type = BYTE_COUNT; 518*efe51d0cSJohn Levon return 1; 519*efe51d0cSJohn Levon } 520*efe51d0cSJohn Levon 521*efe51d0cSJohn Levon if (expr->op == '/' && 522*efe51d0cSJohn Levon is_sizeof(expr->right) && 523*efe51d0cSJohn Levon orig_type == BYTE_COUNT) { 524*efe51d0cSJohn Levon *limit_type = ELEM_COUNT; 525*efe51d0cSJohn Levon return 1; 526*efe51d0cSJohn Levon } 527*efe51d0cSJohn Levon 528*efe51d0cSJohn Levon return 0; 529*efe51d0cSJohn Levon } 530*efe51d0cSJohn Levon 531*efe51d0cSJohn Levon static char *buf_size_param_comparison(struct expression *array, struct expression_list *args, int *limit_type) 532*efe51d0cSJohn Levon { 533*efe51d0cSJohn Levon struct expression *tmp, *arg; 5341f5207b7SJohn Levon struct expression *size; 5351f5207b7SJohn Levon static char buf[32]; 5361f5207b7SJohn Levon int i; 5371f5207b7SJohn Levon 538*efe51d0cSJohn Levon size = get_size_variable(array, limit_type); 5391f5207b7SJohn Levon if (!size) 5401f5207b7SJohn Levon return NULL; 5411f5207b7SJohn Levon 542*efe51d0cSJohn Levon if (*limit_type == USED_LAST) 543*efe51d0cSJohn Levon *limit_type = ELEM_LAST; 544*efe51d0cSJohn Levon if (*limit_type == USED_COUNT) 545*efe51d0cSJohn Levon *limit_type = ELEM_COUNT; 546*efe51d0cSJohn Levon 5471f5207b7SJohn Levon i = -1; 548*efe51d0cSJohn Levon FOR_EACH_PTR(args, tmp) { 5491f5207b7SJohn Levon i++; 550*efe51d0cSJohn Levon arg = tmp; 5511f5207b7SJohn Levon if (arg == array) 5521f5207b7SJohn Levon continue; 553*efe51d0cSJohn Levon if (expr_equiv(arg, size) || 554*efe51d0cSJohn Levon (arg->type == EXPR_BINOP && 555*efe51d0cSJohn Levon match_size_binop(size, arg, limit_type))) { 556*efe51d0cSJohn Levon snprintf(buf, sizeof(buf), "==$%d", i); 557*efe51d0cSJohn Levon return buf; 558*efe51d0cSJohn Levon } 559*efe51d0cSJohn Levon } END_FOR_EACH_PTR(tmp); 5601f5207b7SJohn Levon 5611f5207b7SJohn Levon return NULL; 5621f5207b7SJohn Levon } 5631f5207b7SJohn Levon 5641f5207b7SJohn Levon static void match_call(struct expression *call) 5651f5207b7SJohn Levon { 5661f5207b7SJohn Levon struct expression *arg; 5671f5207b7SJohn Levon char *compare; 5681f5207b7SJohn Levon int param; 569*efe51d0cSJohn Levon char buf[5]; 570*efe51d0cSJohn Levon int limit_type; 5711f5207b7SJohn Levon 5721f5207b7SJohn Levon param = -1; 5731f5207b7SJohn Levon FOR_EACH_PTR(call->args, arg) { 5741f5207b7SJohn Levon param++; 5751f5207b7SJohn Levon if (!is_pointer(arg)) 5761f5207b7SJohn Levon continue; 577*efe51d0cSJohn Levon compare = buf_size_param_comparison(arg, call->args, &limit_type); 5781f5207b7SJohn Levon if (!compare) 5791f5207b7SJohn Levon continue; 580*efe51d0cSJohn Levon snprintf(buf, sizeof(buf), "%d", limit_type); 581*efe51d0cSJohn Levon sql_insert_caller_info(call, limit_type, param, compare, buf); 5821f5207b7SJohn Levon } END_FOR_EACH_PTR(arg); 5831f5207b7SJohn Levon } 5841f5207b7SJohn Levon 5851f5207b7SJohn Levon static int get_param(int param, char **name, struct symbol **sym) 5861f5207b7SJohn Levon { 5871f5207b7SJohn Levon struct symbol *arg; 5881f5207b7SJohn Levon int i; 5891f5207b7SJohn Levon 5901f5207b7SJohn Levon i = 0; 5911f5207b7SJohn Levon FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) { 5921f5207b7SJohn Levon /* 5931f5207b7SJohn Levon * this is a temporary hack to work around a bug (I think in sparse?) 5941f5207b7SJohn Levon * 2.6.37-rc1:fs/reiserfs/journal.o 5951f5207b7SJohn Levon * If there is a function definition without parameter name found 5961f5207b7SJohn Levon * after a function implementation then it causes a crash. 5971f5207b7SJohn Levon * int foo() {} 5981f5207b7SJohn Levon * int bar(char *); 5991f5207b7SJohn Levon */ 6001f5207b7SJohn Levon if (arg->ident->name < (char *)100) 6011f5207b7SJohn Levon continue; 6021f5207b7SJohn Levon if (i == param) { 6031f5207b7SJohn Levon *name = arg->ident->name; 6041f5207b7SJohn Levon *sym = arg; 6051f5207b7SJohn Levon return TRUE; 6061f5207b7SJohn Levon } 6071f5207b7SJohn Levon i++; 6081f5207b7SJohn Levon } END_FOR_EACH_PTR(arg); 6091f5207b7SJohn Levon 6101f5207b7SJohn Levon return FALSE; 6111f5207b7SJohn Levon } 6121f5207b7SJohn Levon 6131f5207b7SJohn Levon static void set_param_compare(const char *array_name, struct symbol *array_sym, char *key, char *value) 6141f5207b7SJohn Levon { 6151f5207b7SJohn Levon struct expression *array_expr; 6161f5207b7SJohn Levon struct expression *size_expr; 6171f5207b7SJohn Levon struct symbol *size_sym; 6181f5207b7SJohn Levon char *size_name; 6191f5207b7SJohn Levon long param; 6201f5207b7SJohn Levon struct sm_state *tmp; 621*efe51d0cSJohn Levon int limit_type; 6221f5207b7SJohn Levon 623*efe51d0cSJohn Levon if (strncmp(key, "==$", 3) != 0) 6241f5207b7SJohn Levon return; 625*efe51d0cSJohn Levon param = strtol(key + 3, NULL, 10); 6261f5207b7SJohn Levon if (!get_param(param, &size_name, &size_sym)) 6271f5207b7SJohn Levon return; 6281f5207b7SJohn Levon array_expr = symbol_expression(array_sym); 6291f5207b7SJohn Levon size_expr = symbol_expression(size_sym); 630*efe51d0cSJohn Levon limit_type = strtol(value, NULL, 10); 6311f5207b7SJohn Levon 632*efe51d0cSJohn Levon tmp = set_state_expr(size_id, array_expr, alloc_compare_size(limit_type, size_expr)); 6331f5207b7SJohn Levon if (!tmp) 6341f5207b7SJohn Levon return; 635*efe51d0cSJohn Levon set_state_expr(link_id, size_expr, alloc_state_expr(array_expr)); 6361f5207b7SJohn Levon } 6371f5207b7SJohn Levon 638*efe51d0cSJohn Levon static void set_implied(struct expression *call, struct expression *array_expr, char *key, char *value) 6391f5207b7SJohn Levon { 6401f5207b7SJohn Levon struct expression *size_expr; 6411f5207b7SJohn Levon struct symbol *size_sym; 6421f5207b7SJohn Levon char *size_name; 6431f5207b7SJohn Levon long param; 6441f5207b7SJohn Levon struct sm_state *tmp; 645*efe51d0cSJohn Levon int limit_type; 6461f5207b7SJohn Levon 647*efe51d0cSJohn Levon if (strncmp(key, "==$", 3) != 0) 648*efe51d0cSJohn Levon return; 649*efe51d0cSJohn Levon param = strtol(key + 3, NULL, 10); 6501f5207b7SJohn Levon if (!get_param(param, &size_name, &size_sym)) 6511f5207b7SJohn Levon return; 6521f5207b7SJohn Levon size_expr = symbol_expression(size_sym); 6531f5207b7SJohn Levon 654*efe51d0cSJohn Levon limit_type = strtol(value, NULL, 10); 655*efe51d0cSJohn Levon tmp = set_state_expr(size_id, array_expr, alloc_compare_size(limit_type, size_expr)); 6561f5207b7SJohn Levon if (!tmp) 6571f5207b7SJohn Levon return; 658*efe51d0cSJohn Levon set_state_expr(link_id, size_expr, alloc_state_expr(array_expr)); 6591f5207b7SJohn Levon } 6601f5207b7SJohn Levon 6611f5207b7SJohn Levon static void munge_start_states(struct statement *stmt) 6621f5207b7SJohn Levon { 6631f5207b7SJohn Levon struct state_list *slist = NULL; 6641f5207b7SJohn Levon struct sm_state *sm; 6651f5207b7SJohn Levon struct sm_state *poss; 6661f5207b7SJohn Levon 6671f5207b7SJohn Levon FOR_EACH_MY_SM(size_id, __get_cur_stree(), sm) { 6681f5207b7SJohn Levon if (sm->state != &merged) 6691f5207b7SJohn Levon continue; 6701f5207b7SJohn Levon /* 6711f5207b7SJohn Levon * screw it. let's just assume that if one caller passes the 6721f5207b7SJohn Levon * size then they all do. 6731f5207b7SJohn Levon */ 6741f5207b7SJohn Levon FOR_EACH_PTR(sm->possible, poss) { 6751f5207b7SJohn Levon if (poss->state != &merged && 6761f5207b7SJohn Levon poss->state != &undefined) { 6771f5207b7SJohn Levon add_ptr_list(&slist, poss); 6781f5207b7SJohn Levon break; 6791f5207b7SJohn Levon } 6801f5207b7SJohn Levon } END_FOR_EACH_PTR(poss); 6811f5207b7SJohn Levon } END_FOR_EACH_SM(sm); 6821f5207b7SJohn Levon 6831f5207b7SJohn Levon FOR_EACH_PTR(slist, sm) { 6841f5207b7SJohn Levon set_state(size_id, sm->name, sm->sym, sm->state); 6851f5207b7SJohn Levon } END_FOR_EACH_PTR(sm); 6861f5207b7SJohn Levon 6871f5207b7SJohn Levon free_slist(&slist); 6881f5207b7SJohn Levon } 6891f5207b7SJohn Levon 690*efe51d0cSJohn Levon static void set_used(struct expression *expr) 691*efe51d0cSJohn Levon { 692*efe51d0cSJohn Levon struct expression *parent; 693*efe51d0cSJohn Levon struct expression *array; 694*efe51d0cSJohn Levon struct expression *offset; 695*efe51d0cSJohn Levon struct sm_state *tmp; 696*efe51d0cSJohn Levon int limit_type; 697*efe51d0cSJohn Levon 698*efe51d0cSJohn Levon if (expr->op != SPECIAL_INCREMENT) 699*efe51d0cSJohn Levon return; 700*efe51d0cSJohn Levon 701*efe51d0cSJohn Levon limit_type = USED_LAST; 702*efe51d0cSJohn Levon if (expr->type == EXPR_POSTOP) 703*efe51d0cSJohn Levon limit_type = USED_COUNT; 704*efe51d0cSJohn Levon 705*efe51d0cSJohn Levon parent = expr_get_parent_expr(expr); 706*efe51d0cSJohn Levon if (!parent || parent->type != EXPR_BINOP) 707*efe51d0cSJohn Levon return; 708*efe51d0cSJohn Levon parent = expr_get_parent_expr(parent); 709*efe51d0cSJohn Levon if (!parent || !is_array(parent)) 710*efe51d0cSJohn Levon return; 711*efe51d0cSJohn Levon 712*efe51d0cSJohn Levon array = get_array_base(parent); 713*efe51d0cSJohn Levon offset = get_array_offset(parent); 714*efe51d0cSJohn Levon if (offset != expr) 715*efe51d0cSJohn Levon return; 716*efe51d0cSJohn Levon 717*efe51d0cSJohn Levon tmp = set_state_expr(size_id, array, alloc_compare_size(limit_type, offset->unop)); 718*efe51d0cSJohn Levon if (!tmp) 719*efe51d0cSJohn Levon return; 720*efe51d0cSJohn Levon set_state_expr(link_id, offset->unop, alloc_state_expr(array)); 721*efe51d0cSJohn Levon } 722*efe51d0cSJohn Levon 723*efe51d0cSJohn Levon static int match_assign_array(struct expression *expr) 724*efe51d0cSJohn Levon { 725*efe51d0cSJohn Levon // FIXME: implement 726*efe51d0cSJohn Levon return 0; 727*efe51d0cSJohn Levon } 728*efe51d0cSJohn Levon 729*efe51d0cSJohn Levon static int match_assign_size(struct expression *expr) 730*efe51d0cSJohn Levon { 731*efe51d0cSJohn Levon struct expression *right, *size, *array; 732*efe51d0cSJohn Levon struct smatch_state *state; 733*efe51d0cSJohn Levon struct sm_state *tmp; 734*efe51d0cSJohn Levon int limit_type; 735*efe51d0cSJohn Levon 736*efe51d0cSJohn Levon right = expr->right; 737*efe51d0cSJohn Levon size = right; 738*efe51d0cSJohn Levon if (size->type == EXPR_BINOP) 739*efe51d0cSJohn Levon size = size->left; 740*efe51d0cSJohn Levon 741*efe51d0cSJohn Levon array = get_array_variable(size); 742*efe51d0cSJohn Levon if (!array) 743*efe51d0cSJohn Levon return 0; 744*efe51d0cSJohn Levon state = get_state_expr(size_id, array); 745*efe51d0cSJohn Levon if (!state || !state->data) 746*efe51d0cSJohn Levon return 0; 747*efe51d0cSJohn Levon 748*efe51d0cSJohn Levon limit_type = state_to_limit(state); 749*efe51d0cSJohn Levon if (limit_type < 0) 750*efe51d0cSJohn Levon return 0; 751*efe51d0cSJohn Levon 752*efe51d0cSJohn Levon if (right->type == EXPR_BINOP && !match_size_binop(size, right, &limit_type)) 753*efe51d0cSJohn Levon return 0; 754*efe51d0cSJohn Levon 755*efe51d0cSJohn Levon tmp = set_state_expr(size_id, array, alloc_compare_size(limit_type, expr->left)); 756*efe51d0cSJohn Levon if (!tmp) 757*efe51d0cSJohn Levon return 0; 758*efe51d0cSJohn Levon set_state_expr(link_id, expr->left, alloc_state_expr(array)); 759*efe51d0cSJohn Levon return 1; 760*efe51d0cSJohn Levon } 761*efe51d0cSJohn Levon 762*efe51d0cSJohn Levon static void match_assign(struct expression *expr) 763*efe51d0cSJohn Levon { 764*efe51d0cSJohn Levon if (expr->op != '=') 765*efe51d0cSJohn Levon return; 766*efe51d0cSJohn Levon 767*efe51d0cSJohn Levon if (match_assign_array(expr)) 768*efe51d0cSJohn Levon return; 769*efe51d0cSJohn Levon match_assign_size(expr); 770*efe51d0cSJohn Levon } 771*efe51d0cSJohn Levon 772*efe51d0cSJohn Levon static void match_copy(const char *fn, struct expression *expr, void *unused) 773*efe51d0cSJohn Levon { 774*efe51d0cSJohn Levon struct expression *src, *size; 775*efe51d0cSJohn Levon int src_param, size_param; 776*efe51d0cSJohn Levon 777*efe51d0cSJohn Levon src = get_argument_from_call_expr(expr->args, 1); 778*efe51d0cSJohn Levon size = get_argument_from_call_expr(expr->args, 2); 779*efe51d0cSJohn Levon src = strip_expr(src); 780*efe51d0cSJohn Levon size = strip_expr(size); 781*efe51d0cSJohn Levon if (!src || !size) 782*efe51d0cSJohn Levon return; 783*efe51d0cSJohn Levon if (src->type != EXPR_SYMBOL || size->type != EXPR_SYMBOL) 784*efe51d0cSJohn Levon return; 785*efe51d0cSJohn Levon 786*efe51d0cSJohn Levon src_param = get_param_num_from_sym(src->symbol); 787*efe51d0cSJohn Levon size_param = get_param_num_from_sym(size->symbol); 788*efe51d0cSJohn Levon if (src_param < 0 || size_param < 0) 789*efe51d0cSJohn Levon return; 790*efe51d0cSJohn Levon 791*efe51d0cSJohn Levon sql_insert_cache(call_implies, "'%s', '%s', 0, %d, %d, %d, '==$%d', '%d'", 792*efe51d0cSJohn Levon get_base_file(), get_function(), fn_static(), 793*efe51d0cSJohn Levon BYTE_COUNT, src_param, size_param, BYTE_COUNT); 794*efe51d0cSJohn Levon } 795*efe51d0cSJohn Levon 7961f5207b7SJohn Levon void register_buf_comparison(int id) 7971f5207b7SJohn Levon { 798*efe51d0cSJohn Levon int i; 799*efe51d0cSJohn Levon 8001f5207b7SJohn Levon size_id = id; 8011f5207b7SJohn Levon 802*efe51d0cSJohn Levon set_dynamic_states(size_id); 803*efe51d0cSJohn Levon 8041f5207b7SJohn Levon add_unmatched_state_hook(size_id, &unmatched_state); 8051f5207b7SJohn Levon 8061f5207b7SJohn Levon add_allocation_function("malloc", &match_alloc, 0); 8071f5207b7SJohn Levon add_allocation_function("memdup", &match_alloc, 1); 8081f5207b7SJohn Levon add_allocation_function("realloc", &match_alloc, 1); 8091f5207b7SJohn Levon if (option_project == PROJ_KERNEL) { 8101f5207b7SJohn Levon add_allocation_function("kmalloc", &match_alloc, 0); 8111f5207b7SJohn Levon add_allocation_function("kzalloc", &match_alloc, 0); 8121f5207b7SJohn Levon add_allocation_function("vmalloc", &match_alloc, 0); 8131f5207b7SJohn Levon add_allocation_function("__vmalloc", &match_alloc, 0); 8141f5207b7SJohn Levon add_allocation_function("sock_kmalloc", &match_alloc, 1); 8151f5207b7SJohn Levon add_allocation_function("kmemdup", &match_alloc, 1); 8161f5207b7SJohn Levon add_allocation_function("kmemdup_user", &match_alloc, 1); 8171f5207b7SJohn Levon add_allocation_function("dma_alloc_attrs", &match_alloc, 1); 8181f5207b7SJohn Levon add_allocation_function("pci_alloc_consistent", &match_alloc, 1); 8191f5207b7SJohn Levon add_allocation_function("pci_alloc_coherent", &match_alloc, 1); 8201f5207b7SJohn Levon add_allocation_function("devm_kmalloc", &match_alloc, 1); 8211f5207b7SJohn Levon add_allocation_function("devm_kzalloc", &match_alloc, 1); 8221f5207b7SJohn Levon add_allocation_function("kcalloc", &match_calloc, 0); 8231f5207b7SJohn Levon add_allocation_function("devm_kcalloc", &match_calloc, 1); 8241f5207b7SJohn Levon add_allocation_function("kmalloc_array", &match_calloc, 0); 8251f5207b7SJohn Levon add_allocation_function("krealloc", &match_alloc, 1); 826*efe51d0cSJohn Levon 827*efe51d0cSJohn Levon add_function_hook("copy_from_user", &match_copy, NULL); 828*efe51d0cSJohn Levon add_function_hook("__copy_from_user", &match_copy, NULL); 8291f5207b7SJohn Levon } 8301f5207b7SJohn Levon 8311f5207b7SJohn Levon add_hook(&array_check, OP_HOOK); 8321f5207b7SJohn Levon add_hook(&array_check_data_info, OP_HOOK); 833*efe51d0cSJohn Levon add_hook(&set_used, OP_HOOK); 8341f5207b7SJohn Levon 8351f5207b7SJohn Levon add_hook(&match_call, FUNCTION_CALL_HOOK); 8361f5207b7SJohn Levon add_hook(&munge_start_states, AFTER_DEF_HOOK); 837*efe51d0cSJohn Levon 838*efe51d0cSJohn Levon add_hook(&match_assign, ASSIGNMENT_HOOK); 839*efe51d0cSJohn Levon 840*efe51d0cSJohn Levon for (i = BYTE_COUNT; i <= USED_COUNT; i++) { 841*efe51d0cSJohn Levon select_call_implies_hook(i, &set_implied); 842*efe51d0cSJohn Levon select_caller_info_hook(set_param_compare, i); 843*efe51d0cSJohn Levon select_return_implies_hook(i, &set_implied); 844*efe51d0cSJohn Levon } 8451f5207b7SJohn Levon } 8461f5207b7SJohn Levon 8471f5207b7SJohn Levon void register_buf_comparison_links(int id) 8481f5207b7SJohn Levon { 8491f5207b7SJohn Levon link_id = id; 850*efe51d0cSJohn Levon set_dynamic_states(link_id); 8511f5207b7SJohn Levon add_merge_hook(link_id, &merge_links); 8521f5207b7SJohn Levon add_modification_hook(link_id, &match_link_modify); 8531f5207b7SJohn Levon } 854