xref: /netbsd-src/common/lib/libc/misc/ubsan.c (revision 84176bea914bbc4aba07ac90d280576c7a2439ea)
1 /*	$NetBSD: ubsan.c,v 1.12 2023/12/07 07:10:44 andvar Exp $	*/
2 
3 /*-
4  * Copyright (c) 2018 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 
30 /*
31  * The micro UBSan implementation for the userland (uUBSan) and kernel (kUBSan).
32  * The uBSSan versions is suitable for inclusion into libc or used standalone
33  * with ATF tests.
34  *
35  * This file due to long symbol names generated by a compiler during the
36  * instrumentation process does not follow the KNF style with 80-column limit.
37  */
38 
39 #include <sys/cdefs.h>
40 #if defined(_KERNEL)
41 __KERNEL_RCSID(0, "$NetBSD: ubsan.c,v 1.12 2023/12/07 07:10:44 andvar Exp $");
42 #else
43 __RCSID("$NetBSD: ubsan.c,v 1.12 2023/12/07 07:10:44 andvar Exp $");
44 #endif
45 
46 #if defined(_KERNEL)
47 #include <sys/param.h>
48 #include <sys/types.h>
49 #include <sys/stdarg.h>
50 #define ASSERT(x) KASSERT(x)
51 #else
52 #if defined(_LIBC)
53 #include "namespace.h"
54 #endif
55 #include <sys/param.h>
56 #include <assert.h>
57 #include <inttypes.h>
58 #include <math.h>
59 #include <signal.h>
60 #include <stdarg.h>
61 #include <stdbool.h>
62 #include <stdint.h>
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <string.h>
66 #include <syslog.h>
67 #include <unistd.h>
68 #if defined(_LIBC)
69 #include "extern.h"
70 #define ubsan_vsyslog vsyslog_ss
71 #define ASSERT(x) _DIAGASSERT(x)
72 #else
73 #define ubsan_vsyslog vsyslog_r
74 #define ASSERT(x) assert(x)
75 #endif
76 /* These macros are available in _KERNEL only */
77 #define SET(t, f)	((t) |= (f))
78 #define ISSET(t, f)	((t) & (f))
79 #define CLR(t, f)	((t) &= ~(f))
80 #endif
81 
82 #ifdef UBSAN_ALWAYS_FATAL
83 static const bool alwaysFatal = true;
84 #else
85 static const bool alwaysFatal = false;
86 #endif
87 
88 #define REINTERPRET_CAST(__dt, __st)	((__dt)(__st))
89 #define STATIC_CAST(__dt, __st)		((__dt)(__st))
90 
91 #define ACK_REPORTED	__BIT(31)
92 
93 #define MUL_STRING	"*"
94 #define PLUS_STRING	"+"
95 #define MINUS_STRING	"-"
96 #define DIVREM_STRING	"divrem"
97 
98 #define CFI_VCALL		0
99 #define CFI_NVCALL		1
100 #define CFI_DERIVEDCAST		2
101 #define CFI_UNRELATEDCAST	3
102 #define CFI_ICALL		4
103 #define CFI_NVMFCALL		5
104 #define CFI_VMFCALL		6
105 
106 #define NUMBER_MAXLEN	128
107 #define LOCATION_MAXLEN	(PATH_MAX + 32 /* ':LINE:COLUMN' */)
108 
109 #define WIDTH_8		8
110 #define WIDTH_16	16
111 #define WIDTH_32	32
112 #define WIDTH_64	64
113 #define WIDTH_80	80
114 #define WIDTH_96	96
115 #define WIDTH_128	128
116 
117 #define NUMBER_SIGNED_BIT	1U
118 
119 #ifdef __SIZEOF_INT128__
120 typedef __int128 longest;
121 typedef unsigned __int128 ulongest;
122 #else
123 typedef int64_t longest;
124 typedef uint64_t ulongest;
125 #endif
126 
127 #ifndef _KERNEL
128 static int ubsan_flags = -1;
129 #define UBSAN_ABORT	__BIT(0)
130 #define UBSAN_STDOUT	__BIT(1)
131 #define UBSAN_STDERR	__BIT(2)
132 #define UBSAN_SYSLOG	__BIT(3)
133 #endif
134 
135 /* Undefined Behavior specific defines and structures */
136 
137 #define KIND_INTEGER	0
138 #define KIND_FLOAT	1
139 #define KIND_UNKNOWN	UINT16_MAX
140 
141 struct CSourceLocation {
142 	char *mFilename;
143 	uint32_t mLine;
144 	uint32_t mColumn;
145 };
146 
147 struct CTypeDescriptor {
148 	uint16_t mTypeKind;
149 	uint16_t mTypeInfo;
150 	uint8_t mTypeName[1];
151 };
152 
153 struct COverflowData {
154 	struct CSourceLocation mLocation;
155 	struct CTypeDescriptor *mType;
156 };
157 
158 struct CUnreachableData {
159 	struct CSourceLocation mLocation;
160 };
161 
162 struct CCFICheckFailData {
163 	uint8_t mCheckKind;
164 	struct CSourceLocation mLocation;
165 	struct CTypeDescriptor *mType;
166 };
167 
168 struct CDynamicTypeCacheMissData {
169 	struct CSourceLocation mLocation;
170 	struct CTypeDescriptor *mType;
171 	void *mTypeInfo;
172 	uint8_t mTypeCheckKind;
173 };
174 
175 struct CFunctionTypeMismatchData {
176 	struct CSourceLocation mLocation;
177 	struct CTypeDescriptor *mType;
178 };
179 
180 struct CInvalidBuiltinData {
181 	struct CSourceLocation mLocation;
182 	uint8_t mKind;
183 };
184 
185 struct CInvalidValueData {
186 	struct CSourceLocation mLocation;
187 	struct CTypeDescriptor *mType;
188 };
189 
190 struct CNonNullArgData {
191 	struct CSourceLocation mLocation;
192 	struct CSourceLocation mAttributeLocation;
193 	int mArgIndex;
194 };
195 
196 struct CNonNullReturnData {
197 	struct CSourceLocation mAttributeLocation;
198 };
199 
200 struct COutOfBoundsData {
201 	struct CSourceLocation mLocation;
202 	struct CTypeDescriptor *mArrayType;
203 	struct CTypeDescriptor *mIndexType;
204 };
205 
206 struct CPointerOverflowData {
207 	struct CSourceLocation mLocation;
208 };
209 
210 struct CShiftOutOfBoundsData {
211 	struct CSourceLocation mLocation;
212 	struct CTypeDescriptor *mLHSType;
213 	struct CTypeDescriptor *mRHSType;
214 };
215 
216 struct CTypeMismatchData {
217 	struct CSourceLocation mLocation;
218 	struct CTypeDescriptor *mType;
219 	unsigned long mLogAlignment;
220 	uint8_t mTypeCheckKind;
221 };
222 
223 struct CTypeMismatchData_v1 {
224 	struct CSourceLocation mLocation;
225 	struct CTypeDescriptor *mType;
226 	uint8_t mLogAlignment;
227 	uint8_t mTypeCheckKind;
228 };
229 
230 struct CVLABoundData {
231 	struct CSourceLocation mLocation;
232 	struct CTypeDescriptor *mType;
233 };
234 
235 struct CFloatCastOverflowData {
236 	struct CSourceLocation mLocation;	/* This field exists in this struct since 2015 August 11th */
237 	struct CTypeDescriptor *mFromType;
238 	struct CTypeDescriptor *mToType;
239 };
240 
241 struct CImplicitConversionData {
242 	struct CSourceLocation mLocation;
243 	struct CTypeDescriptor *mFromType;
244 	struct CTypeDescriptor *mToType;
245 	uint8_t mKind;
246 };
247 
248 struct CAlignmentAssumptionData {
249 	struct CSourceLocation mLocation;
250 	struct CSourceLocation mAssumptionLocation;
251 	struct CTypeDescriptor *mType;
252 };
253 
254 /* Local utility functions */
255 static void Report(bool isFatal, const char *pFormat, ...) __printflike(2, 3);
256 static bool isAlreadyReported(struct CSourceLocation *pLocation);
257 static size_t zDeserializeTypeWidth(struct CTypeDescriptor *pType);
258 static void DeserializeLocation(char *pBuffer, size_t zBUfferLength, struct CSourceLocation *pLocation);
259 #ifdef __SIZEOF_INT128__
260 static void DeserializeUINT128(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, __uint128_t U128);
261 #endif
262 static void DeserializeNumberSigned(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, longest L);
263 static void DeserializeNumberUnsigned(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, ulongest L);
264 #ifndef _KERNEL
265 static void DeserializeFloatOverPointer(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long *pNumber);
266 static void DeserializeFloatInlined(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long ulNumber);
267 #endif
268 static longest llliGetNumber(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber);
269 static ulongest llluGetNumber(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber);
270 #ifndef _KERNEL
271 static void DeserializeNumberFloat(char *szLocation, char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long ulNumber);
272 #endif
273 static void DeserializeNumber(char *szLocation, char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long ulNumber);
274 static const char *DeserializeTypeCheckKind(uint8_t hhuTypeCheckKind);
275 static const char *DeserializeBuiltinCheckKind(uint8_t hhuBuiltinCheckKind);
276 static const char *DeserializeCFICheckKind(uint8_t hhuCFICheckKind);
277 static const char *DeserializeImplicitConversionCheckKind(uint8_t hhuImplicitConversionCheckKind);
278 static bool isNegativeNumber(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber);
279 static bool isShiftExponentTooLarge(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber, size_t zWidth);
280 
281 /* Unused in this implementation, emitted by the C++ check dynamic type cast. */
282 intptr_t __ubsan_vptr_type_cache[128];
283 
284 /* Public symbols used in the instrumentation of the code generation part */
285 void __ubsan_handle_add_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS);
286 void __ubsan_handle_add_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS);
287 void __ubsan_handle_alignment_assumption(struct CAlignmentAssumptionData *pData, unsigned long ulPointer, unsigned long ulAlignment, unsigned long ulOffset);
288 void __ubsan_handle_alignment_assumption_abort(struct CAlignmentAssumptionData *pData, unsigned long ulPointer, unsigned long ulAlignment, unsigned long ulOffset);
289 void __ubsan_handle_builtin_unreachable(struct CUnreachableData *pData);
290 void __ubsan_handle_cfi_bad_type(struct CCFICheckFailData *pData, unsigned long ulVtable, bool bValidVtable, bool FromUnrecoverableHandler, unsigned long ProgramCounter, unsigned long FramePointer);
291 void __ubsan_handle_cfi_check_fail(struct CCFICheckFailData *pData, unsigned long ulValue, unsigned long ulValidVtable);
292 void __ubsan_handle_cfi_check_fail_abort(struct CCFICheckFailData *pData, unsigned long ulValue, unsigned long ulValidVtable);
293 void __ubsan_handle_divrem_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS);
294 void __ubsan_handle_divrem_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS);
295 void __ubsan_handle_dynamic_type_cache_miss(struct CDynamicTypeCacheMissData *pData, unsigned long ulPointer, unsigned long ulHash);
296 void __ubsan_handle_dynamic_type_cache_miss_abort(struct CDynamicTypeCacheMissData *pData, unsigned long ulPointer, unsigned long ulHash);
297 void __ubsan_handle_float_cast_overflow(struct CFloatCastOverflowData *pData, unsigned long ulFrom);
298 void __ubsan_handle_float_cast_overflow_abort(struct CFloatCastOverflowData *pData, unsigned long ulFrom);
299 void __ubsan_handle_function_type_mismatch(struct CFunctionTypeMismatchData *pData, unsigned long ulFunction);
300 void __ubsan_handle_function_type_mismatch_abort(struct CFunctionTypeMismatchData *pData, unsigned long ulFunction);
301 void __ubsan_handle_function_type_mismatch_v1(struct CFunctionTypeMismatchData *pData, unsigned long ulFunction, unsigned long ulCalleeRTTI, unsigned long ulFnRTTI);
302 void __ubsan_handle_function_type_mismatch_v1_abort(struct CFunctionTypeMismatchData *pData, unsigned long ulFunction, unsigned long ulCalleeRTTI, unsigned long ulFnRTTI);
303 void __ubsan_handle_invalid_builtin(struct CInvalidBuiltinData *pData);
304 void __ubsan_handle_invalid_builtin_abort(struct CInvalidBuiltinData *pData);
305 void __ubsan_handle_load_invalid_value(struct CInvalidValueData *pData, unsigned long ulVal);
306 void __ubsan_handle_load_invalid_value_abort(struct CInvalidValueData *pData, unsigned long ulVal);
307 void __ubsan_handle_missing_return(struct CUnreachableData *pData);
308 void __ubsan_handle_mul_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS);
309 void __ubsan_handle_mul_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS);
310 void __ubsan_handle_negate_overflow(struct COverflowData *pData, unsigned long ulOldVal);
311 void __ubsan_handle_negate_overflow_abort(struct COverflowData *pData, unsigned long ulOldVal);
312 void __ubsan_handle_nonnull_arg(struct CNonNullArgData *pData);
313 void __ubsan_handle_nonnull_arg_abort(struct CNonNullArgData *pData);
314 void __ubsan_handle_nonnull_return_v1(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer);
315 void __ubsan_handle_nonnull_return_v1_abort(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer);
316 void __ubsan_handle_nullability_arg(struct CNonNullArgData *pData);
317 void __ubsan_handle_nullability_arg_abort(struct CNonNullArgData *pData);
318 void __ubsan_handle_nullability_return_v1(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer);
319 void __ubsan_handle_nullability_return_v1_abort(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer);
320 void __ubsan_handle_out_of_bounds(struct COutOfBoundsData *pData, unsigned long ulIndex);
321 void __ubsan_handle_out_of_bounds_abort(struct COutOfBoundsData *pData, unsigned long ulIndex);
322 void __ubsan_handle_pointer_overflow(struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult);
323 void __ubsan_handle_pointer_overflow_abort(struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult);
324 void __ubsan_handle_shift_out_of_bounds(struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS);
325 void __ubsan_handle_shift_out_of_bounds_abort(struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS);
326 void __ubsan_handle_sub_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS);
327 void __ubsan_handle_sub_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS);
328 void __ubsan_handle_type_mismatch(struct CTypeMismatchData *pData, unsigned long ulPointer);
329 void __ubsan_handle_type_mismatch_abort(struct CTypeMismatchData *pData, unsigned long ulPointer);
330 void __ubsan_handle_type_mismatch_v1(struct CTypeMismatchData_v1 *pData, unsigned long ulPointer);
331 void __ubsan_handle_type_mismatch_v1_abort(struct CTypeMismatchData_v1 *pData, unsigned long ulPointer);
332 void __ubsan_handle_vla_bound_not_positive(struct CVLABoundData *pData, unsigned long ulBound);
333 void __ubsan_handle_vla_bound_not_positive_abort(struct CVLABoundData *pData, unsigned long ulBound);
334 void __ubsan_handle_implicit_conversion(struct CImplicitConversionData *pData, unsigned long ulFrom, unsigned long ulTo);
335 void __ubsan_handle_implicit_conversion_abort(struct CImplicitConversionData *pData, unsigned long ulFrom, unsigned long ulTo);
336 void __ubsan_get_current_report_data(const char **ppOutIssueKind, const char **ppOutMessage, const char **ppOutFilename, uint32_t *pOutLine, uint32_t *pOutCol, char **ppOutMemoryAddr);
337 
338 static void HandleOverflow(bool isFatal, struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS, const char *szOperation);
339 static void HandleNegateOverflow(bool isFatal, struct COverflowData *pData, unsigned long ulOldValue);
340 static void HandleBuiltinUnreachable(bool isFatal, struct CUnreachableData *pData);
341 static void HandleTypeMismatch(bool isFatal, struct CSourceLocation *mLocation, struct CTypeDescriptor *mType, unsigned long mLogAlignment, uint8_t mTypeCheckKind, unsigned long ulPointer);
342 static void HandleVlaBoundNotPositive(bool isFatal, struct CVLABoundData *pData, unsigned long ulBound);
343 static void HandleOutOfBounds(bool isFatal, struct COutOfBoundsData *pData, unsigned long ulIndex);
344 static void HandleShiftOutOfBounds(bool isFatal, struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS);
345 static void HandleLoadInvalidValue(bool isFatal, struct CInvalidValueData *pData, unsigned long ulValue);
346 static void HandleInvalidBuiltin(bool isFatal, struct CInvalidBuiltinData *pData);
347 static void HandleFunctionTypeMismatch(bool isFatal, struct CFunctionTypeMismatchData *pData, unsigned long ulFunction);
348 static void HandleCFIBadType(bool isFatal, struct CCFICheckFailData *pData, unsigned long ulVtable, bool *bValidVtable, bool *FromUnrecoverableHandler, unsigned long *ProgramCounter, unsigned long *FramePointer);
349 static void HandleDynamicTypeCacheMiss(bool isFatal, struct CDynamicTypeCacheMissData *pData, unsigned long ulPointer, unsigned long ulHash);
350 static void HandleFloatCastOverflow(bool isFatal, struct CFloatCastOverflowData *pData, unsigned long ulFrom);
351 static void HandleMissingReturn(bool isFatal, struct CUnreachableData *pData);
352 static void HandleNonnullArg(bool isFatal, struct CNonNullArgData *pData);
353 static void HandleNonnullReturn(bool isFatal, struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer);
354 static void HandlePointerOverflow(bool isFatal, struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult);
355 static void HandleAlignmentAssumption(bool isFatal, struct CAlignmentAssumptionData *pData, unsigned long ulPointer, unsigned long ulAlignment, unsigned long ulOffset);
356 
357 static void
HandleOverflow(bool isFatal,struct COverflowData * pData,unsigned long ulLHS,unsigned long ulRHS,const char * szOperation)358 HandleOverflow(bool isFatal, struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS, const char *szOperation)
359 {
360 	char szLocation[LOCATION_MAXLEN];
361 	char szLHS[NUMBER_MAXLEN];
362 	char szRHS[NUMBER_MAXLEN];
363 
364 	ASSERT(pData);
365 
366 	if (isAlreadyReported(&pData->mLocation))
367 		return;
368 
369 	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
370 	DeserializeNumber(szLocation, szLHS, NUMBER_MAXLEN, pData->mType, ulLHS);
371 	DeserializeNumber(szLocation, szRHS, NUMBER_MAXLEN, pData->mType, ulRHS);
372 
373 	Report(isFatal, "UBSan: Undefined Behavior in %s, %s integer overflow: %s %s %s cannot be represented in type %s\n",
374 	       szLocation, ISSET(pData->mType->mTypeInfo, NUMBER_SIGNED_BIT) ? "signed" : "unsigned", szLHS, szOperation, szRHS, pData->mType->mTypeName);
375 }
376 
377 static void
HandleNegateOverflow(bool isFatal,struct COverflowData * pData,unsigned long ulOldValue)378 HandleNegateOverflow(bool isFatal, struct COverflowData *pData, unsigned long ulOldValue)
379 {
380 	char szLocation[LOCATION_MAXLEN];
381 	char szOldValue[NUMBER_MAXLEN];
382 
383 	ASSERT(pData);
384 
385 	if (isAlreadyReported(&pData->mLocation))
386 		return;
387 
388 	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
389 	DeserializeNumber(szLocation, szOldValue, NUMBER_MAXLEN, pData->mType, ulOldValue);
390 
391 	Report(isFatal, "UBSan: Undefined Behavior in %s, negation of %s cannot be represented in type %s\n",
392 	       szLocation, szOldValue, pData->mType->mTypeName);
393 }
394 
395 static void
HandleBuiltinUnreachable(bool isFatal,struct CUnreachableData * pData)396 HandleBuiltinUnreachable(bool isFatal, struct CUnreachableData *pData)
397 {
398 	char szLocation[LOCATION_MAXLEN];
399 
400 	ASSERT(pData);
401 
402 	if (isAlreadyReported(&pData->mLocation))
403 		return;
404 
405 	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
406 
407 	Report(isFatal, "UBSan: Undefined Behavior in %s, calling __builtin_unreachable()\n",
408 	       szLocation);
409 }
410 
411 static void
HandleTypeMismatch(bool isFatal,struct CSourceLocation * mLocation,struct CTypeDescriptor * mType,unsigned long mLogAlignment,uint8_t mTypeCheckKind,unsigned long ulPointer)412 HandleTypeMismatch(bool isFatal, struct CSourceLocation *mLocation, struct CTypeDescriptor *mType, unsigned long mLogAlignment, uint8_t mTypeCheckKind, unsigned long ulPointer)
413 {
414 	char szLocation[LOCATION_MAXLEN];
415 
416 	ASSERT(mLocation);
417 	ASSERT(mType);
418 
419 	if (isAlreadyReported(mLocation))
420 		return;
421 
422 	DeserializeLocation(szLocation, LOCATION_MAXLEN, mLocation);
423 
424 	if (ulPointer == 0) {
425 		Report(isFatal, "UBSan: Undefined Behavior in %s, %s null pointer of type %s\n",
426 		       szLocation, DeserializeTypeCheckKind(mTypeCheckKind), mType->mTypeName);
427 	} else if ((mLogAlignment - 1) & ulPointer) {
428 		Report(isFatal, "UBSan: Undefined Behavior in %s, %s misaligned address %p for type %s which requires %ld byte alignment\n",
429 		       szLocation, DeserializeTypeCheckKind(mTypeCheckKind), REINTERPRET_CAST(void *, ulPointer), mType->mTypeName, mLogAlignment);
430 	} else {
431 		Report(isFatal, "UBSan: Undefined Behavior in %s, %s address %p with insufficient space for an object of type %s\n",
432 		       szLocation, DeserializeTypeCheckKind(mTypeCheckKind), REINTERPRET_CAST(void *, ulPointer), mType->mTypeName);
433 	}
434 }
435 
436 static void
HandleVlaBoundNotPositive(bool isFatal,struct CVLABoundData * pData,unsigned long ulBound)437 HandleVlaBoundNotPositive(bool isFatal, struct CVLABoundData *pData, unsigned long ulBound)
438 {
439 	char szLocation[LOCATION_MAXLEN];
440 	char szBound[NUMBER_MAXLEN];
441 
442 	ASSERT(pData);
443 
444 	if (isAlreadyReported(&pData->mLocation))
445 		return;
446 
447 	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
448 	DeserializeNumber(szLocation, szBound, NUMBER_MAXLEN, pData->mType, ulBound);
449 
450 	Report(isFatal, "UBSan: Undefined Behavior in %s, variable length array bound value %s <= 0\n",
451 	       szLocation, szBound);
452 }
453 
454 static void
HandleOutOfBounds(bool isFatal,struct COutOfBoundsData * pData,unsigned long ulIndex)455 HandleOutOfBounds(bool isFatal, struct COutOfBoundsData *pData, unsigned long ulIndex)
456 {
457 	char szLocation[LOCATION_MAXLEN];
458 	char szIndex[NUMBER_MAXLEN];
459 
460 	ASSERT(pData);
461 
462 	if (isAlreadyReported(&pData->mLocation))
463 		return;
464 
465 	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
466 	DeserializeNumber(szLocation, szIndex, NUMBER_MAXLEN, pData->mIndexType, ulIndex);
467 
468 	Report(isFatal, "UBSan: Undefined Behavior in %s, index %s is out of range for type %s\n",
469 	       szLocation, szIndex, pData->mArrayType->mTypeName);
470 }
471 
472 static void
HandleShiftOutOfBounds(bool isFatal,struct CShiftOutOfBoundsData * pData,unsigned long ulLHS,unsigned long ulRHS)473 HandleShiftOutOfBounds(bool isFatal, struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS)
474 {
475 	char szLocation[LOCATION_MAXLEN];
476 	char szLHS[NUMBER_MAXLEN];
477 	char szRHS[NUMBER_MAXLEN];
478 
479 	ASSERT(pData);
480 
481 	if (isAlreadyReported(&pData->mLocation))
482 		return;
483 
484 	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
485 	DeserializeNumber(szLocation, szLHS, NUMBER_MAXLEN, pData->mLHSType, ulLHS);
486 	DeserializeNumber(szLocation, szRHS, NUMBER_MAXLEN, pData->mRHSType, ulRHS);
487 
488 	if (isNegativeNumber(szLocation, pData->mRHSType, ulRHS))
489 		Report(isFatal, "UBSan: Undefined Behavior in %s, shift exponent %s is negative\n",
490 		       szLocation, szRHS);
491 	else if (isShiftExponentTooLarge(szLocation, pData->mRHSType, ulRHS, zDeserializeTypeWidth(pData->mLHSType)))
492 		Report(isFatal, "UBSan: Undefined Behavior in %s, shift exponent %s is too large for %zu-bit type %s\n",
493 		       szLocation, szRHS, zDeserializeTypeWidth(pData->mLHSType), pData->mLHSType->mTypeName);
494 	else if (isNegativeNumber(szLocation, pData->mLHSType, ulLHS))
495 		Report(isFatal, "UBSan: Undefined Behavior in %s, left shift of negative value %s\n",
496 		       szLocation, szLHS);
497 	else
498 		Report(isFatal, "UBSan: Undefined Behavior in %s, left shift of %s by %s places cannot be represented in type %s\n",
499 		       szLocation, szLHS, szRHS, pData->mLHSType->mTypeName);
500 }
501 
502 static void
HandleLoadInvalidValue(bool isFatal,struct CInvalidValueData * pData,unsigned long ulValue)503 HandleLoadInvalidValue(bool isFatal, struct CInvalidValueData *pData, unsigned long ulValue)
504 {
505 	char szLocation[LOCATION_MAXLEN];
506 	char szValue[NUMBER_MAXLEN];
507 
508 	ASSERT(pData);
509 
510 	if (isAlreadyReported(&pData->mLocation))
511 		return;
512 
513 	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
514 	DeserializeNumber(szLocation, szValue, NUMBER_MAXLEN, pData->mType, ulValue);
515 
516 	Report(isFatal, "UBSan: Undefined Behavior in %s, load of value %s is not a valid value for type %s\n",
517 	       szLocation, szValue, pData->mType->mTypeName);
518 }
519 
520 static void
HandleInvalidBuiltin(bool isFatal,struct CInvalidBuiltinData * pData)521 HandleInvalidBuiltin(bool isFatal, struct CInvalidBuiltinData *pData)
522 {
523 	char szLocation[LOCATION_MAXLEN];
524 
525 	ASSERT(pData);
526 
527 	if (isAlreadyReported(&pData->mLocation))
528 		return;
529 
530 	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
531 
532 	Report(isFatal, "UBSan: Undefined Behavior in %s, passing zero to %s, which is not a valid argument\n",
533 	       szLocation, DeserializeBuiltinCheckKind(pData->mKind));
534 }
535 
536 static void
HandleFunctionTypeMismatch(bool isFatal,struct CFunctionTypeMismatchData * pData,unsigned long ulFunction)537 HandleFunctionTypeMismatch(bool isFatal, struct CFunctionTypeMismatchData *pData, unsigned long ulFunction)
538 {
539 	char szLocation[LOCATION_MAXLEN];
540 
541 	/*
542 	 * There is no a portable C solution to translate an address of a
543 	 * function to its name. On the cost of getting this routine simple
544 	 * and portable without ifdefs between the userland and the kernel
545 	 * just print the address of the function as-is.
546 	 *
547 	 * For better diagnostic messages in the userland, users shall use
548 	 * the full upstream version shipped along with the compiler toolchain.
549 	 */
550 
551 	ASSERT(pData);
552 
553 	if (isAlreadyReported(&pData->mLocation))
554 		return;
555 
556 	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
557 
558 	Report(isFatal, "UBSan: Undefined Behavior in %s, call to function %#lx through pointer to incorrect function type %s\n",
559 	      szLocation, ulFunction, pData->mType->mTypeName);
560 }
561 
562 static void
HandleCFIBadType(bool isFatal,struct CCFICheckFailData * pData,unsigned long ulVtable,bool * bValidVtable,bool * FromUnrecoverableHandler,unsigned long * ProgramCounter,unsigned long * FramePointer)563 HandleCFIBadType(bool isFatal, struct CCFICheckFailData *pData, unsigned long ulVtable, bool *bValidVtable, bool *FromUnrecoverableHandler, unsigned long *ProgramCounter, unsigned long *FramePointer)
564 {
565 	char szLocation[LOCATION_MAXLEN];
566 
567 	/*
568 	 * This is a minimal implementation without diving into C++
569 	 * specifics and (Itanium) ABI deserialization.
570 	 */
571 
572 	ASSERT(pData);
573 
574 	if (isAlreadyReported(&pData->mLocation))
575 		return;
576 
577 	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
578 
579 	if (pData->mCheckKind == CFI_ICALL || pData->mCheckKind == CFI_VMFCALL) {
580 		Report(isFatal, "UBSan: Undefined Behavior in %s, control flow integrity check for type %s failed during %s (vtable address %#lx)\n",
581 		      szLocation, pData->mType->mTypeName, DeserializeCFICheckKind(pData->mCheckKind), ulVtable);
582 	} else {
583 		Report(isFatal || FromUnrecoverableHandler, "UBSan: Undefined Behavior in %s, control flow integrity check for type %s failed during %s (vtable address %#lx; %s vtable; from %s handler; Program Counter %#lx; Frame Pointer %#lx)\n",
584 		      szLocation, pData->mType->mTypeName, DeserializeCFICheckKind(pData->mCheckKind), ulVtable, *bValidVtable ? "valid" : "invalid", *FromUnrecoverableHandler ? "unrecoverable" : "recoverable", *ProgramCounter, *FramePointer);
585 	}
586 }
587 
588 static void
HandleDynamicTypeCacheMiss(bool isFatal,struct CDynamicTypeCacheMissData * pData,unsigned long ulPointer,unsigned long ulHash)589 HandleDynamicTypeCacheMiss(bool isFatal, struct CDynamicTypeCacheMissData *pData, unsigned long ulPointer, unsigned long ulHash)
590 {
591 #if 0
592 	char szLocation[LOCATION_MAXLEN];
593 
594 	/*
595 	 * Unimplemented.
596 	 *
597 	 * This UBSan handler is special as the check has to be impelemented
598 	 * in an implementation. In order to handle it there is need to
599 	 * introspect into C++ ABI internals (RTTI) and use low-level
600 	 * C++ runtime interfaces.
601 	 */
602 
603 	ASSERT(pData);
604 
605 	if (isAlreadyReported(&pData->mLocation))
606 		return;
607 
608 	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
609 
610 	Report(isFatal, "UBSan: Undefined Behavior in %s, %s address %#lx which might not point to an object of type %s\n"
611 	      szLocation, DeserializeTypeCheckKind(pData->mTypeCheckKind), ulPointer, pData->mType);
612 #endif
613 }
614 
615 static void
HandleFloatCastOverflow(bool isFatal,struct CFloatCastOverflowData * pData,unsigned long ulFrom)616 HandleFloatCastOverflow(bool isFatal, struct CFloatCastOverflowData *pData, unsigned long ulFrom)
617 {
618 	char szLocation[LOCATION_MAXLEN];
619 	char szFrom[NUMBER_MAXLEN];
620 
621 	ASSERT(pData);
622 
623 	if (isAlreadyReported(&pData->mLocation))
624 		return;
625 
626 	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
627 	DeserializeNumber(szLocation, szFrom, NUMBER_MAXLEN, pData->mFromType, ulFrom);
628 
629 	Report(isFatal, "UBSan: Undefined Behavior in %s, %s (of type %s) is outside the range of representable values of type %s\n",
630 	       szLocation, szFrom, pData->mFromType->mTypeName, pData->mToType->mTypeName);
631 }
632 
633 static void
HandleMissingReturn(bool isFatal,struct CUnreachableData * pData)634 HandleMissingReturn(bool isFatal, struct CUnreachableData *pData)
635 {
636 	char szLocation[LOCATION_MAXLEN];
637 
638 	ASSERT(pData);
639 
640 	if (isAlreadyReported(&pData->mLocation))
641 		return;
642 
643 	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
644 
645 	Report(isFatal, "UBSan: Undefined Behavior in %s, execution reached the end of a value-returning function without returning a value\n",
646 	       szLocation);
647 }
648 
649 static void
HandleNonnullArg(bool isFatal,struct CNonNullArgData * pData)650 HandleNonnullArg(bool isFatal, struct CNonNullArgData *pData)
651 {
652 	char szLocation[LOCATION_MAXLEN];
653 	char szAttributeLocation[LOCATION_MAXLEN];
654 
655 	ASSERT(pData);
656 
657 	if (isAlreadyReported(&pData->mLocation))
658 		return;
659 
660 	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
661 	if (pData->mAttributeLocation.mFilename)
662 		DeserializeLocation(szAttributeLocation, LOCATION_MAXLEN, &pData->mAttributeLocation);
663 	else
664 		szAttributeLocation[0] = '\0';
665 
666 	Report(isFatal, "UBSan: Undefined Behavior in %s, null pointer passed as argument %d, which is declared to never be null%s%s\n",
667 	       szLocation, pData->mArgIndex, pData->mAttributeLocation.mFilename ? ", nonnull/_Nonnull specified in " : "", szAttributeLocation);
668 }
669 
670 static void
HandleNonnullReturn(bool isFatal,struct CNonNullReturnData * pData,struct CSourceLocation * pLocationPointer)671 HandleNonnullReturn(bool isFatal, struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer)
672 {
673 	char szLocation[LOCATION_MAXLEN];
674 	char szAttributeLocation[LOCATION_MAXLEN];
675 
676 	ASSERT(pData);
677 	ASSERT(pLocationPointer);
678 
679 	if (isAlreadyReported(pLocationPointer))
680 		return;
681 
682 	DeserializeLocation(szLocation, LOCATION_MAXLEN, pLocationPointer);
683 	if (pData->mAttributeLocation.mFilename)
684 		DeserializeLocation(szAttributeLocation, LOCATION_MAXLEN, &pData->mAttributeLocation);
685 	else
686 		szAttributeLocation[0] = '\0';
687 
688 	Report(isFatal, "UBSan: Undefined Behavior in %s, null pointer returned from function declared to never return null%s%s\n",
689 	       szLocation, pData->mAttributeLocation.mFilename ? ", nonnull/_Nonnull specified in " : "", szAttributeLocation);
690 }
691 
692 static void
HandlePointerOverflow(bool isFatal,struct CPointerOverflowData * pData,unsigned long ulBase,unsigned long ulResult)693 HandlePointerOverflow(bool isFatal, struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult)
694 {
695 	char szLocation[LOCATION_MAXLEN];
696 
697 	ASSERT(pData);
698 
699 	if (isAlreadyReported(&pData->mLocation))
700 		return;
701 
702 	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
703 
704 	Report(isFatal, "UBSan: Undefined Behavior in %s, pointer expression with base %#lx overflowed to %#lx\n",
705 	       szLocation, ulBase, ulResult);
706 }
707 
708 static void
HandleImplicitConversion(bool isFatal,struct CImplicitConversionData * pData,unsigned long ulFrom,unsigned long ulTo)709 HandleImplicitConversion(bool isFatal, struct CImplicitConversionData *pData, unsigned long ulFrom, unsigned long ulTo)
710 {
711 	char szLocation[LOCATION_MAXLEN];
712 	char szFrom[NUMBER_MAXLEN];
713 	char szTo[NUMBER_MAXLEN];
714 
715 	ASSERT(pData);
716 
717 	if (isAlreadyReported(&pData->mLocation))
718 		return;
719 
720 	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
721 	DeserializeNumber(szLocation, szFrom, NUMBER_MAXLEN, pData->mFromType, ulFrom);
722 	DeserializeNumber(szLocation, szTo, NUMBER_MAXLEN, pData->mToType, ulTo);
723 
724 	Report(isFatal, "UBSan: Undefined Behavior in %s, %s from %s %zu-bit %s (%s) to %s changed the value to %s %zu-bit %s\n",
725 	       szLocation, DeserializeImplicitConversionCheckKind(pData->mKind), szFrom, zDeserializeTypeWidth(pData->mFromType), ISSET(pData->mFromType->mTypeInfo, NUMBER_SIGNED_BIT) ? "signed" : "unsigned", pData->mFromType->mTypeName, pData->mToType->mTypeName, szTo, zDeserializeTypeWidth(pData->mToType), ISSET(pData->mToType->mTypeInfo, NUMBER_SIGNED_BIT) ? "signed" : "unsigned");
726 }
727 
728 static void
HandleAlignmentAssumption(bool isFatal,struct CAlignmentAssumptionData * pData,unsigned long ulPointer,unsigned long ulAlignment,unsigned long ulOffset)729 HandleAlignmentAssumption(bool isFatal, struct CAlignmentAssumptionData *pData, unsigned long ulPointer, unsigned long ulAlignment, unsigned long ulOffset)
730 {
731 	char szLocation[LOCATION_MAXLEN];
732 	char szAssumptionLocation[LOCATION_MAXLEN];
733 	unsigned long ulRealPointer;
734 
735 	ASSERT(pData);
736 
737 	if (isAlreadyReported(&pData->mLocation))
738 		return;
739 
740 	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
741 
742 	ulRealPointer = ulPointer - ulOffset;
743 
744 	if (pData->mAssumptionLocation.mFilename != NULL) {
745 		DeserializeLocation(szAssumptionLocation, LOCATION_MAXLEN,
746 		    &pData->mAssumptionLocation);
747 		Report(isFatal, "UBSan: Undefined Behavior in %s, alignment assumption of %#lx for pointer %#lx (offset %#lx), assumption made in %s\n",
748 		    szLocation, ulAlignment, ulRealPointer, ulOffset,
749 		    szAssumptionLocation);
750 	} else {
751 		Report(isFatal, "UBSan: Undefined Behavior in %s, alignment assumption of %#lx for pointer %#lx (offset %#lx)\n",
752 		    szLocation, ulAlignment, ulRealPointer, ulOffset);
753 	}
754 }
755 
756 /* Definions of public symbols emitted by the instrumentation code */
757 void
__ubsan_handle_add_overflow(struct COverflowData * pData,unsigned long ulLHS,unsigned long ulRHS)758 __ubsan_handle_add_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS)
759 {
760 
761 	ASSERT(pData);
762 
763 	HandleOverflow(false, pData, ulLHS, ulRHS, PLUS_STRING);
764 }
765 
766 void
__ubsan_handle_add_overflow_abort(struct COverflowData * pData,unsigned long ulLHS,unsigned long ulRHS)767 __ubsan_handle_add_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS)
768 {
769 
770 	ASSERT(pData);
771 
772 	HandleOverflow(true, pData, ulLHS, ulRHS, PLUS_STRING);
773 }
774 
775 void
__ubsan_handle_alignment_assumption(struct CAlignmentAssumptionData * pData,unsigned long ulPointer,unsigned long ulAlignment,unsigned long ulOffset)776 __ubsan_handle_alignment_assumption(struct CAlignmentAssumptionData *pData, unsigned long ulPointer, unsigned long ulAlignment, unsigned long ulOffset)
777 {
778 
779 	ASSERT(pData);
780 
781 	HandleAlignmentAssumption(false, pData, ulPointer, ulAlignment, ulOffset);
782 }
783 
784 void
__ubsan_handle_alignment_assumption_abort(struct CAlignmentAssumptionData * pData,unsigned long ulPointer,unsigned long ulAlignment,unsigned long ulOffset)785 __ubsan_handle_alignment_assumption_abort(struct CAlignmentAssumptionData *pData, unsigned long ulPointer, unsigned long ulAlignment, unsigned long ulOffset)
786 {
787 
788 	ASSERT(pData);
789 
790 	HandleAlignmentAssumption(true, pData, ulPointer, ulAlignment, ulOffset);
791 }
792 
793 void
__ubsan_handle_builtin_unreachable(struct CUnreachableData * pData)794 __ubsan_handle_builtin_unreachable(struct CUnreachableData *pData)
795 {
796 
797 	ASSERT(pData);
798 
799 	HandleBuiltinUnreachable(true, pData);
800 }
801 
802 void
__ubsan_handle_cfi_bad_type(struct CCFICheckFailData * pData,unsigned long ulVtable,bool bValidVtable,bool FromUnrecoverableHandler,unsigned long ProgramCounter,unsigned long FramePointer)803 __ubsan_handle_cfi_bad_type(struct CCFICheckFailData *pData, unsigned long ulVtable, bool bValidVtable, bool FromUnrecoverableHandler, unsigned long ProgramCounter, unsigned long FramePointer)
804 {
805 
806 	ASSERT(pData);
807 
808 	HandleCFIBadType(false, pData, ulVtable, &bValidVtable, &FromUnrecoverableHandler, &ProgramCounter, &FramePointer);
809 }
810 
811 void
__ubsan_handle_cfi_check_fail(struct CCFICheckFailData * pData,unsigned long ulValue,unsigned long ulValidVtable)812 __ubsan_handle_cfi_check_fail(struct CCFICheckFailData *pData, unsigned long ulValue, unsigned long ulValidVtable)
813 {
814 
815 	ASSERT(pData);
816 
817 	HandleCFIBadType(false, pData, ulValue, 0, 0, 0, 0);
818 }
819 
820 void
__ubsan_handle_cfi_check_fail_abort(struct CCFICheckFailData * pData,unsigned long ulValue,unsigned long ulValidVtable)821 __ubsan_handle_cfi_check_fail_abort(struct CCFICheckFailData *pData, unsigned long ulValue, unsigned long ulValidVtable)
822 {
823 
824 	ASSERT(pData);
825 
826 	HandleCFIBadType(true, pData, ulValue, 0, 0, 0, 0);
827 }
828 
829 void
__ubsan_handle_divrem_overflow(struct COverflowData * pData,unsigned long ulLHS,unsigned long ulRHS)830 __ubsan_handle_divrem_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS)
831 {
832 
833 	ASSERT(pData);
834 
835 	HandleOverflow(false, pData, ulLHS, ulRHS, DIVREM_STRING);
836 }
837 
838 void
__ubsan_handle_divrem_overflow_abort(struct COverflowData * pData,unsigned long ulLHS,unsigned long ulRHS)839 __ubsan_handle_divrem_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS)
840 {
841 
842 	ASSERT(pData);
843 
844 	HandleOverflow(true, pData, ulLHS, ulRHS, DIVREM_STRING);
845 }
846 
847 void
__ubsan_handle_dynamic_type_cache_miss(struct CDynamicTypeCacheMissData * pData,unsigned long ulPointer,unsigned long ulHash)848 __ubsan_handle_dynamic_type_cache_miss(struct CDynamicTypeCacheMissData *pData, unsigned long ulPointer, unsigned long ulHash)
849 {
850 
851 	ASSERT(pData);
852 
853 	HandleDynamicTypeCacheMiss(false, pData, ulPointer, ulHash);
854 }
855 
856 void
__ubsan_handle_dynamic_type_cache_miss_abort(struct CDynamicTypeCacheMissData * pData,unsigned long ulPointer,unsigned long ulHash)857 __ubsan_handle_dynamic_type_cache_miss_abort(struct CDynamicTypeCacheMissData *pData, unsigned long ulPointer, unsigned long ulHash)
858 {
859 
860 	ASSERT(pData);
861 
862 	HandleDynamicTypeCacheMiss(false, pData, ulPointer, ulHash);
863 }
864 
865 void
__ubsan_handle_float_cast_overflow(struct CFloatCastOverflowData * pData,unsigned long ulFrom)866 __ubsan_handle_float_cast_overflow(struct CFloatCastOverflowData *pData, unsigned long ulFrom)
867 {
868 
869 	ASSERT(pData);
870 
871 	HandleFloatCastOverflow(false, pData, ulFrom);
872 }
873 
874 void
__ubsan_handle_float_cast_overflow_abort(struct CFloatCastOverflowData * pData,unsigned long ulFrom)875 __ubsan_handle_float_cast_overflow_abort(struct CFloatCastOverflowData *pData, unsigned long ulFrom)
876 {
877 
878 	ASSERT(pData);
879 
880 	HandleFloatCastOverflow(true, pData, ulFrom);
881 }
882 
883 void
__ubsan_handle_function_type_mismatch(struct CFunctionTypeMismatchData * pData,unsigned long ulFunction)884 __ubsan_handle_function_type_mismatch(struct CFunctionTypeMismatchData *pData, unsigned long ulFunction)
885 {
886 
887 	ASSERT(pData);
888 
889 	HandleFunctionTypeMismatch(false, pData, ulFunction);
890 }
891 
892 void
__ubsan_handle_function_type_mismatch_abort(struct CFunctionTypeMismatchData * pData,unsigned long ulFunction)893 __ubsan_handle_function_type_mismatch_abort(struct CFunctionTypeMismatchData *pData, unsigned long ulFunction)
894 {
895 
896 	ASSERT(pData);
897 
898 	HandleFunctionTypeMismatch(true, pData, ulFunction);
899 }
900 
901 void
__ubsan_handle_function_type_mismatch_v1(struct CFunctionTypeMismatchData * pData,unsigned long ulFunction,unsigned long ulCalleeRTTI,unsigned long ulFnRTTI)902 __ubsan_handle_function_type_mismatch_v1(struct CFunctionTypeMismatchData *pData, unsigned long ulFunction, unsigned long ulCalleeRTTI, unsigned long ulFnRTTI)
903 {
904 
905 	ASSERT(pData);
906 #if 0
907 	/*
908 	 * Unimplemented.
909 	 *
910 	 * This UBSan handler is special as the check has to be impelemented
911 	 * in an implementation. In order to handle it there is need to
912 	 * introspect into C++ ABI internals (RTTI) and use low-level
913 	 * C++ runtime interfaces.
914 	 */
915 
916 	HandleFunctionTypeMismatch(false, pData, ulFunction);
917 #endif
918 }
919 
920 void
__ubsan_handle_function_type_mismatch_v1_abort(struct CFunctionTypeMismatchData * pData,unsigned long ulFunction,unsigned long ulCalleeRTTI,unsigned long ulFnRTTI)921 __ubsan_handle_function_type_mismatch_v1_abort(struct CFunctionTypeMismatchData *pData, unsigned long ulFunction, unsigned long ulCalleeRTTI, unsigned long ulFnRTTI)
922 {
923 
924 	ASSERT(pData);
925 #if 0
926 	/*
927 	 * Unimplemented.
928 	 *
929 	 * This UBSan handler is special as the check has to be impelemented
930 	 * in an implementation. In order to handle it there is need to
931 	 * introspect into C++ ABI internals (RTTI) and use low-level
932 	 * C++ runtime interfaces.
933 	 */
934 
935 	HandleFunctionTypeMismatch(true, pData, ulFunction);
936 #endif
937 }
938 
939 void
__ubsan_handle_invalid_builtin(struct CInvalidBuiltinData * pData)940 __ubsan_handle_invalid_builtin(struct CInvalidBuiltinData *pData)
941 {
942 
943 	ASSERT(pData);
944 
945 	HandleInvalidBuiltin(true, pData);
946 }
947 
948 void
__ubsan_handle_invalid_builtin_abort(struct CInvalidBuiltinData * pData)949 __ubsan_handle_invalid_builtin_abort(struct CInvalidBuiltinData *pData)
950 {
951 
952 	ASSERT(pData);
953 
954 	HandleInvalidBuiltin(true, pData);
955 }
956 
957 void
__ubsan_handle_load_invalid_value(struct CInvalidValueData * pData,unsigned long ulValue)958 __ubsan_handle_load_invalid_value(struct CInvalidValueData *pData, unsigned long ulValue)
959 {
960 
961 	ASSERT(pData);
962 
963 	HandleLoadInvalidValue(false, pData, ulValue);
964 }
965 
966 void
__ubsan_handle_load_invalid_value_abort(struct CInvalidValueData * pData,unsigned long ulValue)967 __ubsan_handle_load_invalid_value_abort(struct CInvalidValueData *pData, unsigned long ulValue)
968 {
969 
970 	ASSERT(pData);
971 
972 	HandleLoadInvalidValue(true, pData, ulValue);
973 }
974 
975 void
__ubsan_handle_missing_return(struct CUnreachableData * pData)976 __ubsan_handle_missing_return(struct CUnreachableData *pData)
977 {
978 
979 	ASSERT(pData);
980 
981 	HandleMissingReturn(true, pData);
982 }
983 
984 void
__ubsan_handle_mul_overflow(struct COverflowData * pData,unsigned long ulLHS,unsigned long ulRHS)985 __ubsan_handle_mul_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS)
986 {
987 
988 	ASSERT(pData);
989 
990 	HandleOverflow(false, pData, ulLHS, ulRHS, MUL_STRING);
991 }
992 
993 void
__ubsan_handle_mul_overflow_abort(struct COverflowData * pData,unsigned long ulLHS,unsigned long ulRHS)994 __ubsan_handle_mul_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS)
995 {
996 
997 	ASSERT(pData);
998 
999 	HandleOverflow(true, pData, ulLHS, ulRHS, MUL_STRING);
1000 }
1001 
1002 void
__ubsan_handle_negate_overflow(struct COverflowData * pData,unsigned long ulOldValue)1003 __ubsan_handle_negate_overflow(struct COverflowData *pData, unsigned long ulOldValue)
1004 {
1005 
1006 	ASSERT(pData);
1007 
1008 	HandleNegateOverflow(false, pData, ulOldValue);
1009 }
1010 
1011 void
__ubsan_handle_negate_overflow_abort(struct COverflowData * pData,unsigned long ulOldValue)1012 __ubsan_handle_negate_overflow_abort(struct COverflowData *pData, unsigned long ulOldValue)
1013 {
1014 
1015 	ASSERT(pData);
1016 
1017 	HandleNegateOverflow(true, pData, ulOldValue);
1018 }
1019 
1020 void
__ubsan_handle_nonnull_arg(struct CNonNullArgData * pData)1021 __ubsan_handle_nonnull_arg(struct CNonNullArgData *pData)
1022 {
1023 
1024 	ASSERT(pData);
1025 
1026 	HandleNonnullArg(false, pData);
1027 }
1028 
1029 void
__ubsan_handle_nonnull_arg_abort(struct CNonNullArgData * pData)1030 __ubsan_handle_nonnull_arg_abort(struct CNonNullArgData *pData)
1031 {
1032 
1033 	ASSERT(pData);
1034 
1035 	HandleNonnullArg(true, pData);
1036 }
1037 
1038 void
__ubsan_handle_nonnull_return_v1(struct CNonNullReturnData * pData,struct CSourceLocation * pLocationPointer)1039 __ubsan_handle_nonnull_return_v1(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer)
1040 {
1041 
1042 	ASSERT(pData);
1043 	ASSERT(pLocationPointer);
1044 
1045 	HandleNonnullReturn(false, pData, pLocationPointer);
1046 }
1047 
1048 void
__ubsan_handle_nonnull_return_v1_abort(struct CNonNullReturnData * pData,struct CSourceLocation * pLocationPointer)1049 __ubsan_handle_nonnull_return_v1_abort(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer)
1050 {
1051 
1052 	ASSERT(pData);
1053 	ASSERT(pLocationPointer);
1054 
1055 	HandleNonnullReturn(true, pData, pLocationPointer);
1056 }
1057 
1058 void
__ubsan_handle_nullability_arg(struct CNonNullArgData * pData)1059 __ubsan_handle_nullability_arg(struct CNonNullArgData *pData)
1060 {
1061 
1062 	ASSERT(pData);
1063 
1064 	HandleNonnullArg(false, pData);
1065 }
1066 
1067 void
__ubsan_handle_nullability_arg_abort(struct CNonNullArgData * pData)1068 __ubsan_handle_nullability_arg_abort(struct CNonNullArgData *pData)
1069 {
1070 
1071 	ASSERT(pData);
1072 
1073 	HandleNonnullArg(true, pData);
1074 }
1075 
1076 void
__ubsan_handle_nullability_return_v1(struct CNonNullReturnData * pData,struct CSourceLocation * pLocationPointer)1077 __ubsan_handle_nullability_return_v1(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer)
1078 {
1079 
1080 	ASSERT(pData);
1081 	ASSERT(pLocationPointer);
1082 
1083 	HandleNonnullReturn(false, pData, pLocationPointer);
1084 }
1085 
1086 void
__ubsan_handle_nullability_return_v1_abort(struct CNonNullReturnData * pData,struct CSourceLocation * pLocationPointer)1087 __ubsan_handle_nullability_return_v1_abort(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer)
1088 {
1089 
1090 	ASSERT(pData);
1091 	ASSERT(pLocationPointer);
1092 
1093 	HandleNonnullReturn(true, pData, pLocationPointer);
1094 }
1095 
1096 void
__ubsan_handle_out_of_bounds(struct COutOfBoundsData * pData,unsigned long ulIndex)1097 __ubsan_handle_out_of_bounds(struct COutOfBoundsData *pData, unsigned long ulIndex)
1098 {
1099 
1100 	ASSERT(pData);
1101 
1102 	HandleOutOfBounds(false, pData, ulIndex);
1103 }
1104 
1105 void
__ubsan_handle_out_of_bounds_abort(struct COutOfBoundsData * pData,unsigned long ulIndex)1106 __ubsan_handle_out_of_bounds_abort(struct COutOfBoundsData *pData, unsigned long ulIndex)
1107 {
1108 
1109 	ASSERT(pData);
1110 
1111 	HandleOutOfBounds(true, pData, ulIndex);
1112 }
1113 
1114 void
__ubsan_handle_pointer_overflow(struct CPointerOverflowData * pData,unsigned long ulBase,unsigned long ulResult)1115 __ubsan_handle_pointer_overflow(struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult)
1116 {
1117 
1118 	ASSERT(pData);
1119 
1120 	HandlePointerOverflow(false, pData, ulBase, ulResult);
1121 }
1122 
1123 void
__ubsan_handle_pointer_overflow_abort(struct CPointerOverflowData * pData,unsigned long ulBase,unsigned long ulResult)1124 __ubsan_handle_pointer_overflow_abort(struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult)
1125 {
1126 
1127 	ASSERT(pData);
1128 
1129 	HandlePointerOverflow(true, pData, ulBase, ulResult);
1130 }
1131 
1132 void
__ubsan_handle_shift_out_of_bounds(struct CShiftOutOfBoundsData * pData,unsigned long ulLHS,unsigned long ulRHS)1133 __ubsan_handle_shift_out_of_bounds(struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS)
1134 {
1135 
1136 	ASSERT(pData);
1137 
1138 	HandleShiftOutOfBounds(false, pData, ulLHS, ulRHS);
1139 }
1140 
1141 void
__ubsan_handle_shift_out_of_bounds_abort(struct CShiftOutOfBoundsData * pData,unsigned long ulLHS,unsigned long ulRHS)1142 __ubsan_handle_shift_out_of_bounds_abort(struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS)
1143 {
1144 
1145 	ASSERT(pData);
1146 
1147 	HandleShiftOutOfBounds(true, pData, ulLHS, ulRHS);
1148 }
1149 
1150 void
__ubsan_handle_sub_overflow(struct COverflowData * pData,unsigned long ulLHS,unsigned long ulRHS)1151 __ubsan_handle_sub_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS)
1152 {
1153 
1154 	ASSERT(pData);
1155 
1156 	HandleOverflow(false, pData, ulLHS, ulRHS, MINUS_STRING);
1157 }
1158 
1159 void
__ubsan_handle_sub_overflow_abort(struct COverflowData * pData,unsigned long ulLHS,unsigned long ulRHS)1160 __ubsan_handle_sub_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS)
1161 {
1162 
1163 	ASSERT(pData);
1164 
1165 	HandleOverflow(true, pData, ulLHS, ulRHS, MINUS_STRING);
1166 }
1167 
1168 void
__ubsan_handle_type_mismatch(struct CTypeMismatchData * pData,unsigned long ulPointer)1169 __ubsan_handle_type_mismatch(struct CTypeMismatchData *pData, unsigned long ulPointer)
1170 {
1171 
1172 	ASSERT(pData);
1173 
1174 	HandleTypeMismatch(false, &pData->mLocation, pData->mType, pData->mLogAlignment, pData->mTypeCheckKind, ulPointer);
1175 }
1176 
1177 void
__ubsan_handle_type_mismatch_abort(struct CTypeMismatchData * pData,unsigned long ulPointer)1178 __ubsan_handle_type_mismatch_abort(struct CTypeMismatchData *pData, unsigned long ulPointer)
1179 {
1180 
1181 	ASSERT(pData);
1182 
1183 	HandleTypeMismatch(true, &pData->mLocation, pData->mType, pData->mLogAlignment, pData->mTypeCheckKind, ulPointer);
1184 }
1185 
1186 void
__ubsan_handle_type_mismatch_v1(struct CTypeMismatchData_v1 * pData,unsigned long ulPointer)1187 __ubsan_handle_type_mismatch_v1(struct CTypeMismatchData_v1 *pData, unsigned long ulPointer)
1188 {
1189 
1190 	ASSERT(pData);
1191 
1192 	HandleTypeMismatch(false, &pData->mLocation, pData->mType, __BIT(pData->mLogAlignment), pData->mTypeCheckKind, ulPointer);
1193 }
1194 
1195 void
__ubsan_handle_type_mismatch_v1_abort(struct CTypeMismatchData_v1 * pData,unsigned long ulPointer)1196 __ubsan_handle_type_mismatch_v1_abort(struct CTypeMismatchData_v1 *pData, unsigned long ulPointer)
1197 {
1198 
1199 	ASSERT(pData);
1200 
1201 	HandleTypeMismatch(true, &pData->mLocation, pData->mType, __BIT(pData->mLogAlignment), pData->mTypeCheckKind, ulPointer);
1202 }
1203 
1204 void
__ubsan_handle_vla_bound_not_positive(struct CVLABoundData * pData,unsigned long ulBound)1205 __ubsan_handle_vla_bound_not_positive(struct CVLABoundData *pData, unsigned long ulBound)
1206 {
1207 
1208 	ASSERT(pData);
1209 
1210 	HandleVlaBoundNotPositive(false, pData, ulBound);
1211 }
1212 
1213 void
__ubsan_handle_vla_bound_not_positive_abort(struct CVLABoundData * pData,unsigned long ulBound)1214 __ubsan_handle_vla_bound_not_positive_abort(struct CVLABoundData *pData, unsigned long ulBound)
1215 {
1216 
1217 	ASSERT(pData);
1218 
1219 	HandleVlaBoundNotPositive(true, pData, ulBound);
1220 }
1221 
1222 void
__ubsan_handle_implicit_conversion(struct CImplicitConversionData * pData,unsigned long ulFrom,unsigned long ulTo)1223 __ubsan_handle_implicit_conversion(struct CImplicitConversionData *pData, unsigned long ulFrom, unsigned long ulTo)
1224 {
1225 
1226 	ASSERT(pData);
1227 
1228 	HandleImplicitConversion(false, pData, ulFrom, ulTo);
1229 }
1230 
1231 void
__ubsan_handle_implicit_conversion_abort(struct CImplicitConversionData * pData,unsigned long ulFrom,unsigned long ulTo)1232 __ubsan_handle_implicit_conversion_abort(struct CImplicitConversionData *pData, unsigned long ulFrom, unsigned long ulTo)
1233 {
1234 	ASSERT(pData);
1235 
1236 	HandleImplicitConversion(true, pData, ulFrom, ulTo);
1237 }
1238 
1239 void
__ubsan_get_current_report_data(const char ** ppOutIssueKind,const char ** ppOutMessage,const char ** ppOutFilename,uint32_t * pOutLine,uint32_t * pOutCol,char ** ppOutMemoryAddr)1240 __ubsan_get_current_report_data(const char **ppOutIssueKind, const char **ppOutMessage, const char **ppOutFilename, uint32_t *pOutLine, uint32_t *pOutCol, char **ppOutMemoryAddr)
1241 {
1242 	/*
1243 	 * Unimplemented.
1244 	 *
1245 	 * The __ubsan_on_report() feature is non trivial to implement in a
1246 	 * shared code between the kernel and userland. It's also opening
1247 	 * new sets of potential problems as we are not expected to slow down
1248 	 * execution of certain kernel subsystems (synchronization issues,
1249 	 * interrupt handling etc).
1250 	 *
1251 	 * A proper solution would need probably a lock-free bounded queue built
1252 	 * with atomic operations with the property of multiple consumers and
1253 	 * multiple producers. Maintaining and validating such code is not
1254 	 * worth the effort.
1255 	 *
1256 	 * A legitimate user - besides testing framework - is a debugger plugin
1257 	 * intercepting reports from the UBSan instrumentation. For such
1258 	 * scenarios it is better to run the Clang/GCC version.
1259 	 */
1260 }
1261 
1262 /* Local utility functions */
1263 
1264 static void
Report(bool isFatal,const char * pFormat,...)1265 Report(bool isFatal, const char *pFormat, ...)
1266 {
1267 	va_list ap;
1268 
1269 	ASSERT(pFormat);
1270 
1271 	va_start(ap, pFormat);
1272 #if defined(_KERNEL)
1273 	if (isFatal || alwaysFatal)
1274 		vpanic(pFormat, ap);
1275 	else
1276 		vprintf(pFormat, ap);
1277 #else
1278 	if (ubsan_flags == -1) {
1279 		char buf[1024];
1280 		char *p;
1281 
1282 		ubsan_flags = UBSAN_STDERR;
1283 
1284 		if (getenv_r("LIBC_UBSAN", buf, sizeof(buf)) != -1) {
1285 			for (p = buf; *p; p++) {
1286 				switch (*p) {
1287 				case 'a':
1288 					SET(ubsan_flags, UBSAN_ABORT);
1289 					break;
1290 				case 'A':
1291 					CLR(ubsan_flags, UBSAN_ABORT);
1292 					break;
1293 				case 'e':
1294 					SET(ubsan_flags, UBSAN_STDERR);
1295 					break;
1296 				case 'E':
1297 					CLR(ubsan_flags, UBSAN_STDERR);
1298 					break;
1299 				case 'l':
1300 					SET(ubsan_flags, UBSAN_SYSLOG);
1301 					break;
1302 				case 'L':
1303 					CLR(ubsan_flags, UBSAN_SYSLOG);
1304 					break;
1305 				case 'o':
1306 					SET(ubsan_flags, UBSAN_STDOUT);
1307 					break;
1308 				case 'O':
1309 					CLR(ubsan_flags, UBSAN_STDOUT);
1310 					break;
1311 				default:
1312 					break;
1313 				}
1314 			}
1315 		}
1316 	}
1317 
1318 	// The *v*print* functions can flush the va_list argument.
1319 	// Create a local copy for each call to prevent invalid read.
1320 	if (ISSET(ubsan_flags, UBSAN_STDOUT)) {
1321 		va_list tmp;
1322 		va_copy(tmp, ap);
1323 		vprintf(pFormat, tmp);
1324 		va_end(tmp);
1325 		fflush(stdout);
1326 	}
1327 	if (ISSET(ubsan_flags, UBSAN_STDERR)) {
1328 		va_list tmp;
1329 		va_copy(tmp, ap);
1330 		vfprintf(stderr, pFormat, tmp);
1331 		va_end(tmp);
1332 		fflush(stderr);
1333 	}
1334 	if (ISSET(ubsan_flags, UBSAN_SYSLOG)) {
1335 		va_list tmp;
1336 		va_copy(tmp, ap);
1337 		struct syslog_data SyslogData = SYSLOG_DATA_INIT;
1338 		ubsan_vsyslog(LOG_DEBUG | LOG_USER, &SyslogData, pFormat, tmp);
1339 		va_end(tmp);
1340 	}
1341 	if (isFatal || alwaysFatal || ISSET(ubsan_flags, UBSAN_ABORT)) {
1342 		abort();
1343 		__unreachable();
1344 		/* NOTREACHED */
1345 	}
1346 #endif
1347 	va_end(ap);
1348 }
1349 
1350 static bool
isAlreadyReported(struct CSourceLocation * pLocation)1351 isAlreadyReported(struct CSourceLocation *pLocation)
1352 {
1353 	/*
1354 	 * This code is shared between libc, kernel and standalone usage.
1355 	 * It shall work in early bootstrap phase of both of them.
1356 	 */
1357 
1358 	uint32_t siOldValue;
1359 	volatile uint32_t *pLine;
1360 
1361 	ASSERT(pLocation);
1362 
1363 	pLine = &pLocation->mLine;
1364 
1365 	do {
1366 		siOldValue = *pLine;
1367 	} while (__sync_val_compare_and_swap(pLine, siOldValue, siOldValue | ACK_REPORTED) != siOldValue);
1368 
1369 	return ISSET(siOldValue, ACK_REPORTED);
1370 }
1371 
1372 static size_t
zDeserializeTypeWidth(struct CTypeDescriptor * pType)1373 zDeserializeTypeWidth(struct CTypeDescriptor *pType)
1374 {
1375 	size_t zWidth = 0;
1376 
1377 	ASSERT(pType);
1378 
1379 	switch (pType->mTypeKind) {
1380 	case KIND_INTEGER:
1381 		zWidth = __BIT(__SHIFTOUT(pType->mTypeInfo, ~NUMBER_SIGNED_BIT));
1382 		break;
1383 	case KIND_FLOAT:
1384 		zWidth = pType->mTypeInfo;
1385 		break;
1386 	default:
1387 		Report(true, "UBSan: Unknown variable type %#04" PRIx16 "\n", pType->mTypeKind);
1388 		__unreachable();
1389 		/* NOTREACHED */
1390 	}
1391 
1392 	/* Invalid width will be transformed to 0 */
1393 	ASSERT(zWidth > 0);
1394 
1395 	return zWidth;
1396 }
1397 
1398 static void
DeserializeLocation(char * pBuffer,size_t zBUfferLength,struct CSourceLocation * pLocation)1399 DeserializeLocation(char *pBuffer, size_t zBUfferLength, struct CSourceLocation *pLocation)
1400 {
1401 
1402 	ASSERT(pLocation);
1403 	ASSERT(pLocation->mFilename);
1404 
1405 	snprintf(pBuffer, zBUfferLength, "%s:%" PRIu32 ":%" PRIu32, pLocation->mFilename, pLocation->mLine & (uint32_t)~ACK_REPORTED, pLocation->mColumn);
1406 }
1407 
1408 #ifdef __SIZEOF_INT128__
1409 static void
DeserializeUINT128(char * pBuffer,size_t zBUfferLength,struct CTypeDescriptor * pType,__uint128_t U128)1410 DeserializeUINT128(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, __uint128_t U128)
1411 {
1412 	char szBuf[3]; /* 'XX\0' */
1413 	char rgNumber[sizeof(ulongest)];
1414 	ssize_t zI;
1415 
1416 	memcpy(rgNumber, &U128, sizeof(U128));
1417 
1418 	strlcpy(pBuffer, "Undecoded-128-bit-Integer-Type (0x", zBUfferLength);
1419 #if BYTE_ORDER == LITTLE_ENDIAN
1420 	for (zI = sizeof(ulongest) - 1; zI >= 0; zI--) {
1421 #else
1422 	for (zI = 0; zI < (ssize_t)sizeof(ulongest); zI++) {
1423 #endif
1424 		snprintf(szBuf, sizeof(szBuf), "%02" PRIx8, rgNumber[zI]);
1425 		strlcat(pBuffer, szBuf, zBUfferLength);
1426 	}
1427 	strlcat(pBuffer, ")", zBUfferLength);
1428 }
1429 #endif
1430 
1431 static void
1432 DeserializeNumberSigned(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, longest L)
1433 {
1434 
1435 	ASSERT(pBuffer);
1436 	ASSERT(zBUfferLength > 0);
1437 	ASSERT(pType);
1438 	ASSERT(ISSET(pType->mTypeInfo, NUMBER_SIGNED_BIT));
1439 
1440 	switch (zDeserializeTypeWidth(pType)) {
1441 	default:
1442 		ASSERT(0 && "Invalid codepath");
1443 		__unreachable();
1444 		/* NOTREACHED */
1445 #ifdef __SIZEOF_INT128__
1446 	case WIDTH_128:
1447 		DeserializeUINT128(pBuffer, zBUfferLength, pType, STATIC_CAST(__uint128_t, L));
1448 		break;
1449 #endif
1450 	case WIDTH_64:
1451 		/* FALLTHROUGH */
1452 	case WIDTH_32:
1453 		/* FALLTHROUGH */
1454 	case WIDTH_16:
1455 		/* FALLTHROUGH */
1456 	case WIDTH_8:
1457 		snprintf(pBuffer, zBUfferLength, "%" PRId64, STATIC_CAST(int64_t, L));
1458 		break;
1459 	}
1460 }
1461 
1462 static void
1463 DeserializeNumberUnsigned(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, ulongest L)
1464 {
1465 
1466 	ASSERT(pBuffer);
1467 	ASSERT(zBUfferLength > 0);
1468 	ASSERT(pType);
1469 	ASSERT(!ISSET(pType->mTypeInfo, NUMBER_SIGNED_BIT));
1470 
1471 	switch (zDeserializeTypeWidth(pType)) {
1472 	default:
1473 		ASSERT(0 && "Invalid codepath");
1474 		__unreachable();
1475 		/* NOTREACHED */
1476 #ifdef __SIZEOF_INT128__
1477 	case WIDTH_128:
1478 		DeserializeUINT128(pBuffer, zBUfferLength, pType, STATIC_CAST(__uint128_t, L));
1479 		break;
1480 #endif
1481 	case WIDTH_64:
1482 		/* FALLTHROUGH */
1483 	case WIDTH_32:
1484 		/* FALLTHROUGH */
1485 	case WIDTH_16:
1486 		/* FALLTHROUGH */
1487 	case WIDTH_8:
1488 		snprintf(pBuffer, zBUfferLength, "%" PRIu64, STATIC_CAST(uint64_t, L));
1489 		break;
1490 	}
1491 }
1492 
1493 #ifndef _KERNEL
1494 static void
1495 DeserializeFloatOverPointer(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long *pNumber)
1496 {
1497 	double D;
1498 #ifdef __HAVE_LONG_DOUBLE
1499 	long double LD;
1500 #endif
1501 
1502 	ASSERT(pBuffer);
1503 	ASSERT(zBUfferLength > 0);
1504 	ASSERT(pType);
1505 	ASSERT(pNumber);
1506 	/*
1507 	 * This function handles 64-bit number over a pointer on 32-bit CPUs.
1508 	 */
1509 	ASSERT((sizeof(*pNumber) * CHAR_BIT < WIDTH_64) || (zDeserializeTypeWidth(pType) >= WIDTH_64));
1510 	ASSERT(sizeof(D) == sizeof(uint64_t));
1511 #ifdef __HAVE_LONG_DOUBLE
1512 	ASSERT(sizeof(LD) > sizeof(uint64_t));
1513 #endif
1514 
1515 	switch (zDeserializeTypeWidth(pType)) {
1516 #ifdef __HAVE_LONG_DOUBLE
1517 	case WIDTH_128:
1518 		/* FALLTHROUGH */
1519 	case WIDTH_96:
1520 		/* FALLTHROUGH */
1521 	case WIDTH_80:
1522 		memcpy(&LD, pNumber, sizeof(long double));
1523 		snprintf(pBuffer, zBUfferLength, "%Lg", LD);
1524 		break;
1525 #endif
1526 	case WIDTH_64:
1527 		memcpy(&D, pNumber, sizeof(double));
1528 		snprintf(pBuffer, zBUfferLength, "%g", D);
1529 		break;
1530 	}
1531 }
1532 
1533 static void
1534 DeserializeFloatInlined(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long ulNumber)
1535 {
1536 	float F;
1537 	double D;
1538 	uint32_t U32;
1539 
1540 	ASSERT(pBuffer);
1541 	ASSERT(zBUfferLength > 0);
1542 	ASSERT(pType);
1543 	ASSERT(sizeof(F) == sizeof(uint32_t));
1544 	ASSERT(sizeof(D) == sizeof(uint64_t));
1545 
1546 	switch (zDeserializeTypeWidth(pType)) {
1547 	case WIDTH_64:
1548 		ASSERT(sizeof(D) == sizeof(ulNumber));
1549 		memcpy(&D, &ulNumber, sizeof(ulNumber));
1550 		snprintf(pBuffer, zBUfferLength, "%g", D);
1551 		break;
1552 	case WIDTH_32:
1553 		/*
1554 		 * On supported platforms sizeof(float)==sizeof(uint32_t)
1555 		 * unsigned long is either 32 or 64-bit, cast it to 32-bit
1556 		 * value in order to call memcpy(3) in an Endian-aware way.
1557 		 */
1558 		U32 = STATIC_CAST(uint32_t, ulNumber);
1559 		memcpy(&F, &U32, sizeof(float));
1560 		snprintf(pBuffer, zBUfferLength, "%g", F);
1561 		break;
1562 	case WIDTH_16:
1563 		snprintf(pBuffer, zBUfferLength, "Undecoded-16-bit-Floating-Type (%#04" PRIx16 ")", STATIC_CAST(uint16_t, ulNumber));
1564 		break;
1565 	}
1566 }
1567 #endif
1568 
1569 static longest
1570 llliGetNumber(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber)
1571 {
1572 	size_t zNumberWidth;
1573 	longest L = 0;
1574 
1575 	ASSERT(szLocation);
1576 	ASSERT(pType);
1577 
1578 	zNumberWidth = zDeserializeTypeWidth(pType);
1579 	switch (zNumberWidth) {
1580 	default:
1581 		Report(true, "UBSan: Unexpected %zu-Bit Type in %s\n", zNumberWidth, szLocation);
1582 		__unreachable();
1583 		/* NOTREACHED */
1584 	case WIDTH_128:
1585 #ifdef __SIZEOF_INT128__
1586 		memcpy(&L, REINTERPRET_CAST(longest *, ulNumber), sizeof(longest));
1587 		break;
1588 #else
1589 		Report(true, "UBSan: Unexpected 128-Bit Type in %s\n", szLocation);
1590 		__unreachable();
1591 		/* NOTREACHED */
1592 #endif
1593 	case WIDTH_64:
1594 		if (sizeof(ulNumber) * CHAR_BIT < WIDTH_64) {
1595 			L = *REINTERPRET_CAST(int64_t *, ulNumber);
1596 		} else {
1597 			L = STATIC_CAST(int64_t, STATIC_CAST(uint64_t, ulNumber));
1598 		}
1599 		break;
1600 	case WIDTH_32:
1601 		L = STATIC_CAST(int32_t, STATIC_CAST(uint32_t, ulNumber));
1602 		break;
1603 	case WIDTH_16:
1604 		L = STATIC_CAST(int16_t, STATIC_CAST(uint16_t, ulNumber));
1605 		break;
1606 	case WIDTH_8:
1607 		L = STATIC_CAST(int8_t, STATIC_CAST(uint8_t, ulNumber));
1608 		break;
1609 	}
1610 
1611 	return L;
1612 }
1613 
1614 static ulongest
1615 llluGetNumber(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber)
1616 {
1617 	size_t zNumberWidth;
1618 	ulongest UL = 0;
1619 
1620 	ASSERT(pType);
1621 
1622 	zNumberWidth = zDeserializeTypeWidth(pType);
1623 	switch (zNumberWidth) {
1624 	default:
1625 		Report(true, "UBSan: Unexpected %zu-Bit Type in %s\n", zNumberWidth, szLocation);
1626 		__unreachable();
1627 		/* NOTREACHED */
1628 	case WIDTH_128:
1629 #ifdef __SIZEOF_INT128__
1630 		memcpy(&UL, REINTERPRET_CAST(ulongest *, ulNumber), sizeof(ulongest));
1631 		break;
1632 #else
1633 		Report(true, "UBSan: Unexpected 128-Bit Type in %s\n", szLocation);
1634 		__unreachable();
1635 		/* NOTREACHED */
1636 #endif
1637 	case WIDTH_64:
1638 		if (sizeof(ulNumber) * CHAR_BIT < WIDTH_64) {
1639 			UL = *REINTERPRET_CAST(uint64_t *, ulNumber);
1640 			break;
1641 		}
1642 		/* FALLTHROUGH */
1643 	case WIDTH_32:
1644 		/* FALLTHROUGH */
1645 	case WIDTH_16:
1646 		/* FALLTHROUGH */
1647 	case WIDTH_8:
1648 		UL = ulNumber;
1649 		break;
1650 	}
1651 
1652 	return UL;
1653 }
1654 
1655 #ifndef _KERNEL
1656 static void
1657 DeserializeNumberFloat(char *szLocation, char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long ulNumber)
1658 {
1659 	size_t zNumberWidth;
1660 
1661 	ASSERT(szLocation);
1662 	ASSERT(pBuffer);
1663 	ASSERT(zBUfferLength > 0);
1664 	ASSERT(pType);
1665 	ASSERT(pType->mTypeKind == KIND_FLOAT);
1666 
1667 	zNumberWidth = zDeserializeTypeWidth(pType);
1668 	switch (zNumberWidth) {
1669 	default:
1670 		Report(true, "UBSan: Unexpected %zu-Bit Type in %s\n", zNumberWidth, szLocation);
1671 		__unreachable();
1672 		/* NOTREACHED */
1673 #ifdef __HAVE_LONG_DOUBLE
1674 	case WIDTH_128:
1675 		/* FALLTHROUGH */
1676 	case WIDTH_96:
1677 		/* FALLTHROUGH */
1678 	case WIDTH_80:
1679 		DeserializeFloatOverPointer(pBuffer, zBUfferLength, pType, REINTERPRET_CAST(unsigned long *, ulNumber));
1680 		break;
1681 #endif
1682 	case WIDTH_64:
1683 		if (sizeof(ulNumber) * CHAR_BIT < WIDTH_64) {
1684 			DeserializeFloatOverPointer(pBuffer, zBUfferLength, pType, REINTERPRET_CAST(unsigned long *, ulNumber));
1685 			break;
1686 		}
1687 		/* FALLTHROUGH */
1688 	case WIDTH_32:
1689 		/* FALLTHROUGH */
1690 	case WIDTH_16:
1691 		DeserializeFloatInlined(pBuffer, zBUfferLength, pType, ulNumber);
1692 		break;
1693 	}
1694 }
1695 #endif
1696 
1697 static void
1698 DeserializeNumber(char *szLocation, char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long ulNumber)
1699 {
1700 
1701 	ASSERT(szLocation);
1702 	ASSERT(pBuffer);
1703 	ASSERT(zBUfferLength > 0);
1704 	ASSERT(pType);
1705 
1706 	switch(pType->mTypeKind) {
1707 	case KIND_INTEGER:
1708 		if (ISSET(pType->mTypeInfo, NUMBER_SIGNED_BIT)) {
1709 			longest L = llliGetNumber(szLocation, pType, ulNumber);
1710 			DeserializeNumberSigned(pBuffer, zBUfferLength, pType, L);
1711 		} else {
1712 			ulongest UL = llluGetNumber(szLocation, pType, ulNumber);
1713 			DeserializeNumberUnsigned(pBuffer, zBUfferLength, pType, UL);
1714 		}
1715 		break;
1716 	case KIND_FLOAT:
1717 #ifdef _KERNEL
1718 		Report(true, "UBSan: Unexpected Float Type in %s\n", szLocation);
1719 		__unreachable();
1720 		/* NOTREACHED */
1721 #else
1722 		DeserializeNumberFloat(szLocation, pBuffer, zBUfferLength, pType, ulNumber);
1723 		break;
1724 #endif
1725 	case KIND_UNKNOWN:
1726 		Report(true, "UBSan: Unknown Type in %s\n", szLocation);
1727 		__unreachable();
1728 		/* NOTREACHED */
1729 	}
1730 }
1731 
1732 static const char *
1733 DeserializeTypeCheckKind(uint8_t hhuTypeCheckKind)
1734 {
1735 	const char *rgczTypeCheckKinds[] = {
1736 		"load of",
1737 		"store to",
1738 		"reference binding to",
1739 		"member access within",
1740 		"member call on",
1741 		"constructor call on",
1742 		"downcast of",
1743 		"downcast of",
1744 		"upcast of",
1745 		"cast to virtual base of",
1746 		"_Nonnull binding to",
1747 		"dynamic operation on"
1748 	};
1749 
1750 	ASSERT(__arraycount(rgczTypeCheckKinds) > hhuTypeCheckKind);
1751 
1752 	return rgczTypeCheckKinds[hhuTypeCheckKind];
1753 }
1754 
1755 static const char *
1756 DeserializeBuiltinCheckKind(uint8_t hhuBuiltinCheckKind)
1757 {
1758 	const char *rgczBuiltinCheckKinds[] = {
1759 		"ctz()",
1760 		"clz()"
1761 	};
1762 
1763 	ASSERT(__arraycount(rgczBuiltinCheckKinds) > hhuBuiltinCheckKind);
1764 
1765 	return rgczBuiltinCheckKinds[hhuBuiltinCheckKind];
1766 }
1767 
1768 static const char *
1769 DeserializeCFICheckKind(uint8_t hhuCFICheckKind)
1770 {
1771 	const char *rgczCFICheckKinds[] = {
1772 		"virtual call",					// CFI_VCALL
1773 		"non-virtual call",				// CFI_NVCALL
1774 		"base-to-derived cast",				// CFI_DERIVEDCAST
1775 		"cast to unrelated type",			// CFI_UNRELATEDCAST
1776 		"indirect function call",			// CFI_ICALL
1777 		"non-virtual pointer to member function call",	// CFI_NVMFCALL
1778 		"virtual pointer to member function call",	// CFI_VMFCALL
1779 	};
1780 
1781 	ASSERT(__arraycount(rgczCFICheckKinds) > hhuCFICheckKind);
1782 
1783 	return rgczCFICheckKinds[hhuCFICheckKind];
1784 }
1785 
1786 static const char *
1787 DeserializeImplicitConversionCheckKind(uint8_t hhuImplicitConversionCheckKind)
1788 {
1789 	const char *rgczImplicitConversionCheckKind[] = {
1790 		"integer truncation",			/* Not used since 2018 October 11th */
1791 		"unsigned integer truncation",
1792 		"signed integer truncation",
1793 		"integer sign change",
1794 		"signed integer trunctation or sign change",
1795 	};
1796 
1797 	ASSERT(__arraycount(rgczImplicitConversionCheckKind) > hhuImplicitConversionCheckKind);
1798 
1799 	return rgczImplicitConversionCheckKind[hhuImplicitConversionCheckKind];
1800 }
1801 
1802 static bool
1803 isNegativeNumber(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber)
1804 {
1805 
1806 	ASSERT(szLocation);
1807 	ASSERT(pType);
1808 	ASSERT(pType->mTypeKind == KIND_INTEGER);
1809 
1810 	if (!ISSET(pType->mTypeInfo, NUMBER_SIGNED_BIT))
1811 		return false;
1812 
1813 	return llliGetNumber(szLocation, pType, ulNumber) < 0;
1814 }
1815 
1816 static bool
1817 isShiftExponentTooLarge(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber, size_t zWidth)
1818 {
1819 
1820 	ASSERT(szLocation);
1821 	ASSERT(pType);
1822 	ASSERT(pType->mTypeKind == KIND_INTEGER);
1823 
1824 	return llluGetNumber(szLocation, pType, ulNumber) >= zWidth;
1825 }
1826