Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Similar to qsort, bsearch can be called from non-instrumented code of glibc. When it happends tls for arguments can be in uninitialized state. Unlike to qsort, bsearch does not move data, so we don't need to check or initialize searched memory or key. Intrumented comparator will do that on it's own. Differential Revision: https://reviews.llvm.org/D107387
- Loading branch information
1 parent
5643736
commit 9ab590e
Showing
4 changed files
with
130 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// __NO_INLINE__ is defined so bsearch needs interceptor. | ||
// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t | ||
// RUN: %clangxx_msan -DPOISON_DATA -O0 -g %s -o %t && not %run %t 2>&1 | FileCheck %s | ||
// RUN: %clangxx_msan -DPOISON_KEY -O0 -g %s -o %t && not %run %t 2>&1 | FileCheck %s | ||
|
||
// __NO_INLINE__ is undefined so bsearch should be inlined and instrumented and still work as expected. | ||
// RUN: %clangxx_msan -O2 -g %s -o %t && %run %t | ||
// RUN: %clangxx_msan -DPOISON_DATA -O2 -g %s -o %t && not %run %t 2>&1 | FileCheck %s | ||
// RUN: %clangxx_msan -DPOISON_KEY -O2 -g %s -o %t && not %run %t 2>&1 | FileCheck %s | ||
|
||
#include <assert.h> | ||
#include <stdlib.h> | ||
|
||
#include <sanitizer/msan_interface.h> | ||
|
||
long z; | ||
|
||
__attribute__((noinline, optnone)) void | ||
poison_msan_param_tls(long a, long b, long c, long d, long e, long f) { | ||
z = a + b + c + d + e + f; | ||
} | ||
|
||
static int compar(const void *a, const void *b) { | ||
int r = *(const long *)a - *(const long *)b; | ||
long x; | ||
__msan_poison(&x, sizeof(x)); | ||
poison_msan_param_tls(x, x, x, x, x, x); | ||
return r; | ||
} | ||
|
||
int main(int argc, char *argv[]) { | ||
constexpr size_t SZ = 27; | ||
long p[SZ + 1]; | ||
for (int i = 0; i < SZ + 1; ++i) | ||
p[i] = i; | ||
p[SZ] = SZ / 3; | ||
#if defined(POISON_DATA) | ||
__msan_poison(p, sizeof(long) * SZ / 2); | ||
#elif defined(POISON_KEY) | ||
__msan_poison(p + SZ, sizeof(long)); | ||
#endif | ||
const long *r = (const long *)bsearch(p + SZ, p, SZ, sizeof(long), compar); | ||
// CHECK: MemorySanitizer: use-of-uninitialized-value | ||
|
||
assert(r == p + SZ / 3); | ||
|
||
return 0; | ||
} |
55 changes: 55 additions & 0 deletions
55
compiler-rt/test/sanitizer_common/TestCases/Posix/bsearch.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// Check interceptor. | ||
// RUN: %clangxx -O0 %s -o %t && %run %t 2>&1 | FileCheck %s | ||
|
||
// Inlined bsearch works even without interceptors. | ||
// RUN: %clangxx -O2 %s -o %t && %run %t 2>&1 | FileCheck %s | ||
|
||
#include <stdio.h> | ||
#include <stdlib.h> | ||
|
||
static int arr1[] = {8, 7, 6, 5, 4, 3, 2, 1, 0}; | ||
static int arr2[] = {10, 1, 1, 3, 4, 6, 7, 7}; | ||
|
||
#define array_size(x) (sizeof(x) / sizeof(x[0])) | ||
|
||
static int cmp_ints(const void *a, const void *b) { | ||
return *(const int *)b - *(const int *)a; | ||
} | ||
|
||
static int cmp_pos(const void *a, const void *b) { | ||
const int *ap = | ||
(const int *)bsearch(a, arr1, array_size(arr1), sizeof(int), &cmp_ints); | ||
if (!ap) | ||
ap = arr1 + array_size(arr1); | ||
const int *bp = | ||
(const int *)bsearch(b, arr1, array_size(arr1), sizeof(int), &cmp_ints); | ||
if (!bp) | ||
bp = arr1 + array_size(arr1); | ||
return bp - ap; | ||
} | ||
|
||
int main() { | ||
// Simple bsearch. | ||
for (int i = 0; i < 10; ++i) { | ||
const void *r = | ||
bsearch(&i, arr1, array_size(arr1), sizeof(arr1[0]), &cmp_ints); | ||
if (!r) | ||
printf(" null"); | ||
else | ||
printf(" %d", *(const int *)r); | ||
} | ||
printf("\n"); | ||
// CHECK: 0 1 2 3 4 5 6 7 8 null | ||
|
||
// Nested bsearch. | ||
for (int i = 0; i < 10; ++i) { | ||
const void *r = | ||
bsearch(&i, arr2, array_size(arr2), sizeof(arr2[0]), &cmp_pos); | ||
if (!r) | ||
printf(" null"); | ||
else | ||
printf(" %d", *(const int *)r); | ||
} | ||
printf("\n"); | ||
// CHECK: null 1 null 3 4 null 6 7 null 10 | ||
} |