Skip to content

Commit 63a4e48

Browse files
committed
[ubsan] Have -fsanitize=vptr emit a null check if -fsanitize=null isn't available
In r309007, I made -fsanitize=null a hard prerequisite for -fsanitize=vptr. I did not see the need for the two checks to have separate null checking logic for the same pointer. I expected the two checks to either always be enabled together, or to be mutually compatible. In the mailing list discussion re: r309007 it became clear that that isn't the case. If a codebase is -fsanitize=vptr clean but not -fsanitize=null clean, it's useful to have -fsanitize=vptr emit its own null check. That's what this patch does: with it, -fsanitize=vptr can be used without -fsanitize=null. Differential Revision: https://reviews.llvm.org/D36112 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@309846 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent d9009e5 commit 63a4e48

File tree

9 files changed

+29
-40
lines changed

9 files changed

+29
-40
lines changed

docs/ReleaseNotes.rst

+1-3
Original file line numberDiff line numberDiff line change
@@ -198,9 +198,7 @@ Static Analyzer
198198
Undefined Behavior Sanitizer (UBSan)
199199
------------------------------------
200200

201-
The C++ dynamic type check now requires run-time null checking (i.e,
202-
`-fsanitize=vptr` cannot be used without `-fsanitize=null`). This change does
203-
not impact users who rely on UBSan check groups (e.g `-fsanitize=undefined`).
201+
...
204202

205203
Core Analysis Improvements
206204
==========================

docs/UndefinedBehaviorSanitizer.rst

+4-4
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,10 @@ Available checks are:
132132
- ``-fsanitize=vla-bound``: A variable-length array whose bound
133133
does not evaluate to a positive value.
134134
- ``-fsanitize=vptr``: Use of an object whose vptr indicates that it is of
135-
the wrong dynamic type, or that its lifetime has not begun or has ended.
136-
Incompatible with ``-fno-rtti`` and ``-fno-sanitize=null``. Link must be
137-
performed by ``clang++``, not ``clang``, to make sure C++-specific parts of
138-
the runtime library and C++ standard libraries are present.
135+
the wrong dynamic type, or that its lifetime has not begun or has ended.
136+
Incompatible with ``-fno-rtti``. Link must be performed by ``clang++``, not
137+
``clang``, to make sure C++-specific parts of the runtime library and C++
138+
standard libraries are present.
139139

140140
You can also use the following check groups:
141141
- ``-fsanitize=undefined``: All of the checks listed above other than

include/clang/Basic/DiagnosticDriverKinds.td

-3
Original file line numberDiff line numberDiff line change
@@ -232,9 +232,6 @@ def warn_drv_enabling_rtti_with_exceptions : Warning<
232232
def warn_drv_disabling_vptr_no_rtti_default : Warning<
233233
"implicitly disabling vptr sanitizer because rtti wasn't enabled">,
234234
InGroup<AutoDisableVptrSanitizer>;
235-
def warn_drv_disabling_vptr_no_null_check : Warning<
236-
"implicitly disabling vptr sanitizer because null checking wasn't enabled">,
237-
InGroup<AutoDisableVptrSanitizer>;
238235
def warn_drv_object_size_disabled_O0 : Warning<
239236
"the object size sanitizer has no effect at -O0, but is explicitly enabled: %0">,
240237
InGroup<InvalidCommandLineArgument>;

lib/CodeGen/CGExpr.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -694,17 +694,17 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
694694
// -- the [pointer or glvalue] is used to access a non-static data member
695695
// or call a non-static member function
696696
CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
697-
bool HasNullCheck = IsGuaranteedNonNull || IsNonNull;
698697
if (SanOpts.has(SanitizerKind::Vptr) &&
699-
!SkippedChecks.has(SanitizerKind::Vptr) && HasNullCheck &&
698+
!SkippedChecks.has(SanitizerKind::Vptr) &&
700699
(TCK == TCK_MemberAccess || TCK == TCK_MemberCall ||
701700
TCK == TCK_DowncastPointer || TCK == TCK_DowncastReference ||
702701
TCK == TCK_UpcastToVirtualBase) &&
703702
RD && RD->hasDefinition() && RD->isDynamicClass()) {
704703
// Ensure that the pointer is non-null before loading it. If there is no
705-
// compile-time guarantee, reuse the run-time null check.
704+
// compile-time guarantee, reuse the run-time null check or emit a new one.
706705
if (!IsGuaranteedNonNull) {
707-
assert(IsNonNull && "Missing run-time null check");
706+
if (!IsNonNull)
707+
IsNonNull = Builder.CreateIsNotNull(Ptr);
708708
if (!Done)
709709
Done = createBasicBlock("vptr.null");
710710
llvm::BasicBlock *VptrNotNull = createBasicBlock("vptr.not.null");

lib/Driver/SanitizerArgs.cpp

-7
Original file line numberDiff line numberDiff line change
@@ -307,13 +307,6 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
307307
Kinds &= ~Vptr;
308308
}
309309

310-
// Disable -fsanitize=vptr if -fsanitize=null is not enabled (the vptr
311-
// instrumentation is broken without run-time null checks).
312-
if ((Kinds & Vptr) && !(Kinds & Null)) {
313-
Kinds &= ~Vptr;
314-
D.Diag(diag::warn_drv_disabling_vptr_no_null_check);
315-
}
316-
317310
// Check that LTO is enabled if we need it.
318311
if ((Kinds & NeedsLTO) && !D.isUsingLTO()) {
319312
D.Diag(diag::err_drv_argument_only_allowed_with)

test/CodeGenCXX/catch-undef-behavior.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %clang_cc1 -std=c++11 -fsanitize=signed-integer-overflow,integer-divide-by-zero,float-divide-by-zero,shift-base,shift-exponent,unreachable,return,vla-bound,alignment,null,vptr,object-size,float-cast-overflow,bool,enum,array-bounds,function -fsanitize-recover=signed-integer-overflow,integer-divide-by-zero,float-divide-by-zero,shift-base,shift-exponent,vla-bound,alignment,null,vptr,object-size,float-cast-overflow,bool,enum,array-bounds,function -emit-llvm %s -o - -triple x86_64-linux-gnu | opt -instnamer -S | FileCheck %s
2-
// RUN: %clang_cc1 -std=c++11 -fsanitize=null,vptr,address -fsanitize-recover=null,vptr,address -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-ASAN
3-
// RUN: %clang_cc1 -std=c++11 -fsanitize=null,vptr -fsanitize-recover=null,vptr -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=DOWNCAST-NULL
2+
// RUN: %clang_cc1 -std=c++11 -fsanitize=vptr,address -fsanitize-recover=vptr,address -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-ASAN
3+
// RUN: %clang_cc1 -std=c++11 -fsanitize=vptr -fsanitize-recover=vptr -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=DOWNCAST-NULL
44
// RUN: %clang_cc1 -std=c++11 -fsanitize=function -emit-llvm %s -o - -triple x86_64-linux-gnux32 | FileCheck %s --check-prefix=CHECK-X32
55
// RUN: %clang_cc1 -std=c++11 -fsanitize=function -emit-llvm %s -o - -triple i386-linux-gnu | FileCheck %s --check-prefix=CHECK-X86
66

test/CodeGenCXX/ubsan-type-checks.cpp

+10-5
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,22 @@ struct Dog : Animal {
4444

4545
// VPTR-LABEL: define void @_Z12invalid_castP3Cat
4646
void invalid_cast(Cat *cat = nullptr) {
47-
// First, null check the pointer:
47+
// If -fsanitize=null is available, we'll reuse its check:
4848
//
4949
// VPTR: [[ICMP:%.*]] = icmp ne %struct.Dog* {{.*}}, null
5050
// VPTR-NEXT: br i1 [[ICMP]]
5151
// VPTR: call void @__ubsan_handle_type_mismatch
52-
//
53-
// Once we're done emitting the null check, reuse the check to see if we can
54-
// proceed to the vptr check:
55-
//
52+
// VPTR-NOT: icmp ne %struct.Dog* {{.*}}, null
5653
// VPTR: br i1 [[ICMP]]
5754
// VPTR: call void @__ubsan_handle_dynamic_type_cache_miss
55+
//
56+
// Fall back to the vptr sanitizer's null check when -fsanitize=null isn't
57+
// available.
58+
//
59+
// VPTR_NO_NULL-NOT: call void @__ubsan_handle_type_mismatch
60+
// VPTR_NO_NULL: [[ICMP:%.*]] = icmp ne %struct.Dog* {{.*}}, null
61+
// VPTR_NO_NULL-NEXT: br i1 [[ICMP]]
62+
// VPTR_NO_NULL: call void @__ubsan_handle_dynamic_type_cache_miss
5863
auto *badDog = reinterpret_cast<Dog *>(cat);
5964
badDog->speak();
6065
}

test/Driver/fsanitize.c

+2-6
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,6 @@
5858
// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-NO-RTTI
5959
// CHECK-UNDEFINED-NO-RTTI-NOT: vptr
6060

61-
// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fno-sanitize=null %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-NO-NULL
62-
// RUN: %clang -target x86_64-linux-gnu -fsanitize=vptr %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-NO-NULL
63-
// CHECK-VPTR-NO-NULL: warning: implicitly disabling vptr sanitizer because null checking wasn't enabled
64-
6561
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address,thread -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANA-SANT
6662
// CHECK-SANA-SANT: '-fsanitize=address' not allowed with '-fsanitize=thread'
6763

@@ -366,8 +362,8 @@
366362
// RUN: %clang -target x86_64-apple-darwin10 -mmacosx-version-min=10.8 -fsanitize=vptr %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-DARWIN-OLD
367363
// CHECK-VPTR-DARWIN-OLD: unsupported option '-fsanitize=vptr' for target 'x86_64-apple-darwin10'
368364

369-
// RUN: %clang -target x86_64-apple-darwin10 -mmacosx-version-min=10.9 -fsanitize=alignment,null,vptr %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-DARWIN-NEW
370-
// CHECK-VPTR-DARWIN-NEW: -fsanitize=alignment,null,vptr
365+
// RUN: %clang -target x86_64-apple-darwin10 -mmacosx-version-min=10.9 -fsanitize=alignment,vptr %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-DARWIN-NEW
366+
// CHECK-VPTR-DARWIN-NEW: -fsanitize=alignment,vptr
371367

372368
// RUN: %clang -target armv7-apple-ios7 -miphoneos-version-min=7.0 -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-IOS
373369
// CHECK-ASAN-IOS: -fsanitize=address

test/Driver/rtti-options.cpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@
1616
// Make sure we only error/warn once, when trying to enable vptr and
1717
// undefined and have -fno-rtti
1818
// RUN: %clang -### -c -target x86_64-unknown-linux -fsanitize=undefined -fsanitize=vptr -fno-rtti %s 2>&1 | FileCheck -check-prefix=CHECK-SAN-ERROR -check-prefix=CHECK-OK %s
19-
// RUN: %clang -### -c -target x86_64-unknown-linux -fsanitize=null,vptr %s 2>&1 | FileCheck -check-prefix=CHECK-OK %s
20-
// RUN: %clang -### -c -target x86_64-unknown-linux -fsanitize=null,vptr -frtti %s 2>&1 | FileCheck -check-prefix=CHECK-OK %s
21-
// RUN: %clang -### -c -target x86_64-unknown-linux -fsanitize=null,vptr -fno-rtti %s 2>&1 | FileCheck -check-prefix=CHECK-SAN-ERROR %s
19+
// RUN: %clang -### -c -target x86_64-unknown-linux -fsanitize=vptr %s 2>&1 | FileCheck -check-prefix=CHECK-OK %s
20+
// RUN: %clang -### -c -target x86_64-unknown-linux -fsanitize=vptr -frtti %s 2>&1 | FileCheck -check-prefix=CHECK-OK %s
21+
// RUN: %clang -### -c -target x86_64-unknown-linux -fsanitize=vptr -fno-rtti %s 2>&1 | FileCheck -check-prefix=CHECK-SAN-ERROR %s
2222
// RUN: %clang -### -c -target x86_64-unknown-linux -fsanitize=undefined %s 2>&1 | FileCheck -check-prefix=CHECK-OK %s
2323
// RUN: %clang -### -c -target x86_64-unknown-linux -fsanitize=undefined -frtti %s 2>&1 | FileCheck -check-prefix=CHECK-OK %s
24-
// RUN: %clang -### -c -target x86_64-scei-ps4 -fsanitize=null,vptr %s 2>&1 | FileCheck -check-prefix=CHECK-SAN-WARN %s
25-
// RUN: %clang -### -c -target x86_64-scei-ps4 -fsanitize=null,vptr -frtti %s 2>&1 | FileCheck -check-prefix=CHECK-OK %s
26-
// RUN: %clang -### -c -target x86_64-scei-ps4 -fsanitize=null,vptr -fno-rtti %s 2>&1 | FileCheck -check-prefix=CHECK-SAN-ERROR %s
24+
// RUN: %clang -### -c -target x86_64-scei-ps4 -fsanitize=vptr %s 2>&1 | FileCheck -check-prefix=CHECK-SAN-WARN %s
25+
// RUN: %clang -### -c -target x86_64-scei-ps4 -fsanitize=vptr -frtti %s 2>&1 | FileCheck -check-prefix=CHECK-OK %s
26+
// RUN: %clang -### -c -target x86_64-scei-ps4 -fsanitize=vptr -fno-rtti %s 2>&1 | FileCheck -check-prefix=CHECK-SAN-ERROR %s
2727
// RUN: %clang -### -c -target x86_64-scei-ps4 -fsanitize=undefined -frtti %s 2>&1 | FileCheck -check-prefix=CHECK-OK %s
2828

2929
// Exceptions + no/default rtti

0 commit comments

Comments
 (0)