Skip to content

Commit

Permalink
[msan] Check qsort input.
Browse files Browse the repository at this point in the history
Summary:
Qsort interceptor suppresses all checks by unpoisoning the data in the
wrapper of a comparator function, and then unpoisoning the output array
as well.

This change adds an explicit run of the comparator on all elements of
the input array to catch any sanitizer bugs.

Reviewers: vitalybuka

Subscribers: #sanitizers, llvm-commits

Tags: #sanitizers, #llvm

Differential Revision: https://reviews.llvm.org/D71780
  • Loading branch information
eugenis committed Dec 23, 2019
1 parent 7a9ebe9 commit caa48a6
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 0 deletions.
18 changes: 18 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
Expand Up @@ -9665,6 +9665,15 @@ INTERCEPTOR(void, qsort, void *base, SIZE_T nmemb, SIZE_T size,
qsort_compar_f compar) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, qsort, base, nmemb, size, compar);
// Run the comparator over all array elements to detect any memory issues.
for (SIZE_T i = 0; i < nmemb; ++i) {
void *p = (void *)((char *)base + i * size);
COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
// Compare each element with itself to trigger an equality check, which
// typically requires the comparator to look as many of the object fields as
// possible.
compar(p, p);
}
qsort_compar_f old_compar = qsort_compar;
qsort_compar = compar;
SIZE_T old_size = qsort_size;
Expand Down Expand Up @@ -9694,6 +9703,15 @@ INTERCEPTOR(void, qsort_r, void *base, SIZE_T nmemb, SIZE_T size,
qsort_r_compar_f compar, void *arg) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, qsort_r, base, nmemb, size, compar, arg);
// Run the comparator over all array elements to detect any memory issues.
for (SIZE_T i = 0; i < nmemb; ++i) {
void *p = (void *)((char *)base + i * size);
COMMON_INTERCEPTOR_UNPOISON_PARAM(3);
// Compare each element with itself to trigger an equality check, which
// typically requires the comparator to look as many of the object fields as
// possible.
compar(p, p, arg);
}
qsort_r_compar_f old_compar = qsort_r_compar;
qsort_r_compar = compar;
SIZE_T old_size = qsort_r_size;
Expand Down
5 changes: 5 additions & 0 deletions compiler-rt/test/msan/qsort.cpp
@@ -1,4 +1,5 @@
// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t
// RUN: %clangxx_msan -DPOISON -O0 -g %s -o %t && not %run %t 2>&1 | FileCheck %s

#include <assert.h>
#include <errno.h>
Expand Down Expand Up @@ -65,6 +66,10 @@ int main(int argc, char *argv[]) {
for (int i = 0; i < kSize1; ++i)
p[i] = i * 2 + (i % 3 - 1) * 3;
poison_stack_and_param();
#ifdef POISON
__msan_poison(p + 1, sizeof(long));
// CHECK: Uninitialized bytes in __msan_check_mem_is_initialized at offset 0 inside [{{.*}}, 8)
#endif
qsort(p, kSize1, sizeof(long), compar1);
__msan_check_mem_is_initialized(p, sizeof(long) * kSize1);
assert(seen2);
Expand Down

0 comments on commit caa48a6

Please sign in to comment.