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