1 1.1 kamil //===-- ubsan_handlers.cc -------------------------------------------------===// 2 1.1 kamil // 3 1.1 kamil // The LLVM Compiler Infrastructure 4 1.1 kamil // 5 1.1 kamil // This file is distributed under the University of Illinois Open Source 6 1.1 kamil // License. See LICENSE.TXT for details. 7 1.1 kamil // 8 1.1 kamil //===----------------------------------------------------------------------===// 9 1.1 kamil // 10 1.1 kamil // Error logging entry points for the UBSan runtime. 11 1.1 kamil // 12 1.1 kamil //===----------------------------------------------------------------------===// 13 1.1 kamil 14 1.1 kamil #include "ubsan_platform.h" 15 1.1 kamil #if CAN_SANITIZE_UB 16 1.1 kamil #include "ubsan_handlers.h" 17 1.1 kamil #include "ubsan_diag.h" 18 1.1 kamil #include "ubsan_flags.h" 19 1.1 kamil #include "ubsan_monitor.h" 20 1.1 kamil 21 1.1 kamil #include "sanitizer_common/sanitizer_common.h" 22 1.1 kamil 23 1.1 kamil using namespace __sanitizer; 24 1.1 kamil using namespace __ubsan; 25 1.1 kamil 26 1.1 kamil namespace __ubsan { 27 1.1 kamil bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET) { 28 1.1 kamil // We are not allowed to skip error report: if we are in unrecoverable 29 1.1 kamil // handler, we have to terminate the program right now, and therefore 30 1.1 kamil // have to print some diagnostic. 31 1.1 kamil // 32 1.1 kamil // Even if source location is disabled, it doesn't mean that we have 33 1.1 kamil // already report an error to the user: some concurrently running 34 1.1 kamil // thread could have acquired it, but not yet printed the report. 35 1.1 kamil if (Opts.FromUnrecoverableHandler) 36 1.1 kamil return false; 37 1.1 kamil return SLoc.isDisabled() || IsPCSuppressed(ET, Opts.pc, SLoc.getFilename()); 38 1.1 kamil } 39 1.1 kamil 40 1.1 kamil const char *TypeCheckKinds[] = { 41 1.1 kamil "load of", "store to", "reference binding to", "member access within", 42 1.1 kamil "member call on", "constructor call on", "downcast of", "downcast of", 43 1.1 kamil "upcast of", "cast to virtual base of", "_Nonnull binding to", 44 1.1 kamil "dynamic operation on"}; 45 1.1 kamil } 46 1.1 kamil 47 1.1 kamil static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer, 48 1.1 kamil ReportOptions Opts) { 49 1.1 kamil Location Loc = Data->Loc.acquire(); 50 1.1 kamil 51 1.1 kamil uptr Alignment = (uptr)1 << Data->LogAlignment; 52 1.1 kamil ErrorType ET; 53 1.1 kamil if (!Pointer) 54 1.1 kamil ET = ErrorType::NullPointerUse; 55 1.1 kamil else if (Pointer & (Alignment - 1)) 56 1.1 kamil ET = ErrorType::MisalignedPointerUse; 57 1.1 kamil else 58 1.1 kamil ET = ErrorType::InsufficientObjectSize; 59 1.1 kamil 60 1.1 kamil // Use the SourceLocation from Data to track deduplication, even if it's 61 1.1 kamil // invalid. 62 1.1 kamil if (ignoreReport(Loc.getSourceLocation(), Opts, ET)) 63 1.1 kamil return; 64 1.1 kamil 65 1.1 kamil SymbolizedStackHolder FallbackLoc; 66 1.1 kamil if (Data->Loc.isInvalid()) { 67 1.1 kamil FallbackLoc.reset(getCallerLocation(Opts.pc)); 68 1.1 kamil Loc = FallbackLoc; 69 1.1 kamil } 70 1.1 kamil 71 1.1 kamil ScopedReport R(Opts, Loc, ET); 72 1.1 kamil 73 1.1 kamil switch (ET) { 74 1.1 kamil case ErrorType::NullPointerUse: 75 1.1 kamil Diag(Loc, DL_Error, ET, "%0 null pointer of type %1") 76 1.1 kamil << TypeCheckKinds[Data->TypeCheckKind] << Data->Type; 77 1.1 kamil break; 78 1.1 kamil case ErrorType::MisalignedPointerUse: 79 1.1 kamil Diag(Loc, DL_Error, ET, "%0 misaligned address %1 for type %3, " 80 1.1 kamil "which requires %2 byte alignment") 81 1.1 kamil << TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer << Alignment 82 1.1 kamil << Data->Type; 83 1.1 kamil break; 84 1.1 kamil case ErrorType::InsufficientObjectSize: 85 1.1 kamil Diag(Loc, DL_Error, ET, "%0 address %1 with insufficient space " 86 1.1 kamil "for an object of type %2") 87 1.1 kamil << TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer << Data->Type; 88 1.1 kamil break; 89 1.1 kamil default: 90 1.1 kamil UNREACHABLE("unexpected error type!"); 91 1.1 kamil } 92 1.1 kamil 93 1.1 kamil if (Pointer) 94 1.1 kamil Diag(Pointer, DL_Note, ET, "pointer points here"); 95 1.1 kamil } 96 1.1 kamil 97 1.1 kamil void __ubsan::__ubsan_handle_type_mismatch_v1(TypeMismatchData *Data, 98 1.1 kamil ValueHandle Pointer) { 99 1.1 kamil GET_REPORT_OPTIONS(false); 100 1.1 kamil handleTypeMismatchImpl(Data, Pointer, Opts); 101 1.1 kamil } 102 1.1 kamil void __ubsan::__ubsan_handle_type_mismatch_v1_abort(TypeMismatchData *Data, 103 1.1 kamil ValueHandle Pointer) { 104 1.1 kamil GET_REPORT_OPTIONS(true); 105 1.1 kamil handleTypeMismatchImpl(Data, Pointer, Opts); 106 1.1 kamil Die(); 107 1.1 kamil } 108 1.1 kamil 109 1.1 kamil /// \brief Common diagnostic emission for various forms of integer overflow. 110 1.1 kamil template <typename T> 111 1.1 kamil static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS, 112 1.1 kamil const char *Operator, T RHS, 113 1.1 kamil ReportOptions Opts) { 114 1.1 kamil SourceLocation Loc = Data->Loc.acquire(); 115 1.1 kamil bool IsSigned = Data->Type.isSignedIntegerTy(); 116 1.1 kamil ErrorType ET = IsSigned ? ErrorType::SignedIntegerOverflow 117 1.1 kamil : ErrorType::UnsignedIntegerOverflow; 118 1.1 kamil 119 1.1 kamil if (ignoreReport(Loc, Opts, ET)) 120 1.1 kamil return; 121 1.1 kamil 122 1.1 kamil // If this is an unsigned overflow in non-fatal mode, potentially ignore it. 123 1.1 kamil if (!IsSigned && !Opts.FromUnrecoverableHandler && 124 1.1 kamil flags()->silence_unsigned_overflow) 125 1.1 kamil return; 126 1.1 kamil 127 1.1 kamil ScopedReport R(Opts, Loc, ET); 128 1.1 kamil 129 1.1 kamil Diag(Loc, DL_Error, ET, "%0 integer overflow: " 130 1.1 kamil "%1 %2 %3 cannot be represented in type %4") 131 1.1 kamil << (IsSigned ? "signed" : "unsigned") << Value(Data->Type, LHS) 132 1.1 kamil << Operator << RHS << Data->Type; 133 1.1 kamil } 134 1.1 kamil 135 1.1 kamil #define UBSAN_OVERFLOW_HANDLER(handler_name, op, unrecoverable) \ 136 1.1 kamil void __ubsan::handler_name(OverflowData *Data, ValueHandle LHS, \ 137 1.1 kamil ValueHandle RHS) { \ 138 1.1 kamil GET_REPORT_OPTIONS(unrecoverable); \ 139 1.1 kamil handleIntegerOverflowImpl(Data, LHS, op, Value(Data->Type, RHS), Opts); \ 140 1.1 kamil if (unrecoverable) \ 141 1.1 kamil Die(); \ 142 1.1 kamil } 143 1.1 kamil 144 1.1 kamil UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow, "+", false) 145 1.1 kamil UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow_abort, "+", true) 146 1.1 kamil UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow, "-", false) 147 1.1 kamil UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow_abort, "-", true) 148 1.1 kamil UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow, "*", false) 149 1.1 kamil UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow_abort, "*", true) 150 1.1 kamil 151 1.1 kamil static void handleNegateOverflowImpl(OverflowData *Data, ValueHandle OldVal, 152 1.1 kamil ReportOptions Opts) { 153 1.1 kamil SourceLocation Loc = Data->Loc.acquire(); 154 1.1 kamil bool IsSigned = Data->Type.isSignedIntegerTy(); 155 1.1 kamil ErrorType ET = IsSigned ? ErrorType::SignedIntegerOverflow 156 1.1 kamil : ErrorType::UnsignedIntegerOverflow; 157 1.1 kamil 158 1.1 kamil if (ignoreReport(Loc, Opts, ET)) 159 1.1 kamil return; 160 1.1 kamil 161 1.1 kamil if (!IsSigned && flags()->silence_unsigned_overflow) 162 1.1 kamil return; 163 1.1 kamil 164 1.1 kamil ScopedReport R(Opts, Loc, ET); 165 1.1 kamil 166 1.1 kamil if (IsSigned) 167 1.1 kamil Diag(Loc, DL_Error, ET, 168 1.1 kamil "negation of %0 cannot be represented in type %1; " 169 1.1 kamil "cast to an unsigned type to negate this value to itself") 170 1.1 kamil << Value(Data->Type, OldVal) << Data->Type; 171 1.1 kamil else 172 1.1 kamil Diag(Loc, DL_Error, ET, "negation of %0 cannot be represented in type %1") 173 1.1 kamil << Value(Data->Type, OldVal) << Data->Type; 174 1.1 kamil } 175 1.1 kamil 176 1.1 kamil void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data, 177 1.1 kamil ValueHandle OldVal) { 178 1.1 kamil GET_REPORT_OPTIONS(false); 179 1.1 kamil handleNegateOverflowImpl(Data, OldVal, Opts); 180 1.1 kamil } 181 1.1 kamil void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData *Data, 182 1.1 kamil ValueHandle OldVal) { 183 1.1 kamil GET_REPORT_OPTIONS(true); 184 1.1 kamil handleNegateOverflowImpl(Data, OldVal, Opts); 185 1.1 kamil Die(); 186 1.1 kamil } 187 1.1 kamil 188 1.1 kamil static void handleDivremOverflowImpl(OverflowData *Data, ValueHandle LHS, 189 1.1 kamil ValueHandle RHS, ReportOptions Opts) { 190 1.1 kamil SourceLocation Loc = Data->Loc.acquire(); 191 1.1 kamil Value LHSVal(Data->Type, LHS); 192 1.1 kamil Value RHSVal(Data->Type, RHS); 193 1.1 kamil 194 1.1 kamil ErrorType ET; 195 1.1 kamil if (RHSVal.isMinusOne()) 196 1.1 kamil ET = ErrorType::SignedIntegerOverflow; 197 1.1 kamil else if (Data->Type.isIntegerTy()) 198 1.1 kamil ET = ErrorType::IntegerDivideByZero; 199 1.1 kamil else 200 1.1 kamil ET = ErrorType::FloatDivideByZero; 201 1.1 kamil 202 1.1 kamil if (ignoreReport(Loc, Opts, ET)) 203 1.1 kamil return; 204 1.1 kamil 205 1.1 kamil ScopedReport R(Opts, Loc, ET); 206 1.1 kamil 207 1.1 kamil switch (ET) { 208 1.1 kamil case ErrorType::SignedIntegerOverflow: 209 1.1 kamil Diag(Loc, DL_Error, ET, 210 1.1 kamil "division of %0 by -1 cannot be represented in type %1") 211 1.1 kamil << LHSVal << Data->Type; 212 1.1 kamil break; 213 1.1 kamil default: 214 1.1 kamil Diag(Loc, DL_Error, ET, "division by zero"); 215 1.1 kamil break; 216 1.1 kamil } 217 1.1 kamil } 218 1.1 kamil 219 1.1 kamil void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data, 220 1.1 kamil ValueHandle LHS, ValueHandle RHS) { 221 1.1 kamil GET_REPORT_OPTIONS(false); 222 1.1 kamil handleDivremOverflowImpl(Data, LHS, RHS, Opts); 223 1.1 kamil } 224 1.1 kamil void __ubsan::__ubsan_handle_divrem_overflow_abort(OverflowData *Data, 225 1.1 kamil ValueHandle LHS, 226 1.1 kamil ValueHandle RHS) { 227 1.1 kamil GET_REPORT_OPTIONS(true); 228 1.1 kamil handleDivremOverflowImpl(Data, LHS, RHS, Opts); 229 1.1 kamil Die(); 230 1.1 kamil } 231 1.1 kamil 232 1.1 kamil static void handleShiftOutOfBoundsImpl(ShiftOutOfBoundsData *Data, 233 1.1 kamil ValueHandle LHS, ValueHandle RHS, 234 1.1 kamil ReportOptions Opts) { 235 1.1 kamil SourceLocation Loc = Data->Loc.acquire(); 236 1.1 kamil Value LHSVal(Data->LHSType, LHS); 237 1.1 kamil Value RHSVal(Data->RHSType, RHS); 238 1.1 kamil 239 1.1 kamil ErrorType ET; 240 1.1 kamil if (RHSVal.isNegative() || 241 1.1 kamil RHSVal.getPositiveIntValue() >= Data->LHSType.getIntegerBitWidth()) 242 1.1 kamil ET = ErrorType::InvalidShiftExponent; 243 1.1 kamil else 244 1.1 kamil ET = ErrorType::InvalidShiftBase; 245 1.1 kamil 246 1.1 kamil if (ignoreReport(Loc, Opts, ET)) 247 1.1 kamil return; 248 1.1 kamil 249 1.1 kamil ScopedReport R(Opts, Loc, ET); 250 1.1 kamil 251 1.1 kamil if (ET == ErrorType::InvalidShiftExponent) { 252 1.1 kamil if (RHSVal.isNegative()) 253 1.1 kamil Diag(Loc, DL_Error, ET, "shift exponent %0 is negative") << RHSVal; 254 1.1 kamil else 255 1.1 kamil Diag(Loc, DL_Error, ET, 256 1.1 kamil "shift exponent %0 is too large for %1-bit type %2") 257 1.1 kamil << RHSVal << Data->LHSType.getIntegerBitWidth() << Data->LHSType; 258 1.1 kamil } else { 259 1.1 kamil if (LHSVal.isNegative()) 260 1.1 kamil Diag(Loc, DL_Error, ET, "left shift of negative value %0") << LHSVal; 261 1.1 kamil else 262 1.1 kamil Diag(Loc, DL_Error, ET, 263 1.1 kamil "left shift of %0 by %1 places cannot be represented in type %2") 264 1.1 kamil << LHSVal << RHSVal << Data->LHSType; 265 1.1 kamil } 266 1.1 kamil } 267 1.1 kamil 268 1.1 kamil void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data, 269 1.1 kamil ValueHandle LHS, 270 1.1 kamil ValueHandle RHS) { 271 1.1 kamil GET_REPORT_OPTIONS(false); 272 1.1 kamil handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts); 273 1.1 kamil } 274 1.1 kamil void __ubsan::__ubsan_handle_shift_out_of_bounds_abort( 275 1.1 kamil ShiftOutOfBoundsData *Data, 276 1.1 kamil ValueHandle LHS, 277 1.1 kamil ValueHandle RHS) { 278 1.1 kamil GET_REPORT_OPTIONS(true); 279 1.1 kamil handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts); 280 1.1 kamil Die(); 281 1.1 kamil } 282 1.1 kamil 283 1.1 kamil static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index, 284 1.1 kamil ReportOptions Opts) { 285 1.1 kamil SourceLocation Loc = Data->Loc.acquire(); 286 1.1 kamil ErrorType ET = ErrorType::OutOfBoundsIndex; 287 1.1 kamil 288 1.1 kamil if (ignoreReport(Loc, Opts, ET)) 289 1.1 kamil return; 290 1.1 kamil 291 1.1 kamil ScopedReport R(Opts, Loc, ET); 292 1.1 kamil 293 1.1 kamil Value IndexVal(Data->IndexType, Index); 294 1.1 kamil Diag(Loc, DL_Error, ET, "index %0 out of bounds for type %1") 295 1.1 kamil << IndexVal << Data->ArrayType; 296 1.1 kamil } 297 1.1 kamil 298 1.1 kamil void __ubsan::__ubsan_handle_out_of_bounds(OutOfBoundsData *Data, 299 1.1 kamil ValueHandle Index) { 300 1.1 kamil GET_REPORT_OPTIONS(false); 301 1.1 kamil handleOutOfBoundsImpl(Data, Index, Opts); 302 1.1 kamil } 303 1.1 kamil void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data, 304 1.1 kamil ValueHandle Index) { 305 1.1 kamil GET_REPORT_OPTIONS(true); 306 1.1 kamil handleOutOfBoundsImpl(Data, Index, Opts); 307 1.1 kamil Die(); 308 1.1 kamil } 309 1.1 kamil 310 1.1 kamil static void handleBuiltinUnreachableImpl(UnreachableData *Data, 311 1.1 kamil ReportOptions Opts) { 312 1.1 kamil ErrorType ET = ErrorType::UnreachableCall; 313 1.1 kamil ScopedReport R(Opts, Data->Loc, ET); 314 1.1 kamil Diag(Data->Loc, DL_Error, ET, 315 1.1 kamil "execution reached an unreachable program point"); 316 1.1 kamil } 317 1.1 kamil 318 1.1 kamil void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) { 319 1.1 kamil GET_REPORT_OPTIONS(true); 320 1.1 kamil handleBuiltinUnreachableImpl(Data, Opts); 321 1.1 kamil Die(); 322 1.1 kamil } 323 1.1 kamil 324 1.1 kamil static void handleMissingReturnImpl(UnreachableData *Data, ReportOptions Opts) { 325 1.1 kamil ErrorType ET = ErrorType::MissingReturn; 326 1.1 kamil ScopedReport R(Opts, Data->Loc, ET); 327 1.1 kamil Diag(Data->Loc, DL_Error, ET, 328 1.1 kamil "execution reached the end of a value-returning function " 329 1.1 kamil "without returning a value"); 330 1.1 kamil } 331 1.1 kamil 332 1.1 kamil void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) { 333 1.1 kamil GET_REPORT_OPTIONS(true); 334 1.1 kamil handleMissingReturnImpl(Data, Opts); 335 1.1 kamil Die(); 336 1.1 kamil } 337 1.1 kamil 338 1.1 kamil static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound, 339 1.1 kamil ReportOptions Opts) { 340 1.1 kamil SourceLocation Loc = Data->Loc.acquire(); 341 1.1 kamil ErrorType ET = ErrorType::NonPositiveVLAIndex; 342 1.1 kamil 343 1.1 kamil if (ignoreReport(Loc, Opts, ET)) 344 1.1 kamil return; 345 1.1 kamil 346 1.1 kamil ScopedReport R(Opts, Loc, ET); 347 1.1 kamil 348 1.1 kamil Diag(Loc, DL_Error, ET, "variable length array bound evaluates to " 349 1.1 kamil "non-positive value %0") 350 1.1 kamil << Value(Data->Type, Bound); 351 1.1 kamil } 352 1.1 kamil 353 1.1 kamil void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data, 354 1.1 kamil ValueHandle Bound) { 355 1.1 kamil GET_REPORT_OPTIONS(false); 356 1.1 kamil handleVLABoundNotPositive(Data, Bound, Opts); 357 1.1 kamil } 358 1.1 kamil void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData *Data, 359 1.1 kamil ValueHandle Bound) { 360 1.1 kamil GET_REPORT_OPTIONS(true); 361 1.1 kamil handleVLABoundNotPositive(Data, Bound, Opts); 362 1.1 kamil Die(); 363 1.1 kamil } 364 1.1 kamil 365 1.1 kamil static bool looksLikeFloatCastOverflowDataV1(void *Data) { 366 1.1 kamil // First field is either a pointer to filename or a pointer to a 367 1.1 kamil // TypeDescriptor. 368 1.1 kamil u8 *FilenameOrTypeDescriptor; 369 1.1 kamil internal_memcpy(&FilenameOrTypeDescriptor, Data, 370 1.1 kamil sizeof(FilenameOrTypeDescriptor)); 371 1.1 kamil 372 1.1 kamil // Heuristic: For float_cast_overflow, the TypeKind will be either TK_Integer 373 1.1 kamil // (0x0), TK_Float (0x1) or TK_Unknown (0xff). If both types are known, 374 1.1 kamil // adding both bytes will be 0 or 1 (for BE or LE). If it were a filename, 375 1.1 kamil // adding two printable characters will not yield such a value. Otherwise, 376 1.1 kamil // if one of them is 0xff, this is most likely TK_Unknown type descriptor. 377 1.1 kamil u16 MaybeFromTypeKind = 378 1.1 kamil FilenameOrTypeDescriptor[0] + FilenameOrTypeDescriptor[1]; 379 1.1 kamil return MaybeFromTypeKind < 2 || FilenameOrTypeDescriptor[0] == 0xff || 380 1.1 kamil FilenameOrTypeDescriptor[1] == 0xff; 381 1.1 kamil } 382 1.1 kamil 383 1.1 kamil static void handleFloatCastOverflow(void *DataPtr, ValueHandle From, 384 1.1 kamil ReportOptions Opts) { 385 1.1 kamil SymbolizedStackHolder CallerLoc; 386 1.1 kamil Location Loc; 387 1.1 kamil const TypeDescriptor *FromType, *ToType; 388 1.1 kamil ErrorType ET = ErrorType::FloatCastOverflow; 389 1.1 kamil 390 1.1 kamil if (looksLikeFloatCastOverflowDataV1(DataPtr)) { 391 1.1 kamil auto Data = reinterpret_cast<FloatCastOverflowData *>(DataPtr); 392 1.1 kamil CallerLoc.reset(getCallerLocation(Opts.pc)); 393 1.1 kamil Loc = CallerLoc; 394 1.1 kamil FromType = &Data->FromType; 395 1.1 kamil ToType = &Data->ToType; 396 1.1 kamil } else { 397 1.1 kamil auto Data = reinterpret_cast<FloatCastOverflowDataV2 *>(DataPtr); 398 1.1 kamil SourceLocation SLoc = Data->Loc.acquire(); 399 1.1 kamil if (ignoreReport(SLoc, Opts, ET)) 400 1.1 kamil return; 401 1.1 kamil Loc = SLoc; 402 1.1 kamil FromType = &Data->FromType; 403 1.1 kamil ToType = &Data->ToType; 404 1.1 kamil } 405 1.1 kamil 406 1.1 kamil ScopedReport R(Opts, Loc, ET); 407 1.1 kamil 408 1.1 kamil Diag(Loc, DL_Error, ET, 409 1.1 kamil "%0 is outside the range of representable values of type %2") 410 1.1 kamil << Value(*FromType, From) << *FromType << *ToType; 411 1.1 kamil } 412 1.1 kamil 413 1.1 kamil void __ubsan::__ubsan_handle_float_cast_overflow(void *Data, ValueHandle From) { 414 1.1 kamil GET_REPORT_OPTIONS(false); 415 1.1 kamil handleFloatCastOverflow(Data, From, Opts); 416 1.1 kamil } 417 1.1 kamil void __ubsan::__ubsan_handle_float_cast_overflow_abort(void *Data, 418 1.1 kamil ValueHandle From) { 419 1.1 kamil GET_REPORT_OPTIONS(true); 420 1.1 kamil handleFloatCastOverflow(Data, From, Opts); 421 1.1 kamil Die(); 422 1.1 kamil } 423 1.1 kamil 424 1.1 kamil static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val, 425 1.1 kamil ReportOptions Opts) { 426 1.1 kamil SourceLocation Loc = Data->Loc.acquire(); 427 1.1 kamil // This check could be more precise if we used different handlers for 428 1.1 kamil // -fsanitize=bool and -fsanitize=enum. 429 1.1 kamil bool IsBool = (0 == internal_strcmp(Data->Type.getTypeName(), "'bool'")) || 430 1.1 kamil (0 == internal_strncmp(Data->Type.getTypeName(), "'BOOL'", 6)); 431 1.1 kamil ErrorType ET = 432 1.1 kamil IsBool ? ErrorType::InvalidBoolLoad : ErrorType::InvalidEnumLoad; 433 1.1 kamil 434 1.1 kamil if (ignoreReport(Loc, Opts, ET)) 435 1.1 kamil return; 436 1.1 kamil 437 1.1 kamil ScopedReport R(Opts, Loc, ET); 438 1.1 kamil 439 1.1 kamil Diag(Loc, DL_Error, ET, 440 1.1 kamil "load of value %0, which is not a valid value for type %1") 441 1.1 kamil << Value(Data->Type, Val) << Data->Type; 442 1.1 kamil } 443 1.1 kamil 444 1.1 kamil void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data, 445 1.1 kamil ValueHandle Val) { 446 1.1 kamil GET_REPORT_OPTIONS(false); 447 1.1 kamil handleLoadInvalidValue(Data, Val, Opts); 448 1.1 kamil } 449 1.1 kamil void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data, 450 1.1 kamil ValueHandle Val) { 451 1.1 kamil GET_REPORT_OPTIONS(true); 452 1.1 kamil handleLoadInvalidValue(Data, Val, Opts); 453 1.1 kamil Die(); 454 1.1 kamil } 455 1.1 kamil 456 1.1 kamil static void handleImplicitConversion(ImplicitConversionData *Data, 457 1.1 kamil ReportOptions Opts, ValueHandle Src, 458 1.1 kamil ValueHandle Dst) { 459 1.1 kamil SourceLocation Loc = Data->Loc.acquire(); 460 1.1 kamil ErrorType ET = ErrorType::GenericUB; 461 1.1 kamil 462 1.1 kamil const TypeDescriptor &SrcTy = Data->FromType; 463 1.1 kamil const TypeDescriptor &DstTy = Data->ToType; 464 1.1 kamil 465 1.1 kamil bool SrcSigned = SrcTy.isSignedIntegerTy(); 466 1.1 kamil bool DstSigned = DstTy.isSignedIntegerTy(); 467 1.1 kamil 468 1.1 kamil switch (Data->Kind) { 469 1.1 kamil case ICCK_IntegerTruncation: { // Legacy, no longer used. 470 1.1 kamil // Let's figure out what it should be as per the new types, and upgrade. 471 1.1 kamil // If both types are unsigned, then it's an unsigned truncation. 472 1.1 kamil // Else, it is a signed truncation. 473 1.1 kamil if (!SrcSigned && !DstSigned) { 474 1.1 kamil ET = ErrorType::ImplicitUnsignedIntegerTruncation; 475 1.1 kamil } else { 476 1.1 kamil ET = ErrorType::ImplicitSignedIntegerTruncation; 477 1.1 kamil } 478 1.1 kamil break; 479 1.1 kamil } 480 1.1 kamil case ICCK_UnsignedIntegerTruncation: 481 1.1 kamil ET = ErrorType::ImplicitUnsignedIntegerTruncation; 482 1.1 kamil break; 483 1.1 kamil case ICCK_SignedIntegerTruncation: 484 1.1 kamil ET = ErrorType::ImplicitSignedIntegerTruncation; 485 1.1 kamil break; 486 1.1 kamil case ICCK_IntegerSignChange: 487 1.1 kamil ET = ErrorType::ImplicitIntegerSignChange; 488 1.1 kamil break; 489 1.1 kamil case ICCK_SignedIntegerTruncationOrSignChange: 490 1.1 kamil ET = ErrorType::ImplicitSignedIntegerTruncationOrSignChange; 491 1.1 kamil break; 492 1.1 kamil } 493 1.1 kamil 494 1.1 kamil if (ignoreReport(Loc, Opts, ET)) 495 1.1 kamil return; 496 1.1 kamil 497 1.1 kamil ScopedReport R(Opts, Loc, ET); 498 1.1 kamil 499 1.1 kamil // FIXME: is it possible to dump the values as hex with fixed width? 500 1.1 kamil 501 1.1 kamil Diag(Loc, DL_Error, ET, 502 1.1 kamil "implicit conversion from type %0 of value %1 (%2-bit, %3signed) to " 503 1.1 kamil "type %4 changed the value to %5 (%6-bit, %7signed)") 504 1.1 kamil << SrcTy << Value(SrcTy, Src) << SrcTy.getIntegerBitWidth() 505 1.1 kamil << (SrcSigned ? "" : "un") << DstTy << Value(DstTy, Dst) 506 1.1 kamil << DstTy.getIntegerBitWidth() << (DstSigned ? "" : "un"); 507 1.1 kamil } 508 1.1 kamil 509 1.1 kamil void __ubsan::__ubsan_handle_implicit_conversion(ImplicitConversionData *Data, 510 1.1 kamil ValueHandle Src, 511 1.1 kamil ValueHandle Dst) { 512 1.1 kamil GET_REPORT_OPTIONS(false); 513 1.1 kamil handleImplicitConversion(Data, Opts, Src, Dst); 514 1.1 kamil } 515 1.1 kamil void __ubsan::__ubsan_handle_implicit_conversion_abort( 516 1.1 kamil ImplicitConversionData *Data, ValueHandle Src, ValueHandle Dst) { 517 1.1 kamil GET_REPORT_OPTIONS(true); 518 1.1 kamil handleImplicitConversion(Data, Opts, Src, Dst); 519 1.1 kamil Die(); 520 1.1 kamil } 521 1.1 kamil 522 1.1 kamil static void handleInvalidBuiltin(InvalidBuiltinData *Data, ReportOptions Opts) { 523 1.1 kamil SourceLocation Loc = Data->Loc.acquire(); 524 1.1 kamil ErrorType ET = ErrorType::InvalidBuiltin; 525 1.1 kamil 526 1.1 kamil if (ignoreReport(Loc, Opts, ET)) 527 1.1 kamil return; 528 1.1 kamil 529 1.1 kamil ScopedReport R(Opts, Loc, ET); 530 1.1 kamil 531 1.1 kamil Diag(Loc, DL_Error, ET, 532 1.1 kamil "passing zero to %0, which is not a valid argument") 533 1.1 kamil << ((Data->Kind == BCK_CTZPassedZero) ? "ctz()" : "clz()"); 534 1.1 kamil } 535 1.1 kamil 536 1.1 kamil void __ubsan::__ubsan_handle_invalid_builtin(InvalidBuiltinData *Data) { 537 1.1 kamil GET_REPORT_OPTIONS(true); 538 1.1 kamil handleInvalidBuiltin(Data, Opts); 539 1.1 kamil } 540 1.1 kamil void __ubsan::__ubsan_handle_invalid_builtin_abort(InvalidBuiltinData *Data) { 541 1.1 kamil GET_REPORT_OPTIONS(true); 542 1.1 kamil handleInvalidBuiltin(Data, Opts); 543 1.1 kamil Die(); 544 1.1 kamil } 545 1.1 kamil 546 1.1 kamil static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data, 547 1.1 kamil ValueHandle Function, 548 1.1 kamil ReportOptions Opts) { 549 1.1 kamil SourceLocation CallLoc = Data->Loc.acquire(); 550 1.1 kamil ErrorType ET = ErrorType::FunctionTypeMismatch; 551 1.1 kamil 552 1.1 kamil if (ignoreReport(CallLoc, Opts, ET)) 553 1.1 kamil return; 554 1.1 kamil 555 1.1 kamil ScopedReport R(Opts, CallLoc, ET); 556 1.1 kamil 557 1.1 kamil SymbolizedStackHolder FLoc(getSymbolizedLocation(Function)); 558 1.1 kamil const char *FName = FLoc.get()->info.function; 559 1.1 kamil if (!FName) 560 1.1 kamil FName = "(unknown)"; 561 1.1 kamil 562 1.1 kamil Diag(CallLoc, DL_Error, ET, 563 1.1 kamil "call to function %0 through pointer to incorrect function type %1") 564 1.1 kamil << FName << Data->Type; 565 1.1 kamil Diag(FLoc, DL_Note, ET, "%0 defined here") << FName; 566 1.1 kamil } 567 1.1 kamil 568 1.1 kamil void 569 1.1 kamil __ubsan::__ubsan_handle_function_type_mismatch(FunctionTypeMismatchData *Data, 570 1.1 kamil ValueHandle Function) { 571 1.1 kamil GET_REPORT_OPTIONS(false); 572 1.1 kamil handleFunctionTypeMismatch(Data, Function, Opts); 573 1.1 kamil } 574 1.1 kamil 575 1.1 kamil void __ubsan::__ubsan_handle_function_type_mismatch_abort( 576 1.1 kamil FunctionTypeMismatchData *Data, ValueHandle Function) { 577 1.1 kamil GET_REPORT_OPTIONS(true); 578 1.1 kamil handleFunctionTypeMismatch(Data, Function, Opts); 579 1.1 kamil Die(); 580 1.1 kamil } 581 1.1 kamil 582 1.1 kamil static void handleNonNullReturn(NonNullReturnData *Data, SourceLocation *LocPtr, 583 1.1 kamil ReportOptions Opts, bool IsAttr) { 584 1.1 kamil if (!LocPtr) 585 1.1 kamil UNREACHABLE("source location pointer is null!"); 586 1.1 kamil 587 1.1 kamil SourceLocation Loc = LocPtr->acquire(); 588 1.1 kamil ErrorType ET = ErrorType::InvalidNullReturn; 589 1.1 kamil 590 1.1 kamil if (ignoreReport(Loc, Opts, ET)) 591 1.1 kamil return; 592 1.1 kamil 593 1.1 kamil ScopedReport R(Opts, Loc, ET); 594 1.1 kamil 595 1.1 kamil Diag(Loc, DL_Error, ET, 596 1.1 kamil "null pointer returned from function declared to never return null"); 597 1.1 kamil if (!Data->AttrLoc.isInvalid()) 598 1.1 kamil Diag(Data->AttrLoc, DL_Note, ET, "%0 specified here") 599 1.1 kamil << (IsAttr ? "returns_nonnull attribute" 600 1.1 kamil : "_Nonnull return type annotation"); 601 1.1 kamil } 602 1.1 kamil 603 1.1 kamil void __ubsan::__ubsan_handle_nonnull_return_v1(NonNullReturnData *Data, 604 1.1 kamil SourceLocation *LocPtr) { 605 1.1 kamil GET_REPORT_OPTIONS(false); 606 1.1 kamil handleNonNullReturn(Data, LocPtr, Opts, true); 607 1.1 kamil } 608 1.1 kamil 609 1.1 kamil void __ubsan::__ubsan_handle_nonnull_return_v1_abort(NonNullReturnData *Data, 610 1.1 kamil SourceLocation *LocPtr) { 611 1.1 kamil GET_REPORT_OPTIONS(true); 612 1.1 kamil handleNonNullReturn(Data, LocPtr, Opts, true); 613 1.1 kamil Die(); 614 1.1 kamil } 615 1.1 kamil 616 1.1 kamil void __ubsan::__ubsan_handle_nullability_return_v1(NonNullReturnData *Data, 617 1.1 kamil SourceLocation *LocPtr) { 618 1.1 kamil GET_REPORT_OPTIONS(false); 619 1.1 kamil handleNonNullReturn(Data, LocPtr, Opts, false); 620 1.1 kamil } 621 1.1 kamil 622 1.1 kamil void __ubsan::__ubsan_handle_nullability_return_v1_abort( 623 1.1 kamil NonNullReturnData *Data, SourceLocation *LocPtr) { 624 1.1 kamil GET_REPORT_OPTIONS(true); 625 1.1 kamil handleNonNullReturn(Data, LocPtr, Opts, false); 626 1.1 kamil Die(); 627 1.1 kamil } 628 1.1 kamil 629 1.1 kamil static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts, 630 1.1 kamil bool IsAttr) { 631 1.1 kamil SourceLocation Loc = Data->Loc.acquire(); 632 1.1 kamil ErrorType ET = ErrorType::InvalidNullArgument; 633 1.1 kamil 634 1.1 kamil if (ignoreReport(Loc, Opts, ET)) 635 1.1 kamil return; 636 1.1 kamil 637 1.1 kamil ScopedReport R(Opts, Loc, ET); 638 1.1 kamil 639 1.1 kamil Diag(Loc, DL_Error, ET, 640 1.1 kamil "null pointer passed as argument %0, which is declared to " 641 1.1 kamil "never be null") 642 1.1 kamil << Data->ArgIndex; 643 1.1 kamil if (!Data->AttrLoc.isInvalid()) 644 1.1 kamil Diag(Data->AttrLoc, DL_Note, ET, "%0 specified here") 645 1.1 kamil << (IsAttr ? "nonnull attribute" : "_Nonnull type annotation"); 646 1.1 kamil } 647 1.1 kamil 648 1.1 kamil void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData *Data) { 649 1.1 kamil GET_REPORT_OPTIONS(false); 650 1.1 kamil handleNonNullArg(Data, Opts, true); 651 1.1 kamil } 652 1.1 kamil 653 1.1 kamil void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) { 654 1.1 kamil GET_REPORT_OPTIONS(true); 655 1.1 kamil handleNonNullArg(Data, Opts, true); 656 1.1 kamil Die(); 657 1.1 kamil } 658 1.1 kamil 659 1.1 kamil void __ubsan::__ubsan_handle_nullability_arg(NonNullArgData *Data) { 660 1.1 kamil GET_REPORT_OPTIONS(false); 661 1.1 kamil handleNonNullArg(Data, Opts, false); 662 1.1 kamil } 663 1.1 kamil 664 1.1 kamil void __ubsan::__ubsan_handle_nullability_arg_abort(NonNullArgData *Data) { 665 1.1 kamil GET_REPORT_OPTIONS(true); 666 1.1 kamil handleNonNullArg(Data, Opts, false); 667 1.1 kamil Die(); 668 1.1 kamil } 669 1.1 kamil 670 1.1 kamil static void handlePointerOverflowImpl(PointerOverflowData *Data, 671 1.1 kamil ValueHandle Base, 672 1.1 kamil ValueHandle Result, 673 1.1 kamil ReportOptions Opts) { 674 1.1 kamil SourceLocation Loc = Data->Loc.acquire(); 675 1.1 kamil ErrorType ET = ErrorType::PointerOverflow; 676 1.1 kamil 677 1.1 kamil if (ignoreReport(Loc, Opts, ET)) 678 1.1 kamil return; 679 1.1 kamil 680 1.1 kamil ScopedReport R(Opts, Loc, ET); 681 1.1 kamil 682 1.1 kamil if ((sptr(Base) >= 0) == (sptr(Result) >= 0)) { 683 1.1 kamil if (Base > Result) 684 1.1 kamil Diag(Loc, DL_Error, ET, 685 1.1 kamil "addition of unsigned offset to %0 overflowed to %1") 686 1.1 kamil << (void *)Base << (void *)Result; 687 1.1 kamil else 688 1.1 kamil Diag(Loc, DL_Error, ET, 689 1.1 kamil "subtraction of unsigned offset from %0 overflowed to %1") 690 1.1 kamil << (void *)Base << (void *)Result; 691 1.1 kamil } else { 692 1.1 kamil Diag(Loc, DL_Error, ET, 693 1.1 kamil "pointer index expression with base %0 overflowed to %1") 694 1.1 kamil << (void *)Base << (void *)Result; 695 1.1 kamil } 696 1.1 kamil } 697 1.1 kamil 698 1.1 kamil void __ubsan::__ubsan_handle_pointer_overflow(PointerOverflowData *Data, 699 1.1 kamil ValueHandle Base, 700 1.1 kamil ValueHandle Result) { 701 1.1 kamil GET_REPORT_OPTIONS(false); 702 1.1 kamil handlePointerOverflowImpl(Data, Base, Result, Opts); 703 1.1 kamil } 704 1.1 kamil 705 1.1 kamil void __ubsan::__ubsan_handle_pointer_overflow_abort(PointerOverflowData *Data, 706 1.1 kamil ValueHandle Base, 707 1.1 kamil ValueHandle Result) { 708 1.1 kamil GET_REPORT_OPTIONS(true); 709 1.1 kamil handlePointerOverflowImpl(Data, Base, Result, Opts); 710 1.1 kamil Die(); 711 1.1 kamil } 712 1.1 kamil 713 1.1 kamil static void handleCFIBadIcall(CFICheckFailData *Data, ValueHandle Function, 714 1.1 kamil ReportOptions Opts) { 715 1.1 kamil if (Data->CheckKind != CFITCK_ICall && Data->CheckKind != CFITCK_NVMFCall) 716 1.1 kamil Die(); 717 1.1 kamil 718 1.1 kamil SourceLocation Loc = Data->Loc.acquire(); 719 1.1 kamil ErrorType ET = ErrorType::CFIBadType; 720 1.1 kamil 721 1.1 kamil if (ignoreReport(Loc, Opts, ET)) 722 1.1 kamil return; 723 1.1 kamil 724 1.1 kamil ScopedReport R(Opts, Loc, ET); 725 1.1 kamil 726 1.1 kamil const char *CheckKindStr = Data->CheckKind == CFITCK_NVMFCall 727 1.1 kamil ? "non-virtual pointer to member function call" 728 1.1 kamil : "indirect function call"; 729 1.1 kamil Diag(Loc, DL_Error, ET, 730 1.1 kamil "control flow integrity check for type %0 failed during %1") 731 1.1 kamil << Data->Type << CheckKindStr; 732 1.1 kamil 733 1.1 kamil SymbolizedStackHolder FLoc(getSymbolizedLocation(Function)); 734 1.1 kamil const char *FName = FLoc.get()->info.function; 735 1.1 kamil if (!FName) 736 1.1 kamil FName = "(unknown)"; 737 1.1 kamil Diag(FLoc, DL_Note, ET, "%0 defined here") << FName; 738 1.1 kamil 739 1.1 kamil // If the failure involved different DSOs for the check location and icall 740 1.1 kamil // target, report the DSO names. 741 1.1 kamil const char *DstModule = FLoc.get()->info.module; 742 1.1 kamil if (!DstModule) 743 1.1 kamil DstModule = "(unknown)"; 744 1.1 kamil 745 1.1 kamil const char *SrcModule = Symbolizer::GetOrInit()->GetModuleNameForPc(Opts.pc); 746 1.1 kamil if (!SrcModule) 747 1.1 kamil SrcModule = "(unknown)"; 748 1.1 kamil 749 1.1 kamil if (internal_strcmp(SrcModule, DstModule)) 750 1.1 kamil Diag(Loc, DL_Note, ET, 751 1.1 kamil "check failed in %0, destination function located in %1") 752 1.1 kamil << SrcModule << DstModule; 753 1.1 kamil } 754 1.1 kamil 755 1.1 kamil namespace __ubsan { 756 1.1 kamil 757 1.1 kamil #ifdef UBSAN_CAN_USE_CXXABI 758 1.1 kamil 759 1.1 kamil #ifdef _WIN32 760 1.1 kamil 761 1.1 kamil extern "C" void __ubsan_handle_cfi_bad_type_default(CFICheckFailData *Data, 762 1.1 kamil ValueHandle Vtable, 763 1.1 kamil bool ValidVtable, 764 1.1 kamil ReportOptions Opts) { 765 1.1 kamil Die(); 766 1.1 kamil } 767 1.1 kamil 768 1.1 kamil WIN_WEAK_ALIAS(__ubsan_handle_cfi_bad_type, __ubsan_handle_cfi_bad_type_default) 769 1.1 kamil #else 770 1.1 kamil SANITIZER_WEAK_ATTRIBUTE 771 1.1 kamil #endif 772 1.1 kamil void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable, 773 1.1 kamil bool ValidVtable, ReportOptions Opts); 774 1.1 kamil 775 1.1 kamil #else 776 1.1 kamil void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable, 777 1.1 kamil bool ValidVtable, ReportOptions Opts) { 778 1.1 kamil Die(); 779 1.1 kamil } 780 1.1 kamil #endif 781 1.1 kamil 782 1.1 kamil } // namespace __ubsan 783 1.1 kamil 784 1.1 kamil void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data, 785 1.1 kamil ValueHandle Value, 786 1.1 kamil uptr ValidVtable) { 787 1.1 kamil GET_REPORT_OPTIONS(false); 788 1.1 kamil if (Data->CheckKind == CFITCK_ICall || Data->CheckKind == CFITCK_NVMFCall) 789 1.1 kamil handleCFIBadIcall(Data, Value, Opts); 790 1.1 kamil else 791 1.1 kamil __ubsan_handle_cfi_bad_type(Data, Value, ValidVtable, Opts); 792 1.1 kamil } 793 1.1 kamil 794 1.1 kamil void __ubsan::__ubsan_handle_cfi_check_fail_abort(CFICheckFailData *Data, 795 1.1 kamil ValueHandle Value, 796 1.1 kamil uptr ValidVtable) { 797 1.1 kamil GET_REPORT_OPTIONS(true); 798 1.1 kamil if (Data->CheckKind == CFITCK_ICall || Data->CheckKind == CFITCK_NVMFCall) 799 1.1 kamil handleCFIBadIcall(Data, Value, Opts); 800 1.1 kamil else 801 1.1 kamil __ubsan_handle_cfi_bad_type(Data, Value, ValidVtable, Opts); 802 1.1 kamil Die(); 803 1.1 kamil } 804 1.1 kamil 805 1.1 kamil #endif // CAN_SANITIZE_UB 806