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