blob: 424c487f772f3d3833853cb291dc52accc80bdc5 [file] [edit]
// RUN: %clang_cc1 -triple msp430 -emit-llvm -fsanitize=pointer-overflow -O0 %s -o - | FileCheck %s
// Verify that pointer-overflow checks are emitted correctly when the GEP
// offset is a constant that overflows the 16-bit intptr_t. Previously this
// triggered an assertion in EmitCheckedInBoundsGEP because the code assumed
// a constant-folded offset could never have an overflow.
struct sensor_reading { long timestamp; long value; };
struct sensor_reading *readings[];
// CHECK-LABEL: define {{.*}}@test_constant_offset_overflow
// CHECK: getelementptr inbounds %struct.sensor_reading
// CHECK: call void @__ubsan_handle_pointer_overflow
void test_constant_offset_overflow(void) {
// sizeof(struct sensor_reading) == 8, index 4096: 4096 * 8 = 32768 overflows i16.
readings[0][4096];
}
// CHECK-LABEL: define {{.*}}@test_constant_offset_overflow_wraps_to_zero
// CHECK: getelementptr inbounds %struct.sensor_reading
// CHECK: call void @__ubsan_handle_pointer_overflow
void test_constant_offset_overflow_wraps_to_zero(void) {
// sizeof(struct sensor_reading) == 8, index 8192: 8192 * 8 = 65536 wraps to 0 in i16.
readings[0][8192];
}
// CHECK-LABEL: define {{.*}}@test_zero_offset_no_overflow
// CHECK-NOT: __ubsan_handle_pointer_overflow
// CHECK: ret void
void test_zero_offset_no_overflow(void) {
// Genuine zero offset should not emit a check.
readings[0][0];
}
// The cases above index through a pointer loaded from a global, so the GEP has
// a runtime base. The cases below index a global array directly, so the GEP
// itself folds to a constant expression.
struct sensor_reading direct[2];
// CHECK-LABEL: define {{.*}}@test_constant_gep_offset
// CHECK: icmp ne i16 add (i16 ptrtoaddr (ptr @direct to i16), i16 8), 0, !nosanitize
// CHECK: call void @__ubsan_handle_pointer_overflow
void test_constant_gep_offset(void) {
// A plain index: 1 * 8 = 8, no overflow.
direct[1];
}
// CHECK-LABEL: define {{.*}}@test_constant_gep_offset_overflow
// CHECK: icmp ne i16 add (i16 ptrtoaddr (ptr @direct to i16), i16 -32768), 0, !nosanitize
// CHECK: call void @__ubsan_handle_pointer_overflow
void test_constant_gep_offset_overflow(void) {
// 4096 * 8 = 32768 overflows i16 and wraps to -32768.
direct[4096];
}
// CHECK-LABEL: define {{.*}}@test_constant_gep_wraps_to_zero
// CHECK: br i1 true, label %[[CONT:[^,]+]], label %[[HANDLER:[^,]+]], {{.*}}!nosanitize
// CHECK: [[HANDLER]]:
// CHECK: call void @__ubsan_handle_pointer_overflow
void test_constant_gep_wraps_to_zero(void) {
// 8192 * 8 = 65536 wraps to 0 in i16. The offset is zero but computing it
// overflowed, so the zero-offset early return does not apply and a check is
// emitted. The check is trivially valid, since a zero offset leaves the
// computed address equal to the base.
direct[8192];
}