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