C++: Add a query for detecting uses of expired stack pointers that escaped through global variables.

This commit is contained in:
Mathias Vorreiter Pedersen
2022-02-22 18:29:09 +00:00
parent 31d214d5ee
commit ea35f56212
9 changed files with 534 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
| test.cpp:15:16:15:16 | Load: p | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:9:7:9:7 | x | x | test.cpp:10:3:10:13 | Store: ... = ... | here |
| test.cpp:58:16:58:16 | Load: p | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:51:36:51:36 | x | x | test.cpp:52:3:52:13 | Store: ... = ... | here |
| test.cpp:73:16:73:16 | Load: p | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:62:7:62:7 | x | x | test.cpp:68:3:68:13 | Store: ... = ... | here |
| test.cpp:98:15:98:15 | Load: p | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:92:8:92:8 | s | s | test.cpp:93:3:93:15 | Store: ... = ... | here |
| test.cpp:111:16:111:16 | Load: p | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:102:7:102:7 | x | x | test.cpp:106:3:106:14 | Store: ... = ... | here |
| test.cpp:161:16:161:17 | Load: p1 | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:132:7:132:8 | b1 | b1 | test.cpp:136:3:136:12 | Store: ... = ... | here |
| test.cpp:162:16:162:17 | Load: p1 | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:132:7:132:8 | b1 | b1 | test.cpp:137:3:137:16 | Store: ... = ... | here |
| test.cpp:164:16:164:17 | Load: p2 | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:133:7:133:8 | b2 | b2 | test.cpp:139:3:139:12 | Store: ... = ... | here |
| test.cpp:165:16:165:17 | Load: p2 | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:133:7:133:8 | b2 | b2 | test.cpp:139:3:139:12 | Store: ... = ... | here |
| test.cpp:166:17:166:18 | Load: p2 | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:133:7:133:8 | b2 | b2 | test.cpp:140:3:140:16 | Store: ... = ... | here |
| test.cpp:167:16:167:17 | Load: p1 | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:133:7:133:8 | b2 | b2 | test.cpp:141:3:141:15 | Store: ... = ... | here |
| test.cpp:168:17:168:18 | Load: p1 | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:133:7:133:8 | b2 | b2 | test.cpp:142:3:142:19 | Store: ... = ... | here |
| test.cpp:170:16:170:17 | Load: p3 | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:134:7:134:8 | b3 | b3 | test.cpp:144:3:144:12 | Store: ... = ... | here |
| test.cpp:171:17:171:18 | Load: p3 | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:134:7:134:8 | b3 | b3 | test.cpp:145:3:145:16 | Store: ... = ... | here |
| test.cpp:172:18:172:19 | Load: p2 | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:134:7:134:8 | b3 | b3 | test.cpp:146:3:146:15 | Store: ... = ... | here |
| test.cpp:173:18:173:19 | Load: p2 | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:134:7:134:8 | b3 | b3 | test.cpp:147:3:147:19 | Store: ... = ... | here |
| test.cpp:174:18:174:19 | Load: p1 | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:133:7:133:8 | b2 | b2 | test.cpp:142:3:142:19 | Store: ... = ... | here |
| test.cpp:175:16:175:17 | Load: p1 | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:134:7:134:8 | b3 | b3 | test.cpp:148:3:148:18 | Store: ... = ... | here |
| test.cpp:177:14:177:21 | Load: access to array | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:132:7:132:8 | b1 | b1 | test.cpp:151:3:151:15 | Store: ... = ... | here |
| test.cpp:178:14:178:21 | Load: access to array | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:132:7:132:8 | b1 | b1 | test.cpp:152:3:152:19 | Store: ... = ... | here |
| test.cpp:179:14:179:21 | Load: access to array | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:133:7:133:8 | b2 | b2 | test.cpp:153:3:153:18 | Store: ... = ... | here |
| test.cpp:180:14:180:19 | Load: * ... | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:133:7:133:8 | b2 | b2 | test.cpp:154:3:154:22 | Store: ... = ... | here |
| test.cpp:181:13:181:20 | Load: access to array | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:134:7:134:8 | b3 | b3 | test.cpp:155:3:155:21 | Store: ... = ... | here |
| test.cpp:182:14:182:19 | Load: * ... | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:134:7:134:8 | b3 | b3 | test.cpp:156:3:156:25 | Store: ... = ... | here |

View File

@@ -0,0 +1 @@
Likely Bugs/Memory Management/UsingExpiredStackAddress.ql

View File

@@ -0,0 +1,183 @@
struct S100 {
int i;
int* p;
};
static struct S100 s101;
void escape1() {
int x;
s101.p = &x;
}
int simple_field_bad() {
escape1();
return *s101.p; // BAD
}
int simple_field_good() {
escape1();
return s101.i; // GOOD
}
int deref_p() {
return *s101.p;
}
int field_indirect_bad() {
escape1();
return deref_p(); // BAD [NOT DETECTED]
}
int deref_i() {
return s101.i;
}
int field_indirect_good() {
escape1();
return deref_i(); // GOOD
}
void store_argument(int *p) {
s101.p = p;
}
int store_argument_value() {
int x;
store_argument(&x);
return *s101.p; // GOOD
}
void store_address_of_argument(int x) {
s101.p = &x;
}
int store_argument_address() {
int x;
store_address_of_argument(x);
return *s101.p; // BAD
}
void address_escapes_through_pointer_arith() {
int x = 0;
int* p0 = &x;
int* p1 = p0 + 1;
int* p2 = p1 - 1;
int* p3 = 1 + p2;
p3++;
s101.p = p3;
}
int test_pointer_arith_bad() {
address_escapes_through_pointer_arith();
return *s101.p; // BAD
}
int test_pointer_arith_good_1() {
int x;
address_escapes_through_pointer_arith();
s101.p = &x;
return *s101.p; // GOOD [FALSE POSITIVE]
}
int test_pointer_arith_good_2(bool b) {
int x;
if(b) {
address_escapes_through_pointer_arith();
}
return *s101.p; // GOOD (we can't say for sure that this is a local address)
}
void field_address_escapes() {
S100 s;
s101.p = &s.i;
}
int test_field_address_escapes() {
field_address_escapes();
return s101.p[0]; // BAD
}
void escape_through_reference() {
int x = 0;
int& r0 = x;
int& r1 = r0;
r1++;
s101.p = &r1;
}
int test_escapes_through_reference() {
escape_through_reference();
return *s101.p; // BAD
}
struct S300 {
int a1[15];
int a2[14][15];
int a3[13][14][15];
int *p1;
int (*p2)[15];
int (*p3)[14][15];
int** pp;
};
S300 s1;
S300 s2;
S300 s3;
S300 s4;
S300 s5;
S300 s6;
void escape_through_arrays() {
int b1[15];
int b2[14][15];
int b3[13][14][15];
s1.p1 = b1;
s2.p1 = &b1[1];
s1.p2 = b2;
s2.p2 = &b2[1];
s3.p1 = b2[1];
s4.p1 = &b2[1][2];
s1.p3 = b3;
s2.p3 = &b3[1];
s3.p2 = b3[1];
s4.p2 = &b3[1][2];
s5.p1 = b3[1][2];
s6.p1 = &b3[1][2][3];
s1.pp[0] = b1;
s2.pp[0] = &b1[1];
s3.pp[0] = b2[1];
s4.pp[0] = &b2[1][2];
s5.pp[0] = b3[1][2];
s6.pp[0] = &b3[1][2][3];
}
void test_escape_through_arrays() {
escape_through_arrays();
int x1 = *s1.p1; // BAD
int x2 = *s2.p1; // BAD
int* x3 = s1.p2[1]; // BAD
int x4 = *s1.p2[1]; // BAD
int* x5 = *s2.p2; // BAD
int* x6 = s3.p1; // BAD
int x7 = *&s4.p1[1]; // BAD
int x8 = *s1.p3[1][2]; // BAD
int x9 = (*s2.p3[0])[0]; // BAD
int x10 = **s3.p2; // BAD
int x11 = **s4.p2; // BAD
int x12 = (*s4.p1); // BAD
int x13 = s5.p1[1]; // BAD
int* x14 = s1.pp[0]; // BAD
int x15 = *s2.pp[0]; // BAD
int x16 = *s3.pp[0]; // BAD
int x17 = **s4.pp; // BAD
int x18 = s5.pp[0][0]; // BAD
int x19 = (*s6.pp)[0]; // BAD
}