Skip to content

Commit 47c54d5

Browse files
authored
[UBSan] Improve error message when a misalignment is due to target default assumed alignment
1 parent 24c22b7 commit 47c54d5

File tree

6 files changed

+86
-12
lines changed

6 files changed

+86
-12
lines changed

clang/lib/CodeGen/CGExprCXX.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
#include "ConstantEmitter.h"
1919
#include "TargetInfo.h"
2020
#include "clang/Basic/CodeGenOptions.h"
21+
#include "clang/Basic/Sanitizers.h"
22+
#include "clang/Basic/SourceLocation.h"
23+
#include "clang/Basic/SourceManager.h"
2124
#include "clang/CodeGen/CGFunctionInfo.h"
2225
#include "llvm/IR/Intrinsics.h"
2326

@@ -1749,17 +1752,27 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
17491752
allocator->isReservedGlobalPlacementOperator())
17501753
result = Builder.CreateLaunderInvariantGroup(result);
17511754

1755+
// Check the default alignment of the type and why. Users may incorrectly
1756+
// return misaligned memory from a replaced operator new without knowing
1757+
// about default alignment.
1758+
TypeCheckKind checkKind = CodeGenFunction::TCK_ConstructorCall;
1759+
const TargetInfo &TI = getContext().getTargetInfo();
1760+
unsigned DefaultTargetAlignment = TI.getNewAlign() / TI.getCharWidth();
1761+
if (SanOpts.has(SanitizerKind::Alignment) &&
1762+
(DefaultTargetAlignment >
1763+
CGM.getContext().getTypeAlignInChars(allocType).getQuantity()))
1764+
checkKind = CodeGenFunction::TCK_ConstructorCallMinimumAlign;
1765+
17521766
// Emit sanitizer checks for pointer value now, so that in the case of an
17531767
// array it was checked only once and not at each constructor call. We may
17541768
// have already checked that the pointer is non-null.
17551769
// FIXME: If we have an array cookie and a potentially-throwing allocator,
17561770
// we'll null check the wrong pointer here.
17571771
SanitizerSet SkippedChecks;
17581772
SkippedChecks.set(SanitizerKind::Null, nullCheck);
1759-
EmitTypeCheck(CodeGenFunction::TCK_ConstructorCall,
1760-
E->getAllocatedTypeSourceInfo()->getTypeLoc().getBeginLoc(),
1761-
result, allocType, result.getAlignment(), SkippedChecks,
1762-
numElements);
1773+
EmitTypeCheck(
1774+
checkKind, E->getAllocatedTypeSourceInfo()->getTypeLoc().getBeginLoc(),
1775+
result, allocType, result.getAlignment(), SkippedChecks, numElements);
17631776

17641777
EmitNewInitializer(*this, E, allocType, elementTy, result, numElements,
17651778
allocSizeWithoutCookie);

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3296,7 +3296,10 @@ class CodeGenFunction : public CodeGenTypeCache {
32963296
TCK_NonnullAssign,
32973297
/// Checking the operand of a dynamic_cast or a typeid expression. Must be
32983298
/// null or an object within its lifetime.
3299-
TCK_DynamicOperation
3299+
TCK_DynamicOperation,
3300+
/// Checking the 'this' poiner for a constructor call, including that the
3301+
/// alignment is greater or equal to the targets minimum alignment
3302+
TCK_ConstructorCallMinimumAlign
33003303
};
33013304

33023305
/// Determine whether the pointer type check \p TCK permits null pointers.

compiler-rt/lib/ubsan/ubsan_checks.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ UBSAN_CHECK(NullptrAfterNonZeroOffset, "nullptr-after-nonzero-offset",
2828
UBSAN_CHECK(PointerOverflow, "pointer-overflow", "pointer-overflow")
2929
UBSAN_CHECK(MisalignedPointerUse, "misaligned-pointer-use", "alignment")
3030
UBSAN_CHECK(AlignmentAssumption, "alignment-assumption", "alignment")
31+
UBSAN_CHECK(MinumumAssumedAlignment, "minimum-assumed-alignment", "alignment")
3132
UBSAN_CHECK(InsufficientObjectSize, "insufficient-object-size", "object-size")
3233
UBSAN_CHECK(SignedIntegerOverflow, "signed-integer-overflow",
3334
"signed-integer-overflow")

compiler-rt/lib/ubsan/ubsan_handlers.cpp

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,26 @@ enum TypeCheckKind {
7373
TCK_NonnullAssign,
7474
/// Checking the operand of a dynamic_cast or a typeid expression. Must be
7575
/// null or an object within its lifetime.
76-
TCK_DynamicOperation
76+
TCK_DynamicOperation,
77+
/// Checking the 'this' poiner for a constructor call, including that the
78+
/// alignment is greater or equal to the targets minimum alignment
79+
TCK_ConstructorCallMinimumAlign
7780
};
7881

7982
extern const char *const TypeCheckKinds[] = {
80-
"load of", "store to", "reference binding to", "member access within",
81-
"member call on", "constructor call on", "downcast of", "downcast of",
82-
"upcast of", "cast to virtual base of", "_Nonnull binding to",
83-
"dynamic operation on"};
83+
"load of",
84+
"store to",
85+
"reference binding to",
86+
"member access within",
87+
"member call on",
88+
"constructor call on",
89+
"downcast of",
90+
"downcast of",
91+
"upcast of",
92+
"cast to virtual base of",
93+
"_Nonnull binding to",
94+
"dynamic operation on",
95+
"constructor call with pointer from operator new on"};
8496
}
8597

8698
static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
@@ -94,7 +106,9 @@ static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
94106
? ErrorType::NullPointerUseWithNullability
95107
: ErrorType::NullPointerUse;
96108
else if (Pointer & (Alignment - 1))
97-
ET = ErrorType::MisalignedPointerUse;
109+
ET = (Data->TypeCheckKind == TCK_ConstructorCallMinimumAlign)
110+
? ErrorType::MinumumAssumedAlignment
111+
: ErrorType::MisalignedPointerUse;
98112
else
99113
ET = ErrorType::InsufficientObjectSize;
100114

@@ -117,6 +131,13 @@ static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
117131
Diag(Loc, DL_Error, ET, "%0 null pointer of type %1")
118132
<< TypeCheckKinds[Data->TypeCheckKind] << Data->Type;
119133
break;
134+
case ErrorType::MinumumAssumedAlignment:
135+
Diag(Loc, DL_Error, ET,
136+
"%0 misaligned address %1 for type %2, "
137+
"which requires target minimum assumed %3 byte alignment")
138+
<< TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer << Data->Type
139+
<< Alignment;
140+
break;
120141
case ErrorType::MisalignedPointerUse:
121142
Diag(Loc, DL_Error, ET, "%0 misaligned address %1 for type %3, "
122143
"which requires %2 byte alignment")
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %clangxx %gmlt -fsanitize=alignment %s -o %t
2+
// RUN: %run %t 2>&1 | FileCheck %s
3+
4+
// UNSUPPORTED: i386
5+
// UNSUPPORTED: armv7l
6+
7+
// These sanitizers already overload the new operator so won't compile this test
8+
// UNSUPPORTED: ubsan-msan
9+
// UNSUPPORTED: ubsan-tsan
10+
11+
#include <cassert>
12+
#include <cstdlib>
13+
14+
void *operator new(std::size_t count) {
15+
constexpr const size_t offset = 8;
16+
17+
// allocate a bit more so we can safely offset it
18+
void *ptr = std::malloc(count + offset);
19+
20+
// verify malloc returned 16 bytes aligned mem
21+
static_assert(__STDCPP_DEFAULT_NEW_ALIGNMENT__ == 16);
22+
assert(((std::ptrdiff_t)ptr & (__STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1)) == 0);
23+
24+
return (char *)ptr + offset;
25+
}
26+
27+
struct Foo {
28+
void *_cookie1, *_cookie2;
29+
};
30+
31+
static_assert(alignof(Foo) == 8);
32+
int main() {
33+
// CHECK: runtime error: constructor call with pointer from operator new on misaligned address 0x{{.*}} for type 'Foo', which requires target minimum assumed 16 byte alignment
34+
Foo *f = new Foo;
35+
return 0;
36+
}

compiler-rt/test/ubsan/TestCases/TypeCheck/misaligned.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ int main(int, char **argv) {
101101
return s->f() && 0;
102102

103103
case 'n':
104-
// CHECK-NEW: misaligned.cpp:[[@LINE+4]]{{(:21)?}}: runtime error: constructor call on misaligned address [[PTR:0x[0-9a-f]*]] for type 'S', which requires 4 byte alignment
104+
// CHECK-NEW: misaligned.cpp:[[@LINE+4]]{{(:21)?}}: runtime error: constructor call with pointer from operator new on misaligned address [[PTR:0x[0-9a-f]*]] for type 'S', which requires target minimum assumed 4 byte alignment
105105
// CHECK-NEW-NEXT: [[PTR]]: note: pointer points here
106106
// CHECK-NEW-NEXT: {{^ 00 00 00 01 02 03 04 05}}
107107
// CHECK-NEW-NEXT: {{^ \^}}

0 commit comments

Comments
 (0)