Index: lib/ubsan/ubsan_handlers.h =================================================================== --- lib/ubsan/ubsan_handlers.h +++ lib/ubsan/ubsan_handlers.h @@ -24,6 +24,15 @@ unsigned char TypeCheckKind; }; +struct TypeMismatchDataV2 { + SourceLocation Loc; + const TypeDescriptor &Type; + unsigned char Version; + unsigned char Alignment; + unsigned char TypeCheckKind; +}; + + #define UNRECOVERABLE(checkname, ...) \ extern "C" SANITIZER_INTERFACE_ATTRIBUTE NORETURN \ void __ubsan_handle_ ## checkname( __VA_ARGS__ ); @@ -37,7 +46,7 @@ /// \brief Handle a runtime type check failure, caused by either a misaligned /// pointer, a null pointer, or a pointer to insufficient storage for the /// type. -RECOVERABLE(type_mismatch, TypeMismatchData *Data, ValueHandle Pointer) +RECOVERABLE(type_mismatch, void *Data, ValueHandle Pointer) struct OverflowData { SourceLocation Loc; Index: lib/ubsan/ubsan_handlers.cc =================================================================== --- lib/ubsan/ubsan_handlers.cc +++ lib/ubsan/ubsan_handlers.cc @@ -41,14 +41,49 @@ "upcast of", "cast to virtual base of"}; } -static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer, +static bool looksLikeTypeMismatchDataV1(void *Data) { + // TypeMismatchData (V1) uses a uptr for the alignment field. This will always + // be a power of 2. + // TypeMismatchDataV2 uses an unsigned char, and passes the log2 of the + // alignment. This will never be 0 (we emit 1 if we have no information in + // clang). + // + // Because of this, we know that if both (what would be V2) Version and (V2) + // Alignment have bits set, we know we're not looking at a V1 structure (which + // would have 4 or 8 bytes with only one bit set). + unsigned char Bytes[2]; + // Filename + (line + column) + TypeDescriptor + const unsigned Offset = FIRST_32_SECOND_64(4 + 8 + 4, 8 + 8 + 8); + internal_memcpy(Bytes, (char*)Data + Offset, 2); + return !Bytes[0] || !Bytes[1]; +} + +static void handleTypeMismatchImpl(void *DataPtr, ValueHandle Pointer, ReportOptions Opts) { - Location Loc = Data->Loc.acquire(); + Location Loc; + const TypeDescriptor *Type; + uptr Alignment; + unsigned char TypeCheckKind; + + if (looksLikeTypeMismatchDataV1(DataPtr)) { + auto Data = reinterpret_cast(DataPtr); + Loc = Data->Loc.acquire(); + Type = &Data->Type; + Alignment = Data->Alignment; + TypeCheckKind = Data->TypeCheckKind; + } else { + auto Data = reinterpret_cast(DataPtr); + CHECK_EQ(Data->Version, 2); + Loc = Data->Loc.acquire(); + Type = &Data->Type; + Alignment = (uptr)1 << Data->Alignment; + TypeCheckKind = Data->TypeCheckKind; + } ErrorType ET; if (!Pointer) ET = ErrorType::NullPointerUse; - else if (Data->Alignment && (Pointer & (Data->Alignment - 1))) + else if (Alignment && (Pointer & (Alignment - 1))) ET = ErrorType::MisalignedPointerUse; else ET = ErrorType::InsufficientObjectSize; @@ -59,7 +94,7 @@ return; SymbolizedStackHolder FallbackLoc; - if (Data->Loc.isInvalid()) { + if (Loc.getSourceLocation().isInvalid()) { FallbackLoc.reset(getCallerLocation(Opts.pc)); Loc = FallbackLoc; } @@ -69,18 +104,18 @@ switch (ET) { case ErrorType::NullPointerUse: Diag(Loc, DL_Error, "%0 null pointer of type %1") - << TypeCheckKinds[Data->TypeCheckKind] << Data->Type; + << TypeCheckKinds[TypeCheckKind] << *Type; break; case ErrorType::MisalignedPointerUse: Diag(Loc, DL_Error, "%0 misaligned address %1 for type %3, " "which requires %2 byte alignment") - << TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer - << Data->Alignment << Data->Type; + << TypeCheckKinds[TypeCheckKind] << (void *)Pointer << Alignment + << *Type; break; case ErrorType::InsufficientObjectSize: Diag(Loc, DL_Error, "%0 address %1 with insufficient space " "for an object of type %2") - << TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer << Data->Type; + << TypeCheckKinds[TypeCheckKind] << (void *)Pointer << *Type; break; default: UNREACHABLE("unexpected error type!"); @@ -90,12 +125,11 @@ Diag(Pointer, DL_Note, "pointer points here"); } -void __ubsan::__ubsan_handle_type_mismatch(TypeMismatchData *Data, - ValueHandle Pointer) { +void __ubsan::__ubsan_handle_type_mismatch(void *Data, ValueHandle Pointer) { GET_REPORT_OPTIONS(false); handleTypeMismatchImpl(Data, Pointer, Opts); } -void __ubsan::__ubsan_handle_type_mismatch_abort(TypeMismatchData *Data, +void __ubsan::__ubsan_handle_type_mismatch_abort(void *Data, ValueHandle Pointer) { GET_REPORT_OPTIONS(true); handleTypeMismatchImpl(Data, Pointer, Opts);