[clang] [compiler-rt] [test] Prevent generation of the bigendian code inside clang test CodeGen/bit-int-ubsan.c (PR #104607)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Aug 16 08:30:30 PDT 2024
https://github.com/earnol updated https://github.com/llvm/llvm-project/pull/104607
>From 98d3d539c84c917ba7369f688ba26ff172c9d89c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?E=C3=A4nolituri=20L=C3=B3mitaur=C3=AB?=
<vladislav.aranov at ericsson.com>
Date: Wed, 7 Aug 2024 17:29:35 -0400
Subject: [PATCH 1/6] [ubsan] Display correct runtime messages for negative
_BitInt
Without this patch compiler-rt ubsan library has a bug displaying
incorrect values for variables of the _BitInt (previousely called
_ExtInt) type. This patch affects both: generation of metadata
inside code generator and runtime part. The runtime part provided only
for i386 and x86_64 runtimes. Other runtimes should be updated to take
full benefit of this patch.
The patch is constructed the way to be backward compatible and
int and float type runtime diagnostics should be unaffected for not
yet updated runtimes.
Co-authored-by: Aaron Ballman <aaron at aaronballman.com>
Co-authored-by: Paul Kirth <paulkirth at google.com>
---
clang/lib/CodeGen/CGExpr.cpp | 59 +++++-
clang/test/CodeGen/bit-int-ubsan.c | 96 ++++++++++
compiler-rt/lib/ubsan/ubsan_value.cpp | 17 +-
compiler-rt/lib/ubsan/ubsan_value.h | 33 +++-
.../ubsan/TestCases/Integer/bit-int-pass.c | 42 +++++
.../test/ubsan/TestCases/Integer/bit-int.c | 170 ++++++++++++++++++
6 files changed, 404 insertions(+), 13 deletions(-)
create mode 100644 clang/test/CodeGen/bit-int-ubsan.c
create mode 100644 compiler-rt/test/ubsan/TestCases/Integer/bit-int-pass.c
create mode 100644 compiler-rt/test/ubsan/TestCases/Integer/bit-int.c
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 534f46da748627..060ab84992a7e5 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -41,6 +41,7 @@
#include "llvm/IR/MatrixBuilder.h"
#include "llvm/Passes/OptimizationLevel.h"
#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/Endian.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SaveAndRestore.h"
@@ -64,6 +65,22 @@ static llvm::cl::opt<bool> ClSanitizeGuardChecks(
"ubsan-guard-checks", llvm::cl::Optional,
llvm::cl::desc("Guard UBSAN checks with `llvm.allow.ubsan.check()`."));
+//===--------------------------------------------------------------------===//
+// Defines for metadata
+//===--------------------------------------------------------------------===//
+
+// Those values are crucial to be the SAME as in ubsan runtime library.
+enum VariableTypeDescriptorKind : uint16_t {
+ /// An integer type.
+ TK_Integer = 0x0000,
+ /// A floating-point type.
+ TK_Float = 0x0001,
+ /// An _BitInt(N) type.
+ TK_BitInt = 0x0002,
+ /// Any other type. The value representation is unspecified.
+ TK_Unknown = 0xffff
+};
+
//===--------------------------------------------------------------------===//
// Miscellaneous Helper Methods
//===--------------------------------------------------------------------===//
@@ -3298,22 +3315,40 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
/// { i16 TypeKind, i16 TypeInfo }
/// \endcode
///
-/// followed by an array of i8 containing the type name. TypeKind is 0 for an
-/// integer, 1 for a floating point value, and -1 for anything else.
+/// followed by an array of i8 containing the type name with extra information
+/// for BitInt. TypeKind is TK_Integer(0) for an integer, TK_Float(1) for a
+/// floating point value, TK_BitInt(2) for BitInt and TK_Unknown(0xFFFF) for
+/// anything else.
llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) {
// Only emit each type's descriptor once.
if (llvm::Constant *C = CGM.getTypeDescriptorFromMap(T))
return C;
- uint16_t TypeKind = -1;
+ uint16_t TypeKind = TK_Unknown;
uint16_t TypeInfo = 0;
+ bool IsBitInt = false;
if (T->isIntegerType()) {
- TypeKind = 0;
+ TypeKind = TK_Integer;
TypeInfo = (llvm::Log2_32(getContext().getTypeSize(T)) << 1) |
(T->isSignedIntegerType() ? 1 : 0);
+ // Follow suggestion from discussion of issue 64100.
+ // So we can write the exact amount of bits in TypeName after '\0'
+ // making it <diagnostic-like type name>.'\0'.<32-bit width>.
+ if (T->isSignedIntegerType() && T->getAs<BitIntType>()) {
+ // Do a sanity checks as we are using 32-bit type to store bit length.
+ assert(getContext().getTypeSize(T) > 0 &&
+ " non positive amount of bits in __BitInt type");
+ assert(getContext().getTypeSize(T) <= 0xFFFFFFFF &&
+ " too many bits in __BitInt type");
+
+ // Redefine TypeKind with the actual __BitInt type if we have signed
+ // BitInt.
+ TypeKind = TK_BitInt;
+ IsBitInt = true;
+ }
} else if (T->isFloatingType()) {
- TypeKind = 1;
+ TypeKind = TK_Float;
TypeInfo = getContext().getTypeSize(T);
}
@@ -3324,6 +3359,20 @@ llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) {
DiagnosticsEngine::ak_qualtype, (intptr_t)T.getAsOpaquePtr(), StringRef(),
StringRef(), std::nullopt, Buffer, std::nullopt);
+ if (IsBitInt) {
+ // The Structure is: 0 to end the string, 32 bit unsigned integer in target
+ // endianness, zero.
+ char S[6] = {'\0', '\0', '\0', '\0', '\0', '\0'};
+ const auto *EIT = T->castAs<BitIntType>();
+ uint32_t Bits = EIT->getNumBits();
+ llvm::support::endian::write32(S + 1, Bits,
+ getTarget().isBigEndian()
+ ? llvm::endianness::big
+ : llvm::endianness::little);
+ StringRef Str = StringRef(S, sizeof(S) / sizeof(decltype(S[0])));
+ Buffer.append(Str);
+ }
+
llvm::Constant *Components[] = {
Builder.getInt16(TypeKind), Builder.getInt16(TypeInfo),
llvm::ConstantDataArray::getString(getLLVMContext(), Buffer)
diff --git a/clang/test/CodeGen/bit-int-ubsan.c b/clang/test/CodeGen/bit-int-ubsan.c
new file mode 100644
index 00000000000000..35f96963c181d1
--- /dev/null
+++ b/clang/test/CodeGen/bit-int-ubsan.c
@@ -0,0 +1,96 @@
+// REQUIRES: x86-registered-target
+// RUN: %clang -Wno-constant-conversion -Wno-array-bounds -Wno-division-by-zero -Wno-shift-negative-value -Wno-shift-count-negative -Wno-int-to-pointer-cast -fsanitize=array-bounds,enum,float-cast-overflow,integer-divide-by-zero,implicit-unsigned-integer-truncation,implicit-signed-integer-truncation,implicit-integer-sign-change,unsigned-integer-overflow,signed-integer-overflow,shift-base,shift-exponent -O0 -S -emit-llvm -o - %s | FileCheck %s
+
+// The runtime test checking the _BitInt ubsan feature is located in compiler-rt/test/ubsan/TestCases/Integer/bit-int.c
+
+#include <stdint.h>
+#include <stdio.h>
+
+uint32_t float_divide_by_zero() {
+ float f = 1.0f / 0.0f;
+ // CHECK: constant { i16, i16, [8 x i8] } { i16 1, i16 32, [8 x i8] c"'float'\00" }
+ _BitInt(37) r = (_BitInt(37))f;
+ // CHECK: constant { i16, i16, [20 x i8] } { i16 2, i16 13, [20 x i8] c"'_BitInt(37)'\00%\00\00\00\00\00" }
+ return r;
+}
+
+uint32_t integer_divide_by_zero() __attribute__((no_sanitize("memory"))) {
+ _BitInt(37) x = 1 / 0;
+ // CHECK: constant { i16, i16, [32 x i8] } { i16 0, i16 10, [32 x i8] c"'uint32_t' (aka 'unsigned int')\00" }
+ return x;
+}
+
+uint32_t implicit_unsigned_integer_truncation() {
+ unsigned _BitInt(37) x = 2U;
+ x += float_divide_by_zero();
+ x += integer_divide_by_zero();
+ x = x + 0xFFFFFFFFFFFFFFFFULL;
+ // CHECK: constant { i16, i16, [23 x i8] } { i16 0, i16 12, [23 x i8] c"'unsigned _BitInt(37)'\00" }
+ uint32_t r = x & 0xFFFFFFFF;
+ return r;
+}
+
+uint32_t array_bounds() {
+ _BitInt(37) x[4];
+ _BitInt(37) y = x[10];
+ // CHECK: constant { i16, i16, [17 x i8] } { i16 -1, i16 0, [17 x i8] c"'_BitInt(37)[4]'\00" }
+ return (uint32_t)y;
+}
+
+uint32_t float_cast_overflow() {
+ float a = 100000000.0f;
+ _BitInt(7) b = (_BitInt(7))a;
+ // CHECK: constant { i16, i16, [19 x i8] } { i16 2, i16 7, [19 x i8] c"'_BitInt(7)'\00\07\00\00\00\00\00" }
+ return b;
+}
+
+_BitInt(13) implicit_signed_integer_truncation() {
+ _BitInt(73) x = (_BitInt(73)) ~((~0UL) >> 1);
+ return x;
+ // CHECK: constant { i16, i16, [20 x i8] } { i16 2, i16 {{([[:xdigit:]]{2})}}, [20 x i8] c"'_BitInt(73)'\00I\00\00\00\00\00" }
+ // CHECK: constant { i16, i16, [20 x i8] } { i16 2, i16 9, [20 x i8] c"'_BitInt(13)'\00\0D\00\00\00\00\00" }
+}
+
+uint32_t negative_shift1(unsigned _BitInt(37) x)
+ __attribute__((no_sanitize("memory"))) {
+ _BitInt(9) c = -2;
+ return x >> c;
+ // CHECK: constant { i16, i16, [19 x i8] } { i16 2, i16 9, [19 x i8] c"'_BitInt(9)'\00\09\00\00\00\00\00" }
+}
+
+uint32_t negative_shift2(unsigned _BitInt(37) x)
+ __attribute__((no_sanitize("memory"))) {
+ _BitInt(17) c = -2;
+ return x >> c;
+ // CHECK: constant { i16, i16, [20 x i8] } { i16 2, i16 11, [20 x i8] c"'_BitInt(17)'\00\11\00\00\00\00\00" }
+}
+
+uint32_t negative_shift3(unsigned _BitInt(37) x)
+ __attribute__((no_sanitize("memory"))) {
+ _BitInt(34) c = -2;
+ return x >> c;
+ // CHECK: constant { i16, i16, [20 x i8] } { i16 2, i16 13, [20 x i8] c"'_BitInt(34)'\00\22\00\00\00\00\00" }
+}
+
+uint32_t negative_shift5(unsigned _BitInt(37) x)
+ __attribute__((no_sanitize("memory"))) {
+ _BitInt(68) c = -2;
+ return x >> c;
+ // CHECK: constant { i16, i16, [20 x i8] } { i16 2, i16 {{([[:xdigit:]]{2})}}, [20 x i8] c"'_BitInt(68)'\00D\00\00\00\00\00" }
+}
+
+int main(int argc, char **argv) {
+ // clang-format off
+ uint64_t result =
+ 1ULL +
+ implicit_unsigned_integer_truncation() +
+ (uint32_t)array_bounds() +
+ float_cast_overflow() +
+ (uint64_t)implicit_signed_integer_truncation() +
+ negative_shift1(5) +
+ negative_shift2(5) +
+ negative_shift3(5) +
+ negative_shift5(5);
+ // clang-format on
+ printf("%u\n", (uint32_t)(result & 0xFFFFFFFF));
+}
diff --git a/compiler-rt/lib/ubsan/ubsan_value.cpp b/compiler-rt/lib/ubsan/ubsan_value.cpp
index dc61e5b939d952..6e88ebaf34d4be 100644
--- a/compiler-rt/lib/ubsan/ubsan_value.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_value.cpp
@@ -67,18 +67,21 @@ const char *__ubsan::getObjCClassName(ValueHandle Pointer) {
SIntMax Value::getSIntValue() const {
CHECK(getType().isSignedIntegerTy());
+ // Val was zero-extended to ValueHandle. Sign-extend from original width
+ // to SIntMax.
+ const unsigned ExtraBits =
+ sizeof(SIntMax) * 8 - getType().getIntegerBitCount();
if (isInlineInt()) {
- // Val was zero-extended to ValueHandle. Sign-extend from original width
- // to SIntMax.
- const unsigned ExtraBits =
- sizeof(SIntMax) * 8 - getType().getIntegerBitWidth();
return SIntMax(UIntMax(Val) << ExtraBits) >> ExtraBits;
}
- if (getType().getIntegerBitWidth() == 64)
- return *reinterpret_cast<s64*>(Val);
+ if (getType().getIntegerBitWidth() == 64) {
+ return SIntMax(UIntMax(*reinterpret_cast<s64 *>(Val)) << ExtraBits) >>
+ ExtraBits;
+ }
#if HAVE_INT128_T
if (getType().getIntegerBitWidth() == 128)
- return *reinterpret_cast<s128*>(Val);
+ return SIntMax(UIntMax(*reinterpret_cast<s128 *>(Val)) << ExtraBits) >>
+ ExtraBits;
#else
if (getType().getIntegerBitWidth() == 128)
UNREACHABLE("libclang_rt.ubsan was built without __int128 support");
diff --git a/compiler-rt/lib/ubsan/ubsan_value.h b/compiler-rt/lib/ubsan/ubsan_value.h
index e0957276dd2419..430c9ea0dc8d15 100644
--- a/compiler-rt/lib/ubsan/ubsan_value.h
+++ b/compiler-rt/lib/ubsan/ubsan_value.h
@@ -103,6 +103,13 @@ class TypeDescriptor {
/// representation is that of bitcasting the floating-point value to an
/// integer type.
TK_Float = 0x0001,
+ /// An _BitInt(N) type. Lowest bit is 1 for a signed value, 0 for an
+ /// unsigned value. Remaining bits are log_2(bit_width). The value
+ /// representation is the integer itself if it fits into a ValueHandle, and
+ /// a pointer to the integer otherwise. TypeName contains the true width
+ /// of the type for the signed _BitInt(N) type stored after zero bit after
+ /// TypeName as 32-bit unsigned integer.
+ TK_BitInt = 0x0002,
/// Any other type. The value representation is unspecified.
TK_Unknown = 0xffff
};
@@ -113,10 +120,15 @@ class TypeDescriptor {
return static_cast<Kind>(TypeKind);
}
- bool isIntegerTy() const { return getKind() == TK_Integer; }
+ bool isIntegerTy() const {
+ return getKind() == TK_Integer || getKind() == TK_BitInt;
+ }
+ bool isBitIntTy() const { return getKind() == TK_BitInt; }
+
bool isSignedIntegerTy() const {
return isIntegerTy() && (TypeInfo & 1);
}
+ bool isSignedBitIntTy() const { return isBitIntTy() && (TypeInfo & 1); }
bool isUnsignedIntegerTy() const {
return isIntegerTy() && !(TypeInfo & 1);
}
@@ -125,6 +137,25 @@ class TypeDescriptor {
return 1 << (TypeInfo >> 1);
}
+ const char *getBitIntBitCountPointer() const {
+ DCHECK(isBitIntTy());
+ DCHECK(isSignedBitIntTy());
+ // Scan Name for zero and return the next address
+ const char *p = getTypeName();
+ while (*p != '\0')
+ ++p;
+ // Return the next address
+ return p + 1;
+ }
+
+ unsigned getIntegerBitCount() const {
+ DCHECK(isIntegerTy());
+ if (isSignedBitIntTy())
+ return *reinterpret_cast<const u32 *>(getBitIntBitCountPointer());
+ else
+ return getIntegerBitWidth();
+ }
+
bool isFloatTy() const { return getKind() == TK_Float; }
unsigned getFloatBitWidth() const {
CHECK(isFloatTy());
diff --git a/compiler-rt/test/ubsan/TestCases/Integer/bit-int-pass.c b/compiler-rt/test/ubsan/TestCases/Integer/bit-int-pass.c
new file mode 100644
index 00000000000000..a25428f0eb872f
--- /dev/null
+++ b/compiler-rt/test/ubsan/TestCases/Integer/bit-int-pass.c
@@ -0,0 +1,42 @@
+// RUN: %clang -Wno-constant-conversion -Wno-array-bounds -Wno-division-by-zero -Wno-shift-negative-value -Wno-shift-count-negative -Wno-int-to-pointer-cast -O0 -fsanitize=alignment,array-bounds,bool,float-cast-overflow,implicit-integer-sign-change,implicit-signed-integer-truncation,implicit-unsigned-integer-truncation,integer-divide-by-zero,nonnull-attribute,null,nullability-arg,nullability-assign,nullability-return,pointer-overflow,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,unsigned-integer-overflow,unsigned-shift-base,vla-bound %s -o %t1 && %run %t1 2>&1 | FileCheck %s
+
+#include <stdint.h>
+#include <stdio.h>
+
+// In this test there is an expectation of assignment of _BitInt not producing any output.
+uint32_t nullability_arg(_BitInt(37) *_Nonnull x)
+ __attribute__((no_sanitize("address")))
+ __attribute__((no_sanitize("memory"))) {
+ _BitInt(37) y = *(_BitInt(37) *)&x;
+ return (y > 0) ? y : 0;
+}
+
+// In this test there is an expectation of ubsan not triggeting on returning random address which is inside address space of the process.
+_BitInt(37) nonnull_attribute(__attribute__((nonnull)) _BitInt(37) * x)
+ __attribute__((no_sanitize("address")))
+ __attribute__((no_sanitize("memory"))) {
+ return *(_BitInt(37) *)&x;
+}
+
+// In this test there is an expectation of assignment of uint32_t from "invalid" _BitInt is not producing any output.
+uint32_t nullability_assign(_BitInt(7) * x)
+ __attribute__((no_sanitize("address")))
+ __attribute__((no_sanitize("memory"))) {
+ _BitInt(7) *_Nonnull y = x;
+ int32_t r = *(_BitInt(7) *)&y;
+ return (r > 0) ? r : 0;
+}
+
+// In those examples the file is expected to compile & run with no diagnostics
+// CHECK-NOT: runtime error:
+
+int main(int argc, char **argv) {
+ // clang-format off
+ uint64_t result =
+ 1ULL +
+ nullability_arg((_BitInt(37) *)argc) +
+ ((uint64_t)nonnull_attribute((_BitInt(37) *)argc) & 0xFFFFFFFF) +
+ nullability_assign((_BitInt(7) *)argc);
+ // clang-format on
+ printf("%u\n", (uint32_t)(result & 0xFFFFFFFF));
+}
diff --git a/compiler-rt/test/ubsan/TestCases/Integer/bit-int.c b/compiler-rt/test/ubsan/TestCases/Integer/bit-int.c
new file mode 100644
index 00000000000000..18dc10bf3a3889
--- /dev/null
+++ b/compiler-rt/test/ubsan/TestCases/Integer/bit-int.c
@@ -0,0 +1,170 @@
+// RUN: %clang -Wno-constant-conversion -Wno-array-bounds -Wno-division-by-zero -Wno-shift-negative-value -Wno-shift-count-negative -Wno-int-to-pointer-cast -O0 -fsanitize=array-bounds,float-cast-overflow,implicit-integer-sign-change,implicit-signed-integer-truncation,implicit-unsigned-integer-truncation,integer-divide-by-zero,pointer-overflow,shift-base,shift-exponent,signed-integer-overflow,unsigned-integer-overflow,unsigned-shift-base,vla-bound %s -o %t1 && %run %t1 2>&1 | FileCheck %s
+
+#include <stdint.h>
+#include <stdio.h>
+
+uint32_t float_divide_by_zero() {
+ float f = 1.0f / 0.0f;
+ _BitInt(37) r = (_BitInt(37))f;
+ // CHECK: {{.*}}bit-int.c:[[#@LINE-1]]:19: runtime error: inf is outside the range of representable values of type
+ return r;
+}
+
+uint32_t integer_divide_by_zero() __attribute__((no_sanitize("memory"))) {
+ _BitInt(37) x = 1 / 0;
+ // CHECK: {{.*}}bit-int.c:[[#@LINE-1]]:21: runtime error: division by zero
+ return x;
+}
+
+uint32_t implicit_unsigned_integer_truncation() {
+ unsigned _BitInt(37) x = 2U;
+ x += float_divide_by_zero();
+ x += integer_divide_by_zero();
+ x = x + 0xFFFFFFFFFFFFFFFFULL;
+ // CHECK: {{.*}}bit-int.c:[[#@LINE-1]]:9: runtime error: unsigned integer overflow:
+ uint32_t r = x & 0xFFFFFFFF;
+ return r;
+}
+
+uint32_t pointer_overflow() __attribute__((no_sanitize("address"))) {
+ _BitInt(37) *x = (_BitInt(37) *)1;
+ _BitInt(37) *y = x - 1;
+ // CHECK: {{.*}}bit-int.c:[[#@LINE-1]]:22: runtime error: pointer index expression with base
+ uint32_t r = *(_BitInt(37) *)&y;
+ // CHECK: {{.*}}bit-int.c:[[#@LINE-1]]:16: runtime error: implicit conversion from type
+ return r;
+}
+
+uint32_t vla_bound(_BitInt(37) x) {
+ _BitInt(37) a[x - 1];
+ // CHECK: {{.*}}bit-int.c:[[#@LINE-1]]:17: runtime error: variable length array bound evaluates to non-positive value
+ return 0;
+}
+
+uint32_t unsigned_shift_base() {
+ unsigned _BitInt(37) x = ~0U << 1;
+ // CHECK: {{.*}}bit-int.c:[[#@LINE-1]]:32: runtime error: left shift of 4294967295 by 1 places cannot be represented in type
+ return x;
+}
+
+uint32_t array_bounds() {
+ _BitInt(37) x[4];
+ _BitInt(37) y = x[10];
+ // CHECK: {{.*}}bit-int.c:[[#@LINE-1]]:19: runtime error: index 10 out of bounds for type
+ return (uint32_t)y;
+}
+
+uint32_t float_cast_overflow() {
+ float a = 100000000.0f;
+ _BitInt(7) b = (_BitInt(7))a;
+ // CHECK: {{.*}}bit-int.c:[[#@LINE-1]]:18: runtime error: 1e+08 is outside the range of representable values of type
+ return b;
+}
+
+uint32_t implicit_integer_sign_change(unsigned _BitInt(37) x) {
+ _BitInt(37) r = x;
+ // CHECK: {{.*}}bit-int.c:[[#@LINE-1]]:19: runtime error: implicit conversion from type '{{[^']+}}' of value
+ return r & 0xFFFFFFFF;
+}
+
+_BitInt(13) implicit_signed_integer_truncation() {
+#ifdef __SIZEOF_INT128__
+ _BitInt(73) x = (_BitInt(73)) ~((~0UL) >> 1);
+#else
+ uint32_t x = 0x7FFFFFFFUL;
+#endif
+ return x;
+ // CHECK: {{.*}}bit-int.c:[[#@LINE-1]]:10: runtime error: implicit conversion from type
+}
+
+_BitInt(37) shift_exponent() __attribute__((no_sanitize("memory"))) {
+ _BitInt(37) x = 1 << (-1);
+ // CHECK: {{.*}}bit-int.c:[[#@LINE-1]]:21: runtime error: shift exponent -1 is negative
+ return x;
+}
+
+_BitInt(37) shift_base() __attribute__((no_sanitize("memory"))) {
+ _BitInt(37) x = (-1) << 1;
+ // CHECK: {{.*}}bit-int.c:[[#@LINE-1]]:24: runtime error: left shift of negative value -1
+ return x;
+}
+
+uint32_t negative_shift1(unsigned _BitInt(37) x)
+ __attribute__((no_sanitize("memory"))) {
+ _BitInt(9) c = -2;
+ return x >> c;
+ // CHECK: {{.*}}bit-int.c:[[#@LINE-1]]:12: runtime error: shift exponent -2 is negative
+}
+
+uint32_t negative_shift2(unsigned _BitInt(37) x)
+ __attribute__((no_sanitize("memory"))) {
+ _BitInt(17) c = -2;
+ return x >> c;
+ // CHECK: {{.*}}bit-int.c:[[#@LINE-1]]:12: runtime error: shift exponent -2 is negative
+}
+
+uint32_t negative_shift3(unsigned _BitInt(37) x)
+ __attribute__((no_sanitize("memory"))) {
+ _BitInt(34) c = -2;
+ return x >> c;
+ // CHECK: {{.*}}bit-int.c:[[#@LINE-1]]:12: runtime error: shift exponent -2 is negative
+}
+
+uint32_t negative_shift4(unsigned _BitInt(37) x)
+ __attribute__((no_sanitize("memory"))) {
+ int64_t c = -2;
+ return x >> c;
+ // CHECK: {{.*}}bit-int.c:[[#@LINE-1]]:12: runtime error: shift exponent -2 is negative
+}
+
+uint32_t negative_shift5(unsigned _BitInt(37) x)
+ __attribute__((no_sanitize("memory"))) {
+#ifdef __SIZEOF_INT128__
+ _BitInt(68) c = -2;
+#else
+ // We cannot check BitInt values > 64 without int128_t support
+ _BitInt(48) c = -2;
+#endif
+ return x >> c;
+ // CHECK: {{.*}}bit-int.c:[[#@LINE-1]]:12: runtime error: shift exponent -2 is negative
+}
+
+uint32_t unsigned_integer_overflow() __attribute__((no_sanitize("memory"))) {
+ unsigned _BitInt(37) x = ~0U;
+ ++x;
+ return x;
+ // CHECK: {{.*}}bit-int.c:[[#@LINE-1]]:10: runtime error: implicit conversion from type
+}
+
+// In this test no run-time overflow expected, so no diagnostics here, but should be a conversion error from the negative number on return.
+uint32_t signed_integer_overflow() __attribute__((no_sanitize("memory"))) {
+ _BitInt(37) x = (_BitInt(37)) ~((0x8FFFFFFFFFFFFFFFULL) >> 1);
+ --x;
+ return x;
+ // CHECK: {{.*}}bit-int.c:[[#@LINE-1]]:10: runtime error: implicit conversion from type
+}
+
+int main(int argc, char **argv) {
+ // clang-format off
+ uint64_t result =
+ 1ULL +
+ implicit_unsigned_integer_truncation() +
+ pointer_overflow() +
+ vla_bound(argc) +
+ unsigned_shift_base() +
+ (uint32_t)array_bounds() +
+ float_cast_overflow() +
+ implicit_integer_sign_change((unsigned _BitInt(37))(argc - 2)) +
+ (uint64_t)implicit_signed_integer_truncation() +
+ shift_exponent() +
+ (uint32_t)shift_base() +
+ negative_shift1(5) +
+ negative_shift2(5) +
+ negative_shift3(5) +
+ negative_shift4(5) +
+ negative_shift5(5) +
+ unsigned_integer_overflow() +
+ signed_integer_overflow();
+ // clang-format on
+ printf("%u\n", (uint32_t)(result & 0xFFFFFFFF));
+}
>From 4de0f7e4c0e35c4a93cf46f0689a251e2ce16c0f Mon Sep 17 00:00:00 2001
From: Vladislav Aranov <vladislav.aranov at ericsson.com>
Date: Thu, 15 Aug 2024 11:49:25 -0400
Subject: [PATCH 2/6] [bitint] Fix test error due to CRT dependency
Remove CRT dependency in headers stdint.h, stdio.h inside test
clang/test/CodeGen/bit-int-ubsan.c
---
clang/test/CodeGen/bit-int-ubsan.c | 20 +-------------------
1 file changed, 1 insertion(+), 19 deletions(-)
diff --git a/clang/test/CodeGen/bit-int-ubsan.c b/clang/test/CodeGen/bit-int-ubsan.c
index 35f96963c181d1..a6328f90be95ae 100644
--- a/clang/test/CodeGen/bit-int-ubsan.c
+++ b/clang/test/CodeGen/bit-int-ubsan.c
@@ -3,9 +3,7 @@
// The runtime test checking the _BitInt ubsan feature is located in compiler-rt/test/ubsan/TestCases/Integer/bit-int.c
-#include <stdint.h>
-#include <stdio.h>
-
+typedef unsigned int uint32_t;
uint32_t float_divide_by_zero() {
float f = 1.0f / 0.0f;
// CHECK: constant { i16, i16, [8 x i8] } { i16 1, i16 32, [8 x i8] c"'float'\00" }
@@ -78,19 +76,3 @@ uint32_t negative_shift5(unsigned _BitInt(37) x)
return x >> c;
// CHECK: constant { i16, i16, [20 x i8] } { i16 2, i16 {{([[:xdigit:]]{2})}}, [20 x i8] c"'_BitInt(68)'\00D\00\00\00\00\00" }
}
-
-int main(int argc, char **argv) {
- // clang-format off
- uint64_t result =
- 1ULL +
- implicit_unsigned_integer_truncation() +
- (uint32_t)array_bounds() +
- float_cast_overflow() +
- (uint64_t)implicit_signed_integer_truncation() +
- negative_shift1(5) +
- negative_shift2(5) +
- negative_shift3(5) +
- negative_shift5(5);
- // clang-format on
- printf("%u\n", (uint32_t)(result & 0xFFFFFFFF));
-}
>From 0f15cfbea082bee416597a38b8354ddcfd9c690a Mon Sep 17 00:00:00 2001
From: Vladislav Aranov <vladislav.aranov at ericsson.com>
Date: Thu, 15 Aug 2024 12:32:52 -0400
Subject: [PATCH 3/6] [test] Update CodeGen/bit-int-ubsan to invoke only
frontend
Replace %clang with %clang_cc1 and adjust the run line.
---
clang/test/CodeGen/bit-int-ubsan.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/CodeGen/bit-int-ubsan.c b/clang/test/CodeGen/bit-int-ubsan.c
index a6328f90be95ae..10c0d8a23f8f97 100644
--- a/clang/test/CodeGen/bit-int-ubsan.c
+++ b/clang/test/CodeGen/bit-int-ubsan.c
@@ -1,5 +1,5 @@
// REQUIRES: x86-registered-target
-// RUN: %clang -Wno-constant-conversion -Wno-array-bounds -Wno-division-by-zero -Wno-shift-negative-value -Wno-shift-count-negative -Wno-int-to-pointer-cast -fsanitize=array-bounds,enum,float-cast-overflow,integer-divide-by-zero,implicit-unsigned-integer-truncation,implicit-signed-integer-truncation,implicit-integer-sign-change,unsigned-integer-overflow,signed-integer-overflow,shift-base,shift-exponent -O0 -S -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -Wno-constant-conversion -Wno-array-bounds -Wno-division-by-zero -Wno-shift-negative-value -Wno-shift-count-negative -Wno-int-to-pointer-cast -fsanitize=array-bounds,enum,float-cast-overflow,integer-divide-by-zero,implicit-unsigned-integer-truncation,implicit-signed-integer-truncation,implicit-integer-sign-change,unsigned-integer-overflow,signed-integer-overflow,shift-base,shift-exponent -O0 -emit-llvm -o - %s | FileCheck %s
// The runtime test checking the _BitInt ubsan feature is located in compiler-rt/test/ubsan/TestCases/Integer/bit-int.c
>From 0c2cbba674710458bebb0fad2b88f5b0258ed04f Mon Sep 17 00:00:00 2001
From: Vladislav Aranov <vladislav.aranov at ericsson.com>
Date: Thu, 15 Aug 2024 15:59:29 -0400
Subject: [PATCH 4/6] [ubsan] Limit runtime tests to x86-64 target only
Due to failure on spark solaris target apply target limit.
---
compiler-rt/test/ubsan/TestCases/Integer/bit-int-pass.c | 1 +
compiler-rt/test/ubsan/TestCases/Integer/bit-int.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/compiler-rt/test/ubsan/TestCases/Integer/bit-int-pass.c b/compiler-rt/test/ubsan/TestCases/Integer/bit-int-pass.c
index a25428f0eb872f..2255d2d08c7661 100644
--- a/compiler-rt/test/ubsan/TestCases/Integer/bit-int-pass.c
+++ b/compiler-rt/test/ubsan/TestCases/Integer/bit-int-pass.c
@@ -1,3 +1,4 @@
+// REQUIRES: x86_64-target-arch
// RUN: %clang -Wno-constant-conversion -Wno-array-bounds -Wno-division-by-zero -Wno-shift-negative-value -Wno-shift-count-negative -Wno-int-to-pointer-cast -O0 -fsanitize=alignment,array-bounds,bool,float-cast-overflow,implicit-integer-sign-change,implicit-signed-integer-truncation,implicit-unsigned-integer-truncation,integer-divide-by-zero,nonnull-attribute,null,nullability-arg,nullability-assign,nullability-return,pointer-overflow,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,unsigned-integer-overflow,unsigned-shift-base,vla-bound %s -o %t1 && %run %t1 2>&1 | FileCheck %s
#include <stdint.h>
diff --git a/compiler-rt/test/ubsan/TestCases/Integer/bit-int.c b/compiler-rt/test/ubsan/TestCases/Integer/bit-int.c
index 18dc10bf3a3889..27a919b09946ae 100644
--- a/compiler-rt/test/ubsan/TestCases/Integer/bit-int.c
+++ b/compiler-rt/test/ubsan/TestCases/Integer/bit-int.c
@@ -1,3 +1,4 @@
+// REQUIRES: x86_64-target-arch
// RUN: %clang -Wno-constant-conversion -Wno-array-bounds -Wno-division-by-zero -Wno-shift-negative-value -Wno-shift-count-negative -Wno-int-to-pointer-cast -O0 -fsanitize=array-bounds,float-cast-overflow,implicit-integer-sign-change,implicit-signed-integer-truncation,implicit-unsigned-integer-truncation,integer-divide-by-zero,pointer-overflow,shift-base,shift-exponent,signed-integer-overflow,unsigned-integer-overflow,unsigned-shift-base,vla-bound %s -o %t1 && %run %t1 2>&1 | FileCheck %s
#include <stdint.h>
>From 5adf01b804af5dcd6aa0dd3c2c5eae0ee5b8f39d Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at gmail.com>
Date: Thu, 15 Aug 2024 13:46:08 -0700
Subject: [PATCH 5/6] Update bit-int.c
---
compiler-rt/test/ubsan/TestCases/Integer/bit-int.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/compiler-rt/test/ubsan/TestCases/Integer/bit-int.c b/compiler-rt/test/ubsan/TestCases/Integer/bit-int.c
index 27a919b09946ae..48f718285b06a1 100644
--- a/compiler-rt/test/ubsan/TestCases/Integer/bit-int.c
+++ b/compiler-rt/test/ubsan/TestCases/Integer/bit-int.c
@@ -1,6 +1,9 @@
// REQUIRES: x86_64-target-arch
// RUN: %clang -Wno-constant-conversion -Wno-array-bounds -Wno-division-by-zero -Wno-shift-negative-value -Wno-shift-count-negative -Wno-int-to-pointer-cast -O0 -fsanitize=array-bounds,float-cast-overflow,implicit-integer-sign-change,implicit-signed-integer-truncation,implicit-unsigned-integer-truncation,integer-divide-by-zero,pointer-overflow,shift-base,shift-exponent,signed-integer-overflow,unsigned-integer-overflow,unsigned-shift-base,vla-bound %s -o %t1 && %run %t1 2>&1 | FileCheck %s
+// FIXME: make the test pass on windows.
+// XFAIL: target={{.*windows-msvc.*}}
+
#include <stdint.h>
#include <stdio.h>
>From 4aac3cdb4d10fb8423a2273f57a72884a9606f82 Mon Sep 17 00:00:00 2001
From: Vladislav Aranov <vladislav.aranov at ericsson.com>
Date: Fri, 16 Aug 2024 11:16:05 -0400
Subject: [PATCH 6/6] [test] Prevent generation of the big-endian code
Pass triple explicitly in the run-line of the tests.
---
clang/test/CodeGen/bit-int-ubsan.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/CodeGen/bit-int-ubsan.c b/clang/test/CodeGen/bit-int-ubsan.c
index 10c0d8a23f8f97..40e4fde1d1f417 100644
--- a/clang/test/CodeGen/bit-int-ubsan.c
+++ b/clang/test/CodeGen/bit-int-ubsan.c
@@ -1,5 +1,5 @@
// REQUIRES: x86-registered-target
-// RUN: %clang_cc1 -Wno-constant-conversion -Wno-array-bounds -Wno-division-by-zero -Wno-shift-negative-value -Wno-shift-count-negative -Wno-int-to-pointer-cast -fsanitize=array-bounds,enum,float-cast-overflow,integer-divide-by-zero,implicit-unsigned-integer-truncation,implicit-signed-integer-truncation,implicit-integer-sign-change,unsigned-integer-overflow,signed-integer-overflow,shift-base,shift-exponent -O0 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -Wno-constant-conversion -Wno-array-bounds -Wno-division-by-zero -Wno-shift-negative-value -Wno-shift-count-negative -Wno-int-to-pointer-cast -fsanitize=array-bounds,enum,float-cast-overflow,integer-divide-by-zero,implicit-unsigned-integer-truncation,implicit-signed-integer-truncation,implicit-integer-sign-change,unsigned-integer-overflow,signed-integer-overflow,shift-base,shift-exponent -O0 -emit-llvm -o - %s | FileCheck %s
// The runtime test checking the _BitInt ubsan feature is located in compiler-rt/test/ubsan/TestCases/Integer/bit-int.c
More information about the cfe-commits
mailing list