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