You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
193 lines
3.9 KiB
193 lines
3.9 KiB
3 years ago
|
/*
|
||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||
|
*
|
||
|
* This source code is licensed under the MIT license found in the
|
||
|
* LICENSE file in the root directory of this source tree.
|
||
|
*/
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <stdnoreturn.h>
|
||
|
|
||
|
int* malloc_no_check_bad() {
|
||
|
int* p = (int*)malloc(sizeof(int));
|
||
|
*p = 42;
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
void create_null_path_ok(int* p) {
|
||
|
if (p) {
|
||
|
*p = 32;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void call_create_null_path_then_deref_unconditionally_ok(int* p) {
|
||
|
create_null_path_ok(p);
|
||
|
*p = 52;
|
||
|
}
|
||
|
|
||
|
void create_null_path2_latent(int* p) {
|
||
|
int* q = NULL;
|
||
|
if (p) {
|
||
|
*p = 32;
|
||
|
}
|
||
|
// arguably bogus to check p above but not here, but the above could
|
||
|
// also be macro-generated code so both reporting and not reporting
|
||
|
// are sort of justifiable
|
||
|
*p = 52;
|
||
|
}
|
||
|
|
||
|
// combine several of the difficulties above
|
||
|
void malloc_then_call_create_null_path_then_deref_unconditionally_latent(
|
||
|
int* p) {
|
||
|
int* x = (int*)malloc(sizeof(int));
|
||
|
if (p) {
|
||
|
*p = 32;
|
||
|
}
|
||
|
create_null_path_ok(p);
|
||
|
*p = 52;
|
||
|
free(x);
|
||
|
}
|
||
|
|
||
|
// pulse should remember the value of vec[64] because it was just written to
|
||
|
void nullptr_deref_young_bad(int* x) {
|
||
|
int* vec[65] = {x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||
|
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||
|
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||
|
x, x, x, x, x, x, x, x, x, x, x, x, x, NULL};
|
||
|
int p = *vec[64];
|
||
|
}
|
||
|
|
||
|
// due to the recency model of memory accesses, vec[0] can get forgotten
|
||
|
// by the time we have processed the last element of the
|
||
|
// initialization so we don't report here
|
||
|
void FN_nullptr_deref_old_bad(int* x) {
|
||
|
int* vec[65] = {NULL, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||
|
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||
|
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||
|
x, x, x, x, x, x, x, x, x, x, x, x, x, x};
|
||
|
int p = *vec[0];
|
||
|
}
|
||
|
|
||
|
void malloc_free_ok() {
|
||
|
int* p = (int*)malloc(sizeof(int));
|
||
|
free(p);
|
||
|
}
|
||
|
|
||
|
void wrap_free(void* p) { free(p); }
|
||
|
|
||
|
void interproc_free_ok() {
|
||
|
int* p = (int*)malloc(sizeof(int));
|
||
|
wrap_free(p);
|
||
|
}
|
||
|
|
||
|
noreturn void no_return();
|
||
|
|
||
|
void wrap_malloc(int** x) {
|
||
|
*x = (int*)malloc(sizeof(int));
|
||
|
if (!*x) {
|
||
|
no_return();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void call_no_return_good() {
|
||
|
int* x = NULL;
|
||
|
wrap_malloc(&x);
|
||
|
*x = 5;
|
||
|
free(x);
|
||
|
}
|
||
|
|
||
|
void bug_after_malloc_result_test_bad(int* x) {
|
||
|
x = (int*)malloc(sizeof(int));
|
||
|
if (x) {
|
||
|
int* y = NULL;
|
||
|
*y = 42;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void bug_after_abduction_bad(int* x) {
|
||
|
*x = 42;
|
||
|
int* y = NULL;
|
||
|
*y = 42;
|
||
|
}
|
||
|
|
||
|
void bug_with_allocation_bad(int* x) {
|
||
|
x = (int*)malloc(sizeof(int));
|
||
|
int* y = NULL;
|
||
|
*y = 42;
|
||
|
}
|
||
|
|
||
|
void null_alias_bad(int* x) {
|
||
|
int* y = NULL;
|
||
|
x = (int*)malloc(sizeof(int*));
|
||
|
*x = 42;
|
||
|
}
|
||
|
|
||
|
void dereference(int* p) { *p; }
|
||
|
|
||
|
void several_dereferences_ok(int* x, int* y, int* z) {
|
||
|
int* p = x;
|
||
|
*z = 52;
|
||
|
dereference(y);
|
||
|
*y = 42;
|
||
|
*x = 32;
|
||
|
*x = 777;
|
||
|
*y = 888;
|
||
|
*z = 999;
|
||
|
}
|
||
|
|
||
|
void report_correct_error_among_multiple_bad() {
|
||
|
int* p = NULL;
|
||
|
// the trace should complain about the first access inside the callee
|
||
|
several_dereferences_ok(p, p, p);
|
||
|
}
|
||
|
|
||
|
int unknown(int x);
|
||
|
|
||
|
void unknown_is_functional_ok() {
|
||
|
int* p = NULL;
|
||
|
if (unknown(10) != unknown(10)) {
|
||
|
*p = 42;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void unknown_with_different_values_bad() {
|
||
|
int* p = NULL;
|
||
|
if (unknown(32) != unknown(52)) {
|
||
|
*p = 42;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void unknown_from_parameters_latent(int x) {
|
||
|
int* p = NULL;
|
||
|
if (unknown(x) == 999) {
|
||
|
*p = 42;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// is pruned away without the model
|
||
|
void random_non_functional_bad() {
|
||
|
if (random() != random()) {
|
||
|
int* p = NULL;
|
||
|
*p = 42;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// quantifier elimination not powerful enough to discard [\exists v. y = v] in
|
||
|
// the pruned part
|
||
|
void FNlatent_random_modelled_bad(int y) {
|
||
|
int x = random();
|
||
|
if (x == y) {
|
||
|
int* p = NULL;
|
||
|
*p = 42;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void FP_arithmetic_weakness_ok() {
|
||
|
int x = random();
|
||
|
int y = random();
|
||
|
if (x < y && x > y) {
|
||
|
int* p = NULL;
|
||
|
*p = 42;
|
||
|
}
|
||
|
}
|