2010-01-24 04:12:18 +08:00
|
|
|
// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -std=gnu99 %s -Wno-unreachable-code
|
Start of checking for gotos which jump to an illegal destination.
As far as I know, this catches all cases of jumping into the scope of a
variable with a variably modified type (excluding statement
expressions) in C. This is missing some stuff we probably want to check
(other kinds of variably modified declarations, statement expressions,
indirect gotos/addresses of labels in a scope, ObjC @try/@finally, cleanup
attribute), the diagnostics aren't very good, and it's not particularly
efficient, but it's a decent start.
This patch is a slightly modified version of the patch I attached to
PR3259, and it fixes that bug. I was sort of planning on improving
it, but I think it's okay as-is, especially since it looks like CodeGen
doesn't have any use for this sort of data structure. The only
significant change I can think of from the version I attached to PR3259
is that this version skips running the checking code when a function
doesn't contain any labels.
This patch doesn't cover case statements, which also need similar
checking; I'm not sure how we should deal with that. Extending the goto
checking to also check case statements wouldn't be too hard; it's just a
matter of keeping track of the scope of the closest switch and checking that
the scope of every case is the same as the scope of the switch. That said,
it would likely be a performance hit to run this check on every
function (it's an extra pass over the entire function), so we probably want
some other solution.
llvm-svn: 65678
2009-02-28 13:41:13 +08:00
|
|
|
|
|
|
|
int test1(int x) {
|
2010-08-03 07:33:14 +08:00
|
|
|
goto L; // expected-error{{goto into protected scope}}
|
2009-04-19 02:42:55 +08:00
|
|
|
int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
|
|
|
|
int b[x]; // expected-note {{jump bypasses initialization of variable length array}}
|
Start of checking for gotos which jump to an illegal destination.
As far as I know, this catches all cases of jumping into the scope of a
variable with a variably modified type (excluding statement
expressions) in C. This is missing some stuff we probably want to check
(other kinds of variably modified declarations, statement expressions,
indirect gotos/addresses of labels in a scope, ObjC @try/@finally, cleanup
attribute), the diagnostics aren't very good, and it's not particularly
efficient, but it's a decent start.
This patch is a slightly modified version of the patch I attached to
PR3259, and it fixes that bug. I was sort of planning on improving
it, but I think it's okay as-is, especially since it looks like CodeGen
doesn't have any use for this sort of data structure. The only
significant change I can think of from the version I attached to PR3259
is that this version skips running the checking code when a function
doesn't contain any labels.
This patch doesn't cover case statements, which also need similar
checking; I'm not sure how we should deal with that. Extending the goto
checking to also check case statements wouldn't be too hard; it's just a
matter of keeping track of the scope of the closest switch and checking that
the scope of every case is the same as the scope of the switch. That said,
it would likely be a performance hit to run this check on every
function (it's an extra pass over the entire function), so we probably want
some other solution.
llvm-svn: 65678
2009-02-28 13:41:13 +08:00
|
|
|
L:
|
|
|
|
return sizeof a;
|
|
|
|
}
|
2009-02-28 14:22:14 +08:00
|
|
|
|
|
|
|
int test2(int x) {
|
2010-08-03 07:33:14 +08:00
|
|
|
goto L; // expected-error{{goto into protected scope}}
|
2009-04-19 02:42:55 +08:00
|
|
|
typedef int a[x]; // expected-note {{jump bypasses initialization of VLA typedef}}
|
2009-02-28 14:22:14 +08:00
|
|
|
L:
|
|
|
|
return sizeof(a);
|
|
|
|
}
|
|
|
|
|
|
|
|
void test3clean(int*);
|
|
|
|
|
|
|
|
int test3() {
|
2010-08-03 07:33:14 +08:00
|
|
|
goto L; // expected-error{{goto into protected scope}}
|
2010-05-12 09:15:36 +08:00
|
|
|
int a __attribute((cleanup(test3clean))); // expected-note {{jump bypasses initialization of variable with __attribute__((cleanup))}}
|
2009-04-18 15:54:11 +08:00
|
|
|
L:
|
2009-02-28 14:22:14 +08:00
|
|
|
return a;
|
|
|
|
}
|
2009-04-16 00:58:41 +08:00
|
|
|
|
|
|
|
int test4(int x) {
|
2010-08-03 07:33:14 +08:00
|
|
|
goto L; // expected-error{{goto into protected scope}}
|
2009-04-19 02:42:55 +08:00
|
|
|
int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
|
2009-04-18 15:54:11 +08:00
|
|
|
test4(x);
|
|
|
|
L:
|
|
|
|
return sizeof a;
|
2009-04-16 00:58:41 +08:00
|
|
|
}
|
2009-04-18 15:54:11 +08:00
|
|
|
|
|
|
|
int test5(int x) {
|
|
|
|
int a[x];
|
|
|
|
test5(x);
|
|
|
|
goto L; // Ok.
|
|
|
|
L:
|
|
|
|
goto L; // Ok.
|
|
|
|
return sizeof a;
|
|
|
|
}
|
|
|
|
|
2009-04-18 17:36:27 +08:00
|
|
|
int test6() {
|
|
|
|
// just plain invalid.
|
|
|
|
goto x; // expected-error {{use of undeclared label 'x'}}
|
|
|
|
}
|
|
|
|
|
2009-04-19 03:42:37 +08:00
|
|
|
void test7(int x) {
|
2009-04-19 03:50:02 +08:00
|
|
|
switch (x) {
|
2009-04-19 03:42:37 +08:00
|
|
|
case 1: ;
|
|
|
|
int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
|
2010-08-03 07:33:14 +08:00
|
|
|
case 2: // expected-error {{switch case is in protected scope}}
|
2009-04-19 03:42:37 +08:00
|
|
|
a[1] = 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-19 06:42:18 +08:00
|
|
|
int test8(int x) {
|
2009-04-19 06:56:52 +08:00
|
|
|
// For statement.
|
2010-08-03 07:33:14 +08:00
|
|
|
goto L2; // expected-error {{goto into protected scope}}
|
2009-04-19 06:42:18 +08:00
|
|
|
for (int arr[x]; // expected-note {{jump bypasses initialization of variable length array}}
|
2009-04-19 06:56:52 +08:00
|
|
|
; ++x)
|
2009-04-19 07:07:55 +08:00
|
|
|
L2:;
|
2009-04-19 06:56:52 +08:00
|
|
|
|
|
|
|
// Statement expressions.
|
2010-08-03 07:33:14 +08:00
|
|
|
goto L3; // expected-error {{goto into protected scope}}
|
2009-04-19 06:56:52 +08:00
|
|
|
int Y = ({ int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
|
|
|
|
L3: 4; });
|
2009-04-19 06:42:18 +08:00
|
|
|
|
2010-08-03 07:33:14 +08:00
|
|
|
goto L4; // expected-error {{goto into protected scope}}
|
2009-04-19 07:01:20 +08:00
|
|
|
{
|
|
|
|
int A[x], // expected-note {{jump bypasses initialization of variable length array}}
|
|
|
|
B[x]; // expected-note {{jump bypasses initialization of variable length array}}
|
|
|
|
L4: ;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
L5: ;// ok
|
|
|
|
int A[x], B = ({ if (x)
|
|
|
|
goto L5;
|
|
|
|
else
|
|
|
|
goto L6;
|
|
|
|
4; });
|
|
|
|
L6:; // ok.
|
2009-04-19 09:05:26 +08:00
|
|
|
if (x) goto L6; // ok
|
2009-04-19 07:01:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
L7: ;// ok
|
|
|
|
int A[x], B = ({ if (x)
|
|
|
|
goto L7;
|
|
|
|
else
|
2010-08-03 07:33:14 +08:00
|
|
|
goto L8; // expected-error {{goto into protected scope}}
|
2009-04-19 07:01:20 +08:00
|
|
|
4; }),
|
|
|
|
C[x]; // expected-note {{jump bypasses initialization of variable length array}}
|
|
|
|
L8:; // bad
|
|
|
|
}
|
|
|
|
|
2009-04-19 07:07:55 +08:00
|
|
|
{
|
|
|
|
L9: ;// ok
|
|
|
|
int A[({ if (x)
|
|
|
|
goto L9;
|
|
|
|
else
|
|
|
|
// FIXME:
|
2010-08-03 07:33:14 +08:00
|
|
|
goto L10; // fixme-error {{goto into protected scope}}
|
2009-04-19 07:07:55 +08:00
|
|
|
4; })];
|
|
|
|
L10:; // bad
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// FIXME: Crashes goto checker.
|
|
|
|
//goto L11;// ok
|
|
|
|
//int A[({ L11: 4; })];
|
|
|
|
}
|
|
|
|
|
2009-04-19 09:05:26 +08:00
|
|
|
{
|
|
|
|
goto L12;
|
|
|
|
|
|
|
|
int y = 4; // fixme-warn: skips initializer.
|
|
|
|
L12:
|
|
|
|
;
|
|
|
|
}
|
2009-04-19 07:01:20 +08:00
|
|
|
|
2009-04-19 06:56:52 +08:00
|
|
|
// Statement expressions 2.
|
2010-08-03 07:33:14 +08:00
|
|
|
goto L1; // expected-error {{goto into protected scope}}
|
2009-04-19 06:42:18 +08:00
|
|
|
return x == ({
|
|
|
|
int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
|
2009-04-19 06:56:52 +08:00
|
|
|
L1:
|
2009-04-19 06:42:18 +08:00
|
|
|
42; });
|
|
|
|
}
|
2009-04-19 09:05:26 +08:00
|
|
|
|
|
|
|
void test9(int n, void *P) {
|
|
|
|
int Y;
|
|
|
|
int Z = 4;
|
2010-10-28 16:53:48 +08:00
|
|
|
goto *P; // expected-error {{indirect goto might cross protected scopes}}
|
2009-04-19 09:05:26 +08:00
|
|
|
|
|
|
|
L2: ;
|
2010-05-12 08:58:13 +08:00
|
|
|
int a[n]; // expected-note {{jump bypasses initialization of variable length array}}
|
2009-04-19 09:05:26 +08:00
|
|
|
|
2010-05-12 08:58:13 +08:00
|
|
|
L3: // expected-note {{possible target of indirect goto}}
|
2009-04-19 09:16:06 +08:00
|
|
|
L4:
|
2010-05-12 08:58:13 +08:00
|
|
|
goto *P;
|
2009-04-19 09:16:06 +08:00
|
|
|
goto L3; // ok
|
|
|
|
goto L4; // ok
|
2009-04-19 09:05:26 +08:00
|
|
|
|
|
|
|
void *Ptrs[] = {
|
2010-05-12 08:58:13 +08:00
|
|
|
&&L2,
|
|
|
|
&&L3
|
2009-04-19 09:05:26 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2009-04-19 12:48:07 +08:00
|
|
|
void test10(int n, void *P) {
|
2010-08-03 07:33:14 +08:00
|
|
|
goto L0; // expected-error {{goto into protected scope}}
|
2009-04-19 12:48:07 +08:00
|
|
|
typedef int A[n]; // expected-note {{jump bypasses initialization of VLA typedef}}
|
|
|
|
L0:
|
|
|
|
|
2010-08-03 07:33:14 +08:00
|
|
|
goto L1; // expected-error {{goto into protected scope}}
|
2009-04-19 12:48:07 +08:00
|
|
|
A b, c[10]; // expected-note 2 {{jump bypasses initialization of variable length array}}
|
|
|
|
L1:
|
2010-08-03 07:33:14 +08:00
|
|
|
goto L2; // expected-error {{goto into protected scope}}
|
2009-04-19 12:48:07 +08:00
|
|
|
A d[n]; // expected-note {{jump bypasses initialization of variable length array}}
|
|
|
|
L2:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-04-19 13:28:12 +08:00
|
|
|
void test11(int n) {
|
|
|
|
void *P = ^{
|
|
|
|
switch (n) {
|
|
|
|
case 1:;
|
|
|
|
case 2:
|
|
|
|
case 3:;
|
|
|
|
int Arr[n]; // expected-note {{jump bypasses initialization of variable length array}}
|
2010-08-03 07:33:14 +08:00
|
|
|
case 4: // expected-error {{switch case is in protected scope}}
|
2009-04-19 13:28:12 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2009-04-19 13:21:20 +08:00
|
|
|
|
2009-04-19 12:51:27 +08:00
|
|
|
// TODO: When and if gotos are allowed in blocks, this should work.
|
2009-04-19 13:28:12 +08:00
|
|
|
void test12(int n) {
|
2009-04-19 12:51:27 +08:00
|
|
|
void *P = ^{
|
2010-01-20 07:08:01 +08:00
|
|
|
goto L1;
|
2009-04-19 12:51:27 +08:00
|
|
|
L1:
|
2010-01-20 07:08:01 +08:00
|
|
|
goto L2;
|
2009-04-19 12:51:27 +08:00
|
|
|
L2:
|
2010-08-03 07:33:14 +08:00
|
|
|
goto L3; // expected-error {{goto into protected scope}}
|
2010-01-20 07:08:01 +08:00
|
|
|
int Arr[n]; // expected-note {{jump bypasses initialization of variable length array}}
|
2009-04-19 12:51:27 +08:00
|
|
|
L3:
|
2010-01-20 07:08:01 +08:00
|
|
|
goto L4;
|
2009-04-19 12:51:27 +08:00
|
|
|
L4: return;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2010-05-12 08:58:13 +08:00
|
|
|
void test13(int n, void *p) {
|
|
|
|
int vla[n];
|
|
|
|
goto *p;
|
|
|
|
a0: ;
|
|
|
|
static void *ps[] = { &&a0 };
|
|
|
|
}
|
2010-10-28 16:53:48 +08:00
|
|
|
|
|
|
|
int test14(int n) {
|
|
|
|
static void *ps[] = { &&a0, &&a1 };
|
|
|
|
if (n < 0)
|
|
|
|
goto *&&a0;
|
|
|
|
|
|
|
|
if (n > 0) {
|
|
|
|
int vla[n];
|
|
|
|
a1:
|
|
|
|
vla[n-1] = 0;
|
|
|
|
}
|
|
|
|
a0:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// PR8473: IR gen can't deal with indirect gotos past VLA
|
|
|
|
// initialization, so that really needs to be a hard error.
|
|
|
|
void test15(int n, void *pc) {
|
|
|
|
static const void *addrs[] = { &&L1, &&L2 };
|
|
|
|
|
|
|
|
goto *pc; // expected-error {{indirect goto might cross protected scope}}
|
|
|
|
|
|
|
|
L1:
|
|
|
|
{
|
|
|
|
char vla[n]; // expected-note {{jump bypasses initialization}}
|
|
|
|
L2: // expected-note {{possible target}}
|
|
|
|
vla[0] = 'a';
|
|
|
|
}
|
|
|
|
}
|
2011-02-19 05:16:39 +08:00
|
|
|
|
|
|
|
// rdar://9024687
|
|
|
|
int test16(int [sizeof &&z]); // expected-error {{use of address-of-label extension outside of a function body}}
|