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