From b5e7f95cfbeb28ff8b966a2b7e38a03f32410030 Mon Sep 17 00:00:00 2001 From: Evgenii Stepanov Date: Fri, 20 Dec 2019 12:07:04 -0800 Subject: [PATCH] [msan] Check qsort input. 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 --- .../sanitizer_common_interceptors.inc | 14 ++++++++++++++ compiler-rt/test/msan/qsort.cpp | 5 +++++ 2 files changed, 19 insertions(+) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index 8f365ee308546..47e344c9e3f29 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -9670,6 +9670,13 @@ 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 - 1; ++i) { + void *p = (void *)((char *)base + i * size); + void *q = (void *)((char *)base + (i + 1) * size); + COMMON_INTERCEPTOR_UNPOISON_PARAM(2); + compar(p, q); + } qsort_compar_f old_compar = qsort_compar; qsort_compar = compar; SIZE_T old_size = qsort_size; @@ -9699,6 +9706,13 @@ 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 - 1; ++i) { + void *p = (void *)((char *)base + i * size); + void *q = (void *)((char *)base + (i + 1) * size); + COMMON_INTERCEPTOR_UNPOISON_PARAM(3); + compar(p, q, arg); + } qsort_r_compar_f old_compar = qsort_r_compar; qsort_r_compar = compar; SIZE_T old_size = qsort_r_size; diff --git a/compiler-rt/test/msan/qsort.cpp b/compiler-rt/test/msan/qsort.cpp index eb8697011867b..cf754012b2286 100644 --- a/compiler-rt/test/msan/qsort.cpp +++ b/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 #include @@ -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);