1 //===-- ubsan_handlers.cc -------------------------------------------------===// 2 // 3 // This file is distributed under the University of Illinois Open Source 4 // License. See LICENSE.TXT for details. 5 // 6 //===----------------------------------------------------------------------===// 7 // 8 // Error logging entry points for the UBSan runtime. 9 // 10 //===----------------------------------------------------------------------===// 11 12 #include "ubsan_platform.h" 13 #if CAN_SANITIZE_UB 14 #include "ubsan_handlers.h" 15 #include "ubsan_diag.h" 16 17 #include "sanitizer_common/sanitizer_common.h" 18 19 using namespace __sanitizer; 20 using namespace __ubsan; 21 22 static bool ignoreReport(SourceLocation SLoc, ReportOptions Opts) { 23 // If source location is already acquired, we don't need to print an error 24 // report for the second time. However, if we're in an unrecoverable handler, 25 // it's possible that location was required by concurrently running thread. 26 // In this case, we should continue the execution to ensure that any of 27 // threads will grab the report mutex and print the report before 28 // crashing the program. 29 return SLoc.isDisabled() && !Opts.DieAfterReport; 30 } 31 32 namespace __ubsan { 33 const char *TypeCheckKinds[] = { 34 "load of", "store to", "reference binding to", "member access within", 35 "member call on", "constructor call on", "downcast of", "downcast of", 36 "upcast of", "cast to virtual base of"}; 37 } 38 39 static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer, 40 ReportOptions Opts) { 41 Location Loc = Data->Loc.acquire(); 42 // Use the SourceLocation from Data to track deduplication, even if 'invalid' 43 if (ignoreReport(Loc.getSourceLocation(), Opts)) 44 return; 45 46 SymbolizedStackHolder FallbackLoc; 47 if (Data->Loc.isInvalid()) { 48 FallbackLoc.reset(getCallerLocation(Opts.pc)); 49 Loc = FallbackLoc; 50 } 51 52 ScopedReport R(Opts, Loc); 53 54 if (!Pointer) { 55 R.setErrorType(ErrorType::NullPointerUse); 56 Diag(Loc, DL_Error, "%0 null pointer of type %1") 57 << TypeCheckKinds[Data->TypeCheckKind] << Data->Type; 58 } else if (Data->Alignment && (Pointer & (Data->Alignment - 1))) { 59 R.setErrorType(ErrorType::MisalignedPointerUse); 60 Diag(Loc, DL_Error, "%0 misaligned address %1 for type %3, " 61 "which requires %2 byte alignment") 62 << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer 63 << Data->Alignment << Data->Type; 64 } else { 65 R.setErrorType(ErrorType::InsufficientObjectSize); 66 Diag(Loc, DL_Error, "%0 address %1 with insufficient space " 67 "for an object of type %2") 68 << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type; 69 } 70 if (Pointer) 71 Diag(Pointer, DL_Note, "pointer points here"); 72 } 73 74 void __ubsan::__ubsan_handle_type_mismatch(TypeMismatchData *Data, 75 ValueHandle Pointer) { 76 GET_REPORT_OPTIONS(false); 77 handleTypeMismatchImpl(Data, Pointer, Opts); 78 } 79 void __ubsan::__ubsan_handle_type_mismatch_abort(TypeMismatchData *Data, 80 ValueHandle Pointer) { 81 GET_REPORT_OPTIONS(true); 82 handleTypeMismatchImpl(Data, Pointer, Opts); 83 Die(); 84 } 85 86 /// \brief Common diagnostic emission for various forms of integer overflow. 87 template <typename T> 88 static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS, 89 const char *Operator, T RHS, 90 ReportOptions Opts) { 91 SourceLocation Loc = Data->Loc.acquire(); 92 if (ignoreReport(Loc, Opts)) 93 return; 94 95 bool IsSigned = Data->Type.isSignedIntegerTy(); 96 ScopedReport R(Opts, Loc, IsSigned ? ErrorType::SignedIntegerOverflow 97 : ErrorType::UnsignedIntegerOverflow); 98 99 Diag(Loc, DL_Error, "%0 integer overflow: " 100 "%1 %2 %3 cannot be represented in type %4") 101 << (IsSigned ? "signed" : "unsigned") 102 << Value(Data->Type, LHS) << Operator << RHS << Data->Type; 103 } 104 105 #define UBSAN_OVERFLOW_HANDLER(handler_name, op, abort) \ 106 void __ubsan::handler_name(OverflowData *Data, ValueHandle LHS, \ 107 ValueHandle RHS) { \ 108 GET_REPORT_OPTIONS(abort); \ 109 handleIntegerOverflowImpl(Data, LHS, op, Value(Data->Type, RHS), Opts); \ 110 if (abort) Die(); \ 111 } 112 113 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow, "+", false) 114 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow_abort, "+", true) 115 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow, "-", false) 116 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow_abort, "-", true) 117 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow, "*", false) 118 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow_abort, "*", true) 119 120 static void handleNegateOverflowImpl(OverflowData *Data, ValueHandle OldVal, 121 ReportOptions Opts) { 122 SourceLocation Loc = Data->Loc.acquire(); 123 if (ignoreReport(Loc, Opts)) 124 return; 125 126 bool IsSigned = Data->Type.isSignedIntegerTy(); 127 ScopedReport R(Opts, Loc, IsSigned ? ErrorType::SignedIntegerOverflow 128 : ErrorType::UnsignedIntegerOverflow); 129 130 if (IsSigned) 131 Diag(Loc, DL_Error, 132 "negation of %0 cannot be represented in type %1; " 133 "cast to an unsigned type to negate this value to itself") 134 << Value(Data->Type, OldVal) << Data->Type; 135 else 136 Diag(Loc, DL_Error, "negation of %0 cannot be represented in type %1") 137 << Value(Data->Type, OldVal) << Data->Type; 138 } 139 140 void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data, 141 ValueHandle OldVal) { 142 GET_REPORT_OPTIONS(false); 143 handleNegateOverflowImpl(Data, OldVal, Opts); 144 } 145 void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData *Data, 146 ValueHandle OldVal) { 147 GET_REPORT_OPTIONS(true); 148 handleNegateOverflowImpl(Data, OldVal, Opts); 149 Die(); 150 } 151 152 static void handleDivremOverflowImpl(OverflowData *Data, ValueHandle LHS, 153 ValueHandle RHS, ReportOptions Opts) { 154 SourceLocation Loc = Data->Loc.acquire(); 155 if (ignoreReport(Loc, Opts)) 156 return; 157 158 ScopedReport R(Opts, Loc); 159 160 Value LHSVal(Data->Type, LHS); 161 Value RHSVal(Data->Type, RHS); 162 if (RHSVal.isMinusOne()) { 163 R.setErrorType(ErrorType::SignedIntegerOverflow); 164 Diag(Loc, DL_Error, 165 "division of %0 by -1 cannot be represented in type %1") 166 << LHSVal << Data->Type; 167 } else { 168 R.setErrorType(Data->Type.isIntegerTy() ? ErrorType::IntegerDivideByZero 169 : ErrorType::FloatDivideByZero); 170 Diag(Loc, DL_Error, "division by zero"); 171 } 172 } 173 174 void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data, 175 ValueHandle LHS, ValueHandle RHS) { 176 GET_REPORT_OPTIONS(false); 177 handleDivremOverflowImpl(Data, LHS, RHS, Opts); 178 } 179 void __ubsan::__ubsan_handle_divrem_overflow_abort(OverflowData *Data, 180 ValueHandle LHS, 181 ValueHandle RHS) { 182 GET_REPORT_OPTIONS(true); 183 handleDivremOverflowImpl(Data, LHS, RHS, Opts); 184 Die(); 185 } 186 187 static void handleShiftOutOfBoundsImpl(ShiftOutOfBoundsData *Data, 188 ValueHandle LHS, ValueHandle RHS, 189 ReportOptions Opts) { 190 SourceLocation Loc = Data->Loc.acquire(); 191 if (ignoreReport(Loc, Opts)) 192 return; 193 194 ScopedReport R(Opts, Loc); 195 196 Value LHSVal(Data->LHSType, LHS); 197 Value RHSVal(Data->RHSType, RHS); 198 if (RHSVal.isNegative()) { 199 R.setErrorType(ErrorType::InvalidShiftExponent); 200 Diag(Loc, DL_Error, "shift exponent %0 is negative") << RHSVal; 201 } else if (RHSVal.getPositiveIntValue() >= 202 Data->LHSType.getIntegerBitWidth()) { 203 R.setErrorType(ErrorType::InvalidShiftExponent); 204 Diag(Loc, DL_Error, "shift exponent %0 is too large for %1-bit type %2") 205 << RHSVal << Data->LHSType.getIntegerBitWidth() << Data->LHSType; 206 } else if (LHSVal.isNegative()) { 207 R.setErrorType(ErrorType::InvalidShiftBase); 208 Diag(Loc, DL_Error, "left shift of negative value %0") << LHSVal; 209 } else { 210 R.setErrorType(ErrorType::InvalidShiftBase); 211 Diag(Loc, DL_Error, 212 "left shift of %0 by %1 places cannot be represented in type %2") 213 << LHSVal << RHSVal << Data->LHSType; 214 } 215 } 216 217 void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data, 218 ValueHandle LHS, 219 ValueHandle RHS) { 220 GET_REPORT_OPTIONS(false); 221 handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts); 222 } 223 void __ubsan::__ubsan_handle_shift_out_of_bounds_abort( 224 ShiftOutOfBoundsData *Data, 225 ValueHandle LHS, 226 ValueHandle RHS) { 227 GET_REPORT_OPTIONS(true); 228 handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts); 229 Die(); 230 } 231 232 static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index, 233 ReportOptions Opts) { 234 SourceLocation Loc = Data->Loc.acquire(); 235 if (ignoreReport(Loc, Opts)) 236 return; 237 238 ScopedReport R(Opts, Loc, ErrorType::OutOfBoundsIndex); 239 240 Value IndexVal(Data->IndexType, Index); 241 Diag(Loc, DL_Error, "index %0 out of bounds for type %1") 242 << IndexVal << Data->ArrayType; 243 } 244 245 void __ubsan::__ubsan_handle_out_of_bounds(OutOfBoundsData *Data, 246 ValueHandle Index) { 247 GET_REPORT_OPTIONS(false); 248 handleOutOfBoundsImpl(Data, Index, Opts); 249 } 250 void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data, 251 ValueHandle Index) { 252 GET_REPORT_OPTIONS(true); 253 handleOutOfBoundsImpl(Data, Index, Opts); 254 Die(); 255 } 256 257 static void handleBuiltinUnreachableImpl(UnreachableData *Data, 258 ReportOptions Opts) { 259 ScopedReport R(Opts, Data->Loc, ErrorType::UnreachableCall); 260 Diag(Data->Loc, DL_Error, "execution reached a __builtin_unreachable() call"); 261 } 262 263 void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) { 264 GET_REPORT_OPTIONS(true); 265 handleBuiltinUnreachableImpl(Data, Opts); 266 Die(); 267 } 268 269 static void handleMissingReturnImpl(UnreachableData *Data, ReportOptions Opts) { 270 ScopedReport R(Opts, Data->Loc, ErrorType::MissingReturn); 271 Diag(Data->Loc, DL_Error, 272 "execution reached the end of a value-returning function " 273 "without returning a value"); 274 } 275 276 void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) { 277 GET_REPORT_OPTIONS(true); 278 handleMissingReturnImpl(Data, Opts); 279 Die(); 280 } 281 282 static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound, 283 ReportOptions Opts) { 284 SourceLocation Loc = Data->Loc.acquire(); 285 if (ignoreReport(Loc, Opts)) 286 return; 287 288 ScopedReport R(Opts, Loc, ErrorType::NonPositiveVLAIndex); 289 290 Diag(Loc, DL_Error, "variable length array bound evaluates to " 291 "non-positive value %0") 292 << Value(Data->Type, Bound); 293 } 294 295 void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data, 296 ValueHandle Bound) { 297 GET_REPORT_OPTIONS(false); 298 handleVLABoundNotPositive(Data, Bound, Opts); 299 } 300 void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData *Data, 301 ValueHandle Bound) { 302 GET_REPORT_OPTIONS(true); 303 handleVLABoundNotPositive(Data, Bound, Opts); 304 Die(); 305 } 306 307 static bool looksLikeFloatCastOverflowDataV1(void *Data) { 308 // First field is either a pointer to filename or a pointer to a 309 // TypeDescriptor. 310 u8 *FilenameOrTypeDescriptor; 311 internal_memcpy(&FilenameOrTypeDescriptor, Data, 312 sizeof(FilenameOrTypeDescriptor)); 313 314 // Heuristic: For float_cast_overflow, the TypeKind will be either TK_Integer 315 // (0x0), TK_Float (0x1) or TK_Unknown (0xff). If both types are known, 316 // adding both bytes will be 0 or 1 (for BE or LE). If it were a filename, 317 // adding two printable characters will not yield such a value. Otherwise, 318 // if one of them is 0xff, this is most likely TK_Unknown type descriptor. 319 u16 MaybeFromTypeKind = 320 FilenameOrTypeDescriptor[0] + FilenameOrTypeDescriptor[1]; 321 return MaybeFromTypeKind < 2 || FilenameOrTypeDescriptor[0] == 0xff || 322 FilenameOrTypeDescriptor[1] == 0xff; 323 } 324 325 static void handleFloatCastOverflow(void *DataPtr, ValueHandle From, 326 ReportOptions Opts) { 327 SymbolizedStackHolder CallerLoc; 328 Location Loc; 329 const TypeDescriptor *FromType, *ToType; 330 331 if (looksLikeFloatCastOverflowDataV1(DataPtr)) { 332 auto Data = reinterpret_cast<FloatCastOverflowData *>(DataPtr); 333 CallerLoc.reset(getCallerLocation(Opts.pc)); 334 Loc = CallerLoc; 335 FromType = &Data->FromType; 336 ToType = &Data->ToType; 337 } else { 338 auto Data = reinterpret_cast<FloatCastOverflowDataV2 *>(DataPtr); 339 SourceLocation SLoc = Data->Loc.acquire(); 340 if (ignoreReport(SLoc, Opts)) 341 return; 342 Loc = SLoc; 343 FromType = &Data->FromType; 344 ToType = &Data->ToType; 345 } 346 347 ScopedReport R(Opts, Loc, ErrorType::FloatCastOverflow); 348 349 Diag(Loc, DL_Error, 350 "value %0 is outside the range of representable values of type %2") 351 << Value(*FromType, From) << *FromType << *ToType; 352 } 353 354 void __ubsan::__ubsan_handle_float_cast_overflow(void *Data, ValueHandle From) { 355 GET_REPORT_OPTIONS(false); 356 handleFloatCastOverflow(Data, From, Opts); 357 } 358 void __ubsan::__ubsan_handle_float_cast_overflow_abort(void *Data, 359 ValueHandle From) { 360 GET_REPORT_OPTIONS(true); 361 handleFloatCastOverflow(Data, From, Opts); 362 Die(); 363 } 364 365 static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val, 366 ReportOptions Opts) { 367 SourceLocation Loc = Data->Loc.acquire(); 368 if (ignoreReport(Loc, Opts)) 369 return; 370 371 // This check could be more precise if we used different handlers for 372 // -fsanitize=bool and -fsanitize=enum. 373 bool IsBool = (0 == internal_strcmp(Data->Type.getTypeName(), "'bool'")); 374 ScopedReport R(Opts, Loc, IsBool ? ErrorType::InvalidBoolLoad 375 : ErrorType::InvalidEnumLoad); 376 377 Diag(Loc, DL_Error, 378 "load of value %0, which is not a valid value for type %1") 379 << Value(Data->Type, Val) << Data->Type; 380 } 381 382 void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data, 383 ValueHandle Val) { 384 GET_REPORT_OPTIONS(false); 385 handleLoadInvalidValue(Data, Val, Opts); 386 } 387 void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data, 388 ValueHandle Val) { 389 GET_REPORT_OPTIONS(true); 390 handleLoadInvalidValue(Data, Val, Opts); 391 Die(); 392 } 393 394 static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data, 395 ValueHandle Function, 396 ReportOptions Opts) { 397 SourceLocation CallLoc = Data->Loc.acquire(); 398 if (ignoreReport(CallLoc, Opts)) 399 return; 400 401 ScopedReport R(Opts, CallLoc, ErrorType::FunctionTypeMismatch); 402 403 SymbolizedStackHolder FLoc(getSymbolizedLocation(Function)); 404 const char *FName = FLoc.get()->info.function; 405 if (!FName) 406 FName = "(unknown)"; 407 408 Diag(CallLoc, DL_Error, 409 "call to function %0 through pointer to incorrect function type %1") 410 << FName << Data->Type; 411 Diag(FLoc, DL_Note, "%0 defined here") << FName; 412 } 413 414 void 415 __ubsan::__ubsan_handle_function_type_mismatch(FunctionTypeMismatchData *Data, 416 ValueHandle Function) { 417 GET_REPORT_OPTIONS(false); 418 handleFunctionTypeMismatch(Data, Function, Opts); 419 } 420 421 void __ubsan::__ubsan_handle_function_type_mismatch_abort( 422 FunctionTypeMismatchData *Data, ValueHandle Function) { 423 GET_REPORT_OPTIONS(true); 424 handleFunctionTypeMismatch(Data, Function, Opts); 425 Die(); 426 } 427 428 static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts) { 429 SourceLocation Loc = Data->Loc.acquire(); 430 if (ignoreReport(Loc, Opts)) 431 return; 432 433 ScopedReport R(Opts, Loc, ErrorType::InvalidNullReturn); 434 435 Diag(Loc, DL_Error, "null pointer returned from function declared to never " 436 "return null"); 437 if (!Data->AttrLoc.isInvalid()) 438 Diag(Data->AttrLoc, DL_Note, "returns_nonnull attribute specified here"); 439 } 440 441 void __ubsan::__ubsan_handle_nonnull_return(NonNullReturnData *Data) { 442 GET_REPORT_OPTIONS(false); 443 handleNonNullReturn(Data, Opts); 444 } 445 446 void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullReturnData *Data) { 447 GET_REPORT_OPTIONS(true); 448 handleNonNullReturn(Data, Opts); 449 Die(); 450 } 451 452 static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts) { 453 SourceLocation Loc = Data->Loc.acquire(); 454 if (ignoreReport(Loc, Opts)) 455 return; 456 457 ScopedReport R(Opts, Loc, ErrorType::InvalidNullArgument); 458 459 Diag(Loc, DL_Error, "null pointer passed as argument %0, which is declared to " 460 "never be null") << Data->ArgIndex; 461 if (!Data->AttrLoc.isInvalid()) 462 Diag(Data->AttrLoc, DL_Note, "nonnull attribute specified here"); 463 } 464 465 void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData *Data) { 466 GET_REPORT_OPTIONS(false); 467 handleNonNullArg(Data, Opts); 468 } 469 470 void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) { 471 GET_REPORT_OPTIONS(true); 472 handleNonNullArg(Data, Opts); 473 Die(); 474 } 475 476 static void handleCFIBadIcall(CFIBadIcallData *Data, ValueHandle Function, 477 ReportOptions Opts) { 478 SourceLocation Loc = Data->Loc.acquire(); 479 if (ignoreReport(Loc, Opts)) 480 return; 481 482 ScopedReport R(Opts, Loc); 483 484 Diag(Loc, DL_Error, "control flow integrity check for type %0 failed during " 485 "indirect function call") 486 << Data->Type; 487 488 SymbolizedStackHolder FLoc(getSymbolizedLocation(Function)); 489 const char *FName = FLoc.get()->info.function; 490 if (!FName) 491 FName = "(unknown)"; 492 Diag(FLoc, DL_Note, "%0 defined here") << FName; 493 } 494 495 void __ubsan::__ubsan_handle_cfi_bad_icall(CFIBadIcallData *Data, 496 ValueHandle Function) { 497 GET_REPORT_OPTIONS(false); 498 handleCFIBadIcall(Data, Function, Opts); 499 } 500 501 void __ubsan::__ubsan_handle_cfi_bad_icall_abort(CFIBadIcallData *Data, 502 ValueHandle Function) { 503 GET_REPORT_OPTIONS(true); 504 handleCFIBadIcall(Data, Function, Opts); 505 Die(); 506 } 507 508 #endif // CAN_SANITIZE_UB 509