Skip to content

Commit 241994d

Browse files
Merge pull request #1107 from zlaski-semmle/cpp355
Updated query to look for Microsoft-specific '_alloca' and '_malloca' Merge to Semmle/ql:master.
2 parents b211a54 + 09e729f commit 241994d

File tree

8 files changed

+417
-4
lines changed

8 files changed

+417
-4
lines changed

cpp/ql/src/Likely Bugs/Memory Management/AllocaInLoop.ql

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* correctness
99
* external/cwe/cwe-770
1010
*/
11+
1112
import cpp
1213

1314
Loop getAnEnclosingLoopOfExpr(Expr e) {
@@ -21,7 +22,15 @@ Loop getAnEnclosingLoopOfStmt(Stmt s) {
2122
}
2223

2324
from Loop l, FunctionCall fc
24-
where getAnEnclosingLoopOfExpr(fc) = l
25-
and fc.getTarget().getName() = "__builtin_alloca"
26-
and not l.(DoStmt).getCondition().getValue() = "0"
27-
select fc, "Stack allocation is inside a $@ and could lead to overflow.", l, l.toString()
25+
where
26+
getAnEnclosingLoopOfExpr(fc) = l and
27+
(
28+
fc.getTarget().getName() = "__builtin_alloca"
29+
or
30+
(
31+
(fc.getTarget().getName() = "_alloca" or fc.getTarget().getName() = "_malloca") and
32+
fc.getTarget().getADeclarationEntry().getFile().getBaseName() = "malloc.h"
33+
)
34+
) and
35+
not l.(DoStmt).getCondition().getValue() = "0"
36+
select fc, "Stack allocation is inside a $@ and could lead to stack overflow.", l, l.toString()
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
| AllocaInLoop1.cpp:31:18:31:23 | call to __builtin_alloca | Stack allocation is inside a $@ and could lead to stack overflow. | AllocaInLoop1.cpp:22:2:39:2 | for(...;...;...) ... | for(...;...;...) ... |
2+
| AllocaInLoop1.cpp:55:19:55:24 | call to __builtin_alloca | Stack allocation is inside a $@ and could lead to stack overflow. | AllocaInLoop1.cpp:45:2:64:2 | for(...;...;...) ... | for(...;...;...) ... |
3+
| AllocaInLoop1.cpp:80:19:80:24 | call to __builtin_alloca | Stack allocation is inside a $@ and could lead to stack overflow. | AllocaInLoop1.cpp:71:3:88:3 | for(...;...;...) ... | for(...;...;...) ... |
4+
| AllocaInLoop1ms.cpp:28:18:28:24 | call to _alloca | Stack allocation is inside a $@ and could lead to stack overflow. | AllocaInLoop1ms.cpp:19:2:36:2 | for(...;...;...) ... | for(...;...;...) ... |
5+
| AllocaInLoop1ms.cpp:52:19:52:26 | call to _malloca | Stack allocation is inside a $@ and could lead to stack overflow. | AllocaInLoop1ms.cpp:42:2:63:2 | for(...;...;...) ... | for(...;...;...) ... |
6+
| AllocaInLoop1ms.cpp:79:19:79:25 | call to _alloca | Stack allocation is inside a $@ and could lead to stack overflow. | AllocaInLoop1ms.cpp:70:3:87:3 | for(...;...;...) ... | for(...;...;...) ... |
7+
| AllocaInLoop2.c:39:30:39:35 | call to __builtin_alloca | Stack allocation is inside a $@ and could lead to stack overflow. | AllocaInLoop2.c:29:5:48:19 | do (...) ... | do (...) ... |
8+
| AllocaInLoop3.cpp:45:23:45:28 | call to __builtin_alloca | Stack allocation is inside a $@ and could lead to stack overflow. | AllocaInLoop3.cpp:43:2:49:19 | do (...) ... | do (...) ... |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Likely Bugs/Memory Management/AllocaInLoop.ql
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// semmle-extractor-options: --clang
2+
struct vtype {
3+
int i1, i2;
4+
};
5+
extern int w1, w2;
6+
7+
#ifdef _MSC_VER
8+
#define restrict __restrict
9+
#else
10+
#define restrict __restrict__
11+
#endif
12+
13+
void *__builtin_alloca(unsigned long sz);
14+
#define alloca __builtin_alloca
15+
typedef unsigned long long size_t;
16+
17+
int printf(const char *restrict format, ...);
18+
void *memcpy(void *restrict s1, const void *restrict s2, size_t n);
19+
20+
// case 1: alloca directly contained in an unbounded loop
21+
void foo(const struct vtype* vec, int count) {
22+
for (int i = 0; i < count; i++) {
23+
const vtype* v = vec + i;
24+
char *b1 = 0;
25+
if (b1 == nullptr) {
26+
if (w1 > w2) {
27+
// Allocate the buffer on heap
28+
b1 = new char[w1];
29+
} else {
30+
// Allocate the buffer on stack
31+
b1 = (char*) alloca(w1); // BAD
32+
}
33+
}
34+
memcpy(b1, v, w1);
35+
printf("%s\n", b1);
36+
if (w1 > w2) {
37+
delete b1;
38+
}
39+
}
40+
}
41+
42+
// case 2: alloca contained in a do-while(0) that is in turn contained
43+
// in an unbounded loop
44+
void bar(const struct vtype* vec, int count) {
45+
for (int i = 0; i < count; i++) {
46+
const vtype* v = vec + i;
47+
char *b1 = 0;
48+
do {
49+
if (b1 == nullptr) {
50+
if (w1 > w2) {
51+
// Allocate the buffer on heap
52+
b1 = new char[w1];
53+
} else {
54+
// Allocate the buffer on stack
55+
b1 = (char*) alloca(w1); // BAD
56+
}
57+
}
58+
} while (0);
59+
memcpy(b1, v, w1);
60+
printf("%s\n", b1);
61+
if (w1 > w2) {
62+
delete b1;
63+
}
64+
}
65+
}
66+
67+
// case 3: alloca contained in an unbounded loop that is in turn contained
68+
// in a do-while(0)
69+
void baz(const struct vtype* vec, int count) {
70+
do {
71+
for (int i = 0; i < count; i++) {
72+
const vtype* v = vec + i;
73+
char *b1 = 0;
74+
if (b1 == nullptr) {
75+
if (w1 > w2) {
76+
// Allocate the buffer on heap
77+
b1 = new char[w1];
78+
} else {
79+
// Allocate the buffer on stack
80+
b1 = (char*) alloca(w1); // BAD
81+
}
82+
}
83+
memcpy(b1, v, w1);
84+
printf("%s\n", b1);
85+
if (w1 > w2) {
86+
delete b1;
87+
}
88+
}
89+
} while (0);
90+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// semmle-extractor-options: --clang
2+
#include "malloc.h"
3+
struct vtype {
4+
int i1, i2;
5+
};
6+
extern int w1, w2;
7+
8+
#ifdef _MSC_VER
9+
#define restrict __restrict
10+
#else
11+
#define restrict __restrict__
12+
#endif
13+
14+
int printf(const char *restrict format, ...);
15+
void *memcpy(void *restrict s1, const void *restrict s2, size_t n);
16+
17+
// case 1: _alloca directly contained in an unbounded loop
18+
void foo(const struct vtype* vec, int count) {
19+
for (int i = 0; i < count; i++) {
20+
const vtype* v = vec + i;
21+
char *b1 = 0;
22+
if (b1 == nullptr) {
23+
if (w1 > w2) {
24+
// Allocate the buffer on heap
25+
b1 = new char[w1];
26+
} else {
27+
// Allocate the buffer on stack
28+
b1 = (char*) _alloca(w1); // BAD
29+
}
30+
}
31+
memcpy(b1, v, w1);
32+
printf("%s\n", b1);
33+
if (w1 > w2) {
34+
delete b1;
35+
}
36+
}
37+
}
38+
39+
// case 2: _malloca contained in a do-while(0) that is in turn contained
40+
// in an unbounded loop
41+
void bar(const struct vtype* vec, int count) {
42+
for (int i = 0; i < count; i++) {
43+
const vtype* v = vec + i;
44+
char *b1 = 0;
45+
do {
46+
if (b1 == nullptr) {
47+
if (w1 > w2) {
48+
// Allocate the buffer on heap
49+
b1 = new char[w1];
50+
} else {
51+
// Allocate the buffer on stack
52+
b1 = (char*) _malloca(w1); // BAD
53+
}
54+
}
55+
} while (0);
56+
memcpy(b1, v, w1);
57+
printf("%s\n", b1);
58+
if (w1 > w2) {
59+
delete b1;
60+
} else {
61+
_freea(b1);
62+
}
63+
}
64+
}
65+
66+
// case 3: _alloca contained in an unbounded loop that is in turn contained
67+
// in a do-while(0)
68+
void baz(const struct vtype* vec, int count) {
69+
do {
70+
for (int i = 0; i < count; i++) {
71+
const vtype* v = vec + i;
72+
char *b1 = 0;
73+
if (b1 == nullptr) {
74+
if (w1 > w2) {
75+
// Allocate the buffer on heap
76+
b1 = new char[w1];
77+
} else {
78+
// Allocate the buffer on stack
79+
b1 = (char*) _alloca(w1); // BAD
80+
}
81+
}
82+
memcpy(b1, v, w1);
83+
printf("%s\n", b1);
84+
if (w1 > w2) {
85+
delete b1;
86+
}
87+
}
88+
} while (0);
89+
}
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
// semmle-extractor-options: --clang
2+
int printf(const char *restrict format, ...);
3+
int sprintf(char *restrict s, const char *restrict format, ...);
4+
typedef unsigned long long size_t;
5+
void *memcpy(void *restrict s1, const void *restrict s2, size_t n);
6+
void *malloc(size_t size);
7+
void free(void *ptr);
8+
9+
struct vtype { int i1, i2; };
10+
extern int w1, w2;
11+
12+
void *_builtin_alloca(unsigned long sz);
13+
#define alloca __builtin_alloca
14+
15+
// We forward-declare the Microsoft routines
16+
//_alloca and _malloca here. Since they do not
17+
// originate from the <malloc.h> header, they
18+
// should not be flagged by our queries
19+
void *_alloca(size_t sz);
20+
void *_malloca(size_t sz);
21+
void _freea(void *ptr);
22+
23+
#define NULL (void *)0
24+
25+
// case 1: alloca called within a provably infinite loop
26+
void foo(const struct vtype* vec, int count) {
27+
char iter;
28+
29+
do {
30+
const struct vtype* v = vec + 2;
31+
char *b1 = 0;
32+
iter = 0;
33+
if (b1 == NULL) {
34+
if (w1 > w2) {
35+
// Allocate the buffer on heap
36+
b1 = (char *)malloc(w1);
37+
} else {
38+
// Allocate the buffer on stack
39+
b1 = (char*) alloca(w1); // BAD
40+
iter = 1;
41+
}
42+
}
43+
memcpy(b1, v, w1);
44+
printf("%s\n", b1);
45+
if (w1 > w2) {
46+
free(b1);
47+
}
48+
} while (iter);
49+
}
50+
51+
// case 2: alloca called within nested do-while(0) loops
52+
void bar(const struct vtype* vec, int count) {
53+
54+
do {
55+
const struct vtype* v = vec + 2;
56+
char *b1 = 0;
57+
do {
58+
if (b1 == NULL) {
59+
if (w1 > w2) {
60+
// Allocate the buffer on heap
61+
b1 = (char *)malloc(w1);
62+
} else {
63+
// Allocate the buffer on stack
64+
b1 = (char*) alloca(w1); // GOOD
65+
}
66+
}
67+
} while (0);
68+
memcpy(b1, v, w1);
69+
printf("%s\n", b1);
70+
if (w1 > w2) {
71+
free(b1);
72+
}
73+
} while (0);
74+
}
75+
76+
// case 3: alloca called outside any loops
77+
void baz(int count) {
78+
79+
char *buf = (char *)alloca(32); // GOOD
80+
sprintf(buf, "Value is %d\n", count);
81+
printf("%s", buf);
82+
}
83+
84+
////// Negative Microsoft test cases
85+
86+
// case 4: _alloca directly contained in an unbounded loop
87+
void foo_ms(const struct vtype* vec, int count) {
88+
for (int i = 0; i < count; i++) {
89+
const struct vtype* v = vec + i;
90+
char *b1 = 0;
91+
if (b1 == NULL) {
92+
if (w1 > w2) {
93+
// Allocate the buffer on heap
94+
(char *)malloc(w1);
95+
} else {
96+
// Allocate the buffer on stack
97+
b1 = (char*) _alloca(w1); // GOOD
98+
}
99+
}
100+
memcpy(b1, v, w1);
101+
printf("%s\n", b1);
102+
if (w1 > w2) {
103+
free(b1);
104+
}
105+
}
106+
}
107+
108+
// case 5: _malloca contained in a do-while(0) that is in turn contained
109+
// in an unbounded loop
110+
void bar_ms(const struct vtype* vec, int count) {
111+
for (int i = 0; i < count; i++) {
112+
const struct vtype* v = vec + i;
113+
char *b1 = 0;
114+
do {
115+
if (b1 == NULL) {
116+
if (w1 > w2) {
117+
// Allocate the buffer on heap
118+
b1 = (char *)malloc(w1);
119+
} else {
120+
// Allocate the buffer on stack
121+
b1 = (char*) _malloca(w1); // GOOD
122+
}
123+
}
124+
} while (0);
125+
memcpy(b1, v, w1);
126+
printf("%s\n", b1);
127+
if (w1 > w2) {
128+
free(b1);
129+
} else {
130+
_freea(b1);
131+
}
132+
}
133+
}
134+
135+
// case 6: _alloca contained in an unbounded loop that is in turn contained
136+
// in a do-while(0)
137+
void baz_ms(const struct vtype* vec, int count) {
138+
do {
139+
for (int i = 0; i < count; i++) {
140+
const struct vtype* v = vec + i;
141+
char *b1 = 0;
142+
if (b1 == NULL) {
143+
if (w1 > w2) {
144+
// Allocate the buffer on heap
145+
b1 = (char *)malloc(w1);
146+
} else {
147+
// Allocate the buffer on stack
148+
b1 = (char*) _alloca(w1); // GOOD
149+
}
150+
}
151+
memcpy(b1, v, w1);
152+
printf("%s\n", b1);
153+
if (w1 > w2) {
154+
free(b1);
155+
}
156+
}
157+
} while (0);
158+
}

0 commit comments

Comments
 (0)