aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/validation
diff options
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-05-21 18:23:04 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-05-21 18:23:04 +0200
commit4d96f72782e076f7c4410394364aa77336c09bd2 (patch)
tree6cc86b72f196f6b4465edb74797903f3cf4711b5 /validation
parent18351292096b1b90ed7f3bc34459d371aa095588 (diff)
parent384008074a8d8881fefaa4fdda330120385d1259 (diff)
downloadsparse-dev-4d96f72782e076f7c4410394364aa77336c09bd2.tar.gz
Merge branch 'bad-goto'
* warn when jumping into statement expressions * warn when using undefined labels * warn on defined but unused labels It's not allowed to do a goto into an expression statement. For example, it's not well defined what should happen if such an expression is not otherwise reachable and/or can be optimized away. For such situations GCC issues an error, clang doesn't and produce a valid IR but Spare produce an invalid IR with branches to unexisting BBs. The goals of the patches in this series are: *) to detect such gotos at evaluation time; *) issue a sensible error message; *) avoid the linearization of functions with invalid gotos. The implementation principle behind these is to add a new kind of scope (label_scope), one for the usual function scope of labels one for each statement expressions. This new scope, instead of being used as a real scope for the visibility of labels, is used to mark where labels are defined and where they're used. Using this label scope as a real scope controling the visibility of labels was quite appealing and was the initial drive for this implementation but has the problem of inner scope shadowing earlier occurence of labels identically named. This is of course desired for 'normal' symbols but for labels (which are normally visible in the whole function and which may be used before being declared/defined) it has the disadvantage of: *) inhibiting the detecting of misuses once an inner scope is closed *) allowing several distinct labels with the same name in a single function (this can be regarded as a feature but __label__ at block scope should be used for this) *) create diffrences about what is permssble or not between sparse and GCC or clang.
Diffstat (limited to 'validation')
-rw-r--r--validation/__func__-scope.c8
-rw-r--r--validation/asm-goto-labels.c (renamed from validation/asm-goto-lables.c)0
-rw-r--r--validation/label-asm.c1
-rw-r--r--validation/label-attr.c2
-rw-r--r--validation/label-scope-cgoto.c82
-rw-r--r--validation/label-scope.c5
-rw-r--r--validation/label-scope1.c42
-rw-r--r--validation/label-scope2.c31
-rw-r--r--validation/label-stmt-expr0.c38
-rw-r--r--validation/label-stmt-expr1.c28
-rw-r--r--validation/label-stmt-expr2.c46
-rw-r--r--validation/label-unused.c29
-rw-r--r--validation/linear/goto-invalid.c18
-rw-r--r--validation/linear/goto-stmt-expr-conditional.c27
-rw-r--r--validation/linear/goto-stmt-expr-short-circuit.c31
-rw-r--r--validation/linear/label-scope-cgoto.c10
-rw-r--r--validation/linear/label-stmt-dropped.c (renamed from validation/discarded-label-statement.c)4
-rw-r--r--validation/linear/label-stmt-expr0.c (renamed from validation/label-expr.c)4
-rw-r--r--validation/linear/label-unreachable.c (renamed from validation/linear/unreachable-label0.c)3
-rw-r--r--validation/nested-functions.c43
-rw-r--r--validation/typeof-safe.c27
21 files changed, 463 insertions, 16 deletions
diff --git a/validation/__func__-scope.c b/validation/__func__-scope.c
new file mode 100644
index 00000000..508a8b91
--- /dev/null
+++ b/validation/__func__-scope.c
@@ -0,0 +1,8 @@
+static void foo(void)
+{
+ const char *name = ({ __func__; });
+}
+/*
+ * check-name: __func__'s scope
+ * check-command: sparse -Wall $file
+ */
diff --git a/validation/asm-goto-lables.c b/validation/asm-goto-labels.c
index ac2bf2ad..ac2bf2ad 100644
--- a/validation/asm-goto-lables.c
+++ b/validation/asm-goto-labels.c
diff --git a/validation/label-asm.c b/validation/label-asm.c
index 411020ac..b58d1e52 100644
--- a/validation/label-asm.c
+++ b/validation/label-asm.c
@@ -3,6 +3,7 @@
static void f(void)
{
barrier();
+ goto l;
l:
barrier();
}
diff --git a/validation/label-attr.c b/validation/label-attr.c
index a82d7bc9..81c4ac3c 100644
--- a/validation/label-attr.c
+++ b/validation/label-attr.c
@@ -1,6 +1,6 @@
static int foo(void)
{
- return 0;
+ goto rtattr_failure;
rtattr_failure: __attribute__ ((unused))
return -1;
}
diff --git a/validation/label-scope-cgoto.c b/validation/label-scope-cgoto.c
new file mode 100644
index 00000000..1edb9948
--- /dev/null
+++ b/validation/label-scope-cgoto.c
@@ -0,0 +1,82 @@
+void foo(void)
+{
+ void *p = &&l;
+ {
+l: ;
+ }
+ goto *p; // OK
+}
+
+void bar(void)
+{
+ void *p = &&l; // KO: 'jump' inside
+ ({
+l: 1;
+ });
+ goto *p;
+}
+
+void baz(void)
+{
+ void *p = &&l; // KO: 'jump' inside
+ 0 ? 1 : ({
+l: 1;
+ });
+ goto *p;
+}
+
+void qux(void)
+{
+ void *p = &&l; // KO: 'jump' inside + removed
+ 1 ? 1 : ({
+l: 1;
+ });
+ goto *p;
+}
+
+void quz(void)
+{
+ void *p;
+ p = &&l; // KO: undeclared
+ goto *p;
+}
+
+void qxu(void)
+{
+ void *p;
+ ({
+l: 1;
+ });
+ p = &&l; // KO: 'jump' inside
+ goto *p;
+}
+
+void qzu(void)
+{
+ void *p;
+ 1 ? 1 : ({
+l: 1;
+ });
+ p = &&l; // KO: 'jump' inside + removed
+ goto *p;
+}
+
+
+/*
+ * check-name: label-scope-cgoto
+ * check-command: sparse -Wno-decl $file
+ *
+ * check-error-start
+label-scope-cgoto.c:12:19: error: label 'l' used outside statement expression
+label-scope-cgoto.c:14:1: label 'l' defined here
+label-scope-cgoto.c:21:19: error: label 'l' used outside statement expression
+label-scope-cgoto.c:23:1: label 'l' defined here
+label-scope-cgoto.c:30:19: error: label 'l' used outside statement expression
+label-scope-cgoto.c:32:1: label 'l' defined here
+label-scope-cgoto.c:50:13: error: label 'l' used outside statement expression
+label-scope-cgoto.c:48:1: label 'l' defined here
+label-scope-cgoto.c:60:13: error: label 'l' used outside statement expression
+label-scope-cgoto.c:58:1: label 'l' defined here
+label-scope-cgoto.c:40:13: error: label 'l' was not declared
+ * check-error-end
+ */
diff --git a/validation/label-scope.c b/validation/label-scope.c
index 7af3d916..0ffaaf4a 100644
--- a/validation/label-scope.c
+++ b/validation/label-scope.c
@@ -3,10 +3,7 @@ static int f(int n)
__label__ n;
n: return n;
}
-static int g(int n)
-{
-n: return n;
-}
+
/*
* check-name: __label__ scope
*/
diff --git a/validation/label-scope1.c b/validation/label-scope1.c
new file mode 100644
index 00000000..f2b1ae9b
--- /dev/null
+++ b/validation/label-scope1.c
@@ -0,0 +1,42 @@
+static void ok_top(void)
+{
+ __label__ l;
+l:
+ goto l;
+}
+
+static void ko_undecl(void)
+{
+ __label__ l;
+ goto l; // KO: undeclared
+}
+
+static void ok_local(void)
+{
+l:
+ {
+ __label__ l;
+l:
+ goto l;
+ }
+goto l;
+}
+
+static void ko_scope(void)
+{
+ {
+ __label__ l;
+l:
+ goto l;
+ }
+goto l; // KO: undeclared
+}
+
+/*
+ * check-name: label-scope1
+ *
+ * check-error-start
+label-scope1.c:11:9: error: label 'l' was not declared
+label-scope1.c:32:1: error: label 'l' was not declared
+ * check-error-end
+ */
diff --git a/validation/label-scope2.c b/validation/label-scope2.c
new file mode 100644
index 00000000..44864752
--- /dev/null
+++ b/validation/label-scope2.c
@@ -0,0 +1,31 @@
+static void ok_lvl2(void)
+{
+ __label__ l;
+
+ {
+ l:
+ goto l;
+ }
+}
+
+static void ko_expr2(void)
+{
+ {
+ __label__ a;
+
+ ({
+a:
+ 0;
+ });
+ goto a;
+ }
+}
+
+/*
+ * check-name: label-scope2
+ *
+ * check-error-start
+label-scope2.c:20:17: error: label 'a' used outside statement expression
+label-scope2.c:17:1: label 'a' defined here
+ * check-error-end
+ */
diff --git a/validation/label-stmt-expr0.c b/validation/label-stmt-expr0.c
new file mode 100644
index 00000000..5fc452ab
--- /dev/null
+++ b/validation/label-stmt-expr0.c
@@ -0,0 +1,38 @@
+void aft(void)
+{
+ ({
+l: 1;
+ });
+ goto l; // KO
+}
+
+void bef(void)
+{
+ goto l; // KO
+ ({
+l: 1;
+ });
+}
+
+void lab(void)
+{
+ __label__ l;
+ ({
+l: 1;
+ });
+ goto l; // KO
+}
+
+/*
+ * check-name: label-stmt-expr0
+ * check-command: sparse -Wno-decl $file
+ *
+ * check-error-start
+label-stmt-expr0.c:6:9: error: label 'l' used outside statement expression
+label-stmt-expr0.c:4:1: label 'l' defined here
+label-stmt-expr0.c:11:9: error: label 'l' used outside statement expression
+label-stmt-expr0.c:13:1: label 'l' defined here
+label-stmt-expr0.c:23:9: error: label 'l' used outside statement expression
+label-stmt-expr0.c:21:1: label 'l' defined here
+ * check-error-end
+ */
diff --git a/validation/label-stmt-expr1.c b/validation/label-stmt-expr1.c
new file mode 100644
index 00000000..32a89aad
--- /dev/null
+++ b/validation/label-stmt-expr1.c
@@ -0,0 +1,28 @@
+static int foo(void)
+{
+ goto l;
+ ({
+l:
+ 0;
+ });
+}
+
+static void bar(void)
+{
+ ({
+l:
+ 0;
+ });
+ goto l;
+}
+
+/*
+ * check-name: label-stmt-expr1
+ *
+ * check-error-start
+label-stmt-expr1.c:3:9: error: label 'l' used outside statement expression
+label-stmt-expr1.c:5:1: label 'l' defined here
+label-stmt-expr1.c:16:9: error: label 'l' used outside statement expression
+label-stmt-expr1.c:13:1: label 'l' defined here
+ * check-error-end
+ */
diff --git a/validation/label-stmt-expr2.c b/validation/label-stmt-expr2.c
new file mode 100644
index 00000000..8c54477a
--- /dev/null
+++ b/validation/label-stmt-expr2.c
@@ -0,0 +1,46 @@
+static int foo(void)
+{
+ goto l;
+ ({
+l:
+ 0;
+ });
+ goto l;
+}
+
+static void bar(void)
+{
+ goto l;
+ goto l;
+ ({
+l:
+ 0;
+ });
+}
+
+static void baz(void)
+{
+ ({
+l:
+ 0;
+ });
+ goto l;
+ goto l;
+}
+
+/*
+ * check-name: label-stmt-expr2
+ *
+ * check-error-start
+label-stmt-expr2.c:3:9: error: label 'l' used outside statement expression
+label-stmt-expr2.c:5:1: label 'l' defined here
+label-stmt-expr2.c:8:9: error: label 'l' used outside statement expression
+label-stmt-expr2.c:5:1: label 'l' defined here
+label-stmt-expr2.c:13:9: error: label 'l' used outside statement expression
+label-stmt-expr2.c:16:1: label 'l' defined here
+label-stmt-expr2.c:27:9: error: label 'l' used outside statement expression
+label-stmt-expr2.c:24:1: label 'l' defined here
+label-stmt-expr2.c:28:9: error: label 'l' used outside statement expression
+label-stmt-expr2.c:24:1: label 'l' defined here
+ * check-error-end
+ */
diff --git a/validation/label-unused.c b/validation/label-unused.c
new file mode 100644
index 00000000..e3f255e1
--- /dev/null
+++ b/validation/label-unused.c
@@ -0,0 +1,29 @@
+static void foo(void)
+{
+l:
+ return;
+}
+
+static int bar(void)
+{
+ return ({
+l:
+ ;
+ 0;
+ });
+}
+
+static void baz(void)
+{
+l: __attribute__((unused));
+ return;
+}
+
+/*
+ * check-name: label-unused
+ *
+ * check-error-start
+label-unused.c:3:1: warning: unused label 'l'
+label-unused.c:10:1: warning: unused label 'l'
+ * check-error-end
+ */
diff --git a/validation/linear/goto-invalid.c b/validation/linear/goto-invalid.c
new file mode 100644
index 00000000..860b32a4
--- /dev/null
+++ b/validation/linear/goto-invalid.c
@@ -0,0 +1,18 @@
+static void foo(void)
+{
+ goto return;
+}
+
+void bar(void)
+{
+ goto neverland;
+}
+
+/*
+ * check-name: goto-invalid
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-error-ignore
+ * check-output-ignore
+ * check-output-excludes: END
+ */
diff --git a/validation/linear/goto-stmt-expr-conditional.c b/validation/linear/goto-stmt-expr-conditional.c
new file mode 100644
index 00000000..bbfcb3eb
--- /dev/null
+++ b/validation/linear/goto-stmt-expr-conditional.c
@@ -0,0 +1,27 @@
+int t(void)
+{
+ goto inside;
+ return 1 ? 2 : ({
+inside:
+ return 3;
+ 4;
+ });
+}
+
+void f(int x, int y)
+{
+ 1 ? x : ({
+a:
+ y;
+ });
+ goto a;
+}
+
+/*
+ * check-name: goto-stmt-expr-conditional
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-error-ignore
+ * check-output-ignore
+ * check-output-excludes: END
+ */
diff --git a/validation/linear/goto-stmt-expr-short-circuit.c b/validation/linear/goto-stmt-expr-short-circuit.c
new file mode 100644
index 00000000..a5953e73
--- /dev/null
+++ b/validation/linear/goto-stmt-expr-short-circuit.c
@@ -0,0 +1,31 @@
+int foo(int p)
+{
+ goto inside;
+ if (0 && ({
+inside:
+ return 1;
+ 2;
+ }))
+ return 3;
+ return 4;
+}
+
+int bar(int p)
+{
+ if (0 && ({
+inside:
+ return 1;
+ 2;
+ }))
+ return 3;
+ goto inside;
+}
+
+/*
+ * check-name: goto-stmt-expr-short-circuit
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-error-ignore
+ * check-output-ignore
+ * check-output-excludes: END
+ */
diff --git a/validation/linear/label-scope-cgoto.c b/validation/linear/label-scope-cgoto.c
new file mode 100644
index 00000000..0eba05ae
--- /dev/null
+++ b/validation/linear/label-scope-cgoto.c
@@ -0,0 +1,10 @@
+#include <label-scope-cgoto.c>
+
+/*
+ * check-name: linear/label-scope-cgoto
+ * check-command: test-linearize -Wno-decl -I. $file
+ *
+ * check-error-ignore
+ * check-output-ignore
+ * check-output-excludes: END
+ */
diff --git a/validation/discarded-label-statement.c b/validation/linear/label-stmt-dropped.c
index b4e58ac6..74e0f2e6 100644
--- a/validation/discarded-label-statement.c
+++ b/validation/linear/label-stmt-dropped.c
@@ -11,11 +11,13 @@ start:
r += a;
r += b;
+ if (!r)
+ goto start;
return r;
}
/*
- * check-name: discarded-label-statement
+ * check-name: label-stmt-dropped
* check-command: test-linearize $file
*
* check-output-ignore
diff --git a/validation/label-expr.c b/validation/linear/label-stmt-expr0.c
index e578ed00..ff3c0980 100644
--- a/validation/label-expr.c
+++ b/validation/linear/label-stmt-expr0.c
@@ -3,12 +3,12 @@ int foo(void)
{
int r;
- r = ({ label: 1; });
+ r = ({ goto label; label: 1; });
return r;
}
/*
- * check-name: label-expr
+ * check-name: label-stmt-expr0
* check-command: test-linearize $file
* check-output-ignore
*
diff --git a/validation/linear/unreachable-label0.c b/validation/linear/label-unreachable.c
index 695e5cb0..a44e1211 100644
--- a/validation/linear/unreachable-label0.c
+++ b/validation/linear/label-unreachable.c
@@ -10,9 +10,10 @@ label:
}
/*
- * check-name: unreachable-label0
+ * check-name: label-unreachable
* check-command: test-linearize $file
*
+ * check-error-ignore
* check-output-ignore
* check-output-contains: ret\\.
* check-output-excludes: END
diff --git a/validation/nested-functions.c b/validation/nested-functions.c
new file mode 100644
index 00000000..349edb5a
--- /dev/null
+++ b/validation/nested-functions.c
@@ -0,0 +1,43 @@
+static int test_ok(int a, int b)
+{
+ int nested_ok(int i)
+ {
+ return i * 2;
+ }
+ return nested_ok(b);
+}
+
+static int test_ko(int a, int b)
+{
+ int nested_ko(int i)
+ {
+ return i * 2 + a;
+ }
+ return nested_ko(b);
+}
+
+static int test_inline(int a, int b)
+{
+ inline int nested(int i)
+ {
+ return i * 2;
+ }
+ return nested(b);
+}
+
+static int test_inline_ko(int a, int b)
+{
+ inline int nested(int i)
+ {
+ return i * 2 + a;
+ }
+ return nested(b);
+}
+
+/*
+ * check-name: nested-functions
+ *
+ * check-error-start
+nested-functions.c:32:32: warning: unreplaced symbol 'a'
+ * check-error-end
+ */
diff --git a/validation/typeof-safe.c b/validation/typeof-safe.c
index 614863fb..797c759f 100644
--- a/validation/typeof-safe.c
+++ b/validation/typeof-safe.c
@@ -2,22 +2,35 @@
static void test_safe(void)
{
- int __safe obj, *ptr;
- typeof(obj) var = obj;
- typeof(ptr) ptr2 = ptr;
+ int obj;
+ int __safe *ptr;
+
+ int __safe *ptr2 = ptr;
+ typeof(ptr) ptr3 = ptr;
typeof(*ptr) var2 = obj;
- typeof(*ptr) *ptr3 = ptr;
- typeof(obj) *ptr4 = ptr;
+ int __safe var3 = obj;
+ int *ptr4 = &obj;
+ int *ptr5 = ptr; // KO
+
+ typeof(*ptr) sobj;
+ typeof(&sobj) ptr6 = &obj;
+ typeof(&sobj) ptr7 = ptr; // KO
+
obj = obj;
ptr = ptr;
- ptr = &obj;
obj = *ptr;
+ ptr = (int __safe *) &obj;
}
/*
* check-name: typeof-safe
- * check-known-to-fail
*
* check-error-start
+typeof-safe.c:13:21: warning: incorrect type in initializer (different modifiers)
+typeof-safe.c:13:21: expected int *ptr5
+typeof-safe.c:13:21: got int [safe] *ptr
+typeof-safe.c:17:30: warning: incorrect type in initializer (different modifiers)
+typeof-safe.c:17:30: expected int *ptr7
+typeof-safe.c:17:30: got int [safe] *ptr
* check-error-end
*/