From af53d34a19f086c02955948f90502d231671fc4a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 12 Apr 2017 15:37:12 +0300 Subject: [PATCH] flow: fix initialization of nested structs Before if we had an initialization like: struct foo foo = { aaa.bbb.ccc = 100, }; Then it would try to set "foo.ccc = 100;" which does not exist. Signed-off-by: Dan Carpenter --- smatch_flow.c | 43 ++++++++++++++++++++++++++++++++----------- validation/sm_initializer.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 11 deletions(-) create mode 100644 validation/sm_initializer.c diff --git a/smatch_flow.c b/smatch_flow.c index 250528f4..6597287e 100644 --- a/smatch_flow.c +++ b/smatch_flow.c @@ -1305,7 +1305,7 @@ static void set_unset_to_zero(struct symbol *type, struct expression *expr) static void fake_member_assigns_helper(struct expression *symbol, struct expression_list *members, fake_cb *fake_cb) { - struct expression *deref, *assign, *tmp; + struct expression *deref, *assign, *tmp, *right; struct symbol *struct_type, *type; struct ident *member; int member_idx; @@ -1318,25 +1318,46 @@ static void fake_member_assigns_helper(struct expression *symbol, struct express member_set = alloc_member_set(struct_type); + /* + * We're parsing an initializer that could look something like this: + * struct foo foo = { + * 42, + * .whatever.xxx = 11, + * .zzz = 12, + * }; + * + * So what we have here is a list with 42, .whatever, and .zzz. We need + * to break it up into left and right sides of the assignments. + * + */ member_idx = 0; FOR_EACH_PTR(members, tmp) { - member = number_to_member(symbol, member_idx); - while (tmp->type == EXPR_IDENTIFIER) { - member = tmp->expr_ident; - member_idx = member_to_number(symbol, member); - tmp = tmp->ident_expression; + deref = NULL; + if (tmp->type == EXPR_IDENTIFIER) { + member_idx = member_to_number(symbol, tmp->expr_ident); + while (tmp->type == EXPR_IDENTIFIER) { + member = tmp->expr_ident; + tmp = tmp->ident_expression; + if (deref) + deref = member_expression(deref, '.', member); + else + deref = member_expression(symbol, '.', member); + } + } else { + member = number_to_member(symbol, member_idx); + deref = member_expression(symbol, '.', member); } + right = tmp; mark_member_as_set(struct_type, member_set, member); member_idx++; - deref = member_expression(symbol, '.', member); - if (tmp->type == EXPR_INITIALIZER) { + if (right->type == EXPR_INITIALIZER) { type = get_type(deref); if (type && type->type == SYM_ARRAY) - fake_element_assigns_helper(deref, tmp->expr_list, fake_cb); + fake_element_assigns_helper(deref, right->expr_list, fake_cb); else - fake_member_assigns_helper(deref, tmp->expr_list, fake_cb); + fake_member_assigns_helper(deref, right->expr_list, fake_cb); } else { - assign = assign_expression(deref, tmp); + assign = assign_expression(deref, right); fake_cb(assign); } } END_FOR_EACH_PTR(tmp); diff --git a/validation/sm_initializer.c b/validation/sm_initializer.c new file mode 100644 index 00000000..238d575f --- /dev/null +++ b/validation/sm_initializer.c @@ -0,0 +1,37 @@ +#include "check_debug.h" + +struct bar { + int a, b, c; +}; + +struct foo { + struct bar bar; + int x, y, z; +}; + +int test(int size) +{ + struct foo foo = { + .bar.a = 42, + .bar.b = 43, + -1, + }; + __smatch_implied(foo.bar.b); + __smatch_implied(foo.bar.c); + __smatch_implied(foo.x); + __smatch_implied(foo.y); + + return 0; +} + +/* + * check-name: smatch: nested initializer + * check-command: smatch -I.. sm_initializer.c + * + * check-output-start +sm_initializer.c:19 test() implied: foo.bar.b = '43' +sm_initializer.c:20 test() implied: foo.bar.c = '0' +sm_initializer.c:21 test() implied: foo.x = '(-1)' +sm_initializer.c:22 test() implied: foo.y = '0' + * check-output-end + */ -- 2.11.4.GIT