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_handlers.h" 13 #include "ubsan_diag.h" 14 15 #include "sanitizer_common/sanitizer_common.h" 16 17 using namespace __sanitizer; 18 using namespace __ubsan; 19 20 static bool ignoreReport(SourceLocation SLoc, ReportOptions Opts) { 21 // If source location is already acquired, we don't need to print an error 22 // report for the second time. However, if we're in an unrecoverable handler, 23 // it's possible that location was required by concurrently running thread. 24 // In this case, we should continue the execution to ensure that any of 25 // threads will grab the report mutex and print the report before 26 // crashing the program. 27 return SLoc.isDisabled() && !Opts.DieAfterReport; 28 } 29 30 namespace __ubsan { 31 const char *TypeCheckKinds[] = { 32 "load of", "store to", "reference binding to", "member access within", 33 "member call on", "constructor call on", "downcast of", "downcast of", 34 "upcast of", "cast to virtual base of"}; 35 } 36 37 static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer, 38 Location FallbackLoc, ReportOptions Opts) { 39 Location Loc = Data->Loc.acquire(); 40 // Use the SourceLocation from Data to track deduplication, even if 'invalid' 41 if (ignoreReport(Loc.getSourceLocation(), Opts)) 42 return; 43 44 if (Data->Loc.isInvalid()) 45 Loc = FallbackLoc; 46 47 ScopedReport R(Opts, Loc); 48 49 if (!Pointer) 50 Diag(Loc, DL_Error, "%0 null pointer of type %1") 51 << TypeCheckKinds[Data->TypeCheckKind] << Data->Type; 52 else if (Data->Alignment && (Pointer & (Data->Alignment - 1))) 53 Diag(Loc, DL_Error, "%0 misaligned address %1 for type %3, " 54 "which requires %2 byte alignment") 55 << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer 56 << Data->Alignment << Data->Type; 57 else 58 Diag(Loc, DL_Error, "%0 address %1 with insufficient space " 59 "for an object of type %2") 60 << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type; 61 if (Pointer) 62 Diag(Pointer, DL_Note, "pointer points here"); 63 } 64 65 void __ubsan::__ubsan_handle_type_mismatch(TypeMismatchData *Data, 66 ValueHandle Pointer) { 67 GET_REPORT_OPTIONS(false); 68 handleTypeMismatchImpl(Data, Pointer, getCallerLocation(), Opts); 69 } 70 void __ubsan::__ubsan_handle_type_mismatch_abort(TypeMismatchData *Data, 71 ValueHandle Pointer) { 72 GET_REPORT_OPTIONS(true); 73 handleTypeMismatchImpl(Data, Pointer, getCallerLocation(), Opts); 74 Die(); 75 } 76 77 /// \brief Common diagnostic emission for various forms of integer overflow. 78 template <typename T> 79 static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS, 80 const char *Operator, T RHS, 81 ReportOptions Opts) { 82 SourceLocation Loc = Data->Loc.acquire(); 83 if (ignoreReport(Loc, Opts)) 84 return; 85 86 ScopedReport R(Opts, Loc); 87 88 Diag(Loc, DL_Error, "%0 integer overflow: " 89 "%1 %2 %3 cannot be represented in type %4") 90 << (Data->Type.isSignedIntegerTy() ? "signed" : "unsigned") 91 << Value(Data->Type, LHS) << Operator << RHS << Data->Type; 92 } 93 94 #define UBSAN_OVERFLOW_HANDLER(handler_name, op, abort) \ 95 void __ubsan::handler_name(OverflowData *Data, ValueHandle LHS, \ 96 ValueHandle RHS) { \ 97 GET_REPORT_OPTIONS(abort); \ 98 handleIntegerOverflowImpl(Data, LHS, op, Value(Data->Type, RHS), Opts); \ 99 if (abort) Die(); \ 100 } 101 102 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow, "+", false) 103 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow_abort, "+", true) 104 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow, "-", false) 105 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow_abort, "-", true) 106 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow, "*", false) 107 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow_abort, "*", true) 108 109 static void handleNegateOverflowImpl(OverflowData *Data, ValueHandle OldVal, 110 ReportOptions Opts) { 111 SourceLocation Loc = Data->Loc.acquire(); 112 if (ignoreReport(Loc, Opts)) 113 return; 114 115 ScopedReport R(Opts, Loc); 116 117 if (Data->Type.isSignedIntegerTy()) 118 Diag(Loc, DL_Error, 119 "negation of %0 cannot be represented in type %1; " 120 "cast to an unsigned type to negate this value to itself") 121 << Value(Data->Type, OldVal) << Data->Type; 122 else 123 Diag(Loc, DL_Error, 124 "negation of %0 cannot be represented in type %1") 125 << Value(Data->Type, OldVal) << Data->Type; 126 } 127 128 void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data, 129 ValueHandle OldVal) { 130 GET_REPORT_OPTIONS(false); 131 handleNegateOverflowImpl(Data, OldVal, Opts); 132 } 133 void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData *Data, 134 ValueHandle OldVal) { 135 GET_REPORT_OPTIONS(true); 136 handleNegateOverflowImpl(Data, OldVal, Opts); 137 Die(); 138 } 139 140 static void handleDivremOverflowImpl(OverflowData *Data, ValueHandle LHS, 141 ValueHandle RHS, ReportOptions Opts) { 142 SourceLocation Loc = Data->Loc.acquire(); 143 if (ignoreReport(Loc, Opts)) 144 return; 145 146 ScopedReport R(Opts, Loc); 147 148 Value LHSVal(Data->Type, LHS); 149 Value RHSVal(Data->Type, RHS); 150 if (RHSVal.isMinusOne()) 151 Diag(Loc, DL_Error, 152 "division of %0 by -1 cannot be represented in type %1") 153 << LHSVal << Data->Type; 154 else 155 Diag(Loc, DL_Error, "division by zero"); 156 } 157 158 void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data, 159 ValueHandle LHS, ValueHandle RHS) { 160 GET_REPORT_OPTIONS(false); 161 handleDivremOverflowImpl(Data, LHS, RHS, Opts); 162 } 163 void __ubsan::__ubsan_handle_divrem_overflow_abort(OverflowData *Data, 164 ValueHandle LHS, 165 ValueHandle RHS) { 166 GET_REPORT_OPTIONS(true); 167 handleDivremOverflowImpl(Data, LHS, RHS, Opts); 168 Die(); 169 } 170 171 static void handleShiftOutOfBoundsImpl(ShiftOutOfBoundsData *Data, 172 ValueHandle LHS, ValueHandle RHS, 173 ReportOptions Opts) { 174 SourceLocation Loc = Data->Loc.acquire(); 175 if (ignoreReport(Loc, Opts)) 176 return; 177 178 ScopedReport R(Opts, Loc); 179 180 Value LHSVal(Data->LHSType, LHS); 181 Value RHSVal(Data->RHSType, RHS); 182 if (RHSVal.isNegative()) 183 Diag(Loc, DL_Error, "shift exponent %0 is negative") << RHSVal; 184 else if (RHSVal.getPositiveIntValue() >= Data->LHSType.getIntegerBitWidth()) 185 Diag(Loc, DL_Error, 186 "shift exponent %0 is too large for %1-bit type %2") 187 << RHSVal << Data->LHSType.getIntegerBitWidth() << Data->LHSType; 188 else if (LHSVal.isNegative()) 189 Diag(Loc, DL_Error, "left shift of negative value %0") << LHSVal; 190 else 191 Diag(Loc, DL_Error, 192 "left shift of %0 by %1 places cannot be represented in type %2") 193 << LHSVal << RHSVal << Data->LHSType; 194 } 195 196 void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data, 197 ValueHandle LHS, 198 ValueHandle RHS) { 199 GET_REPORT_OPTIONS(false); 200 handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts); 201 } 202 void __ubsan::__ubsan_handle_shift_out_of_bounds_abort( 203 ShiftOutOfBoundsData *Data, 204 ValueHandle LHS, 205 ValueHandle RHS) { 206 GET_REPORT_OPTIONS(true); 207 handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts); 208 Die(); 209 } 210 211 static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index, 212 ReportOptions Opts) { 213 SourceLocation Loc = Data->Loc.acquire(); 214 if (ignoreReport(Loc, Opts)) 215 return; 216 217 ScopedReport R(Opts, Loc); 218 219 Value IndexVal(Data->IndexType, Index); 220 Diag(Loc, DL_Error, "index %0 out of bounds for type %1") 221 << IndexVal << Data->ArrayType; 222 } 223 224 void __ubsan::__ubsan_handle_out_of_bounds(OutOfBoundsData *Data, 225 ValueHandle Index) { 226 GET_REPORT_OPTIONS(false); 227 handleOutOfBoundsImpl(Data, Index, Opts); 228 } 229 void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data, 230 ValueHandle Index) { 231 GET_REPORT_OPTIONS(true); 232 handleOutOfBoundsImpl(Data, Index, Opts); 233 Die(); 234 } 235 236 static void handleBuiltinUnreachableImpl(UnreachableData *Data, 237 ReportOptions Opts) { 238 ScopedReport R(Opts, Data->Loc); 239 Diag(Data->Loc, DL_Error, "execution reached a __builtin_unreachable() call"); 240 } 241 242 void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) { 243 GET_REPORT_OPTIONS(true); 244 handleBuiltinUnreachableImpl(Data, Opts); 245 Die(); 246 } 247 248 static void handleMissingReturnImpl(UnreachableData *Data, ReportOptions Opts) { 249 ScopedReport R(Opts, Data->Loc); 250 Diag(Data->Loc, DL_Error, 251 "execution reached the end of a value-returning function " 252 "without returning a value"); 253 } 254 255 void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) { 256 GET_REPORT_OPTIONS(true); 257 handleMissingReturnImpl(Data, Opts); 258 Die(); 259 } 260 261 static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound, 262 ReportOptions Opts) { 263 SourceLocation Loc = Data->Loc.acquire(); 264 if (ignoreReport(Loc, Opts)) 265 return; 266 267 ScopedReport R(Opts, Loc); 268 269 Diag(Loc, DL_Error, "variable length array bound evaluates to " 270 "non-positive value %0") 271 << Value(Data->Type, Bound); 272 } 273 274 void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data, 275 ValueHandle Bound) { 276 GET_REPORT_OPTIONS(false); 277 handleVLABoundNotPositive(Data, Bound, Opts); 278 } 279 void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData *Data, 280 ValueHandle Bound) { 281 GET_REPORT_OPTIONS(true); 282 handleVLABoundNotPositive(Data, Bound, Opts); 283 Die(); 284 } 285 286 static void handleFloatCastOverflow(FloatCastOverflowData *Data, 287 ValueHandle From, ReportOptions Opts) { 288 // TODO: Add deduplication once a SourceLocation is generated for this check. 289 Location Loc = getCallerLocation(); 290 ScopedReport R(Opts, Loc); 291 292 Diag(Loc, DL_Error, 293 "value %0 is outside the range of representable values of type %2") 294 << Value(Data->FromType, From) << Data->FromType << Data->ToType; 295 } 296 297 void __ubsan::__ubsan_handle_float_cast_overflow(FloatCastOverflowData *Data, 298 ValueHandle From) { 299 GET_REPORT_OPTIONS(false); 300 handleFloatCastOverflow(Data, From, Opts); 301 } 302 void 303 __ubsan::__ubsan_handle_float_cast_overflow_abort(FloatCastOverflowData *Data, 304 ValueHandle From) { 305 GET_REPORT_OPTIONS(true); 306 handleFloatCastOverflow(Data, From, Opts); 307 Die(); 308 } 309 310 static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val, 311 ReportOptions Opts) { 312 SourceLocation Loc = Data->Loc.acquire(); 313 if (ignoreReport(Loc, Opts)) 314 return; 315 316 ScopedReport R(Opts, Loc); 317 318 Diag(Loc, DL_Error, 319 "load of value %0, which is not a valid value for type %1") 320 << Value(Data->Type, Val) << Data->Type; 321 } 322 323 void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data, 324 ValueHandle Val) { 325 GET_REPORT_OPTIONS(false); 326 handleLoadInvalidValue(Data, Val, Opts); 327 } 328 void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data, 329 ValueHandle Val) { 330 GET_REPORT_OPTIONS(true); 331 handleLoadInvalidValue(Data, Val, Opts); 332 Die(); 333 } 334 335 static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data, 336 ValueHandle Function, 337 ReportOptions Opts) { 338 const char *FName = "(unknown)"; 339 340 Location Loc = getFunctionLocation(Function, &FName); 341 342 ScopedReport R(Opts, Loc); 343 344 Diag(Data->Loc, DL_Error, 345 "call to function %0 through pointer to incorrect function type %1") 346 << FName << Data->Type; 347 Diag(Loc, DL_Note, "%0 defined here") << FName; 348 } 349 350 void 351 __ubsan::__ubsan_handle_function_type_mismatch(FunctionTypeMismatchData *Data, 352 ValueHandle Function) { 353 GET_REPORT_OPTIONS(false); 354 handleFunctionTypeMismatch(Data, Function, Opts); 355 } 356 357 void __ubsan::__ubsan_handle_function_type_mismatch_abort( 358 FunctionTypeMismatchData *Data, ValueHandle Function) { 359 GET_REPORT_OPTIONS(true); 360 handleFunctionTypeMismatch(Data, Function, Opts); 361 Die(); 362 } 363 364 static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts) { 365 SourceLocation Loc = Data->Loc.acquire(); 366 if (ignoreReport(Loc, Opts)) 367 return; 368 369 ScopedReport R(Opts, Loc); 370 371 Diag(Loc, DL_Error, "null pointer returned from function declared to never " 372 "return null"); 373 if (!Data->AttrLoc.isInvalid()) 374 Diag(Data->AttrLoc, DL_Note, "returns_nonnull attribute specified here"); 375 } 376 377 void __ubsan::__ubsan_handle_nonnull_return(NonNullReturnData *Data) { 378 GET_REPORT_OPTIONS(false); 379 handleNonNullReturn(Data, Opts); 380 } 381 382 void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullReturnData *Data) { 383 GET_REPORT_OPTIONS(true); 384 handleNonNullReturn(Data, Opts); 385 Die(); 386 } 387 388 static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts) { 389 SourceLocation Loc = Data->Loc.acquire(); 390 if (ignoreReport(Loc, Opts)) 391 return; 392 393 ScopedReport R(Opts, Loc); 394 395 Diag(Loc, DL_Error, "null pointer passed as argument %0, which is declared to " 396 "never be null") << Data->ArgIndex; 397 if (!Data->AttrLoc.isInvalid()) 398 Diag(Data->AttrLoc, DL_Note, "nonnull attribute specified here"); 399 } 400 401 void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData *Data) { 402 GET_REPORT_OPTIONS(false); 403 handleNonNullArg(Data, Opts); 404 } 405 406 void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) { 407 GET_REPORT_OPTIONS(true); 408 handleNonNullArg(Data, Opts); 409 Die(); 410 } 411