From 3b9aa9647f5f4f0aac3dc4218128b94281a1264c Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Thu, 5 Dec 2019 03:30:37 +0100 Subject: split testcases for type punning & constant initializer expansion Several issues were covered by the same testcase. Fix this by splitting the testcases. Also, rename these testcases to a more descriptive name. Signed-off-by: Luc Van Oostenryck --- validation/bug-expand-union0.c | 21 --------------------- validation/bug-expand-union1.c | 20 -------------------- validation/expand/constant-union-flt2int.c | 21 +++++++++++++++++++++ validation/expand/constant-union-int2flt.c | 20 ++++++++++++++++++++ validation/expand/constant-union-size.c | 21 +++++++++++++++++++++ validation/memops/type-punning-flt2int.c | 20 ++++++++++++++++++++ validation/memops/type-punning-int2flt.c | 20 ++++++++++++++++++++ 7 files changed, 102 insertions(+), 41 deletions(-) delete mode 100644 validation/bug-expand-union0.c delete mode 100644 validation/bug-expand-union1.c create mode 100644 validation/expand/constant-union-flt2int.c create mode 100644 validation/expand/constant-union-int2flt.c create mode 100644 validation/expand/constant-union-size.c create mode 100644 validation/memops/type-punning-flt2int.c create mode 100644 validation/memops/type-punning-int2flt.c diff --git a/validation/bug-expand-union0.c b/validation/bug-expand-union0.c deleted file mode 100644 index dd6d60c3..00000000 --- a/validation/bug-expand-union0.c +++ /dev/null @@ -1,21 +0,0 @@ -union u { - char c; - float f; -}; - -static int foo(void) -{ - union u u = { .f = 0.123 }; - return u.c; -} - -/* - * check-name: bug-expand-union - * check description: must not infer the value from the float - * check-command: test-linearize $file - * check-known-to-fail - * - * check-output-ignore - * check-output-contains: load\\. - * check-output-excludes: ret\\..*\\$ - */ diff --git a/validation/bug-expand-union1.c b/validation/bug-expand-union1.c deleted file mode 100644 index 582a1f4f..00000000 --- a/validation/bug-expand-union1.c +++ /dev/null @@ -1,20 +0,0 @@ -union u { - int i; - float f; -}; - -static int foo(void) -{ - union u u = { .f = 0.123 }; - return u.i; -} - -/* - * check-name: bug-expand-union - * check description: must not infer the value from the float - * check-command: test-linearize $file - * check-known-to-fail - * - * check-output-ignore - * check-output-contains: load\\. - */ diff --git a/validation/expand/constant-union-flt2int.c b/validation/expand/constant-union-flt2int.c new file mode 100644 index 00000000..1c8f480b --- /dev/null +++ b/validation/expand/constant-union-flt2int.c @@ -0,0 +1,21 @@ +union u { + int i; + float f; +}; + +static int foo(void) +{ + union u u = { .f = 0.123 }; + return u.i; +} + +/* + * check-name: constant-union-float-to-int + * check description: must not infer the int value from the float + * check-command: test-linearize -fdump-ir $file + * check-known-to-fail + * + * check-output-ignore + * check-output-pattern(1): setfval\\. + * check-output-pattern(1): load\\. + */ diff --git a/validation/expand/constant-union-int2flt.c b/validation/expand/constant-union-int2flt.c new file mode 100644 index 00000000..ff0a642a --- /dev/null +++ b/validation/expand/constant-union-int2flt.c @@ -0,0 +1,20 @@ +union u { + int i; + float f; +}; + +static float foo(void) +{ + union u u = { .i = 3 }; + return u.f; +} + +/* + * check-name: constant-union-int-to-float + * check description: must not infer the float value from the int + * check-command: test-linearize -fdump-ir $file + * check-known-to-fail + * + * check-output-ignore + * check-output-pattern(1): load\\. + */ diff --git a/validation/expand/constant-union-size.c b/validation/expand/constant-union-size.c new file mode 100644 index 00000000..b6c3ac75 --- /dev/null +++ b/validation/expand/constant-union-size.c @@ -0,0 +1,21 @@ +union u { + char c; + float f; +}; + +static int foo(void) +{ + union u u = { .f = 0.123 }; + return u.c; +} + +/* + * check-name: constant-union-size + * check description: the size of the initializer doesn't match + * check-command: test-linearize -fdump-ir $file + * check-known-to-fail + * + * check-output-ignore + * check-output-contains: load\\. + * check-output-excludes: ret\\..*\\$ + */ diff --git a/validation/memops/type-punning-flt2int.c b/validation/memops/type-punning-flt2int.c new file mode 100644 index 00000000..a76c6c1d --- /dev/null +++ b/validation/memops/type-punning-flt2int.c @@ -0,0 +1,20 @@ +union u { + int i; + float f; +}; + +static int foo(void) +{ + union u u = { .f = 0.123 }; + return u.i; +} + +/* + * check-name: type-punning-float-to-int + * check description: must not infer the int value from the float + * check-command: test-linearize $file + * check-known-to-fail + * + * check-output-ignore + * check-output-contains: load\\. + */ diff --git a/validation/memops/type-punning-int2flt.c b/validation/memops/type-punning-int2flt.c new file mode 100644 index 00000000..c05ce252 --- /dev/null +++ b/validation/memops/type-punning-int2flt.c @@ -0,0 +1,20 @@ +union u { + int i; + float f; +}; + +static float foo(void) +{ + union u u = { .i = 3 }; + return u.f; +} + +/* + * check-name: type-punning-int-to-float + * check description: must not infer the float value from the int + * check-command: test-linearize $file + * check-known-to-fail + * + * check-output-ignore + * check-output-contains: load\\. + */ -- cgit 1.2.3-korg From aa2235905e9afd2f14fbc26b0159e5b64e07314e Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Fri, 6 Dec 2019 01:32:38 +0100 Subject: add testcase for expansion of default initializers Currently, constant_symbol_value() is doing the expansion of a constant initializer when an explicit one is found but nothing is done for the default/implicit ones. Add a testcase to illustrate this. Signed-off-by: Luc Van Oostenryck --- validation/expand/default-init-array.c | 16 ++++++++++++++++ validation/expand/default-init-struct.c | 23 +++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 validation/expand/default-init-array.c create mode 100644 validation/expand/default-init-struct.c diff --git a/validation/expand/default-init-array.c b/validation/expand/default-init-array.c new file mode 100644 index 00000000..b372ea09 --- /dev/null +++ b/validation/expand/default-init-array.c @@ -0,0 +1,16 @@ +int test_array(int i) +{ + static const int a[3] = { [0] = 1, [2] = 3, }; + + return a[1]; +} + +/* + * check-name: default-init-array + * check-command: test-linearize -Wno-decl -fdump-ir $file + * check-known-to-fail + * + * check-output-ignore + * check-output-contains: phisrc\\..*return.*\\$0 + * check-output-excludes: load\\. + */ diff --git a/validation/expand/default-init-struct.c b/validation/expand/default-init-struct.c new file mode 100644 index 00000000..c843a1ab --- /dev/null +++ b/validation/expand/default-init-struct.c @@ -0,0 +1,23 @@ +struct s { + int a; + int b; + int c; +}; + + +int test_struct(void) +{ + struct s s = { .a = 1, .c = 3, }; + + return s.b; +} + +/* + * check-name: default-init-struct + * check-command: test-linearize -Wno-decl -fdump-ir $file + * check-known-to-fail + * + * check-output-ignore + * check-output-contains: phisrc\\..*return.*\\$0 + * check-output-excludes: load\\. + */ -- cgit 1.2.3-korg From ae0ec237a888ee6a2c755d4cdf8b1015e63e55a7 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Sun, 8 Dec 2019 18:36:43 +0100 Subject: add testcase for addressability of degenerated symbol An array or a function that degenerates into a pointer has its address implicitly taken since the result is equivalent to '&array[0]' or '&fun'. So, the corresponding symbol needs to be marked as addressable, like when its address is explicitly taken. Add a testcase to illustrate this. Signed-off-by: Luc Van Oostenryck --- validation/eval/addressable-degen.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 validation/eval/addressable-degen.c diff --git a/validation/eval/addressable-degen.c b/validation/eval/addressable-degen.c new file mode 100644 index 00000000..e1dc5107 --- /dev/null +++ b/validation/eval/addressable-degen.c @@ -0,0 +1,18 @@ +extern void def(void *, unsigned int); + +static int bar(void) +{ + int x[2] = { 1, 2 }; + + def(x, sizeof(x)); + return x[1]; +} + +/* + * check-name: eval/addressable-degen + * check-command: test-linearize -fdump-ir $file + * check-known-to-fail + * + * check-output-ignore + * check-output-contains: load\\. + */ -- cgit 1.2.3-korg From 613a671f31d2a44aa2e04ce05b77d1daad972f20 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Fri, 6 Dec 2019 01:51:04 +0100 Subject: add testcase for addressability of 'complex' symbols Once a symbol has its address taken, a lot of simplifications must be avoided because the symbol can now be modified via a pointer. This is currently done but the symbol addressability does not take in account the fact that a symbol can be accessed via one of its subfields. Add a testcase to illustrate this. Signed-off-by: Luc Van Oostenryck --- validation/eval/addressable-complex.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 validation/eval/addressable-complex.c diff --git a/validation/eval/addressable-complex.c b/validation/eval/addressable-complex.c new file mode 100644 index 00000000..62ab59f0 --- /dev/null +++ b/validation/eval/addressable-complex.c @@ -0,0 +1,24 @@ +extern void def(void *); + +struct s1 { + int a; +}; + +int use1(void) +{ + struct s1 s = { 3 }; + + def(&s.a); + + return s.a; +} + +/* + * check-name: eval/addressable-complex + * check-command: test-linearize -Wno-decl -fdump-ir $file + * check-known-to-fail + * + * check-output-ignore + * check-output-contains: load\\. + * check-output-excludes: return\\..*\\$3 + */ -- cgit 1.2.3-korg From 391bd454457e496410f92b1c730a48b277f460e4 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Fri, 6 Dec 2019 04:36:21 +0100 Subject: add test for union cast Sparse can't do this yet. So, add a testcase for it. Signed-off-by: Luc Van Oostenryck --- validation/expand/union-cast.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 validation/expand/union-cast.c diff --git a/validation/expand/union-cast.c b/validation/expand/union-cast.c new file mode 100644 index 00000000..a28d01f2 --- /dev/null +++ b/validation/expand/union-cast.c @@ -0,0 +1,27 @@ +union u { + int i; + struct s { + int a; + } s; +}; + +int foo(void) +{ + struct s s = { 3 }; + union u u = (union u)s; + return u.s.a; +} + +/* + * check-name: union-cast + * check-command: test-linearize -Wno-decl -fdump-ir $file + * check-known-to-fail + * + * check-output-ignore + * check-output-excludes: load\\. + * + * check-error-start +union-cast.c:11:22: warning: cast to non-scalar +union-cast.c:11:22: warning: cast from non-scalar + * check-error-end + */ -- cgit 1.2.3-korg From 2a6c80fdd0616e20d6227eb4ab51feb84ba57c4e Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Sun, 8 Dec 2019 03:26:40 +0100 Subject: add test for dereference cost of symbol with complex type Currently, in expand_dereference(), the dereference of a symbol with a complex type is considered as costing as high as a non-symbol because it's not recognised it's a symbol. Add a testcase for this. Signed-off-by: Luc Van Oostenryck --- validation/expand/cost-deref-nested.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 validation/expand/cost-deref-nested.c diff --git a/validation/expand/cost-deref-nested.c b/validation/expand/cost-deref-nested.c new file mode 100644 index 00000000..b09602b6 --- /dev/null +++ b/validation/expand/cost-deref-nested.c @@ -0,0 +1,21 @@ +struct s { + struct { + int u, v; + } a, b; +}; + +static const struct s s; + +static int foo(int c) +{ + return c && s.b.v; +} + +/* + * check-name: cost-deref-nested + * check-command: test-linearize -fdump-ir $file + * check-known-to-fail + * + * check-output-ignore + * check-output-excludes: cbr + */ -- cgit 1.2.3-korg From 9fe9cc26a024923483d9ae3b6133c36b037cc4ab Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Sat, 7 Dec 2019 02:43:13 +0100 Subject: add test for constant expansion of complex initializer Constant expansion of symbols with a complex type is not done like for simpler ones. Only the first-level EXPR_INITIALIZER is handled. Add some testcases for this. Signed-off-by: Luc Van Oostenryck --- validation/expand/constant-init-nested-array.c | 15 +++++++++++++++ validation/expand/constant-init-nested-struct.c | 23 +++++++++++++++++++++++ validation/expand/constant-init-string.c | 15 +++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 validation/expand/constant-init-nested-array.c create mode 100644 validation/expand/constant-init-nested-struct.c create mode 100644 validation/expand/constant-init-string.c diff --git a/validation/expand/constant-init-nested-array.c b/validation/expand/constant-init-nested-array.c new file mode 100644 index 00000000..0d50d955 --- /dev/null +++ b/validation/expand/constant-init-nested-array.c @@ -0,0 +1,15 @@ +int foo(void) +{ + int a[2][3] = {{0, 1, 2},{3, 4, 5}}; + return a[1][2]; +} + +/* + * check-name: constant-init-nested-array + * check-command: test-linearize -Wno-decl -fdump-ir $file + * check-known-to-fail + * + * check-output-ignore + * check-output-contains: phisrc\\..*\\$5 + * check-output-excludes: load\\. + */ diff --git a/validation/expand/constant-init-nested-struct.c b/validation/expand/constant-init-nested-struct.c new file mode 100644 index 00000000..f27de556 --- /dev/null +++ b/validation/expand/constant-init-nested-struct.c @@ -0,0 +1,23 @@ +struct s { + int a; + struct { + int b; + int c; + } s; +}; + +int foo(void) +{ + struct s s = {1, {2, 3}}; + return s.s.c; +} + +/* + * check-name: constant-init-nested-struct + * check-command: test-linearize -Wno-decl -fdump-ir $file + * check-known-to-fail + * + * check-output-ignore + * check-output-contains: phisrc\\..*\\$3 + * check-output-excludes: load\\. + */ diff --git a/validation/expand/constant-init-string.c b/validation/expand/constant-init-string.c new file mode 100644 index 00000000..42ae9bd3 --- /dev/null +++ b/validation/expand/constant-init-string.c @@ -0,0 +1,15 @@ +char foo(void) +{ + static const char s[] = "abc?"; + return s[3]; +} + +/* + * check-name: constant-init-nested-array + * check-command: test-linearize -Wno-decl -fdump-ir $file + * check-known-to-fail + * + * check-output-ignore + * check-output-contains: phisrc\\..*\\$63 + * check-output-pattern(0,1): load\\. + */ -- cgit 1.2.3-korg From aa42d419661df95820ba8c28e93b0b1359e0f8d7 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Thu, 5 Dec 2019 23:39:11 +0100 Subject: extract mark_addressable() from evaluate_addressof(). This is just moving the 3 lines of code to mark a symbol as addressable in a speparate function. This is a preparatory step for one of the next patches. Signed-off-by: Luc Van Oostenryck --- evaluate.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/evaluate.c b/evaluate.c index 19bdab92..d78de2ed 100644 --- a/evaluate.c +++ b/evaluate.c @@ -1540,6 +1540,14 @@ static int compatible_argument_type(struct expression *expr, struct symbol *targ return compatible_assignment_types(expr, target, rp, where); } +static void mark_addressable(struct expression *expr) +{ + if (expr->type == EXPR_SYMBOL) { + struct symbol *sym = expr->symbol; + sym->ctype.modifiers |= MOD_ADDRESSABLE; + } +} + static void mark_assigned(struct expression *expr) { struct symbol *sym; @@ -1780,10 +1788,7 @@ static struct symbol *evaluate_addressof(struct expression *expr) ctype = op->ctype; *expr = *op->unop; - if (expr->type == EXPR_SYMBOL) { - struct symbol *sym = expr->symbol; - sym->ctype.modifiers |= MOD_ADDRESSABLE; - } + mark_addressable(expr); /* * symbol expression evaluation is lazy about the type -- cgit 1.2.3-korg From f9b443940a8515132035435d3b4fec232a26c582 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Thu, 5 Dec 2019 23:35:34 +0100 Subject: fix addressability marking in evaluate_addressof() mark_addressable() is used to track if a symbol has its address taken but does not take in account the fact that a symbol can be accessed via one of its subfields. A failure occurs in case like: struct { int a; } s = { 3 }; ... def(&s.a); return s.a; where 's' is not marked as being addressable and so the the initializer will be expanded and the return expression will always be replaced by 3, while def() can redefine it. Signed-off-by: Luc Van Oostenryck --- evaluate.c | 2 ++ validation/eval/addressable-complex.c | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/evaluate.c b/evaluate.c index d78de2ed..c0281e9b 100644 --- a/evaluate.c +++ b/evaluate.c @@ -1542,6 +1542,8 @@ static int compatible_argument_type(struct expression *expr, struct symbol *targ static void mark_addressable(struct expression *expr) { + while (expr->type == EXPR_BINOP && expr->op == '+') + expr = expr->left; if (expr->type == EXPR_SYMBOL) { struct symbol *sym = expr->symbol; sym->ctype.modifiers |= MOD_ADDRESSABLE; diff --git a/validation/eval/addressable-complex.c b/validation/eval/addressable-complex.c index 62ab59f0..e3d4aca4 100644 --- a/validation/eval/addressable-complex.c +++ b/validation/eval/addressable-complex.c @@ -16,7 +16,6 @@ int use1(void) /* * check-name: eval/addressable-complex * check-command: test-linearize -Wno-decl -fdump-ir $file - * check-known-to-fail * * check-output-ignore * check-output-contains: load\\. -- cgit 1.2.3-korg From 41ba12bf8e76ee2c69222c1c3dfb1a3d420a73d9 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Sun, 8 Dec 2019 17:09:54 +0100 Subject: degenerated arrays & functions are addressable too Symbols which have their address taken (with the 'addressof' operator: &) are marked as such (with the modifier MOD_ADDRESSABLE). But degenerated arrays and functions have their address implicitly taken. MOD_ADDRESSABLE is used to prevent to replace a symbol dereference nto the value used to initialize to it. For example, in code like: static int foo(void) { int x[2] = { 1, 2 }; return x[1]; } the return expression can be replaced by 2. This is not the case case if the array is first passed in a function call, like here: extern void def(void *, unsigned int); static int bar(void) { int x[2] = { 1, 2 }; def(x, sizeof(x)); return x[1]; } Fix this by marking degenerated arrays (and functions) as also being addressable. Signed-off-by: Luc Van Oostenryck --- evaluate.c | 1 + validation/eval/addressable-degen.c | 1 - validation/expand/constant-init-array.c | 15 +++++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 validation/expand/constant-init-array.c diff --git a/evaluate.c b/evaluate.c index c0281e9b..11ad6a22 100644 --- a/evaluate.c +++ b/evaluate.c @@ -1772,6 +1772,7 @@ static struct symbol *degenerate(struct expression *expr) *expr = *expr->unop; ctype = create_pointer(expr, ctype, 1); expr->ctype = ctype; + mark_addressable(expr); default: /* nothing */; } diff --git a/validation/eval/addressable-degen.c b/validation/eval/addressable-degen.c index e1dc5107..d420927e 100644 --- a/validation/eval/addressable-degen.c +++ b/validation/eval/addressable-degen.c @@ -11,7 +11,6 @@ static int bar(void) /* * check-name: eval/addressable-degen * check-command: test-linearize -fdump-ir $file - * check-known-to-fail * * check-output-ignore * check-output-contains: load\\. diff --git a/validation/expand/constant-init-array.c b/validation/expand/constant-init-array.c new file mode 100644 index 00000000..94949be5 --- /dev/null +++ b/validation/expand/constant-init-array.c @@ -0,0 +1,15 @@ +int test_array(int i) +{ + static const int a[3] = { 1, 2, 3, }; + + return a[1]; +} + +/* + * check-name: constant-init-array + * check-command: test-linearize -Wno-decl -fdump-ir $file + * + * check-output-ignore + * check-output-excludes: phisrc\\..*return.*\\$2 + * check-output-contains: load\\. + */ -- cgit 1.2.3-korg From 9e1c8ec13686b2c9ca726066501f5988b78a0504 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Thu, 5 Dec 2019 03:35:13 +0100 Subject: fix expansion of initializer (mismatching size) Currently, the expansion of constant initializers is done whenever the offset in the initializer match the one we're expanding. However, it's not correct to do this expansion if their size doesn't match since in this case the value of one doesn't represent the value of the other. Fix this by adding a check for the size. Signed-off-by: Luc Van Oostenryck --- expand.c | 8 ++++---- validation/expand/constant-union-size.c | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/expand.c b/expand.c index ae764153..04b072c5 100644 --- a/expand.c +++ b/expand.c @@ -625,8 +625,6 @@ static int expand_addressof(struct expression *expr) * Look up a trustable initializer value at the requested offset. * * Return NULL if no such value can be found or statically trusted. - * - * FIXME!! We should check that the size is right! */ static struct expression *constant_symbol_value(struct symbol *sym, int offset) { @@ -688,11 +686,13 @@ static int expand_dereference(struct expression *expr) if (unop->type == EXPR_SYMBOL) { struct symbol *sym = unop->symbol; + struct symbol *ctype = expr->ctype; struct expression *value = constant_symbol_value(sym, offset); /* Const symbol with a constant initializer? */ - if (value) { - /* FIXME! We should check that the size is right! */ + if (value && value->ctype) { + if (ctype->bit_size != value->ctype->bit_size) + return UNSAFE; if (value->type == EXPR_VALUE) { if (is_bitfield_type(value->ctype)) return UNSAFE; diff --git a/validation/expand/constant-union-size.c b/validation/expand/constant-union-size.c index b6c3ac75..8a16bf3e 100644 --- a/validation/expand/constant-union-size.c +++ b/validation/expand/constant-union-size.c @@ -13,7 +13,6 @@ static int foo(void) * check-name: constant-union-size * check description: the size of the initializer doesn't match * check-command: test-linearize -fdump-ir $file - * check-known-to-fail * * check-output-ignore * check-output-contains: load\\. -- cgit 1.2.3-korg From c0123a2f917241e52c5844655abbd83f56ff1017 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Thu, 5 Dec 2019 03:36:26 +0100 Subject: fix expansion of initializer (mismatching type) Currently, the expansion of constant initializers is done whenever the offset in the initializer match the one being expanded. However, it's not correct to do this expansion of an integer with the initializer for a float and vice-versa. Fix this by adding the corresponding tests to the other tests of the value. Signed-off-by: Luc Van Oostenryck --- expand.c | 4 ++++ validation/expand/constant-union-flt2int.c | 1 - validation/expand/constant-union-int2flt.c | 1 - 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/expand.c b/expand.c index 04b072c5..9ab259b1 100644 --- a/expand.c +++ b/expand.c @@ -694,6 +694,8 @@ static int expand_dereference(struct expression *expr) if (ctype->bit_size != value->ctype->bit_size) return UNSAFE; if (value->type == EXPR_VALUE) { + if (!is_integral_type(ctype)) + return UNSAFE; if (is_bitfield_type(value->ctype)) return UNSAFE; expr->type = EXPR_VALUE; @@ -701,6 +703,8 @@ static int expand_dereference(struct expression *expr) expr->taint = 0; return 0; } else if (value->type == EXPR_FVALUE) { + if (!is_float_type(ctype)) + return UNSAFE; expr->type = EXPR_FVALUE; expr->fvalue = value->fvalue; return 0; diff --git a/validation/expand/constant-union-flt2int.c b/validation/expand/constant-union-flt2int.c index 1c8f480b..5e25b592 100644 --- a/validation/expand/constant-union-flt2int.c +++ b/validation/expand/constant-union-flt2int.c @@ -13,7 +13,6 @@ static int foo(void) * check-name: constant-union-float-to-int * check description: must not infer the int value from the float * check-command: test-linearize -fdump-ir $file - * check-known-to-fail * * check-output-ignore * check-output-pattern(1): setfval\\. diff --git a/validation/expand/constant-union-int2flt.c b/validation/expand/constant-union-int2flt.c index ff0a642a..16ce1c6f 100644 --- a/validation/expand/constant-union-int2flt.c +++ b/validation/expand/constant-union-int2flt.c @@ -13,7 +13,6 @@ static float foo(void) * check-name: constant-union-int-to-float * check description: must not infer the float value from the int * check-command: test-linearize -fdump-ir $file - * check-known-to-fail * * check-output-ignore * check-output-pattern(1): load\\. -- cgit 1.2.3-korg From 706254f20d357735884c5e7b78c03d49bcad9cd3 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Thu, 5 Dec 2019 03:36:57 +0100 Subject: fix expansion of initializer (default) Currently, constant_symbol_value() is doing the expansion of a constant initializer when an explicit one is found but nothing is done if the initilizer is an implicit one. Fix this by: * adding an helper to lookup the corresponding type from offset; * using this helper to get the correct kind for the value: - a 0-valued EXPR_VALUE for integers - a 0.0-valued EXPR_FVALUE for floats. Signed-off-by: Luc Van Oostenryck --- expand.c | 65 ++++++++++++++++++++++++++++++++- validation/expand/default-init-struct.c | 1 - 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/expand.c b/expand.c index 9ab259b1..cd348bf5 100644 --- a/expand.c +++ b/expand.c @@ -621,6 +621,66 @@ static int expand_addressof(struct expression *expr) return expand_expression(expr->unop); } +/// +// lookup the type of a struct's memeber at the requested offset +static struct symbol *find_member(struct symbol *sym, int offset) +{ + struct ptr_list *head, *list; + + head = (struct ptr_list *) sym->symbol_list; + list = head; + if (!head) + return NULL; + do { + int nr = list->nr; + int i; + for (i = 0; i < nr; i++) { + struct symbol *ent = (struct symbol *) list->list[i]; + int curr = ent->offset; + if (curr == offset) + return ent; + if (curr > offset) + return NULL; + } + } while ((list = list->next) != head); + return NULL; +} + +/// +// lookup a suitable default initializer value at the requested offset +static struct expression *default_initializer(struct symbol *sym, int offset) +{ + static struct expression value; + struct symbol *type; + +redo: + switch (sym->type) { + case SYM_NODE: + sym = sym->ctype.base_type; + goto redo; + case SYM_STRUCT: + type = find_member(sym, offset); + if (!type) + return NULL; + break; + case SYM_ARRAY: + type = sym->ctype.base_type; + break; + default: + return NULL; + } + + if (is_integral_type(type)) + value.type = EXPR_VALUE; + else if (is_float_type(type)) + value.type = EXPR_FVALUE; + else + return NULL; + + value.ctype = type; + return &value; +} + /* * Look up a trustable initializer value at the requested offset. * @@ -646,10 +706,11 @@ static struct expression *constant_symbol_value(struct symbol *sym, int offset) if (entry->init_offset < offset) continue; if (entry->init_offset > offset) - return NULL; + break; return entry->init_expr; } END_FOR_EACH_PTR(entry); - return NULL; + + value = default_initializer(sym, offset); } return value; } diff --git a/validation/expand/default-init-struct.c b/validation/expand/default-init-struct.c index c843a1ab..085dd2d6 100644 --- a/validation/expand/default-init-struct.c +++ b/validation/expand/default-init-struct.c @@ -15,7 +15,6 @@ int test_struct(void) /* * check-name: default-init-struct * check-command: test-linearize -Wno-decl -fdump-ir $file - * check-known-to-fail * * check-output-ignore * check-output-contains: phisrc\\..*return.*\\$0 -- cgit 1.2.3-korg From 5d02fb958506ba44d85b449bef68883c68d6ecfa Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Thu, 5 Dec 2019 23:41:47 +0100 Subject: fix simplify_loads() when doing type punning When doing loads simplification for a location where floats & integers are mixed, loads are systematically replaced with the value of their dominating memop (this checks if the corresponding write or load overlaps). However, this must not be done if the involved operations are doing some form of integer/float type punning. Fix this by refusing to convert load of an integer by a previous float value or the opposite. Note: another way to describe this problem would be to say that floats need to have their own memory operations: OP_FSTORE & OP_FLOAD or that instructions need to have some form of 'machine type' in addition of the size (like clang's i32/f32, ...). Signed-off-by: Luc Van Oostenryck --- memops.c | 11 +++++++++++ validation/memops/type-punning-flt2int.c | 1 - validation/memops/type-punning-int2flt.c | 1 - 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/memops.c b/memops.c index 5df2c033..f071e556 100644 --- a/memops.c +++ b/memops.c @@ -82,6 +82,15 @@ static int local_pseudo(pseudo_t pseudo) && !address_taken(pseudo); } +static bool compatible_loads(struct instruction *a, struct instruction *b) +{ + if (is_integral_type(a->type) && is_float_type(b->type)) + return false; + if (is_float_type(a->type) && is_integral_type(b->type)) + return false; + return true; +} + static void simplify_loads(struct basic_block *bb) { struct instruction *insn; @@ -114,6 +123,8 @@ static void simplify_loads(struct basic_block *bb) continue; goto next_load; } + if (!compatible_loads(insn, dom)) + goto next_load; /* Yeehaa! Found one! */ convert_load_instruction(insn, dom->target); goto next_load; diff --git a/validation/memops/type-punning-flt2int.c b/validation/memops/type-punning-flt2int.c index a76c6c1d..fadaf687 100644 --- a/validation/memops/type-punning-flt2int.c +++ b/validation/memops/type-punning-flt2int.c @@ -13,7 +13,6 @@ static int foo(void) * check-name: type-punning-float-to-int * check description: must not infer the int value from the float * check-command: test-linearize $file - * check-known-to-fail * * check-output-ignore * check-output-contains: load\\. diff --git a/validation/memops/type-punning-int2flt.c b/validation/memops/type-punning-int2flt.c index c05ce252..061b7423 100644 --- a/validation/memops/type-punning-int2flt.c +++ b/validation/memops/type-punning-int2flt.c @@ -13,7 +13,6 @@ static float foo(void) * check-name: type-punning-int-to-float * check description: must not infer the float value from the int * check-command: test-linearize $file - * check-known-to-fail * * check-output-ignore * check-output-contains: load\\. -- cgit 1.2.3-korg From 0d92426b4e15d7565e1a1d45cb41e06059ed2043 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Sun, 8 Dec 2019 00:43:05 +0100 Subject: fix cost of dereference of symbols with complex type Currently, in expand_dereference(), the dereference of a symbol with a complex type is considered as costing as high as a non-symbol because it's not recognised it's a symbol. However, both cases should have exactly the same cost since they address calculation amounts to 'symbol + offset'. So, instead of taking in account a single level of symbol + offset let's use a loop for this in order to handle symbol [+ offset]* Signed-off-by: Luc Van Oostenryck --- expand.c | 10 +++++----- validation/expand/cost-deref-nested.c | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/expand.c b/expand.c index cd348bf5..36612c86 100644 --- a/expand.c +++ b/expand.c @@ -737,12 +737,12 @@ static int expand_dereference(struct expression *expr) * Is it "symbol" or "symbol + offset"? */ offset = 0; - if (unop->type == EXPR_BINOP && unop->op == '+') { + while (unop->type == EXPR_BINOP && unop->op == '+') { struct expression *right = unop->right; - if (right->type == EXPR_VALUE) { - offset = right->value; - unop = unop->left; - } + if (right->type != EXPR_VALUE) + break; + offset += right->value; + unop = unop->left; } if (unop->type == EXPR_SYMBOL) { diff --git a/validation/expand/cost-deref-nested.c b/validation/expand/cost-deref-nested.c index b09602b6..d6b62396 100644 --- a/validation/expand/cost-deref-nested.c +++ b/validation/expand/cost-deref-nested.c @@ -14,7 +14,6 @@ static int foo(int c) /* * check-name: cost-deref-nested * check-command: test-linearize -fdump-ir $file - * check-known-to-fail * * check-output-ignore * check-output-excludes: cbr -- cgit 1.2.3-korg