[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
This commit is contained in:
Evgenii Stepanov 2019-12-20 12:07:04 -08:00
parent 59fadc14ee
commit b5e7f95cfb
2 changed files with 19 additions and 0 deletions

View File

@ -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;

View File

@ -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>
@ -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);