1 /*
2  * Copyright (C) 2012 Oracle.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16  */
17 
18 #include "smatch.h"
19 #include "smatch_extra.h"
20 #include "smatch_slist.h"
21 
22 #define NOBUF -2
23 
24 static int my_id;
25 
get_returned_expr(struct expression * expr)26 static struct expression *get_returned_expr(struct expression *expr)
27 {
28 	struct statement *stmt;
29 
30 	stmt = last_ptr_list((struct ptr_list *)big_statement_stack);
31 	if (!stmt || stmt->type != STMT_EXPRESSION || !stmt->expression)
32 		return NULL;
33 	if (stmt->expression->type != EXPR_ASSIGNMENT)
34 		return NULL;
35 	if (stmt->expression->right != expr)
36 		return NULL;
37 	return stmt->expression->left;
38 }
39 
remove_dereference(struct expression * expr)40 static struct expression *remove_dereference(struct expression *expr)
41 {
42 	if (!expr || expr->type != EXPR_PREOP || expr->op != '*')
43 		return expr;
44 	expr = expr->unop;
45 	if (!expr || expr->type != EXPR_PREOP || expr->op != '*')
46 		return expr;
47 	return expr->unop;
48 }
49 
get_buf_number(struct expression * call,struct expression * size_arg)50 static int get_buf_number(struct expression *call, struct expression *size_arg)
51 {
52 	struct expression *arg;
53 	int idx = -1;
54 
55 	size_arg = strip_expr(size_arg->cast_expression);
56 	size_arg = remove_dereference(size_arg);
57 
58 	arg = get_returned_expr(call);
59 	if (arg && expr_equiv(arg, size_arg))
60 		return idx;
61 
62 	FOR_EACH_PTR(call->args, arg) {
63 		idx++;
64 		if (expr_equiv(arg, size_arg))
65 			return idx;
66 	} END_FOR_EACH_PTR(arg);
67 
68 	return NOBUF;
69 }
70 
match_call(struct expression * call)71 static void match_call(struct expression *call)
72 {
73 	struct expression *arg;
74 	char *name;
75 	int buf_nr;
76 	int i = -1;
77 
78 	if (call->fn->type != EXPR_SYMBOL)
79 		return;
80 
81 	name = expr_to_var(call->fn);
82 	FOR_EACH_PTR(call->args, arg) {
83 		i++;
84 		if (arg->type != EXPR_SIZEOF)
85 			continue;
86 		buf_nr = get_buf_number(call, arg);
87 		if (buf_nr == NOBUF)
88 			sm_msg("info: sizeof_param '%s' %d", name, i);
89 		else
90 			sm_msg("info: sizeof_param '%s' %d %d", name, i, buf_nr);
91 	} END_FOR_EACH_PTR(arg);
92 	free_string(name);
93 }
94 
check_passes_sizeof(int id)95 void check_passes_sizeof(int id)
96 {
97 	if (!option_info)
98 		return;
99 
100 	my_id = id;
101 	add_hook(&match_call, FUNCTION_CALL_HOOK);
102 }
103