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