Merge pull request #1107 from zlaski-semmle/cpp355

Updated query to look for Microsoft-specific '_alloca' and '_malloca'
Merge to Semmle/ql:master.
This commit is contained in:
zlaski-semmle
2019-03-19 13:40:27 -07:00
committed by GitHub
8 changed files with 417 additions and 4 deletions

View File

@@ -0,0 +1,8 @@
| 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(...;...;...) ... |
| 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(...;...;...) ... |
| 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(...;...;...) ... |
| 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(...;...;...) ... |
| 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(...;...;...) ... |
| 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(...;...;...) ... |
| 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 (...) ... |
| 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 (...) ... |

View File

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

View File

@@ -0,0 +1,90 @@
// semmle-extractor-options: --clang
struct vtype {
int i1, i2;
};
extern int w1, w2;
#ifdef _MSC_VER
#define restrict __restrict
#else
#define restrict __restrict__
#endif
void *__builtin_alloca(unsigned long sz);
#define alloca __builtin_alloca
typedef unsigned long long size_t;
int printf(const char *restrict format, ...);
void *memcpy(void *restrict s1, const void *restrict s2, size_t n);
// case 1: alloca directly contained in an unbounded loop
void foo(const struct vtype* vec, int count) {
for (int i = 0; i < count; i++) {
const vtype* v = vec + i;
char *b1 = 0;
if (b1 == nullptr) {
if (w1 > w2) {
// Allocate the buffer on heap
b1 = new char[w1];
} else {
// Allocate the buffer on stack
b1 = (char*) alloca(w1); // BAD
}
}
memcpy(b1, v, w1);
printf("%s\n", b1);
if (w1 > w2) {
delete b1;
}
}
}
// case 2: alloca contained in a do-while(0) that is in turn contained
// in an unbounded loop
void bar(const struct vtype* vec, int count) {
for (int i = 0; i < count; i++) {
const vtype* v = vec + i;
char *b1 = 0;
do {
if (b1 == nullptr) {
if (w1 > w2) {
// Allocate the buffer on heap
b1 = new char[w1];
} else {
// Allocate the buffer on stack
b1 = (char*) alloca(w1); // BAD
}
}
} while (0);
memcpy(b1, v, w1);
printf("%s\n", b1);
if (w1 > w2) {
delete b1;
}
}
}
// case 3: alloca contained in an unbounded loop that is in turn contained
// in a do-while(0)
void baz(const struct vtype* vec, int count) {
do {
for (int i = 0; i < count; i++) {
const vtype* v = vec + i;
char *b1 = 0;
if (b1 == nullptr) {
if (w1 > w2) {
// Allocate the buffer on heap
b1 = new char[w1];
} else {
// Allocate the buffer on stack
b1 = (char*) alloca(w1); // BAD
}
}
memcpy(b1, v, w1);
printf("%s\n", b1);
if (w1 > w2) {
delete b1;
}
}
} while (0);
}

View File

@@ -0,0 +1,89 @@
// semmle-extractor-options: --clang
#include "malloc.h"
struct vtype {
int i1, i2;
};
extern int w1, w2;
#ifdef _MSC_VER
#define restrict __restrict
#else
#define restrict __restrict__
#endif
int printf(const char *restrict format, ...);
void *memcpy(void *restrict s1, const void *restrict s2, size_t n);
// case 1: _alloca directly contained in an unbounded loop
void foo(const struct vtype* vec, int count) {
for (int i = 0; i < count; i++) {
const vtype* v = vec + i;
char *b1 = 0;
if (b1 == nullptr) {
if (w1 > w2) {
// Allocate the buffer on heap
b1 = new char[w1];
} else {
// Allocate the buffer on stack
b1 = (char*) _alloca(w1); // BAD
}
}
memcpy(b1, v, w1);
printf("%s\n", b1);
if (w1 > w2) {
delete b1;
}
}
}
// case 2: _malloca contained in a do-while(0) that is in turn contained
// in an unbounded loop
void bar(const struct vtype* vec, int count) {
for (int i = 0; i < count; i++) {
const vtype* v = vec + i;
char *b1 = 0;
do {
if (b1 == nullptr) {
if (w1 > w2) {
// Allocate the buffer on heap
b1 = new char[w1];
} else {
// Allocate the buffer on stack
b1 = (char*) _malloca(w1); // BAD
}
}
} while (0);
memcpy(b1, v, w1);
printf("%s\n", b1);
if (w1 > w2) {
delete b1;
} else {
_freea(b1);
}
}
}
// case 3: _alloca contained in an unbounded loop that is in turn contained
// in a do-while(0)
void baz(const struct vtype* vec, int count) {
do {
for (int i = 0; i < count; i++) {
const vtype* v = vec + i;
char *b1 = 0;
if (b1 == nullptr) {
if (w1 > w2) {
// Allocate the buffer on heap
b1 = new char[w1];
} else {
// Allocate the buffer on stack
b1 = (char*) _alloca(w1); // BAD
}
}
memcpy(b1, v, w1);
printf("%s\n", b1);
if (w1 > w2) {
delete b1;
}
}
} while (0);
}

View File

@@ -0,0 +1,158 @@
// semmle-extractor-options: --clang
int printf(const char *restrict format, ...);
int sprintf(char *restrict s, const char *restrict format, ...);
typedef unsigned long long size_t;
void *memcpy(void *restrict s1, const void *restrict s2, size_t n);
void *malloc(size_t size);
void free(void *ptr);
struct vtype { int i1, i2; };
extern int w1, w2;
void *_builtin_alloca(unsigned long sz);
#define alloca __builtin_alloca
// We forward-declare the Microsoft routines
//_alloca and _malloca here. Since they do not
// originate from the <malloc.h> header, they
// should not be flagged by our queries
void *_alloca(size_t sz);
void *_malloca(size_t sz);
void _freea(void *ptr);
#define NULL (void *)0
// case 1: alloca called within a provably infinite loop
void foo(const struct vtype* vec, int count) {
char iter;
do {
const struct vtype* v = vec + 2;
char *b1 = 0;
iter = 0;
if (b1 == NULL) {
if (w1 > w2) {
// Allocate the buffer on heap
b1 = (char *)malloc(w1);
} else {
// Allocate the buffer on stack
b1 = (char*) alloca(w1); // BAD
iter = 1;
}
}
memcpy(b1, v, w1);
printf("%s\n", b1);
if (w1 > w2) {
free(b1);
}
} while (iter);
}
// case 2: alloca called within nested do-while(0) loops
void bar(const struct vtype* vec, int count) {
do {
const struct vtype* v = vec + 2;
char *b1 = 0;
do {
if (b1 == NULL) {
if (w1 > w2) {
// Allocate the buffer on heap
b1 = (char *)malloc(w1);
} else {
// Allocate the buffer on stack
b1 = (char*) alloca(w1); // GOOD
}
}
} while (0);
memcpy(b1, v, w1);
printf("%s\n", b1);
if (w1 > w2) {
free(b1);
}
} while (0);
}
// case 3: alloca called outside any loops
void baz(int count) {
char *buf = (char *)alloca(32); // GOOD
sprintf(buf, "Value is %d\n", count);
printf("%s", buf);
}
////// Negative Microsoft test cases
// case 4: _alloca directly contained in an unbounded loop
void foo_ms(const struct vtype* vec, int count) {
for (int i = 0; i < count; i++) {
const struct vtype* v = vec + i;
char *b1 = 0;
if (b1 == NULL) {
if (w1 > w2) {
// Allocate the buffer on heap
(char *)malloc(w1);
} else {
// Allocate the buffer on stack
b1 = (char*) _alloca(w1); // GOOD
}
}
memcpy(b1, v, w1);
printf("%s\n", b1);
if (w1 > w2) {
free(b1);
}
}
}
// case 5: _malloca contained in a do-while(0) that is in turn contained
// in an unbounded loop
void bar_ms(const struct vtype* vec, int count) {
for (int i = 0; i < count; i++) {
const struct vtype* v = vec + i;
char *b1 = 0;
do {
if (b1 == NULL) {
if (w1 > w2) {
// Allocate the buffer on heap
b1 = (char *)malloc(w1);
} else {
// Allocate the buffer on stack
b1 = (char*) _malloca(w1); // GOOD
}
}
} while (0);
memcpy(b1, v, w1);
printf("%s\n", b1);
if (w1 > w2) {
free(b1);
} else {
_freea(b1);
}
}
}
// case 6: _alloca contained in an unbounded loop that is in turn contained
// in a do-while(0)
void baz_ms(const struct vtype* vec, int count) {
do {
for (int i = 0; i < count; i++) {
const struct vtype* v = vec + i;
char *b1 = 0;
if (b1 == NULL) {
if (w1 > w2) {
// Allocate the buffer on heap
b1 = (char *)malloc(w1);
} else {
// Allocate the buffer on stack
b1 = (char*) _alloca(w1); // GOOD
}
}
memcpy(b1, v, w1);
printf("%s\n", b1);
if (w1 > w2) {
free(b1);
}
}
} while (0);
}

View File

@@ -0,0 +1,51 @@
// semmle-extractor-options: --clang
#ifdef _MSC_VER
#define restrict __restrict
#else
#define restrict __restrict__
#endif
int sprintf(char *restrict s, const char *restrict format, ...);
char * strdup(const char *restrict s);
void *__builtin_alloca(unsigned long sz);
#define alloca __builtin_alloca
// case 1: a GNU c/c++ lambda with an alloca in it
char *foo(int count) {
char *buf = ({
char *b = (char *)alloca(32); // GOOD
sprintf(b, "Value is %d\n", count);
b;
});
return strdup(buf);
}
// case 1: a GNU expression statement with an alloca in it
// nested inside a do-while(0)
char *bar(int count) {
char *buf;
do {
buf = ({
char *b = (char *)alloca(32); // GOOD
sprintf(b, "Value is %d\n", count);
b;
});
} while (0);
return strdup(buf);
}
// case 2: a GNU expression statement with an alloca in it
// nested inside an unbounded loop
char *baz(int count) {
char *buf;
do {
buf = ({
char *b = (char *)alloca(32); // BAD
sprintf(b, "Value is %d\n", count);
b;
});
} while (count++);
return strdup(buf);
}

View File

@@ -0,0 +1,7 @@
typedef unsigned long size_t;
// These are Microsoft routines for stack allocation
// but should only be treated as such if they are declared
// in the <malloc.h> header (i.e., this file)
void *_alloca(size_t sz);
void *_malloca(size_t sz);
void _freea(void *ptr);