text: /*	$NetBSD: ubsan.c,v 1.3 2018/08/03 16:31:04 kamil Exp $	*/
  
  /*-
   * Copyright (c) 2018 The NetBSD Foundation, Inc.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in the
   *    documentation and/or other materials provided with the distribution.
   *
   * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   * POSSIBILITY OF SUCH DAMAGE.
   */
  
  
  /*
   * The micro UBSan implementation for the userland (uUBSan) and kernel (kUBSan).
   * The uBSSan versions is suitable for inclusion into libc or used standalone
   * with ATF tests.
   *
   * This file due to long symbol names generated by a compiler during the
   * instrumentation process does not follow the KNF style with 80-column limit.
   */
  
  #if defined(SANITIZE) && SANITIZE == 1
  #include <PrivateHeaders/kern_ubsan.h>
  
  #include <sys/cdefs.h>
  #if defined(_KERNEL)
  __KERNEL_RCSID(0, "$NetBSD: ubsan.c,v 1.3 2018/08/03 16:31:04 kamil Exp $");
  #else
  __RCSID("$NetBSD: ubsan.c,v 1.3 2018/08/03 16:31:04 kamil Exp $");
  #endif
  
  #if defined(_KERNEL)
  #include <sys/param.h>
  #include <sys/types.h>
  // Lilu change: unsupported in XNU
  // #include <sys/stdarg.h>
  #define ASSERT(x) KASSERT(x)
  #else
  #if defined(_LIBC)
  #include "namespace.h"
  #endif
  #include <sys/param.h>
  #include <assert.h>
  #include <inttypes.h>
  #include <math.h>
  #include <signal.h>
  #include <stdarg.h>
  #include <stdbool.h>
  #include <stdint.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <syslog.h>
  #include <unistd.h>
  #if defined(_LIBC)
  #include "extern.h"
  #define ubsan_vsyslog vsyslog_ss
  #define ASSERT(x) _DIAGASSERT(x)
  #else
  #define ubsan_vsyslog vsyslog_r
  #define ASSERT(x) assert(x)
  #endif
  /* These macros are available in _KERNEL only */
  #define SET(t, f)	((t) |= (f))
  #define ISSET(t, f)	((t) & (f))
  #define CLR(t, f)	((t) &= ~(f))
  #endif
  
  #define REINTERPRET_CAST(__dt, __st)	((__dt)(__st))
  #define STATIC_CAST(__dt, __st)		((__dt)(__st))
  
  #define ACK_REPORTED	__BIT(31)
  
  #define MUL_STRING	"*"
  #define PLUS_STRING	"+"
  #define MINUS_STRING	"-"
  #define DIVREM_STRING	"divrem"
  
  #define CFI_VCALL		0
  #define CFI_NVCALL		1
  #define CFI_DERIVEDCAST		2
  #define CFI_UNRELATEDCAST	3
  #define CFI_ICALL		4
  #define CFI_NVMFCALL		5
  #define CFI_VMFCALL		6
  
  #define NUMBER_MAXLEN	128
  #define LOCATION_MAXLEN	(PATH_MAX + 32 /* ':LINE:COLUMN' */)
  
  #define WIDTH_8		8
  #define WIDTH_16	16
  #define WIDTH_32	32
  #define WIDTH_64	64
  #define WIDTH_80	80
  #define WIDTH_96	96
  #define WIDTH_128	128
  
  #define NUMBER_SIGNED_BIT	1U
  
  #if __SIZEOF_INT128__
  typedef __int128 longest;
  typedef unsigned __int128 ulongest;
  #else
  typedef int64_t longest;
  typedef uint64_t ulongest;
  #endif
  
  #ifndef _KERNEL
  static int ubsan_flags = -1;
  #define UBSAN_ABORT	__BIT(0)
  #define UBSAN_STDOUT	__BIT(1)
  #define UBSAN_STDERR	__BIT(2)
  #define UBSAN_SYSLOG	__BIT(3)
  #endif
  
  /* Undefined Behavior specific defines and structures */
  
  #define KIND_INTEGER	0
  #define KIND_FLOAT	1
  #define KIND_UNKNOWN	UINT16_MAX
  
  struct CSourceLocation {
  	char *mFilename;
  	uint32_t mLine;
  	uint32_t mColumn;
  };
  
  struct CTypeDescriptor {
  	uint16_t mTypeKind;
  	uint16_t mTypeInfo;
  	uint8_t mTypeName[1];
  };
  
  struct COverflowData {
  	struct CSourceLocation mLocation;
  	struct CTypeDescriptor *mType;
  };
  
  struct CUnreachableData {
  	struct CSourceLocation mLocation;
  };
  
  struct CCFICheckFailData {
  	uint8_t mCheckKind;
  	struct CSourceLocation mLocation;
  	struct CTypeDescriptor *mType;
  };
  
  struct CDynamicTypeCacheMissData {
  	struct CSourceLocation mLocation;
  	struct CTypeDescriptor *mType;
  	void *mTypeInfo;
  	uint8_t mTypeCheckKind;
  };
  
  struct CFunctionTypeMismatchData {
  	struct CSourceLocation mLocation;
  	struct CTypeDescriptor *mType;
  };
  
  struct CInvalidBuiltinData {
  	struct CSourceLocation mLocation;
  	uint8_t mKind;
  };
  
  struct CInvalidValueData {
  	struct CSourceLocation mLocation;
  	struct CTypeDescriptor *mType;
  };
  
  struct CNonNullArgData {
  	struct CSourceLocation mLocation;
  	struct CSourceLocation mAttributeLocation;
  	int mArgIndex;
  };
  
  struct CNonNullReturnData {
  	struct CSourceLocation mAttributeLocation;
  };
  
  struct COutOfBoundsData {
  	struct CSourceLocation mLocation;
  	struct CTypeDescriptor *mArrayType;
  	struct CTypeDescriptor *mIndexType;
  };
  
  struct CPointerOverflowData {
  	struct CSourceLocation mLocation;
  };
  
  struct CShiftOutOfBoundsData {
  	struct CSourceLocation mLocation;
  	struct CTypeDescriptor *mLHSType;
  	struct CTypeDescriptor *mRHSType;
  };
  
  struct CTypeMismatchData {
  	struct CSourceLocation mLocation;
  	struct CTypeDescriptor *mType;
  	unsigned long mLogAlignment;
  	uint8_t mTypeCheckKind;
  };
  
  struct CTypeMismatchData_v1 {
  	struct CSourceLocation mLocation;
  	struct CTypeDescriptor *mType;
  	uint8_t mLogAlignment;
  	uint8_t mTypeCheckKind;
  };
  
  struct CVLABoundData {
  	struct CSourceLocation mLocation;
  	struct CTypeDescriptor *mType;
  };
  
  struct CFloatCastOverflowData {
  	struct CSourceLocation mLocation;	/* This field exists in this struct since 2015 August 11th */
  	struct CTypeDescriptor *mFromType;
  	struct CTypeDescriptor *mToType;
  };
  
  /* Local utility functions */
  static void Report(bool isFatal, const char *pFormat, ...) __printflike(2, 3);
  static bool isAlreadyReported(struct CSourceLocation *pLocation);
  static size_t zDeserializeTypeWidth(struct CTypeDescriptor *pType);
  static void DeserializeLocation(char *pBuffer, size_t zBUfferLength, struct CSourceLocation *pLocation);
  #ifdef __SIZEOF_INT128__
  static void DeserializeUINT128(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, __uint128_t U128);
  #endif
  static void DeserializeNumberSigned(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, longest L);
  static void DeserializeNumberUnsigned(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, ulongest L);
  #ifndef _KERNEL
  static void DeserializeFloatOverPointer(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long *pNumber);
  static void DeserializeFloatInlined(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long ulNumber);
  #endif
  static longest llliGetNumber(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber);
  static ulongest llluGetNumber(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber);
  #ifndef _KERNEL
  static void DeserializeNumberFloat(char *szLocation, char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long ulNumber);
  #endif
  static void DeserializeNumber(char *szLocation, char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long ulNumber);
  static const char *DeserializeTypeCheckKind(uint8_t hhuTypeCheckKind);
  static const char *DeserializeBuiltinCheckKind(uint8_t hhuBuiltinCheckKind);
  static const char *DeserializeCFICheckKind(uint8_t hhuCFICheckKind);
  static bool isNegativeNumber(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber);
  static bool isShiftExponentTooLarge(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber, size_t zWidth);
  
  /* Unused in this implementation, emitted by the C++ check dynamic type cast. */
  intptr_t __ubsan_vptr_type_cache[128];
  
  /* Public symbols used in the instrumentation of the code generation part */
  void __ubsan_handle_add_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS);
  void __ubsan_handle_add_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS);
  void __ubsan_handle_builtin_unreachable(struct CUnreachableData *pData);
  void __ubsan_handle_cfi_bad_type(struct CCFICheckFailData *pData, unsigned long ulVtable, bool bValidVtable, bool FromUnrecoverableHandler, unsigned long ProgramCounter, unsigned long FramePointer);
  void __ubsan_handle_cfi_check_fail(struct CCFICheckFailData *pData, unsigned long ulValue, unsigned long ulValidVtable);
  void __ubsan_handle_cfi_check_fail_abort(struct CCFICheckFailData *pData, unsigned long ulValue, unsigned long ulValidVtable);
  void __ubsan_handle_divrem_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS);
  void __ubsan_handle_divrem_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS);
  void __ubsan_handle_dynamic_type_cache_miss(struct CDynamicTypeCacheMissData *pData, unsigned long ulPointer, unsigned long ulHash);
  void __ubsan_handle_dynamic_type_cache_miss_abort(struct CDynamicTypeCacheMissData *pData, unsigned long ulPointer, unsigned long ulHash);
  void __ubsan_handle_float_cast_overflow(struct CFloatCastOverflowData *pData, unsigned long ulFrom);
  void __ubsan_handle_float_cast_overflow_abort(struct CFloatCastOverflowData *pData, unsigned long ulFrom);
  void __ubsan_handle_function_type_mismatch(struct CFunctionTypeMismatchData *pData, unsigned long ulFunction);
  void __ubsan_handle_function_type_mismatch_abort(struct CFunctionTypeMismatchData *pData, unsigned long ulFunction);
  void __ubsan_handle_invalid_builtin(struct CInvalidBuiltinData *pData);
  void __ubsan_handle_invalid_builtin_abort(struct CInvalidBuiltinData *pData);
  void __ubsan_handle_load_invalid_value(struct CInvalidValueData *pData, unsigned long ulVal);
  void __ubsan_handle_load_invalid_value_abort(struct CInvalidValueData *pData, unsigned long ulVal);
  void __ubsan_handle_missing_return(struct CUnreachableData *pData);
  void __ubsan_handle_mul_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS);
  void __ubsan_handle_mul_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS);
  void __ubsan_handle_negate_overflow(struct COverflowData *pData, unsigned long ulOldVal);
  void __ubsan_handle_negate_overflow_abort(struct COverflowData *pData, unsigned long ulOldVal);
  void __ubsan_handle_nonnull_arg(struct CNonNullArgData *pData);
  void __ubsan_handle_nonnull_arg_abort(struct CNonNullArgData *pData);
  void __ubsan_handle_nonnull_return_v1(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer);
  void __ubsan_handle_nonnull_return_v1_abort(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer);
  void __ubsan_handle_nullability_arg(struct CNonNullArgData *pData);
  void __ubsan_handle_nullability_arg_abort(struct CNonNullArgData *pData);
  void __ubsan_handle_nullability_return_v1(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer);
  void __ubsan_handle_nullability_return_v1_abort(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer);
  void __ubsan_handle_out_of_bounds(struct COutOfBoundsData *pData, unsigned long ulIndex);
  void __ubsan_handle_out_of_bounds_abort(struct COutOfBoundsData *pData, unsigned long ulIndex);
  void __ubsan_handle_pointer_overflow(struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult);
  void __ubsan_handle_pointer_overflow_abort(struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult);
  void __ubsan_handle_shift_out_of_bounds(struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS);
  void __ubsan_handle_shift_out_of_bounds_abort(struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS);
  void __ubsan_handle_sub_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS);
  void __ubsan_handle_sub_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS);
  void __ubsan_handle_type_mismatch(struct CTypeMismatchData *pData, unsigned long ulPointer);
  void __ubsan_handle_type_mismatch_abort(struct CTypeMismatchData *pData, unsigned long ulPointer);
  void __ubsan_handle_type_mismatch_v1(struct CTypeMismatchData_v1 *pData, unsigned long ulPointer);
  void __ubsan_handle_type_mismatch_v1_abort(struct CTypeMismatchData_v1 *pData, unsigned long ulPointer);
  void __ubsan_handle_vla_bound_not_positive(struct CVLABoundData *pData, unsigned long ulBound);
  void __ubsan_handle_vla_bound_not_positive_abort(struct CVLABoundData *pData, unsigned long ulBound);
  void __ubsan_get_current_report_data(const char **ppOutIssueKind, const char **ppOutMessage, const char **ppOutFilename, uint32_t *pOutLine, uint32_t *pOutCol, char **ppOutMemoryAddr);
  
  static void HandleOverflow(bool isFatal, struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS, const char *szOperation);
  static void HandleNegateOverflow(bool isFatal, struct COverflowData *pData, unsigned long ulOldValue);
  static void HandleBuiltinUnreachable(bool isFatal, struct CUnreachableData *pData);
  static void HandleTypeMismatch(bool isFatal, struct CSourceLocation *mLocation, struct CTypeDescriptor *mType, unsigned long mLogAlignment, uint8_t mTypeCheckKind, unsigned long ulPointer);
  static void HandleVlaBoundNotPositive(bool isFatal, struct CVLABoundData *pData, unsigned long ulBound);
  static void HandleOutOfBounds(bool isFatal, struct COutOfBoundsData *pData, unsigned long ulIndex);
  static void HandleShiftOutOfBounds(bool isFatal, struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS);
  static void HandleLoadInvalidValue(bool isFatal, struct CInvalidValueData *pData, unsigned long ulValue);
  static void HandleInvalidBuiltin(bool isFatal, struct CInvalidBuiltinData *pData);
  static void HandleFunctionTypeMismatch(bool isFatal, struct CFunctionTypeMismatchData *pData, unsigned long ulFunction);
  static void HandleCFIBadType(bool isFatal, struct CCFICheckFailData *pData, unsigned long ulVtable, bool *bValidVtable, bool *FromUnrecoverableHandler, unsigned long *ProgramCounter, unsigned long *FramePointer);
  static void HandleDynamicTypeCacheMiss(bool isFatal, struct CDynamicTypeCacheMissData *pData, unsigned long ulPointer, unsigned long ulHash);
  static void HandleFloatCastOverflow(bool isFatal, struct CFloatCastOverflowData *pData, unsigned long ulFrom);
  static void HandleMissingReturn(bool isFatal, struct CUnreachableData *pData);
  static void HandleNonnullArg(bool isFatal, struct CNonNullArgData *pData);
  static void HandleNonnullReturn(bool isFatal, struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer);
  static void HandlePointerOverflow(bool isFatal, struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult);
  
  static void
  HandleOverflow(bool isFatal, struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS, const char *szOperation)
  {
  	char szLocation[LOCATION_MAXLEN];
  	char szLHS[NUMBER_MAXLEN];
  	char szRHS[NUMBER_MAXLEN];
  
  	ASSERT(pData);
  
  	if (isAlreadyReported(&pData->mLocation))
  		return;
  
  	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
  	DeserializeNumber(szLocation, szLHS, NUMBER_MAXLEN, pData->mType, ulLHS);
  	DeserializeNumber(szLocation, szRHS, NUMBER_MAXLEN, pData->mType, ulRHS);
  
  	Report(isFatal, "UBSan: Undefined Behavior in %s, %s integer overflow: %s %s %s cannot be represented in type %s\n",
  	       szLocation, ISSET(pData->mType->mTypeInfo, NUMBER_SIGNED_BIT) ? "signed" : "unsigned", szLHS, szOperation, szRHS, pData->mType->mTypeName);
  }
  
  static void
  HandleNegateOverflow(bool isFatal, struct COverflowData *pData, unsigned long ulOldValue)
  {
  	char szLocation[LOCATION_MAXLEN];
  	char szOldValue[NUMBER_MAXLEN];
  
  	ASSERT(pData);
  
  	if (isAlreadyReported(&pData->mLocation))
  		return;
  
  	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
  	DeserializeNumber(szLocation, szOldValue, NUMBER_MAXLEN, pData->mType, ulOldValue);
  
  	Report(isFatal, "UBSan: Undefined Behavior in %s, negation of %s cannot be represented in type %s\n",
  	       szLocation, szOldValue, pData->mType->mTypeName);
  }
  
  static void
  HandleBuiltinUnreachable(bool isFatal, struct CUnreachableData *pData)
  {
  	char szLocation[LOCATION_MAXLEN];
  
  	ASSERT(pData);
  
  	if (isAlreadyReported(&pData->mLocation))
  		return;
  
  	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
  
  	Report(isFatal, "UBSan: Undefined Behavior in %s, calling __builtin_unreachable()\n",
  	       szLocation);
  }
  
  static void
  HandleTypeMismatch(bool isFatal, struct CSourceLocation *mLocation, struct CTypeDescriptor *mType, unsigned long mLogAlignment, uint8_t mTypeCheckKind, unsigned long ulPointer)
  {
  	char szLocation[LOCATION_MAXLEN];
  
  	ASSERT(mLocation);
  	ASSERT(mType);
  
  	if (isAlreadyReported(mLocation))
  		return;
  
  	DeserializeLocation(szLocation, LOCATION_MAXLEN, mLocation);
  
  	if (ulPointer == 0) {
  		Report(isFatal, "UBSan: Undefined Behavior in %s, %s null pointer of type %s\n",
  		       szLocation, DeserializeTypeCheckKind(mTypeCheckKind), mType->mTypeName);
  	} else if ((mLogAlignment - 1) & ulPointer) {
  		Report(isFatal, "UBSan: Undefined Behavior in %s, %s misaligned address %p for type %s which requires %ld byte alignment\n",
  		       szLocation, DeserializeTypeCheckKind(mTypeCheckKind), REINTERPRET_CAST(void *, ulPointer), mType->mTypeName, mLogAlignment);
  	} else {
  		Report(isFatal, "UBSan: Undefined Behavior in %s, %s address %p with insufficient space for an object of type %s\n",
  		       szLocation, DeserializeTypeCheckKind(mTypeCheckKind), REINTERPRET_CAST(void *, ulPointer), mType->mTypeName);
  	}
  }
  
  static void
  HandleVlaBoundNotPositive(bool isFatal, struct CVLABoundData *pData, unsigned long ulBound)
  {
  	char szLocation[LOCATION_MAXLEN];
  	char szBound[NUMBER_MAXLEN];
  
  	ASSERT(pData);
  
  	if (isAlreadyReported(&pData->mLocation))
  		return;
  
  	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
  	DeserializeNumber(szLocation, szBound, NUMBER_MAXLEN, pData->mType, ulBound);
  
  	Report(isFatal, "UBSan: Undefined Behavior in %s, variable length array bound value %s <= 0\n",
  	       szLocation, szBound);
  }
  
  static void
  HandleOutOfBounds(bool isFatal, struct COutOfBoundsData *pData, unsigned long ulIndex)
  {
  	char szLocation[LOCATION_MAXLEN];
  	char szIndex[NUMBER_MAXLEN];
  
  	ASSERT(pData);
  
  	if (isAlreadyReported(&pData->mLocation))
  		return;
  
  	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
  	DeserializeNumber(szLocation, szIndex, NUMBER_MAXLEN, pData->mIndexType, ulIndex);
  
  	Report(isFatal, "UBSan: Undefined Behavior in %s, index %s is out of range for type %s\n",
  	       szLocation, szIndex, pData->mArrayType->mTypeName);
  }
  
  static void
  HandleShiftOutOfBounds(bool isFatal, struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS)
  {
  	char szLocation[LOCATION_MAXLEN];
  	char szLHS[NUMBER_MAXLEN];
  	char szRHS[NUMBER_MAXLEN];
  
  	ASSERT(pData);
  
  	if (isAlreadyReported(&pData->mLocation))
  		return;
  
  	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
  	DeserializeNumber(szLocation, szLHS, NUMBER_MAXLEN, pData->mLHSType, ulLHS);
  	DeserializeNumber(szLocation, szRHS, NUMBER_MAXLEN, pData->mRHSType, ulRHS);
  
  	if (isNegativeNumber(szLocation, pData->mRHSType, ulRHS))
  		Report(isFatal, "UBSan: Undefined Behavior in %s, shift exponent %s is negative\n",
  		       szLocation, szRHS);
  	else if (isShiftExponentTooLarge(szLocation, pData->mRHSType, ulRHS, zDeserializeTypeWidth(pData->mLHSType)))
  		Report(isFatal, "UBSan: Undefined Behavior in %s, shift exponent %s is too large for %zu-bit type %s\n",
  		       szLocation, szRHS, zDeserializeTypeWidth(pData->mLHSType), pData->mLHSType->mTypeName);
  	else if (isNegativeNumber(szLocation, pData->mLHSType, ulLHS))
  		Report(isFatal, "UBSan: Undefined Behavior in %s, left shift of negative value %s\n",
  		       szLocation, szLHS);
  	else
  		Report(isFatal, "UBSan: Undefined Behavior in %s, left shift of %s by %s places cannot be represented in type %s\n",
  		       szLocation, szLHS, szRHS, pData->mLHSType->mTypeName);
  }
  
  static void
  HandleLoadInvalidValue(bool isFatal, struct CInvalidValueData *pData, unsigned long ulValue)
  {
  	char szLocation[LOCATION_MAXLEN];
  	char szValue[NUMBER_MAXLEN];
  
  	ASSERT(pData);
  
  	if (isAlreadyReported(&pData->mLocation))
  		return;
  
  	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
  	DeserializeNumber(szLocation, szValue, NUMBER_MAXLEN, pData->mType, ulValue);
  
  	Report(isFatal, "UBSan: Undefined Behavior in %s, load of value %s is not a valid value for type %s\n",
  	       szLocation, szValue, pData->mType->mTypeName);
  }
  
  static void
  HandleInvalidBuiltin(bool isFatal, struct CInvalidBuiltinData *pData)
  {
  	char szLocation[LOCATION_MAXLEN];
  
  	ASSERT(pData);
  
  	if (isAlreadyReported(&pData->mLocation))
  		return;
  
  	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
  
  	Report(isFatal, "UBSan: Undefined Behavior in %s, passing zero to %s, which is not a valid argument\n",
  	       szLocation, DeserializeBuiltinCheckKind(pData->mKind));
  }
  
  static void
  HandleFunctionTypeMismatch(bool isFatal, struct CFunctionTypeMismatchData *pData, unsigned long ulFunction)
  {
  	char szLocation[LOCATION_MAXLEN];
  
  	/*
  	 * There is no a portable C solution to translate an address of a
  	 * function to its name. On the cost of getting this routine simple
  	 * and portable without ifdefs between the userland and the kernel
  	 * just print the address of the function as-is.
  	 *
  	 * For better diagnostic messages in the userland, users shall use
  	 * the full upstream version shipped along with the compiler toolchain.
  	 */
  
  	ASSERT(pData);
  
  	if (isAlreadyReported(&pData->mLocation))
  		return;
  
  	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
  
  	Report(isFatal, "UBSan: Undefined Behavior in %s, call to function %#lx through pointer to incorrect function type %s\n",
  	      szLocation, ulFunction, pData->mType->mTypeName);
  }
  
  static void
  HandleCFIBadType(bool isFatal, struct CCFICheckFailData *pData, unsigned long ulVtable, bool *bValidVtable, bool *FromUnrecoverableHandler, unsigned long *ProgramCounter, unsigned long *FramePointer)
  {
  	char szLocation[LOCATION_MAXLEN];
  
  	/*
  	 * This is a minimal implementation without diving into C++
  	 * specifics and (Itanium) ABI deserialization.
  	 */
  
  	ASSERT(pData);
  
  	if (isAlreadyReported(&pData->mLocation))
  		return;
  
  	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
  
  	if (pData->mCheckKind == CFI_ICALL || pData->mCheckKind == CFI_VMFCALL) {
  		Report(isFatal, "UBSan: Undefined Behavior in %s, control flow integrity check for type %s failed during %s (vtable address %#lx)\n",
  		      szLocation, pData->mType->mTypeName, DeserializeCFICheckKind(pData->mCheckKind), ulVtable);
  	} else {
  		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",
  			   szLocation, pData->mType->mTypeName, DeserializeCFICheckKind(pData->mCheckKind), ulVtable, bValidVtable && *bValidVtable ? "valid" : "invalid", FromUnrecoverableHandler && *FromUnrecoverableHandler ? "unrecoverable" : "recoverable", ProgramCounter ? *ProgramCounter : 0, FramePointer ? *FramePointer : 0);
  	}
  }
  
  static void
  HandleDynamicTypeCacheMiss(bool isFatal, struct CDynamicTypeCacheMissData *pData, unsigned long ulPointer, unsigned long ulHash)
  {
  #if 0
  	char szLocation[LOCATION_MAXLEN];
  
  	/*
  	 * Unimplemented.
  	 *
  	 * This UBSan handler is special as the check has to be impelemented
  	 * in an implementation. In order to handle it there is need to
  	 * introspect into C++ ABI internals (RTTI) and use low-level
  	 * C++ runtime interfaces.
  	 */
  
  	ASSERT(pData);
  
  	if (isAlreadyReported(&pData->mLocation))
  		return;
  
  	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
  
  	Report(isFatal, "UBSan: Undefined Behavior in %s, %s address %#lx which might not point to an object of type %s\n"
  	      szLocation, DeserializeTypeCheckKind(pData->mTypeCheckKind), ulPointer, pData->mType);
  #endif
  }
  
  static void
  HandleFloatCastOverflow(bool isFatal, struct CFloatCastOverflowData *pData, unsigned long ulFrom)
  {
  	char szLocation[LOCATION_MAXLEN];
  	char szFrom[NUMBER_MAXLEN];
  
  	ASSERT(pData);
  
  	if (isAlreadyReported(&pData->mLocation))
  		return;
  
  	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
  	DeserializeNumber(szLocation, szFrom, NUMBER_MAXLEN, pData->mFromType, ulFrom);
  
  	Report(isFatal, "UBSan: Undefined Behavior in %s, %s (of type %s) is outside the range of representable values of type %s\n",
  	       szLocation, szFrom, pData->mFromType->mTypeName, pData->mToType->mTypeName);
  }
  
  static void
  HandleMissingReturn(bool isFatal, struct CUnreachableData *pData)
  {
  	char szLocation[LOCATION_MAXLEN];
  
  	ASSERT(pData);
  
  	if (isAlreadyReported(&pData->mLocation))
  		return;
  
  	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
  
  	Report(isFatal, "UBSan: Undefined Behavior in %s, execution reached the end of a value-returning function without returning a value\n",
  	       szLocation);
  }
  
  static void
  HandleNonnullArg(bool isFatal, struct CNonNullArgData *pData)
  {
  	char szLocation[LOCATION_MAXLEN];
  	char szAttributeLocation[LOCATION_MAXLEN];
  
  	ASSERT(pData);
  
  	if (isAlreadyReported(&pData->mLocation))
  		return;
  
  	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
  	if (pData->mAttributeLocation.mFilename)
  		DeserializeLocation(szAttributeLocation, LOCATION_MAXLEN, &pData->mAttributeLocation);
  	else
  		szAttributeLocation[0] = '\0';
  
  	Report(isFatal, "UBSan: Undefined Behavior in %s, null pointer passed as argument %d, which is declared to never be null%s%s\n",
  	       szLocation, pData->mArgIndex, pData->mAttributeLocation.mFilename ? ", nonnull/_Nonnull specified in " : "", szAttributeLocation);
  }
  
  static void
  HandleNonnullReturn(bool isFatal, struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer)
  {
  	char szLocation[LOCATION_MAXLEN];
  	char szAttributeLocation[LOCATION_MAXLEN];
  
  	ASSERT(pData);
  	ASSERT(pLocationPointer);
  
  	if (isAlreadyReported(pLocationPointer))
  		return;
  
  	DeserializeLocation(szLocation, LOCATION_MAXLEN, pLocationPointer);
  	if (pData->mAttributeLocation.mFilename)
  		DeserializeLocation(szAttributeLocation, LOCATION_MAXLEN, &pData->mAttributeLocation);
  	else
  		szAttributeLocation[0] = '\0';
  
  	Report(isFatal, "UBSan: Undefined Behavior in %s, null pointer returned from function declared to never return null%s%s\n",
  	       szLocation, pData->mAttributeLocation.mFilename ? ", nonnull/_Nonnull specified in " : "", szAttributeLocation);
  }
  
  static void
  HandlePointerOverflow(bool isFatal, struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult)
  {
  	char szLocation[LOCATION_MAXLEN];
  
  	ASSERT(pData);
  
  	if (isAlreadyReported(&pData->mLocation))
  		return;
  
  	DeserializeLocation(szLocation, LOCATION_MAXLEN, &pData->mLocation);
  
  	Report(isFatal, "UBSan: Undefined Behavior in %s, pointer expression with base %#lx overflowed to %#lx\n",
  	       szLocation, ulBase, ulResult);
  }
  
  /* Definions of public symbols emitted by the instrumentation code */
  void
  __ubsan_handle_add_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS)
  {
  
  	ASSERT(pData);
  
  	HandleOverflow(false, pData, ulLHS, ulRHS, PLUS_STRING);
  }
  
  void
  __ubsan_handle_add_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS)
  {
  
  	ASSERT(pData);
  
  	HandleOverflow(true, pData, ulLHS, ulRHS, PLUS_STRING);
  }
  
  void
  __ubsan_handle_builtin_unreachable(struct CUnreachableData *pData)
  {
  
  	ASSERT(pData);
  
  	HandleBuiltinUnreachable(true, pData);
  }
  
  void
  __ubsan_handle_cfi_bad_type(struct CCFICheckFailData *pData, unsigned long ulVtable, bool bValidVtable, bool FromUnrecoverableHandler, unsigned long ProgramCounter, unsigned long FramePointer)
  {
  
  	ASSERT(pData);
  
  	HandleCFIBadType(false, pData, ulVtable, &bValidVtable, &FromUnrecoverableHandler, &ProgramCounter, &FramePointer);
  }
  
  void
  __ubsan_handle_cfi_check_fail(struct CCFICheckFailData *pData, unsigned long ulValue, unsigned long ulValidVtable)
  {
  
  	ASSERT(pData);
  
  	HandleCFIBadType(false, pData, ulValue, 0, 0, 0, 0);
  }
  
  void
  __ubsan_handle_cfi_check_fail_abort(struct CCFICheckFailData *pData, unsigned long ulValue, unsigned long ulValidVtable)
  {
  
  	ASSERT(pData);
  
  	HandleCFIBadType(true, pData, ulValue, 0, 0, 0, 0);
  }
  
  void
  __ubsan_handle_divrem_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS)
  {
  
  	ASSERT(pData);
  
  	HandleOverflow(false, pData, ulLHS, ulRHS, DIVREM_STRING);
  }
  
  void
  __ubsan_handle_divrem_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS)
  {
  
  	ASSERT(pData);
  
  	HandleOverflow(true, pData, ulLHS, ulRHS, DIVREM_STRING);
  }
  
  void
  __ubsan_handle_dynamic_type_cache_miss(struct CDynamicTypeCacheMissData *pData, unsigned long ulPointer, unsigned long ulHash)
  {
  
  	ASSERT(pData);
  
  	HandleDynamicTypeCacheMiss(false, pData, ulPointer, ulHash);
  }
  
  void
  __ubsan_handle_dynamic_type_cache_miss_abort(struct CDynamicTypeCacheMissData *pData, unsigned long ulPointer, unsigned long ulHash)
  {
  
  	ASSERT(pData);
  
  	HandleDynamicTypeCacheMiss(false, pData, ulPointer, ulHash);
  }
  
  void
  __ubsan_handle_float_cast_overflow(struct CFloatCastOverflowData *pData, unsigned long ulFrom)
  {
  
  	ASSERT(pData);
  
  	HandleFloatCastOverflow(false, pData, ulFrom);
  }
  
  void
  __ubsan_handle_float_cast_overflow_abort(struct CFloatCastOverflowData *pData, unsigned long ulFrom)
  {
  
  	ASSERT(pData);
  
  	HandleFloatCastOverflow(true, pData, ulFrom);
  }
  
  void
  __ubsan_handle_function_type_mismatch(struct CFunctionTypeMismatchData *pData, unsigned long ulFunction)
  {
  
  	ASSERT(pData);
  
  	HandleFunctionTypeMismatch(false, pData, ulFunction);
  }
  
  void
  __ubsan_handle_function_type_mismatch_abort(struct CFunctionTypeMismatchData *pData, unsigned long ulFunction)
  {
  
  	ASSERT(pData);
  
  	HandleFunctionTypeMismatch(false, pData, ulFunction);
  }
  
  void
  __ubsan_handle_invalid_builtin(struct CInvalidBuiltinData *pData)
  {
  
  	ASSERT(pData);
  
  	HandleInvalidBuiltin(true, pData);
  }
  
  void
  __ubsan_handle_invalid_builtin_abort(struct CInvalidBuiltinData *pData)
  {
  
  	ASSERT(pData);
  
  	HandleInvalidBuiltin(true, pData);
  }
  
  void
  __ubsan_handle_load_invalid_value(struct CInvalidValueData *pData, unsigned long ulValue)
  {
  
  	ASSERT(pData);
  
  	HandleLoadInvalidValue(false, pData, ulValue);
  }
  
  void
  __ubsan_handle_load_invalid_value_abort(struct CInvalidValueData *pData, unsigned long ulValue)
  {
  
  	ASSERT(pData);
  
  	HandleLoadInvalidValue(true, pData, ulValue);
  }
  
  void
  __ubsan_handle_missing_return(struct CUnreachableData *pData)
  {
  
  	ASSERT(pData);
  
  	HandleMissingReturn(true, pData);
  }
  
  void
  __ubsan_handle_mul_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS)
  {
  
  	ASSERT(pData);
  
  	HandleOverflow(false, pData, ulLHS, ulRHS, MUL_STRING);
  }
  
  void
  __ubsan_handle_mul_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS)
  {
  
  	ASSERT(pData);
  
  	HandleOverflow(true, pData, ulLHS, ulRHS, MUL_STRING);
  }
  
  void
  __ubsan_handle_negate_overflow(struct COverflowData *pData, unsigned long ulOldValue)
  {
  
  	ASSERT(pData);
  
  	HandleNegateOverflow(false, pData, ulOldValue);
  }
  
  void
  __ubsan_handle_negate_overflow_abort(struct COverflowData *pData, unsigned long ulOldValue)
  {
  
  	ASSERT(pData);
  
  	HandleNegateOverflow(true, pData, ulOldValue);
  }
  
  void
  __ubsan_handle_nonnull_arg(struct CNonNullArgData *pData)
  {
  
  	ASSERT(pData);
  
  	HandleNonnullArg(false, pData);
  }
  
  void
  __ubsan_handle_nonnull_arg_abort(struct CNonNullArgData *pData)
  {
  
  	ASSERT(pData);
  
  	HandleNonnullArg(true, pData);
  }
  
  void
  __ubsan_handle_nonnull_return_v1(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer)
  {
  
  	ASSERT(pData);
  	ASSERT(pLocationPointer);
  
  	HandleNonnullReturn(false, pData, pLocationPointer);
  }
  
  void
  __ubsan_handle_nonnull_return_v1_abort(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer)
  {
  
  	ASSERT(pData);
  	ASSERT(pLocationPointer);
  
  	HandleNonnullReturn(true, pData, pLocationPointer);
  }
  
  void
  __ubsan_handle_nullability_arg(struct CNonNullArgData *pData)
  {
  
  	ASSERT(pData);
  
  	HandleNonnullArg(false, pData);
  }
  
  void
  __ubsan_handle_nullability_arg_abort(struct CNonNullArgData *pData)
  {
  
  	ASSERT(pData);
  
  	HandleNonnullArg(true, pData);
  }
  
  void
  __ubsan_handle_nullability_return_v1(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer)
  {
  
  	ASSERT(pData);
  	ASSERT(pLocationPointer);
  
  	HandleNonnullReturn(false, pData, pLocationPointer);
  }
  
  void
  __ubsan_handle_nullability_return_v1_abort(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer)
  {
  
  	ASSERT(pData);
  	ASSERT(pLocationPointer);
  
  	HandleNonnullReturn(true, pData, pLocationPointer);
  }
  
  void
  __ubsan_handle_out_of_bounds(struct COutOfBoundsData *pData, unsigned long ulIndex)
  {
  
  	ASSERT(pData);
  
  	HandleOutOfBounds(false, pData, ulIndex);
  }
  
  void
  __ubsan_handle_out_of_bounds_abort(struct COutOfBoundsData *pData, unsigned long ulIndex)
  {
  
  	ASSERT(pData);
  
  	HandleOutOfBounds(true, pData, ulIndex);
  }
  
  void
  __ubsan_handle_pointer_overflow(struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult)
  {
  
  	ASSERT(pData);
  
  	HandlePointerOverflow(false, pData, ulBase, ulResult);
  }
  
  void
  __ubsan_handle_pointer_overflow_abort(struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult)
  {
  
  	ASSERT(pData);
  
  	HandlePointerOverflow(true, pData, ulBase, ulResult);
  }
  
  void
  __ubsan_handle_shift_out_of_bounds(struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS)
  {
  
  	ASSERT(pData);
  
  	HandleShiftOutOfBounds(false, pData, ulLHS, ulRHS);
  }
  
  void
  __ubsan_handle_shift_out_of_bounds_abort(struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS)
  {
  
  	ASSERT(pData);
  
  	HandleShiftOutOfBounds(true, pData, ulLHS, ulRHS);
  }
  
  void
  __ubsan_handle_sub_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS)
  {
  
  	ASSERT(pData);
  
  	HandleOverflow(false, pData, ulLHS, ulRHS, MINUS_STRING);
  }
  
  void
  __ubsan_handle_sub_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS)
  {
  
  	ASSERT(pData);
  
  	HandleOverflow(true, pData, ulLHS, ulRHS, MINUS_STRING);
  }
  
  void
  __ubsan_handle_type_mismatch(struct CTypeMismatchData *pData, unsigned long ulPointer)
  {
  
  	ASSERT(pData);
  
  	HandleTypeMismatch(false, &pData->mLocation, pData->mType, pData->mLogAlignment, pData->mTypeCheckKind, ulPointer);
  }
  
  void
  __ubsan_handle_type_mismatch_abort(struct CTypeMismatchData *pData, unsigned long ulPointer)
  {
  
  	ASSERT(pData);
  
  	HandleTypeMismatch(true, &pData->mLocation, pData->mType, pData->mLogAlignment, pData->mTypeCheckKind, ulPointer);
  }
  
  void
  __ubsan_handle_type_mismatch_v1(struct CTypeMismatchData_v1 *pData, unsigned long ulPointer)
  {
  
  	ASSERT(pData);
  
  	HandleTypeMismatch(false, &pData->mLocation, pData->mType, __BIT(pData->mLogAlignment), pData->mTypeCheckKind, ulPointer);
  }
  
  void
  __ubsan_handle_type_mismatch_v1_abort(struct CTypeMismatchData_v1 *pData, unsigned long ulPointer)
  {
  
  	ASSERT(pData);
  
  	HandleTypeMismatch(true, &pData->mLocation, pData->mType, __BIT(pData->mLogAlignment), pData->mTypeCheckKind, ulPointer);
  }
  
  void
  __ubsan_handle_vla_bound_not_positive(struct CVLABoundData *pData, unsigned long ulBound)
  {
  
  	ASSERT(pData);
  
  	HandleVlaBoundNotPositive(false, pData, ulBound);
  }
  
  void
  __ubsan_handle_vla_bound_not_positive_abort(struct CVLABoundData *pData, unsigned long ulBound)
  {
  
  	ASSERT(pData);
  
  	HandleVlaBoundNotPositive(true, pData, ulBound);
  }
  
  void
  __ubsan_get_current_report_data(const char **ppOutIssueKind, const char **ppOutMessage, const char **ppOutFilename, uint32_t *pOutLine, uint32_t *pOutCol, char **ppOutMemoryAddr)
  {
  	/*
  	 * Unimplemented.
  	 *
  	 * The __ubsan_on_report() feature is non trivial to implement in a
  	 * shared code between the kernel and userland. It's also opening
  	 * new sets of potential problems as we are not expected to slow down
  	 * execution of certain kernel subsystems (synchronization issues,
  	 * interrupt handling etc).
  	 *
  	 * A proper solution would need probably a lock-free bounded queue built
  	 * with atomic operations with the property of miltiple consumers and
  	 * multiple producers. Maintaining and validating such code is not
  	 * worth the effort.
  	 *
  	 * A legitimate user - besides testing framework - is a debugger plugin
  	 * intercepting reports from the UBSan instrumentation. For such
  	 * scenarios it is better to run the Clang/GCC version.
  	 */
  }
  
  /* Local utility functions */
  
  static void
  Report(bool isFatal, const char *pFormat, ...)
  {
  	va_list ap;
  
  	ASSERT(pFormat);
  
  	va_start(ap, pFormat);
  #if defined(_KERNEL)
  	if (isFatal)
  		vpanic(pFormat, ap);
  	else
  		vprintf(pFormat, ap);
  #else
  	if (ubsan_flags == -1) {
  		char buf[1024];
  		char *p;
  
  		ubsan_flags = UBSAN_STDERR;
  
  		if (getenv_r("LIBC_UBSAN", buf, sizeof(buf)) != -1) {
  			for (p = buf; *p; p++) {
  				switch (*p) {
  				case 'a':
  					SET(ubsan_flags, UBSAN_ABORT);
  					break;
  				case 'A':
  					CLR(ubsan_flags, UBSAN_ABORT);
  					break;
  				case 'e':
  					SET(ubsan_flags, UBSAN_STDERR);
  					break;
  				case 'E':
  					CLR(ubsan_flags, UBSAN_STDERR);
  					break;
  				case 'l':
  					SET(ubsan_flags, UBSAN_SYSLOG);
  					break;
  				case 'L':
  					CLR(ubsan_flags, UBSAN_SYSLOG);
  					break;
  				case 'o':
  					SET(ubsan_flags, UBSAN_STDOUT);
  					break;
  				case 'O':
  					CLR(ubsan_flags, UBSAN_STDOUT);
  					break;
  				default:
  					break;
  				}
  			}
  		}
  	}
  
  	// The *v*print* functions can flush the va_list argument.
  	// Create a local copy for each call to prevent invalid read.
  	if (ISSET(ubsan_flags, UBSAN_STDOUT)) {
  		va_list tmp;
  		va_copy(tmp, ap);
  		vprintf(pFormat, tmp);
  		va_end(tmp);
  		fflush(stdout);
  	}
  	if (ISSET(ubsan_flags, UBSAN_STDERR)) {
  		va_list tmp;
  		va_copy(tmp, ap);
  		vfprintf(stderr, pFormat, tmp);
  		va_end(tmp);
  		fflush(stderr);
  	}
  	if (ISSET(ubsan_flags, UBSAN_SYSLOG)) {
  		va_list tmp;
  		va_copy(tmp, ap);
  		struct syslog_data SyslogData = SYSLOG_DATA_INIT;
  		ubsan_vsyslog(LOG_DEBUG | LOG_USER, &SyslogData, pFormat, tmp);
  		va_end(tmp);
  	}
  	if (isFatal || ISSET(ubsan_flags, UBSAN_ABORT)) {
  		abort();
  		/* NOTREACHED */
  	}
  #endif
  	va_end(ap);
  }
  
  static bool
  isAlreadyReported(struct CSourceLocation *pLocation)
  {
  	/*
  	 * This code is shared between libc, kernel and standalone usage.
  	 * It shall work in early bootstrap phase of both of them.
  	 */
  
  	uint32_t siOldValue;
  	volatile uint32_t *pLine;
  
  	ASSERT(pLocation);
  
  	pLine = &pLocation->mLine;
  
  	do {
  		siOldValue = *pLine;
  	} while (__sync_val_compare_and_swap(pLine, siOldValue, siOldValue | ACK_REPORTED) != siOldValue);
  
  	return ISSET(siOldValue, ACK_REPORTED);
  }
  
  static size_t
  zDeserializeTypeWidth(struct CTypeDescriptor *pType)
  {
  	size_t zWidth = 0;
  
  	ASSERT(pType);
  
  	switch (pType->mTypeKind) {
  	case KIND_INTEGER:
  		zWidth = __BIT(__SHIFTOUT(pType->mTypeInfo, ~NUMBER_SIGNED_BIT));
  		break;
  	case KIND_FLOAT:
  		zWidth = pType->mTypeInfo;
  		break;
  	default:
  		Report(true, "UBSan: Unknown variable type %#04" PRIx16 "\n", pType->mTypeKind);
  		/* NOTREACHED */
  	}
  
  	/* Invalid width will be transformed to 0 */
  	ASSERT(zWidth > 0);
  
  	return zWidth;
  }
  
  static void
  DeserializeLocation(char *pBuffer, size_t zBUfferLength, struct CSourceLocation *pLocation)
  {
  
  	ASSERT(pLocation);
  	ASSERT(pLocation->mFilename);
  
  	snprintf(pBuffer, zBUfferLength, "%s:%" PRIu32 ":%" PRIu32, pLocation->mFilename, pLocation->mLine & (uint32_t)~ACK_REPORTED, pLocation->mColumn);
  }
  
  #ifdef __SIZEOF_INT128__
  static void
  DeserializeUINT128(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, __uint128_t U128)
  {
  	char szBuf[3]; /* 'XX\0' */
  	char rgNumber[sizeof(ulongest)];
  	ssize_t zI;
  
  	memcpy(rgNumber, &U128, sizeof(U128));
  
  	strlcpy(pBuffer, "Undecoded-128-bit-Integer-Type (0x", zBUfferLength);
  #if BYTE_ORDER == LITTLE_ENDIAN
  	for (zI = sizeof(ulongest) - 1; zI >= 0; zI--) {
  #else
  	for (zI = 0; zI < (ssize_t)sizeof(ulongest); zI++) {
  #endif
  		snprintf(szBuf, sizeof(szBuf), "%02" PRIx8, rgNumber[zI]);
  		strlcat(pBuffer, szBuf, zBUfferLength);
  	}
  	strlcat(pBuffer, ")", zBUfferLength);
  }
  #endif
  
  static void
  DeserializeNumberSigned(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, longest L)
  {
  
  	ASSERT(pBuffer);
  	ASSERT(zBUfferLength > 0);
  	ASSERT(pType);
  	ASSERT(ISSET(pType->mTypeInfo, NUMBER_SIGNED_BIT));
  
  	switch (zDeserializeTypeWidth(pType)) {
  	default:
  		ASSERT(0 && "Invalid codepath");
  		/* NOTREACHED */
  #ifdef __SIZEOF_INT128__
  	case WIDTH_128:
  		DeserializeUINT128(pBuffer, zBUfferLength, pType, STATIC_CAST(__uint128_t, L));
  		break;
  #endif
  	case WIDTH_64:
  	case WIDTH_32:
  	case WIDTH_16:
  	case WIDTH_8:
  		snprintf(pBuffer, zBUfferLength, "%" PRId64, STATIC_CAST(int64_t, L));
  		break;
  	}
  }
  
  static void
  DeserializeNumberUnsigned(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, ulongest L)
  {
  
  	ASSERT(pBuffer);
  	ASSERT(zBUfferLength > 0);
  	ASSERT(pType);
  	ASSERT(!ISSET(pType->mTypeInfo, NUMBER_SIGNED_BIT));
  
  	switch (zDeserializeTypeWidth(pType)) {
  	default:
  		ASSERT(0 && "Invalid codepath");
  		/* NOTREACHED */
  #ifdef __SIZEOF_INT128__
  	case WIDTH_128:
  		DeserializeUINT128(pBuffer, zBUfferLength, pType, STATIC_CAST(__uint128_t, L));
  		break;
  #endif
  	case WIDTH_64:
  	case WIDTH_32:
  	case WIDTH_16:
  	case WIDTH_8:
  		snprintf(pBuffer, zBUfferLength, "%" PRIu64, STATIC_CAST(uint64_t, L));
  		break;
  	}
  }
  
  #ifndef _KERNEL
  static void
  DeserializeFloatOverPointer(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long *pNumber)
  {
  	double D;
  #ifdef __HAVE_LONG_DOUBLE
  	long double LD;
  #endif
  
  	ASSERT(pBuffer);
  	ASSERT(zBUfferLength > 0);
  	ASSERT(pType);
  	ASSERT(pNumber);
  	/*
  	 * This function handles 64-bit number over a pointer on 32-bit CPUs.
  	 */
  	ASSERT((sizeof(*pNumber) * CHAR_BIT < WIDTH_64) || (zDeserializeTypeWidth(pType) >= WIDTH_64));
  	ASSERT(sizeof(D) == sizeof(uint64_t));
  #ifdef __HAVE_LONG_DOUBLE
  	ASSERT(sizeof(LD) > sizeof(uint64_t));
  #endif
  
  	switch (zDeserializeTypeWidth(pType)) {
  #ifdef __HAVE_LONG_DOUBLE
  	case WIDTH_128:
  	case WIDTH_96:
  	case WIDTH_80:
  		memcpy(&LD, pNumber, sizeof(long double));
  		snprintf(pBuffer, zBUfferLength, "%Lg", LD);
  		break;
  #endif
  	case WIDTH_64:
  		memcpy(&D, pNumber, sizeof(double));
  		snprintf(pBuffer, zBUfferLength, "%g", D);
  		break;
  	}
  }
  
  static void
  DeserializeFloatInlined(char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long ulNumber)
  {
  	float F;
  	double D;
  	uint32_t U32;
  
  	ASSERT(pBuffer);
  	ASSERT(zBUfferLength > 0);
  	ASSERT(pType);
  	ASSERT(sizeof(F) == sizeof(uint32_t));
  	ASSERT(sizeof(D) == sizeof(uint64_t));
  
  	switch (zDeserializeTypeWidth(pType)) {
  	case WIDTH_64:
  		memcpy(&D, &ulNumber, sizeof(double));
  		snprintf(pBuffer, zBUfferLength, "%g", D);
  		break;
  	case WIDTH_32:
  		/*
  		 * On supported platforms sizeof(float)==sizeof(uint32_t)
  		 * unsigned long is either 32 or 64-bit, cast it to 32-bit
  		 * value in order to call memcpy(3) in an Endian-aware way.
  		 */
  		U32 = STATIC_CAST(uint32_t, ulNumber);
  		memcpy(&F, &U32, sizeof(float));
  		snprintf(pBuffer, zBUfferLength, "%g", F);
  		break;
  	case WIDTH_16:
  		snprintf(pBuffer, zBUfferLength, "Undecoded-16-bit-Floating-Type (%#04" PRIx16 ")", STATIC_CAST(uint16_t, ulNumber));
  		break;
  	}
  }
  #endif
  
  static longest
  llliGetNumber(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber)
  {
  	size_t zNumberWidth;
  	longest L = 0;
  
  	ASSERT(szLocation);
  	ASSERT(pType);
  
  	zNumberWidth = zDeserializeTypeWidth(pType);
  	switch (zNumberWidth) {
  	default:
  		Report(true, "UBSan: Unexpected %zu-Bit Type in %s\n", zNumberWidth, szLocation);
  		/* NOTREACHED */
  	case WIDTH_128:
  #ifdef __SIZEOF_INT128__
  		memcpy(&L, REINTERPRET_CAST(longest *, ulNumber), sizeof(longest));
  #else
  		Report(true, "UBSan: Unexpected 128-Bit Type in %s\n", szLocation);
  		/* NOTREACHED */
  #endif
  		break;
  	case WIDTH_64:
  		if (sizeof(ulNumber) * CHAR_BIT < WIDTH_64) {
  			L = *REINTERPRET_CAST(int64_t *, ulNumber);
  		} else {
  			L = STATIC_CAST(int64_t, STATIC_CAST(uint64_t, ulNumber));
  		}
  		break;
  	case WIDTH_32:
  		L = STATIC_CAST(int32_t, STATIC_CAST(uint32_t, ulNumber));
  		break;
  	case WIDTH_16:
  		L = STATIC_CAST(int16_t, STATIC_CAST(uint16_t, ulNumber));
  		break;
  	case WIDTH_8:
  		L = STATIC_CAST(int8_t, STATIC_CAST(uint8_t, ulNumber));
  		break;
  	}
  
  	return L;
  }
  
  static ulongest
  llluGetNumber(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber)
  {
  	size_t zNumberWidth;
  	ulongest UL = 0;
  
  	ASSERT(pType);
  
  	zNumberWidth = zDeserializeTypeWidth(pType);
  	switch (zNumberWidth) {
  	default:
  		Report(true, "UBSan: Unexpected %zu-Bit Type in %s\n", zNumberWidth, szLocation);
  		/* NOTREACHED */
  	case WIDTH_128:
  #ifdef __SIZEOF_INT128__
  		memcpy(&UL, REINTERPRET_CAST(ulongest *, ulNumber), sizeof(ulongest));
  		break;
  #else
  		Report(true, "UBSan: Unexpected 128-Bit Type in %s\n", szLocation);
  		/* NOTREACHED */
  #endif
  	case WIDTH_64:
  		if (sizeof(ulNumber) * CHAR_BIT < WIDTH_64) {
  			UL = *REINTERPRET_CAST(uint64_t *, ulNumber);
  			break;
  		}
  		/* FALLTHROUGH */
  	case WIDTH_32:
  		/* FALLTHROUGH */
  	case WIDTH_16:
  		/* FALLTHROUGH */
  	case WIDTH_8:
  		UL = ulNumber;
  		break;
  	}
  
  	return UL;
  }
  
  #ifndef _KERNEL
  static void
  DeserializeNumberFloat(char *szLocation, char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long ulNumber)
  {
  	size_t zNumberWidth;
  
  	ASSERT(szLocation);
  	ASSERT(pBuffer);
  	ASSERT(zBUfferLength > 0);
  	ASSERT(pType);
  	ASSERT(pType->mTypeKind == KIND_FLOAT);
  
  	zNumberWidth = zDeserializeTypeWidth(pType);
  	switch (zNumberWidth) {
  	default:
  		Report(true, "UBSan: Unexpected %zu-Bit Type in %s\n", zNumberWidth, szLocation);
  		/* NOTREACHED */
  #ifdef __HAVE_LONG_DOUBLE
  	case WIDTH_128:
  	case WIDTH_96:
  	case WIDTH_80:
  		DeserializeFloatOverPointer(pBuffer, zBUfferLength, pType, REINTERPRET_CAST(unsigned long *, ulNumber));
  		break;
  #endif
  	case WIDTH_64:
  		if (sizeof(ulNumber) * CHAR_BIT < WIDTH_64) {
  			DeserializeFloatOverPointer(pBuffer, zBUfferLength, pType, REINTERPRET_CAST(unsigned long *, ulNumber));
  			break;
  		}
  	case WIDTH_32:
  	case WIDTH_16:
  		DeserializeFloatInlined(pBuffer, zBUfferLength, pType, ulNumber);
  		break;
  	}
  }
  #endif
  
  static void
  DeserializeNumber(char *szLocation, char *pBuffer, size_t zBUfferLength, struct CTypeDescriptor *pType, unsigned long ulNumber)
  {
  
  	ASSERT(szLocation);
  	ASSERT(pBuffer);
  	ASSERT(zBUfferLength > 0);
  	ASSERT(pType);
  
  	switch(pType->mTypeKind) {
  	case KIND_INTEGER:
  		if (ISSET(pType->mTypeInfo, NUMBER_SIGNED_BIT)) {
  			longest L = llliGetNumber(szLocation, pType, ulNumber);
  			DeserializeNumberSigned(pBuffer, zBUfferLength, pType, L);
  		} else {
  			ulongest UL = llluGetNumber(szLocation, pType, ulNumber);
  			DeserializeNumberUnsigned(pBuffer, zBUfferLength, pType, UL);
  		}
  		break;
  	case KIND_FLOAT:
  #ifdef _KERNEL
  		Report(true, "UBSan: Unexpected Float Type in %s\n", szLocation);
  		/* NOTREACHED */
  #else
  		DeserializeNumberFloat(szLocation, pBuffer, zBUfferLength, pType, ulNumber);
  #endif
  		break;
  	case KIND_UNKNOWN:
  		Report(true, "UBSan: Unknown Type in %s\n", szLocation);
  		/* NOTREACHED */
  		break;
  	}
  }
  
  static const char *
  DeserializeTypeCheckKind(uint8_t hhuTypeCheckKind)
  {
  	const char *rgczTypeCheckKinds[] = {
  		"load of",
  		"store to",
  		"reference binding to",
  		"member access within",
  		"member call on",
  		"constructor call on",
  		"downcast of",
  		"downcast of",
  		"upcast of",
  		"cast to virtual base of",
  		"_Nonnull binding to",
  		"dynamic operation on"
  	};
  
  	ASSERT(__arraycount(rgczTypeCheckKinds) > hhuTypeCheckKind);
  
  	return rgczTypeCheckKinds[hhuTypeCheckKind];
  }
  
  static const char *
  DeserializeBuiltinCheckKind(uint8_t hhuBuiltinCheckKind)
  {
  	const char *rgczBuiltinCheckKinds[] = {
  		"ctz()",
  		"clz()"
  	};
  
  	ASSERT(__arraycount(rgczBuiltinCheckKinds) > hhuBuiltinCheckKind);
  
  	return rgczBuiltinCheckKinds[hhuBuiltinCheckKind];
  }
  
  static const char *
  DeserializeCFICheckKind(uint8_t hhuCFICheckKind)
  {
  	const char *rgczCFICheckKinds[] = {
  		"virtual call",					// CFI_VCALL
  		"non-virtual call",				// CFI_NVCALL
  		"base-to-derived cast",				// CFI_DERIVEDCAST
  		"cast to unrelated type",			// CFI_UNRELATEDCAST
  		"indirect function call",			// CFI_ICALL
  		"non-virtual pointer to member function call",	// CFI_NVMFCALL
  		"virtual pointer to member function call",	// CFI_VMFCALL
  	};
  
  	ASSERT(__arraycount(rgczCFICheckKinds) > hhuCFICheckKind);
  
  	return rgczCFICheckKinds[hhuCFICheckKind];
  }
  
  static bool
  isNegativeNumber(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber)
  {
  
  	ASSERT(szLocation);
  	ASSERT(pType);
  	ASSERT(pType->mTypeKind == KIND_INTEGER);
  
  	if (!ISSET(pType->mTypeInfo, NUMBER_SIGNED_BIT))
  		return false;
  
  	return llliGetNumber(szLocation, pType, ulNumber) < 0;
  }
  
  static bool
  isShiftExponentTooLarge(char *szLocation, struct CTypeDescriptor *pType, unsigned long ulNumber, size_t zWidth)
  {
  
  	ASSERT(szLocation);
  	ASSERT(pType);
  	ASSERT(pType->mTypeKind == KIND_INTEGER);
  
  	return llluGetNumber(szLocation, pType, ulNumber) >= zWidth;
  }
  
  #endif /* SANITIZE */
  