Skip to content

Commit 5745ecc

Browse files
committed
Adapt -fsanitize=function to SANITIZER_NON_UNIQUE_TYPEINFO
This follows up after b7692bc "[UBSan] Fix isDerivedFromAtOffset on iOS ARM64" fixed the RTTI comparison in isDerivedFromAtOffset on just one platform and then a25a2c7 "Always compare C++ typeinfo (based on libstdc++ implementation)" extended that fix to more platforms. But there is another RTTI comparison for -fsanitize=function generated in clang's CodeGenFunction::EmitCall as just a pointer comparison. For SANITIZER_NON_UNIQUE_TYPEINFO platforms this needs to be extended to also do string comparison. For that, __ubsan_handle_function_type_mismatch[_abort] takes the two std::type_info pointers as additional parameters now, checks them internally for potential equivalence, and returns without reporting failure if they turn out to be equivalent after all. (NORETURN needed to be dropped from the _abort variant for that.) Also these functions depend on ABI-specific RTTI now, so needed to be moved from plain UBSAN_SOURCES (ubsan_handlers.h/cc) to UBSAN_CXXABI_SOURCES (ubsan_handlers_cxx.h/cc), but as -fsanitize=function is only supported in C++ mode that's not a problem. Differential Revision: https://reviews.llvm.org/D60760 llvm-svn: 359759
1 parent 7d0e8cb commit 5745ecc

8 files changed

+81
-49
lines changed

clang/lib/CodeGen/CGExpr.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -4672,7 +4672,8 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee
46724672
llvm::Constant *StaticData[] = {EmitCheckSourceLocation(E->getBeginLoc()),
46734673
EmitCheckTypeDescriptor(CalleeType)};
46744674
EmitCheck(std::make_pair(CalleeRTTIMatch, SanitizerKind::Function),
4675-
SanitizerHandler::FunctionTypeMismatch, StaticData, CalleePtr);
4675+
SanitizerHandler::FunctionTypeMismatch, StaticData,
4676+
{CalleePtr, CalleeRTTI, FTRTTIConst});
46764677

46774678
Builder.CreateBr(Cont);
46784679
EmitBlock(Cont);

compiler-rt/lib/ubsan/ubsan_handlers.cc

-36
Original file line numberDiff line numberDiff line change
@@ -598,42 +598,6 @@ void __ubsan::__ubsan_handle_invalid_builtin_abort(InvalidBuiltinData *Data) {
598598
Die();
599599
}
600600

601-
static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data,
602-
ValueHandle Function,
603-
ReportOptions Opts) {
604-
SourceLocation CallLoc = Data->Loc.acquire();
605-
ErrorType ET = ErrorType::FunctionTypeMismatch;
606-
607-
if (ignoreReport(CallLoc, Opts, ET))
608-
return;
609-
610-
ScopedReport R(Opts, CallLoc, ET);
611-
612-
SymbolizedStackHolder FLoc(getSymbolizedLocation(Function));
613-
const char *FName = FLoc.get()->info.function;
614-
if (!FName)
615-
FName = "(unknown)";
616-
617-
Diag(CallLoc, DL_Error, ET,
618-
"call to function %0 through pointer to incorrect function type %1")
619-
<< FName << Data->Type;
620-
Diag(FLoc, DL_Note, ET, "%0 defined here") << FName;
621-
}
622-
623-
void
624-
__ubsan::__ubsan_handle_function_type_mismatch(FunctionTypeMismatchData *Data,
625-
ValueHandle Function) {
626-
GET_REPORT_OPTIONS(false);
627-
handleFunctionTypeMismatch(Data, Function, Opts);
628-
}
629-
630-
void __ubsan::__ubsan_handle_function_type_mismatch_abort(
631-
FunctionTypeMismatchData *Data, ValueHandle Function) {
632-
GET_REPORT_OPTIONS(true);
633-
handleFunctionTypeMismatch(Data, Function, Opts);
634-
Die();
635-
}
636-
637601
static void handleNonNullReturn(NonNullReturnData *Data, SourceLocation *LocPtr,
638602
ReportOptions Opts, bool IsAttr) {
639603
if (!LocPtr)

compiler-rt/lib/ubsan/ubsan_handlers.h

-9
Original file line numberDiff line numberDiff line change
@@ -168,15 +168,6 @@ struct InvalidBuiltinData {
168168
/// Handle a builtin called in an invalid way.
169169
RECOVERABLE(invalid_builtin, InvalidBuiltinData *Data)
170170

171-
struct FunctionTypeMismatchData {
172-
SourceLocation Loc;
173-
const TypeDescriptor &Type;
174-
};
175-
176-
RECOVERABLE(function_type_mismatch,
177-
FunctionTypeMismatchData *Data,
178-
ValueHandle Val)
179-
180171
struct NonNullReturnData {
181172
SourceLocation AttrLoc;
182173
};

compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc

+45
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,51 @@ void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,
156156
Diag(Loc, DL_Note, ET, "check failed in %0, vtable located in %1")
157157
<< SrcModule << DstModule;
158158
}
159+
160+
static bool handleFunctionTypeMismatch(FunctionTypeMismatchData *Data,
161+
ValueHandle Function,
162+
ValueHandle calleeRTTI,
163+
ValueHandle fnRTTI, ReportOptions Opts) {
164+
if (checkTypeInfoEquality(reinterpret_cast<void *>(calleeRTTI),
165+
reinterpret_cast<void *>(fnRTTI)))
166+
return false;
167+
168+
SourceLocation CallLoc = Data->Loc.acquire();
169+
ErrorType ET = ErrorType::FunctionTypeMismatch;
170+
171+
if (ignoreReport(CallLoc, Opts, ET))
172+
return true;
173+
174+
ScopedReport R(Opts, CallLoc, ET);
175+
176+
SymbolizedStackHolder FLoc(getSymbolizedLocation(Function));
177+
const char *FName = FLoc.get()->info.function;
178+
if (!FName)
179+
FName = "(unknown)";
180+
181+
Diag(CallLoc, DL_Error, ET,
182+
"call to function %0 through pointer to incorrect function type %1")
183+
<< FName << Data->Type;
184+
Diag(FLoc, DL_Note, ET, "%0 defined here") << FName;
185+
return true;
186+
}
187+
188+
void __ubsan_handle_function_type_mismatch(FunctionTypeMismatchData *Data,
189+
ValueHandle Function,
190+
ValueHandle calleeRTTI,
191+
ValueHandle fnRTTI) {
192+
GET_REPORT_OPTIONS(false);
193+
handleFunctionTypeMismatch(Data, Function, calleeRTTI, fnRTTI, Opts);
194+
}
195+
196+
void __ubsan_handle_function_type_mismatch_abort(FunctionTypeMismatchData *Data,
197+
ValueHandle Function,
198+
ValueHandle calleeRTTI,
199+
ValueHandle fnRTTI) {
200+
GET_REPORT_OPTIONS(true);
201+
if (handleFunctionTypeMismatch(Data, Function, calleeRTTI, fnRTTI, Opts))
202+
Die();
203+
}
159204
} // namespace __ubsan
160205

161206
#endif // CAN_SANITIZE_UB

compiler-rt/lib/ubsan/ubsan_handlers_cxx.h

+15
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,21 @@ void __ubsan_handle_dynamic_type_cache_miss(
3333
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
3434
void __ubsan_handle_dynamic_type_cache_miss_abort(
3535
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash);
36+
37+
struct FunctionTypeMismatchData {
38+
SourceLocation Loc;
39+
const TypeDescriptor &Type;
40+
};
41+
42+
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
43+
__ubsan_handle_function_type_mismatch(FunctionTypeMismatchData *Data,
44+
ValueHandle Val, ValueHandle calleeRTTI,
45+
ValueHandle fnRTTI);
46+
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
47+
__ubsan_handle_function_type_mismatch_abort(FunctionTypeMismatchData *Data,
48+
ValueHandle Val,
49+
ValueHandle calleeRTTI,
50+
ValueHandle fnRTTI);
3651
}
3752

3853
#endif // UBSAN_HANDLERS_H

compiler-rt/lib/ubsan/ubsan_type_hash.h

+4
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ const int VptrMaxOffsetToTop = 1<<20;
6464
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
6565
HashValue __ubsan_vptr_type_cache[VptrTypeCacheSize];
6666

67+
/// \brief Do whatever is required by the ABI to check for std::type_info
68+
/// equivalence beyond simple pointer comparison.
69+
bool checkTypeInfoEquality(const void *TypeInfo1, const void *TypeInfo2);
70+
6771
} // namespace __ubsan
6872

6973
#endif // UBSAN_TYPE_HASH_H

compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cc

+10-3
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,7 @@ static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived,
117117
const abi::__class_type_info *Base,
118118
sptr Offset) {
119119
if (Derived->__type_name == Base->__type_name ||
120-
(SANITIZER_NON_UNIQUE_TYPEINFO &&
121-
Derived->__type_name[0] != '*' &&
122-
!internal_strcmp(Derived->__type_name, Base->__type_name)))
120+
__ubsan::checkTypeInfoEquality(Derived, Base))
123121
return Offset == 0;
124122

125123
if (const abi::__si_class_type_info *SI =
@@ -258,4 +256,13 @@ __ubsan::getDynamicTypeInfoFromVtable(void *VtablePtr) {
258256
ObjectType ? ObjectType->__type_name : "<unknown>");
259257
}
260258

259+
bool __ubsan::checkTypeInfoEquality(const void *TypeInfo1,
260+
const void *TypeInfo2) {
261+
auto TI1 = static_cast<const std::type_info *>(TypeInfo1);
262+
auto TI2 = static_cast<const std::type_info *>(TypeInfo2);
263+
return SANITIZER_NON_UNIQUE_TYPEINFO && TI1->__type_name[0] != '*' &&
264+
TI2->__type_name[0] != '*' &&
265+
!internal_strcmp(TI1->__type_name, TI2->__type_name);
266+
}
267+
261268
#endif // CAN_SANITIZE_UB && !SANITIZER_WINDOWS

compiler-rt/lib/ubsan/ubsan_type_hash_win.cc

+5
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,9 @@ __ubsan::getDynamicTypeInfoFromVtable(void *VtablePtr) {
7777
"<unknown>");
7878
}
7979

80+
bool __ubsan::checkTypeInfoEquality(const std::type_info *,
81+
const std::type_info *) {
82+
return false;
83+
}
84+
8085
#endif // CAN_SANITIZE_UB && SANITIZER_WINDOWS

0 commit comments

Comments
 (0)