The 'counted_by' attribute is used on flexible array members. The
argument for the attribute is the name of the field member in the same
structure holding the count of elements in the flexible array. This
information can be used to improve the results of the array bound
sanitizer and the '__builtin_dynamic_object_size' builtin.
This example specifies the that the flexible array member 'array' has
the number of elements allocated for it in 'count':
struct bar;
struct foo {
size_t count;
/* ... */
struct bar *array[] __attribute__((counted_by(count)));
};
This establishes a relationship between 'array' and 'count',
specifically that 'p->array' must have *at least* 'p->count' number of
elements available. It's the user's responsibility to ensure that this
relationship is maintained through changes to the structure.
In the following, the allocated array erroneously has fewer elements
than what's specified by 'p->count'. This would result in an
out-of-bounds access not not being detected:
struct foo *p;
void foo_alloc(size_t count) {
p = malloc(MAX(sizeof(struct foo),
offsetof(struct foo, array[0]) + count *
sizeof(struct bar *)));
p->count = count + 42;
}
The next example updates 'p->count', breaking the relationship
requirement that 'p->array' must have at least 'p->count' number of
elements available:
struct foo *p;
void foo_alloc(size_t count) {
p = malloc(MAX(sizeof(struct foo),
offsetof(struct foo, array[0]) + count *
sizeof(struct bar *)));
p->count = count + 42;
}
void use_foo(int index) {
p->count += 42;
p->array[index] = 0; /* The sanitizer cannot properly check this access */
}
Reviewed By: nickdesaulniers, aaron.ballman
Differential Revision: https://reviews.llvm.org/D148381
93 lines
2.4 KiB
C
93 lines
2.4 KiB
C
// RUN: %clang_cc1 -fsanitize=local-bounds -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
|
|
// RUN: %clang_cc1 -fsanitize=array-bounds -O -fsanitize-trap=array-bounds -emit-llvm -triple x86_64-apple-darwin10 -DNO_DYNAMIC %s -o - | FileCheck %s
|
|
// RUN: %clang_cc1 -fsanitize=local-bounds -fsanitize-trap=local-bounds -O3 -mllvm -bounds-checking-unique-traps -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s --check-prefixes=NOOPTLOCAL
|
|
// RUN: %clang_cc1 -fsanitize=array-bounds -fsanitize-trap=array-bounds -O3 -mllvm -ubsan-unique-traps -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s --check-prefixes=NOOPTARRAY
|
|
//
|
|
// REQUIRES: x86-registered-target
|
|
|
|
// CHECK-LABEL: @f1
|
|
double f1(int b, int i) {
|
|
double a[b];
|
|
// CHECK: call {{.*}} @llvm.{{(ubsan)?trap}}
|
|
return a[i];
|
|
}
|
|
|
|
// CHECK-LABEL: @f2
|
|
void f2(void) {
|
|
// everything is constant; no trap possible
|
|
// CHECK-NOT: call {{.*}} @llvm.{{(ubsan)?trap}}
|
|
int a[2];
|
|
a[1] = 42;
|
|
|
|
#ifndef NO_DYNAMIC
|
|
extern void *malloc(__typeof__(sizeof(0)));
|
|
short *b = malloc(64);
|
|
b[5] = *a + a[1] + 2;
|
|
#endif
|
|
}
|
|
|
|
// CHECK-LABEL: @f3
|
|
void f3(void) {
|
|
int a[1];
|
|
// CHECK: call {{.*}} @llvm.{{(ubsan)?trap}}
|
|
a[2] = 1;
|
|
}
|
|
|
|
// CHECK-LABEL: @f4
|
|
__attribute__((no_sanitize("bounds")))
|
|
int f4(int i) {
|
|
int b[64];
|
|
// CHECK-NOT: call void @llvm.trap()
|
|
// CHECK-NOT: trap:
|
|
// CHECK-NOT: cont:
|
|
return b[i];
|
|
}
|
|
|
|
// Union flexible-array memebers are a C99 extension. All array members with a
|
|
// constant size should be considered FAMs.
|
|
|
|
union U { int a[0]; int b[1]; int c[2]; };
|
|
|
|
// CHECK-LABEL: @f5
|
|
int f5(union U *u, int i) {
|
|
// a is treated as a flexible array member.
|
|
// CHECK-NOT: @llvm.ubsantrap
|
|
return u->a[i];
|
|
}
|
|
|
|
// CHECK-LABEL: @f6
|
|
int f6(union U *u, int i) {
|
|
// b is treated as a flexible array member.
|
|
// CHECK-NOT: call {{.*}} @llvm.{{(ubsan)?trap}}
|
|
return u->b[i];
|
|
}
|
|
|
|
// CHECK-LABEL: @f7
|
|
int f7(union U *u, int i) {
|
|
// c is treated as a flexible array member.
|
|
// CHECK-NOT: @llvm.ubsantrap
|
|
return u->c[i];
|
|
}
|
|
|
|
char B[10];
|
|
char B2[10];
|
|
// CHECK-LABEL: @f8
|
|
void f8(int i, int k) {
|
|
// NOOPTLOCAL: call void @llvm.ubsantrap(i8 3)
|
|
// NOOPTARRAY: call void @llvm.ubsantrap(i8 2)
|
|
B[i] = '\0';
|
|
|
|
// NOOPTLOCAL: call void @llvm.ubsantrap(i8 5)
|
|
// NOOPTARRAY: call void @llvm.ubsantrap(i8 4)
|
|
B2[k] = '\0';
|
|
}
|
|
|
|
// See commit 9a954c6 that caused a SEGFAULT in this code.
|
|
struct S {
|
|
__builtin_va_list ap;
|
|
} *s;
|
|
// CHECK-LABEL: @f9
|
|
struct S *f9(int i) {
|
|
return &s[i];
|
|
}
|