1*0fca6ea1SDimitry Andric //===-- nsan.cc -----------------------------------------------------------===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric //
9*0fca6ea1SDimitry Andric // NumericalStabilitySanitizer runtime.
10*0fca6ea1SDimitry Andric //
11*0fca6ea1SDimitry Andric // This implements:
12*0fca6ea1SDimitry Andric // - The public nsan interface (include/sanitizer/nsan_interface.h).
13*0fca6ea1SDimitry Andric // - The private nsan interface (./nsan.h).
14*0fca6ea1SDimitry Andric // - The internal instrumentation interface. These are function emitted by the
15*0fca6ea1SDimitry Andric // instrumentation pass:
16*0fca6ea1SDimitry Andric // * __nsan_get_shadow_ptr_for_{float,double,longdouble}_load
17*0fca6ea1SDimitry Andric // These return the shadow memory pointer for loading the shadow value,
18*0fca6ea1SDimitry Andric // after checking that the types are consistent. If the types are not
19*0fca6ea1SDimitry Andric // consistent, returns nullptr.
20*0fca6ea1SDimitry Andric // * __nsan_get_shadow_ptr_for_{float,double,longdouble}_store
21*0fca6ea1SDimitry Andric // Sets the shadow types appropriately and returns the shadow memory
22*0fca6ea1SDimitry Andric // pointer for storing the shadow value.
23*0fca6ea1SDimitry Andric // * __nsan_internal_check_{float,double,long double}_{f,d,l} checks the
24*0fca6ea1SDimitry Andric // accuracy of a value against its shadow and emits a warning depending
25*0fca6ea1SDimitry Andric // on the runtime configuration. The middle part indicates the type of
26*0fca6ea1SDimitry Andric // the application value, the suffix (f,d,l) indicates the type of the
27*0fca6ea1SDimitry Andric // shadow, and depends on the instrumentation configuration.
28*0fca6ea1SDimitry Andric // * __nsan_fcmp_fail_* emits a warning for an fcmp instruction whose
29*0fca6ea1SDimitry Andric // corresponding shadow fcmp result differs.
30*0fca6ea1SDimitry Andric //
31*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
32*0fca6ea1SDimitry Andric
33*0fca6ea1SDimitry Andric #include <assert.h>
34*0fca6ea1SDimitry Andric #include <math.h>
35*0fca6ea1SDimitry Andric #include <stdint.h>
36*0fca6ea1SDimitry Andric #include <stdio.h>
37*0fca6ea1SDimitry Andric #include <stdlib.h>
38*0fca6ea1SDimitry Andric
39*0fca6ea1SDimitry Andric #include "sanitizer_common/sanitizer_atomic.h"
40*0fca6ea1SDimitry Andric #include "sanitizer_common/sanitizer_common.h"
41*0fca6ea1SDimitry Andric #include "sanitizer_common/sanitizer_libc.h"
42*0fca6ea1SDimitry Andric #include "sanitizer_common/sanitizer_report_decorator.h"
43*0fca6ea1SDimitry Andric #include "sanitizer_common/sanitizer_stacktrace.h"
44*0fca6ea1SDimitry Andric #include "sanitizer_common/sanitizer_symbolizer.h"
45*0fca6ea1SDimitry Andric
46*0fca6ea1SDimitry Andric #include "nsan/nsan.h"
47*0fca6ea1SDimitry Andric #include "nsan/nsan_flags.h"
48*0fca6ea1SDimitry Andric #include "nsan/nsan_stats.h"
49*0fca6ea1SDimitry Andric #include "nsan/nsan_suppressions.h"
50*0fca6ea1SDimitry Andric
51*0fca6ea1SDimitry Andric using namespace __sanitizer;
52*0fca6ea1SDimitry Andric using namespace __nsan;
53*0fca6ea1SDimitry Andric
54*0fca6ea1SDimitry Andric constexpr int kMaxVectorWidth = 8;
55*0fca6ea1SDimitry Andric
56*0fca6ea1SDimitry Andric // When copying application memory, we also copy its shadow and shadow type.
57*0fca6ea1SDimitry Andric // FIXME: We could provide fixed-size versions that would nicely
58*0fca6ea1SDimitry Andric // vectorize for known sizes.
59*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__nsan_copy_values(const u8 * daddr,const u8 * saddr,uptr size)60*0fca6ea1SDimitry Andric __nsan_copy_values(const u8 *daddr, const u8 *saddr, uptr size) {
61*0fca6ea1SDimitry Andric internal_memmove((void *)GetShadowTypeAddrFor(daddr),
62*0fca6ea1SDimitry Andric GetShadowTypeAddrFor(saddr), size);
63*0fca6ea1SDimitry Andric internal_memmove((void *)GetShadowAddrFor(daddr), GetShadowAddrFor(saddr),
64*0fca6ea1SDimitry Andric size * kShadowScale);
65*0fca6ea1SDimitry Andric }
66*0fca6ea1SDimitry Andric
67*0fca6ea1SDimitry Andric // FIXME: We could provide fixed-size versions that would nicely
68*0fca6ea1SDimitry Andric // vectorize for known sizes.
69*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__nsan_set_value_unknown(const u8 * addr,uptr size)70*0fca6ea1SDimitry Andric __nsan_set_value_unknown(const u8 *addr, uptr size) {
71*0fca6ea1SDimitry Andric internal_memset((void *)GetShadowTypeAddrFor(addr), 0, size);
72*0fca6ea1SDimitry Andric }
73*0fca6ea1SDimitry Andric
74*0fca6ea1SDimitry Andric
75*0fca6ea1SDimitry Andric const char *FTInfo<float>::kCppTypeName = "float";
76*0fca6ea1SDimitry Andric const char *FTInfo<double>::kCppTypeName = "double";
77*0fca6ea1SDimitry Andric const char *FTInfo<long double>::kCppTypeName = "long double";
78*0fca6ea1SDimitry Andric const char *FTInfo<__float128>::kCppTypeName = "__float128";
79*0fca6ea1SDimitry Andric
80*0fca6ea1SDimitry Andric const char FTInfo<float>::kTypePattern[sizeof(float)];
81*0fca6ea1SDimitry Andric const char FTInfo<double>::kTypePattern[sizeof(double)];
82*0fca6ea1SDimitry Andric const char FTInfo<long double>::kTypePattern[sizeof(long double)];
83*0fca6ea1SDimitry Andric
84*0fca6ea1SDimitry Andric // Helper for __nsan_dump_shadow_mem: Reads the value at address `ptr`,
85*0fca6ea1SDimitry Andric // identified by its type id.
86*0fca6ea1SDimitry Andric template <typename ShadowFT>
ReadShadowInternal(const u8 * ptr)87*0fca6ea1SDimitry Andric static __float128 ReadShadowInternal(const u8 *ptr) {
88*0fca6ea1SDimitry Andric ShadowFT Shadow;
89*0fca6ea1SDimitry Andric __builtin_memcpy(&Shadow, ptr, sizeof(Shadow));
90*0fca6ea1SDimitry Andric return Shadow;
91*0fca6ea1SDimitry Andric }
92*0fca6ea1SDimitry Andric
ReadShadow(const u8 * ptr,const char ShadowTypeId)93*0fca6ea1SDimitry Andric static __float128 ReadShadow(const u8 *ptr, const char ShadowTypeId) {
94*0fca6ea1SDimitry Andric switch (ShadowTypeId) {
95*0fca6ea1SDimitry Andric case 'd':
96*0fca6ea1SDimitry Andric return ReadShadowInternal<double>(ptr);
97*0fca6ea1SDimitry Andric case 'l':
98*0fca6ea1SDimitry Andric return ReadShadowInternal<long double>(ptr);
99*0fca6ea1SDimitry Andric case 'q':
100*0fca6ea1SDimitry Andric return ReadShadowInternal<__float128>(ptr);
101*0fca6ea1SDimitry Andric default:
102*0fca6ea1SDimitry Andric return 0.0;
103*0fca6ea1SDimitry Andric }
104*0fca6ea1SDimitry Andric }
105*0fca6ea1SDimitry Andric
106*0fca6ea1SDimitry Andric namespace {
107*0fca6ea1SDimitry Andric class Decorator : public __sanitizer::SanitizerCommonDecorator {
108*0fca6ea1SDimitry Andric public:
Decorator()109*0fca6ea1SDimitry Andric Decorator() : SanitizerCommonDecorator() {}
Warning()110*0fca6ea1SDimitry Andric const char *Warning() { return Red(); }
Name()111*0fca6ea1SDimitry Andric const char *Name() { return Green(); }
End()112*0fca6ea1SDimitry Andric const char *End() { return Default(); }
113*0fca6ea1SDimitry Andric };
114*0fca6ea1SDimitry Andric
115*0fca6ea1SDimitry Andric // Workaround for the fact that Printf() does not support floats.
116*0fca6ea1SDimitry Andric struct PrintBuffer {
117*0fca6ea1SDimitry Andric char Buffer[64];
118*0fca6ea1SDimitry Andric };
119*0fca6ea1SDimitry Andric template <typename FT> struct FTPrinter {};
120*0fca6ea1SDimitry Andric
121*0fca6ea1SDimitry Andric template <> struct FTPrinter<double> {
dec__anon36c45c920111::FTPrinter122*0fca6ea1SDimitry Andric static PrintBuffer dec(double value) {
123*0fca6ea1SDimitry Andric PrintBuffer result;
124*0fca6ea1SDimitry Andric snprintf(result.Buffer, sizeof(result.Buffer) - 1, "%.20f", value);
125*0fca6ea1SDimitry Andric return result;
126*0fca6ea1SDimitry Andric }
hex__anon36c45c920111::FTPrinter127*0fca6ea1SDimitry Andric static PrintBuffer hex(double value) {
128*0fca6ea1SDimitry Andric PrintBuffer result;
129*0fca6ea1SDimitry Andric snprintf(result.Buffer, sizeof(result.Buffer) - 1, "%.20a", value);
130*0fca6ea1SDimitry Andric return result;
131*0fca6ea1SDimitry Andric }
132*0fca6ea1SDimitry Andric };
133*0fca6ea1SDimitry Andric
134*0fca6ea1SDimitry Andric template <> struct FTPrinter<float> : FTPrinter<double> {};
135*0fca6ea1SDimitry Andric
136*0fca6ea1SDimitry Andric template <> struct FTPrinter<long double> {
dec__anon36c45c920111::FTPrinter137*0fca6ea1SDimitry Andric static PrintBuffer dec(long double value) {
138*0fca6ea1SDimitry Andric PrintBuffer result;
139*0fca6ea1SDimitry Andric snprintf(result.Buffer, sizeof(result.Buffer) - 1, "%.20Lf", value);
140*0fca6ea1SDimitry Andric return result;
141*0fca6ea1SDimitry Andric }
hex__anon36c45c920111::FTPrinter142*0fca6ea1SDimitry Andric static PrintBuffer hex(long double value) {
143*0fca6ea1SDimitry Andric PrintBuffer result;
144*0fca6ea1SDimitry Andric snprintf(result.Buffer, sizeof(result.Buffer) - 1, "%.20La", value);
145*0fca6ea1SDimitry Andric return result;
146*0fca6ea1SDimitry Andric }
147*0fca6ea1SDimitry Andric };
148*0fca6ea1SDimitry Andric
149*0fca6ea1SDimitry Andric // FIXME: print with full precision.
150*0fca6ea1SDimitry Andric template <> struct FTPrinter<__float128> : FTPrinter<long double> {};
151*0fca6ea1SDimitry Andric
152*0fca6ea1SDimitry Andric // This is a template so that there are no implicit conversions.
153*0fca6ea1SDimitry Andric template <typename FT> inline FT ftAbs(FT v);
154*0fca6ea1SDimitry Andric
ftAbs(long double v)155*0fca6ea1SDimitry Andric template <> inline long double ftAbs(long double v) { return fabsl(v); }
ftAbs(double v)156*0fca6ea1SDimitry Andric template <> inline double ftAbs(double v) { return fabs(v); }
157*0fca6ea1SDimitry Andric
158*0fca6ea1SDimitry Andric // We don't care about nans.
159*0fca6ea1SDimitry Andric // std::abs(__float128) code is suboptimal and generates a function call to
160*0fca6ea1SDimitry Andric // __getf2().
ftAbs(FT v)161*0fca6ea1SDimitry Andric template <typename FT> inline FT ftAbs(FT v) { return v >= FT{0} ? v : -v; }
162*0fca6ea1SDimitry Andric
163*0fca6ea1SDimitry Andric template <typename FT1, typename FT2, bool Enable> struct LargestFTImpl {
164*0fca6ea1SDimitry Andric using type = FT2;
165*0fca6ea1SDimitry Andric };
166*0fca6ea1SDimitry Andric
167*0fca6ea1SDimitry Andric template <typename FT1, typename FT2> struct LargestFTImpl<FT1, FT2, true> {
168*0fca6ea1SDimitry Andric using type = FT1;
169*0fca6ea1SDimitry Andric };
170*0fca6ea1SDimitry Andric
171*0fca6ea1SDimitry Andric template <typename FT1, typename FT2>
172*0fca6ea1SDimitry Andric using LargestFT =
173*0fca6ea1SDimitry Andric typename LargestFTImpl<FT1, FT2, (sizeof(FT1) > sizeof(FT2))>::type;
174*0fca6ea1SDimitry Andric
max(T a,T b)175*0fca6ea1SDimitry Andric template <typename T> T max(T a, T b) { return a < b ? b : a; }
176*0fca6ea1SDimitry Andric
177*0fca6ea1SDimitry Andric } // end anonymous namespace
178*0fca6ea1SDimitry Andric
UnwindImpl(uptr pc,uptr bp,void * context,bool request_fast,u32 max_depth)179*0fca6ea1SDimitry Andric void __sanitizer::BufferedStackTrace::UnwindImpl(uptr pc, uptr bp,
180*0fca6ea1SDimitry Andric void *context,
181*0fca6ea1SDimitry Andric bool request_fast,
182*0fca6ea1SDimitry Andric u32 max_depth) {
183*0fca6ea1SDimitry Andric using namespace __nsan;
184*0fca6ea1SDimitry Andric return Unwind(max_depth, pc, bp, context, 0, 0, false);
185*0fca6ea1SDimitry Andric }
186*0fca6ea1SDimitry Andric
__nsan_print_accumulated_stats()187*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_print_accumulated_stats() {
188*0fca6ea1SDimitry Andric if (nsan_stats)
189*0fca6ea1SDimitry Andric nsan_stats->Print();
190*0fca6ea1SDimitry Andric }
191*0fca6ea1SDimitry Andric
NsanAtexit()192*0fca6ea1SDimitry Andric static void NsanAtexit() {
193*0fca6ea1SDimitry Andric Printf("Numerical Sanitizer exit stats:\n");
194*0fca6ea1SDimitry Andric __nsan_print_accumulated_stats();
195*0fca6ea1SDimitry Andric nsan_stats = nullptr;
196*0fca6ea1SDimitry Andric }
197*0fca6ea1SDimitry Andric
198*0fca6ea1SDimitry Andric // The next three functions return a pointer for storing a shadow value for `n`
199*0fca6ea1SDimitry Andric // values, after setting the shadow types. We return the pointer instead of
200*0fca6ea1SDimitry Andric // storing ourselves because it avoids having to rely on the calling convention
201*0fca6ea1SDimitry Andric // around long double being the same for nsan and the target application.
202*0fca6ea1SDimitry Andric // We have to have 3 versions because we need to know which type we are storing
203*0fca6ea1SDimitry Andric // since we are setting the type shadow memory.
getShadowPtrForStore(u8 * store_addr,uptr n)204*0fca6ea1SDimitry Andric template <typename FT> static u8 *getShadowPtrForStore(u8 *store_addr, uptr n) {
205*0fca6ea1SDimitry Andric unsigned char *shadow_type = GetShadowTypeAddrFor(store_addr);
206*0fca6ea1SDimitry Andric for (uptr i = 0; i < n; ++i) {
207*0fca6ea1SDimitry Andric __builtin_memcpy(shadow_type + i * sizeof(FT), FTInfo<FT>::kTypePattern,
208*0fca6ea1SDimitry Andric sizeof(FTInfo<FT>::kTypePattern));
209*0fca6ea1SDimitry Andric }
210*0fca6ea1SDimitry Andric return GetShadowAddrFor(store_addr);
211*0fca6ea1SDimitry Andric }
212*0fca6ea1SDimitry Andric
213*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8 *
__nsan_get_shadow_ptr_for_float_store(u8 * store_addr,uptr n)214*0fca6ea1SDimitry Andric __nsan_get_shadow_ptr_for_float_store(u8 *store_addr, uptr n) {
215*0fca6ea1SDimitry Andric return getShadowPtrForStore<float>(store_addr, n);
216*0fca6ea1SDimitry Andric }
217*0fca6ea1SDimitry Andric
218*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8 *
__nsan_get_shadow_ptr_for_double_store(u8 * store_addr,uptr n)219*0fca6ea1SDimitry Andric __nsan_get_shadow_ptr_for_double_store(u8 *store_addr, uptr n) {
220*0fca6ea1SDimitry Andric return getShadowPtrForStore<double>(store_addr, n);
221*0fca6ea1SDimitry Andric }
222*0fca6ea1SDimitry Andric
223*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8 *
__nsan_get_shadow_ptr_for_longdouble_store(u8 * store_addr,uptr n)224*0fca6ea1SDimitry Andric __nsan_get_shadow_ptr_for_longdouble_store(u8 *store_addr, uptr n) {
225*0fca6ea1SDimitry Andric return getShadowPtrForStore<long double>(store_addr, n);
226*0fca6ea1SDimitry Andric }
227*0fca6ea1SDimitry Andric
IsValidShadowType(const u8 * shadow_type)228*0fca6ea1SDimitry Andric template <typename FT> static bool IsValidShadowType(const u8 *shadow_type) {
229*0fca6ea1SDimitry Andric return __builtin_memcmp(shadow_type, FTInfo<FT>::kTypePattern, sizeof(FT)) ==
230*0fca6ea1SDimitry Andric 0;
231*0fca6ea1SDimitry Andric }
232*0fca6ea1SDimitry Andric
IsZero(const T * ptr)233*0fca6ea1SDimitry Andric template <int kSize, typename T> static bool IsZero(const T *ptr) {
234*0fca6ea1SDimitry Andric constexpr const char kZeros[kSize] = {}; // Zero initialized.
235*0fca6ea1SDimitry Andric return __builtin_memcmp(ptr, kZeros, kSize) == 0;
236*0fca6ea1SDimitry Andric }
237*0fca6ea1SDimitry Andric
IsUnknownShadowType(const u8 * shadow_type)238*0fca6ea1SDimitry Andric template <typename FT> static bool IsUnknownShadowType(const u8 *shadow_type) {
239*0fca6ea1SDimitry Andric return IsZero<sizeof(FTInfo<FT>::kTypePattern)>(shadow_type);
240*0fca6ea1SDimitry Andric }
241*0fca6ea1SDimitry Andric
242*0fca6ea1SDimitry Andric // The three folowing functions check that the address stores a complete
243*0fca6ea1SDimitry Andric // shadow value of the given type and return a pointer for loading.
244*0fca6ea1SDimitry Andric // They return nullptr if the type of the value is unknown or incomplete.
245*0fca6ea1SDimitry Andric template <typename FT>
getShadowPtrForLoad(const u8 * load_addr,uptr n)246*0fca6ea1SDimitry Andric static const u8 *getShadowPtrForLoad(const u8 *load_addr, uptr n) {
247*0fca6ea1SDimitry Andric const u8 *const shadow_type = GetShadowTypeAddrFor(load_addr);
248*0fca6ea1SDimitry Andric for (uptr i = 0; i < n; ++i) {
249*0fca6ea1SDimitry Andric if (!IsValidShadowType<FT>(shadow_type + i * sizeof(FT))) {
250*0fca6ea1SDimitry Andric // If loadtracking stats are enabled, log loads with invalid types
251*0fca6ea1SDimitry Andric // (tampered with through type punning).
252*0fca6ea1SDimitry Andric if (flags().enable_loadtracking_stats) {
253*0fca6ea1SDimitry Andric if (IsUnknownShadowType<FT>(shadow_type + i * sizeof(FT))) {
254*0fca6ea1SDimitry Andric // Warn only if the value is non-zero. Zero is special because
255*0fca6ea1SDimitry Andric // applications typically initialize large buffers to zero in an
256*0fca6ea1SDimitry Andric // untyped way.
257*0fca6ea1SDimitry Andric if (!IsZero<sizeof(FT)>(load_addr)) {
258*0fca6ea1SDimitry Andric GET_CALLER_PC_BP;
259*0fca6ea1SDimitry Andric nsan_stats->AddUnknownLoadTrackingEvent(pc, bp);
260*0fca6ea1SDimitry Andric }
261*0fca6ea1SDimitry Andric } else {
262*0fca6ea1SDimitry Andric GET_CALLER_PC_BP;
263*0fca6ea1SDimitry Andric nsan_stats->AddInvalidLoadTrackingEvent(pc, bp);
264*0fca6ea1SDimitry Andric }
265*0fca6ea1SDimitry Andric }
266*0fca6ea1SDimitry Andric return nullptr;
267*0fca6ea1SDimitry Andric }
268*0fca6ea1SDimitry Andric }
269*0fca6ea1SDimitry Andric return GetShadowAddrFor(load_addr);
270*0fca6ea1SDimitry Andric }
271*0fca6ea1SDimitry Andric
272*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE const u8 *
__nsan_get_shadow_ptr_for_float_load(const u8 * load_addr,uptr n)273*0fca6ea1SDimitry Andric __nsan_get_shadow_ptr_for_float_load(const u8 *load_addr, uptr n) {
274*0fca6ea1SDimitry Andric return getShadowPtrForLoad<float>(load_addr, n);
275*0fca6ea1SDimitry Andric }
276*0fca6ea1SDimitry Andric
277*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE const u8 *
__nsan_get_shadow_ptr_for_double_load(const u8 * load_addr,uptr n)278*0fca6ea1SDimitry Andric __nsan_get_shadow_ptr_for_double_load(const u8 *load_addr, uptr n) {
279*0fca6ea1SDimitry Andric return getShadowPtrForLoad<double>(load_addr, n);
280*0fca6ea1SDimitry Andric }
281*0fca6ea1SDimitry Andric
282*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE const u8 *
__nsan_get_shadow_ptr_for_longdouble_load(const u8 * load_addr,uptr n)283*0fca6ea1SDimitry Andric __nsan_get_shadow_ptr_for_longdouble_load(const u8 *load_addr, uptr n) {
284*0fca6ea1SDimitry Andric return getShadowPtrForLoad<long double>(load_addr, n);
285*0fca6ea1SDimitry Andric }
286*0fca6ea1SDimitry Andric
287*0fca6ea1SDimitry Andric // Returns the raw shadow pointer. The returned pointer should be considered
288*0fca6ea1SDimitry Andric // opaque.
289*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8 *
__nsan_internal_get_raw_shadow_ptr(const u8 * addr)290*0fca6ea1SDimitry Andric __nsan_internal_get_raw_shadow_ptr(const u8 *addr) {
291*0fca6ea1SDimitry Andric return GetShadowAddrFor(const_cast<u8 *>(addr));
292*0fca6ea1SDimitry Andric }
293*0fca6ea1SDimitry Andric
294*0fca6ea1SDimitry Andric // Returns the raw shadow type pointer. The returned pointer should be
295*0fca6ea1SDimitry Andric // considered opaque.
296*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8 *
__nsan_internal_get_raw_shadow_type_ptr(const u8 * addr)297*0fca6ea1SDimitry Andric __nsan_internal_get_raw_shadow_type_ptr(const u8 *addr) {
298*0fca6ea1SDimitry Andric return reinterpret_cast<u8 *>(GetShadowTypeAddrFor(const_cast<u8 *>(addr)));
299*0fca6ea1SDimitry Andric }
300*0fca6ea1SDimitry Andric
getValueType(u8 c)301*0fca6ea1SDimitry Andric static ValueType getValueType(u8 c) { return static_cast<ValueType>(c & 0x3); }
302*0fca6ea1SDimitry Andric
getValuePos(u8 c)303*0fca6ea1SDimitry Andric static int getValuePos(u8 c) { return c >> kValueSizeSizeBits; }
304*0fca6ea1SDimitry Andric
305*0fca6ea1SDimitry Andric // Checks the consistency of the value types at the given type pointer.
306*0fca6ea1SDimitry Andric // If the value is inconsistent, returns ValueType::kUnknown. Else, return the
307*0fca6ea1SDimitry Andric // consistent type.
308*0fca6ea1SDimitry Andric template <typename FT>
checkValueConsistency(const u8 * shadow_type)309*0fca6ea1SDimitry Andric static bool checkValueConsistency(const u8 *shadow_type) {
310*0fca6ea1SDimitry Andric const int pos = getValuePos(*shadow_type);
311*0fca6ea1SDimitry Andric // Check that all bytes from the start of the value are ordered.
312*0fca6ea1SDimitry Andric for (uptr i = 0; i < sizeof(FT); ++i) {
313*0fca6ea1SDimitry Andric const u8 T = *(shadow_type - pos + i);
314*0fca6ea1SDimitry Andric if (!(getValueType(T) == FTInfo<FT>::kValueType && getValuePos(T) == i))
315*0fca6ea1SDimitry Andric return false;
316*0fca6ea1SDimitry Andric }
317*0fca6ea1SDimitry Andric return true;
318*0fca6ea1SDimitry Andric }
319*0fca6ea1SDimitry Andric
320*0fca6ea1SDimitry Andric // The instrumentation automatically appends `shadow_value_type_ids`, see
321*0fca6ea1SDimitry Andric // maybeAddSuffixForNsanInterface.
322*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__nsan_dump_shadow_mem(const u8 * addr,size_t size_bytes,size_t bytes_per_line,size_t shadow_value_type_ids)323*0fca6ea1SDimitry Andric __nsan_dump_shadow_mem(const u8 *addr, size_t size_bytes, size_t bytes_per_line,
324*0fca6ea1SDimitry Andric size_t shadow_value_type_ids) {
325*0fca6ea1SDimitry Andric const u8 *const shadow_type = GetShadowTypeAddrFor(addr);
326*0fca6ea1SDimitry Andric const u8 *const shadow = GetShadowAddrFor(addr);
327*0fca6ea1SDimitry Andric
328*0fca6ea1SDimitry Andric constexpr int kMaxNumDecodedValues = 16;
329*0fca6ea1SDimitry Andric __float128 decoded_values[kMaxNumDecodedValues];
330*0fca6ea1SDimitry Andric int num_decoded_values = 0;
331*0fca6ea1SDimitry Andric if (bytes_per_line > 4 * kMaxNumDecodedValues)
332*0fca6ea1SDimitry Andric bytes_per_line = 4 * kMaxNumDecodedValues;
333*0fca6ea1SDimitry Andric
334*0fca6ea1SDimitry Andric // We keep track of the current type and position as we go.
335*0fca6ea1SDimitry Andric ValueType LastValueTy = kUnknownValueType;
336*0fca6ea1SDimitry Andric int LastPos = -1;
337*0fca6ea1SDimitry Andric size_t Offset = 0;
338*0fca6ea1SDimitry Andric for (size_t R = 0; R < (size_bytes + bytes_per_line - 1) / bytes_per_line;
339*0fca6ea1SDimitry Andric ++R) {
340*0fca6ea1SDimitry Andric printf("%p: ", (void *)(addr + R * bytes_per_line));
341*0fca6ea1SDimitry Andric for (size_t C = 0; C < bytes_per_line && Offset < size_bytes; ++C) {
342*0fca6ea1SDimitry Andric const ValueType ValueTy = getValueType(shadow_type[Offset]);
343*0fca6ea1SDimitry Andric const int pos = getValuePos(shadow_type[Offset]);
344*0fca6ea1SDimitry Andric if (ValueTy == LastValueTy && pos == LastPos + 1) {
345*0fca6ea1SDimitry Andric ++LastPos;
346*0fca6ea1SDimitry Andric } else {
347*0fca6ea1SDimitry Andric LastValueTy = ValueTy;
348*0fca6ea1SDimitry Andric LastPos = pos == 0 ? 0 : -1;
349*0fca6ea1SDimitry Andric }
350*0fca6ea1SDimitry Andric
351*0fca6ea1SDimitry Andric switch (ValueTy) {
352*0fca6ea1SDimitry Andric case kUnknownValueType:
353*0fca6ea1SDimitry Andric printf("__ ");
354*0fca6ea1SDimitry Andric break;
355*0fca6ea1SDimitry Andric case kFloatValueType:
356*0fca6ea1SDimitry Andric printf("f%x ", pos);
357*0fca6ea1SDimitry Andric if (LastPos == sizeof(float) - 1) {
358*0fca6ea1SDimitry Andric decoded_values[num_decoded_values] =
359*0fca6ea1SDimitry Andric ReadShadow(shadow + kShadowScale * (Offset + 1 - sizeof(float)),
360*0fca6ea1SDimitry Andric static_cast<char>(shadow_value_type_ids & 0xff));
361*0fca6ea1SDimitry Andric ++num_decoded_values;
362*0fca6ea1SDimitry Andric }
363*0fca6ea1SDimitry Andric break;
364*0fca6ea1SDimitry Andric case kDoubleValueType:
365*0fca6ea1SDimitry Andric printf("d%x ", pos);
366*0fca6ea1SDimitry Andric if (LastPos == sizeof(double) - 1) {
367*0fca6ea1SDimitry Andric decoded_values[num_decoded_values] = ReadShadow(
368*0fca6ea1SDimitry Andric shadow + kShadowScale * (Offset + 1 - sizeof(double)),
369*0fca6ea1SDimitry Andric static_cast<char>((shadow_value_type_ids >> 8) & 0xff));
370*0fca6ea1SDimitry Andric ++num_decoded_values;
371*0fca6ea1SDimitry Andric }
372*0fca6ea1SDimitry Andric break;
373*0fca6ea1SDimitry Andric case kFp80ValueType:
374*0fca6ea1SDimitry Andric printf("l%x ", pos);
375*0fca6ea1SDimitry Andric if (LastPos == sizeof(long double) - 1) {
376*0fca6ea1SDimitry Andric decoded_values[num_decoded_values] = ReadShadow(
377*0fca6ea1SDimitry Andric shadow + kShadowScale * (Offset + 1 - sizeof(long double)),
378*0fca6ea1SDimitry Andric static_cast<char>((shadow_value_type_ids >> 16) & 0xff));
379*0fca6ea1SDimitry Andric ++num_decoded_values;
380*0fca6ea1SDimitry Andric }
381*0fca6ea1SDimitry Andric break;
382*0fca6ea1SDimitry Andric }
383*0fca6ea1SDimitry Andric ++Offset;
384*0fca6ea1SDimitry Andric }
385*0fca6ea1SDimitry Andric for (int i = 0; i < num_decoded_values; ++i) {
386*0fca6ea1SDimitry Andric printf(" (%s)", FTPrinter<__float128>::dec(decoded_values[i]).Buffer);
387*0fca6ea1SDimitry Andric }
388*0fca6ea1SDimitry Andric num_decoded_values = 0;
389*0fca6ea1SDimitry Andric printf("\n");
390*0fca6ea1SDimitry Andric }
391*0fca6ea1SDimitry Andric }
392*0fca6ea1SDimitry Andric
393*0fca6ea1SDimitry Andric alignas(16) SANITIZER_INTERFACE_ATTRIBUTE
394*0fca6ea1SDimitry Andric thread_local uptr __nsan_shadow_ret_tag = 0;
395*0fca6ea1SDimitry Andric
396*0fca6ea1SDimitry Andric alignas(16) SANITIZER_INTERFACE_ATTRIBUTE
397*0fca6ea1SDimitry Andric thread_local char __nsan_shadow_ret_ptr[kMaxVectorWidth *
398*0fca6ea1SDimitry Andric sizeof(__float128)];
399*0fca6ea1SDimitry Andric
400*0fca6ea1SDimitry Andric alignas(16) SANITIZER_INTERFACE_ATTRIBUTE
401*0fca6ea1SDimitry Andric thread_local uptr __nsan_shadow_args_tag = 0;
402*0fca6ea1SDimitry Andric
403*0fca6ea1SDimitry Andric // Maximum number of args. This should be enough for anyone (tm). An alternate
404*0fca6ea1SDimitry Andric // scheme is to have the generated code create an alloca and make
405*0fca6ea1SDimitry Andric // __nsan_shadow_args_ptr point ot the alloca.
406*0fca6ea1SDimitry Andric constexpr const int kMaxNumArgs = 128;
407*0fca6ea1SDimitry Andric alignas(16) SANITIZER_INTERFACE_ATTRIBUTE
408*0fca6ea1SDimitry Andric thread_local char __nsan_shadow_args_ptr[kMaxVectorWidth * kMaxNumArgs *
409*0fca6ea1SDimitry Andric sizeof(__float128)];
410*0fca6ea1SDimitry Andric
411*0fca6ea1SDimitry Andric enum ContinuationType { // Keep in sync with instrumentation pass.
412*0fca6ea1SDimitry Andric kContinueWithShadow = 0,
413*0fca6ea1SDimitry Andric kResumeFromValue = 1,
414*0fca6ea1SDimitry Andric };
415*0fca6ea1SDimitry Andric
416*0fca6ea1SDimitry Andric // Checks the consistency between application and shadow value. Returns true
417*0fca6ea1SDimitry Andric // when the instrumented code should resume computations from the original value
418*0fca6ea1SDimitry Andric // rather than the shadow value. This prevents one error to propagate to all
419*0fca6ea1SDimitry Andric // subsequent operations. This behaviour is tunable with flags.
420*0fca6ea1SDimitry Andric template <typename FT, typename ShadowFT>
checkFT(const FT value,ShadowFT Shadow,CheckTypeT CheckType,uptr CheckArg)421*0fca6ea1SDimitry Andric int32_t checkFT(const FT value, ShadowFT Shadow, CheckTypeT CheckType,
422*0fca6ea1SDimitry Andric uptr CheckArg) {
423*0fca6ea1SDimitry Andric // We do all comparisons in the InternalFT domain, which is the largest FT
424*0fca6ea1SDimitry Andric // type.
425*0fca6ea1SDimitry Andric using InternalFT = LargestFT<FT, ShadowFT>;
426*0fca6ea1SDimitry Andric const InternalFT check_value = value;
427*0fca6ea1SDimitry Andric const InternalFT check_shadow = Shadow;
428*0fca6ea1SDimitry Andric
429*0fca6ea1SDimitry Andric // See this article for an interesting discussion of how to compare floats:
430*0fca6ea1SDimitry Andric // https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
431*0fca6ea1SDimitry Andric static constexpr const FT Eps = FTInfo<FT>::kEpsilon;
432*0fca6ea1SDimitry Andric
433*0fca6ea1SDimitry Andric const InternalFT abs_err = ftAbs(check_value - check_shadow);
434*0fca6ea1SDimitry Andric
435*0fca6ea1SDimitry Andric if (flags().enable_check_stats) {
436*0fca6ea1SDimitry Andric GET_CALLER_PC_BP;
437*0fca6ea1SDimitry Andric // We are re-computing `largest` here because this is a cold branch, and we
438*0fca6ea1SDimitry Andric // want to avoid having to move the computation of `largest` before the
439*0fca6ea1SDimitry Andric // absolute value check when this branch is not taken.
440*0fca6ea1SDimitry Andric const InternalFT largest = max(ftAbs(check_value), ftAbs(check_shadow));
441*0fca6ea1SDimitry Andric nsan_stats->AddCheck(CheckType, pc, bp, abs_err / largest);
442*0fca6ea1SDimitry Andric }
443*0fca6ea1SDimitry Andric
444*0fca6ea1SDimitry Andric // Note: writing the comparison that way ensures that when `abs_err` is Nan
445*0fca6ea1SDimitry Andric // (value and shadow are inf or -inf), we pass the test.
446*0fca6ea1SDimitry Andric if (!(abs_err >= flags().cached_absolute_error_threshold))
447*0fca6ea1SDimitry Andric return kContinueWithShadow;
448*0fca6ea1SDimitry Andric
449*0fca6ea1SDimitry Andric const InternalFT largest = max(ftAbs(check_value), ftAbs(check_shadow));
450*0fca6ea1SDimitry Andric if (abs_err * (1ull << flags().log2_max_relative_error) <= largest)
451*0fca6ea1SDimitry Andric return kContinueWithShadow; // No problem here.
452*0fca6ea1SDimitry Andric
453*0fca6ea1SDimitry Andric if (!flags().disable_warnings) {
454*0fca6ea1SDimitry Andric GET_CALLER_PC_BP;
455*0fca6ea1SDimitry Andric BufferedStackTrace stack;
456*0fca6ea1SDimitry Andric stack.Unwind(pc, bp, nullptr, false);
457*0fca6ea1SDimitry Andric if (GetSuppressionForStack(&stack, CheckKind::Consistency)) {
458*0fca6ea1SDimitry Andric // FIXME: optionally print.
459*0fca6ea1SDimitry Andric return flags().resume_after_suppression ? kResumeFromValue
460*0fca6ea1SDimitry Andric : kContinueWithShadow;
461*0fca6ea1SDimitry Andric }
462*0fca6ea1SDimitry Andric
463*0fca6ea1SDimitry Andric Decorator D;
464*0fca6ea1SDimitry Andric Printf("%s", D.Warning());
465*0fca6ea1SDimitry Andric // Printf does not support float formatting.
466*0fca6ea1SDimitry Andric char RelErrBuf[64] = "inf";
467*0fca6ea1SDimitry Andric if (largest > Eps) {
468*0fca6ea1SDimitry Andric snprintf(RelErrBuf, sizeof(RelErrBuf) - 1, "%.20Lf%% (2^%.0Lf epsilons)",
469*0fca6ea1SDimitry Andric static_cast<long double>(100.0 * abs_err / largest),
470*0fca6ea1SDimitry Andric log2l(static_cast<long double>(abs_err / largest / Eps)));
471*0fca6ea1SDimitry Andric }
472*0fca6ea1SDimitry Andric char ulp_err_buf[128] = "";
473*0fca6ea1SDimitry Andric const double shadow_ulp_diff = GetULPDiff(check_value, check_shadow);
474*0fca6ea1SDimitry Andric if (shadow_ulp_diff != kMaxULPDiff) {
475*0fca6ea1SDimitry Andric // This is the ULP diff in the internal domain. The user actually cares
476*0fca6ea1SDimitry Andric // about that in the original domain.
477*0fca6ea1SDimitry Andric const double ulp_diff =
478*0fca6ea1SDimitry Andric shadow_ulp_diff / (u64{1} << (FTInfo<InternalFT>::kMantissaBits -
479*0fca6ea1SDimitry Andric FTInfo<FT>::kMantissaBits));
480*0fca6ea1SDimitry Andric snprintf(ulp_err_buf, sizeof(ulp_err_buf) - 1,
481*0fca6ea1SDimitry Andric "(%.0f ULPs == %.1f digits == %.1f bits)", ulp_diff,
482*0fca6ea1SDimitry Andric log10(ulp_diff), log2(ulp_diff));
483*0fca6ea1SDimitry Andric }
484*0fca6ea1SDimitry Andric Printf("WARNING: NumericalStabilitySanitizer: inconsistent shadow results");
485*0fca6ea1SDimitry Andric switch (CheckType) {
486*0fca6ea1SDimitry Andric case CheckTypeT::kUnknown:
487*0fca6ea1SDimitry Andric case CheckTypeT::kFcmp:
488*0fca6ea1SDimitry Andric case CheckTypeT::kMaxCheckType:
489*0fca6ea1SDimitry Andric break;
490*0fca6ea1SDimitry Andric case CheckTypeT::kRet:
491*0fca6ea1SDimitry Andric Printf(" while checking return value");
492*0fca6ea1SDimitry Andric break;
493*0fca6ea1SDimitry Andric case CheckTypeT::kArg:
494*0fca6ea1SDimitry Andric Printf(" while checking call argument #%d", static_cast<int>(CheckArg));
495*0fca6ea1SDimitry Andric break;
496*0fca6ea1SDimitry Andric case CheckTypeT::kLoad:
497*0fca6ea1SDimitry Andric Printf(
498*0fca6ea1SDimitry Andric " while checking load from address 0x%lx. This is due to incorrect "
499*0fca6ea1SDimitry Andric "shadow memory tracking, typically due to uninstrumented code "
500*0fca6ea1SDimitry Andric "writing to memory.",
501*0fca6ea1SDimitry Andric CheckArg);
502*0fca6ea1SDimitry Andric break;
503*0fca6ea1SDimitry Andric case CheckTypeT::kStore:
504*0fca6ea1SDimitry Andric Printf(" while checking store to address 0x%lx", CheckArg);
505*0fca6ea1SDimitry Andric break;
506*0fca6ea1SDimitry Andric case CheckTypeT::kInsert:
507*0fca6ea1SDimitry Andric Printf(" while checking vector insert");
508*0fca6ea1SDimitry Andric break;
509*0fca6ea1SDimitry Andric case CheckTypeT::kUser:
510*0fca6ea1SDimitry Andric Printf(" in user-initiated check");
511*0fca6ea1SDimitry Andric break;
512*0fca6ea1SDimitry Andric }
513*0fca6ea1SDimitry Andric using ValuePrinter = FTPrinter<FT>;
514*0fca6ea1SDimitry Andric using ShadowPrinter = FTPrinter<ShadowFT>;
515*0fca6ea1SDimitry Andric Printf("%s", D.Default());
516*0fca6ea1SDimitry Andric
517*0fca6ea1SDimitry Andric Printf("\n"
518*0fca6ea1SDimitry Andric "%-12s precision (native): dec: %s hex: %s\n"
519*0fca6ea1SDimitry Andric "%-12s precision (shadow): dec: %s hex: %s\n"
520*0fca6ea1SDimitry Andric "shadow truncated to %-12s: dec: %s hex: %s\n"
521*0fca6ea1SDimitry Andric "Relative error: %s\n"
522*0fca6ea1SDimitry Andric "Absolute error: %s\n"
523*0fca6ea1SDimitry Andric "%s\n",
524*0fca6ea1SDimitry Andric FTInfo<FT>::kCppTypeName, ValuePrinter::dec(value).Buffer,
525*0fca6ea1SDimitry Andric ValuePrinter::hex(value).Buffer, FTInfo<ShadowFT>::kCppTypeName,
526*0fca6ea1SDimitry Andric ShadowPrinter::dec(Shadow).Buffer, ShadowPrinter::hex(Shadow).Buffer,
527*0fca6ea1SDimitry Andric FTInfo<FT>::kCppTypeName, ValuePrinter::dec(Shadow).Buffer,
528*0fca6ea1SDimitry Andric ValuePrinter::hex(Shadow).Buffer, RelErrBuf,
529*0fca6ea1SDimitry Andric ValuePrinter::hex(abs_err).Buffer, ulp_err_buf);
530*0fca6ea1SDimitry Andric stack.Print();
531*0fca6ea1SDimitry Andric }
532*0fca6ea1SDimitry Andric
533*0fca6ea1SDimitry Andric if (flags().enable_warning_stats) {
534*0fca6ea1SDimitry Andric GET_CALLER_PC_BP;
535*0fca6ea1SDimitry Andric nsan_stats->AddWarning(CheckType, pc, bp, abs_err / largest);
536*0fca6ea1SDimitry Andric }
537*0fca6ea1SDimitry Andric
538*0fca6ea1SDimitry Andric if (flags().halt_on_error) {
539*0fca6ea1SDimitry Andric if (common_flags()->abort_on_error)
540*0fca6ea1SDimitry Andric Printf("ABORTING\n");
541*0fca6ea1SDimitry Andric else
542*0fca6ea1SDimitry Andric Printf("Exiting\n");
543*0fca6ea1SDimitry Andric Die();
544*0fca6ea1SDimitry Andric }
545*0fca6ea1SDimitry Andric return flags().resume_after_warning ? kResumeFromValue : kContinueWithShadow;
546*0fca6ea1SDimitry Andric }
547*0fca6ea1SDimitry Andric
__nsan_internal_check_float_d(float value,double shadow,int32_t check_type,uptr check_arg)548*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE int32_t __nsan_internal_check_float_d(
549*0fca6ea1SDimitry Andric float value, double shadow, int32_t check_type, uptr check_arg) {
550*0fca6ea1SDimitry Andric return checkFT(value, shadow, static_cast<CheckTypeT>(check_type), check_arg);
551*0fca6ea1SDimitry Andric }
552*0fca6ea1SDimitry Andric
__nsan_internal_check_double_l(double value,long double shadow,int32_t check_type,uptr check_arg)553*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE int32_t __nsan_internal_check_double_l(
554*0fca6ea1SDimitry Andric double value, long double shadow, int32_t check_type, uptr check_arg) {
555*0fca6ea1SDimitry Andric return checkFT(value, shadow, static_cast<CheckTypeT>(check_type), check_arg);
556*0fca6ea1SDimitry Andric }
557*0fca6ea1SDimitry Andric
__nsan_internal_check_double_q(double value,__float128 shadow,int32_t check_type,uptr check_arg)558*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE int32_t __nsan_internal_check_double_q(
559*0fca6ea1SDimitry Andric double value, __float128 shadow, int32_t check_type, uptr check_arg) {
560*0fca6ea1SDimitry Andric return checkFT(value, shadow, static_cast<CheckTypeT>(check_type), check_arg);
561*0fca6ea1SDimitry Andric }
562*0fca6ea1SDimitry Andric
563*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE int32_t
__nsan_internal_check_longdouble_q(long double value,__float128 shadow,int32_t check_type,uptr check_arg)564*0fca6ea1SDimitry Andric __nsan_internal_check_longdouble_q(long double value, __float128 shadow,
565*0fca6ea1SDimitry Andric int32_t check_type, uptr check_arg) {
566*0fca6ea1SDimitry Andric return checkFT(value, shadow, static_cast<CheckTypeT>(check_type), check_arg);
567*0fca6ea1SDimitry Andric }
568*0fca6ea1SDimitry Andric
GetTruthValueName(bool v)569*0fca6ea1SDimitry Andric static const char *GetTruthValueName(bool v) { return v ? "true" : "false"; }
570*0fca6ea1SDimitry Andric
571*0fca6ea1SDimitry Andric // This uses the same values as CmpInst::Predicate.
GetPredicateName(int v)572*0fca6ea1SDimitry Andric static const char *GetPredicateName(int v) {
573*0fca6ea1SDimitry Andric switch (v) {
574*0fca6ea1SDimitry Andric case 0:
575*0fca6ea1SDimitry Andric return "(false)";
576*0fca6ea1SDimitry Andric case 1:
577*0fca6ea1SDimitry Andric return "==";
578*0fca6ea1SDimitry Andric case 2:
579*0fca6ea1SDimitry Andric return ">";
580*0fca6ea1SDimitry Andric case 3:
581*0fca6ea1SDimitry Andric return ">=";
582*0fca6ea1SDimitry Andric case 4:
583*0fca6ea1SDimitry Andric return "<";
584*0fca6ea1SDimitry Andric case 5:
585*0fca6ea1SDimitry Andric return "<=";
586*0fca6ea1SDimitry Andric case 6:
587*0fca6ea1SDimitry Andric return "!=";
588*0fca6ea1SDimitry Andric case 7:
589*0fca6ea1SDimitry Andric return "(ordered)";
590*0fca6ea1SDimitry Andric case 8:
591*0fca6ea1SDimitry Andric return "(unordered)";
592*0fca6ea1SDimitry Andric case 9:
593*0fca6ea1SDimitry Andric return "==";
594*0fca6ea1SDimitry Andric case 10:
595*0fca6ea1SDimitry Andric return ">";
596*0fca6ea1SDimitry Andric case 11:
597*0fca6ea1SDimitry Andric return ">=";
598*0fca6ea1SDimitry Andric case 12:
599*0fca6ea1SDimitry Andric return "<";
600*0fca6ea1SDimitry Andric case 13:
601*0fca6ea1SDimitry Andric return "<=";
602*0fca6ea1SDimitry Andric case 14:
603*0fca6ea1SDimitry Andric return "!=";
604*0fca6ea1SDimitry Andric case 15:
605*0fca6ea1SDimitry Andric return "(true)";
606*0fca6ea1SDimitry Andric }
607*0fca6ea1SDimitry Andric return "??";
608*0fca6ea1SDimitry Andric }
609*0fca6ea1SDimitry Andric
610*0fca6ea1SDimitry Andric template <typename FT, typename ShadowFT>
fCmpFailFT(const FT Lhs,const FT Rhs,ShadowFT LhsShadow,ShadowFT RhsShadow,int Predicate,bool result,bool ShadowResult)611*0fca6ea1SDimitry Andric void fCmpFailFT(const FT Lhs, const FT Rhs, ShadowFT LhsShadow,
612*0fca6ea1SDimitry Andric ShadowFT RhsShadow, int Predicate, bool result,
613*0fca6ea1SDimitry Andric bool ShadowResult) {
614*0fca6ea1SDimitry Andric if (result == ShadowResult) {
615*0fca6ea1SDimitry Andric // When a vector comparison fails, we fail each element of the comparison
616*0fca6ea1SDimitry Andric // to simplify instrumented code. Skip elements where the shadow comparison
617*0fca6ea1SDimitry Andric // gave the same result as the original one.
618*0fca6ea1SDimitry Andric return;
619*0fca6ea1SDimitry Andric }
620*0fca6ea1SDimitry Andric
621*0fca6ea1SDimitry Andric GET_CALLER_PC_BP;
622*0fca6ea1SDimitry Andric BufferedStackTrace stack;
623*0fca6ea1SDimitry Andric stack.Unwind(pc, bp, nullptr, false);
624*0fca6ea1SDimitry Andric
625*0fca6ea1SDimitry Andric if (GetSuppressionForStack(&stack, CheckKind::Fcmp)) {
626*0fca6ea1SDimitry Andric // FIXME: optionally print.
627*0fca6ea1SDimitry Andric return;
628*0fca6ea1SDimitry Andric }
629*0fca6ea1SDimitry Andric
630*0fca6ea1SDimitry Andric if (flags().enable_warning_stats)
631*0fca6ea1SDimitry Andric nsan_stats->AddWarning(CheckTypeT::kFcmp, pc, bp, 0.0);
632*0fca6ea1SDimitry Andric
633*0fca6ea1SDimitry Andric if (flags().disable_warnings)
634*0fca6ea1SDimitry Andric return;
635*0fca6ea1SDimitry Andric
636*0fca6ea1SDimitry Andric // FIXME: ideally we would print the shadow value as FP128. Right now because
637*0fca6ea1SDimitry Andric // we truncate to long double we can sometimes see stuff like:
638*0fca6ea1SDimitry Andric // shadow <value> == <value> (false)
639*0fca6ea1SDimitry Andric using ValuePrinter = FTPrinter<FT>;
640*0fca6ea1SDimitry Andric using ShadowPrinter = FTPrinter<ShadowFT>;
641*0fca6ea1SDimitry Andric Decorator D;
642*0fca6ea1SDimitry Andric const char *const PredicateName = GetPredicateName(Predicate);
643*0fca6ea1SDimitry Andric Printf("%s", D.Warning());
644*0fca6ea1SDimitry Andric Printf("WARNING: NumericalStabilitySanitizer: floating-point comparison "
645*0fca6ea1SDimitry Andric "results depend on precision\n");
646*0fca6ea1SDimitry Andric Printf("%s", D.Default());
647*0fca6ea1SDimitry Andric Printf("%-12s precision dec (native): %s %s %s (%s)\n"
648*0fca6ea1SDimitry Andric "%-12s precision dec (shadow): %s %s %s (%s)\n"
649*0fca6ea1SDimitry Andric "%-12s precision hex (native): %s %s %s (%s)\n"
650*0fca6ea1SDimitry Andric "%-12s precision hex (shadow): %s %s %s (%s)\n"
651*0fca6ea1SDimitry Andric "%s",
652*0fca6ea1SDimitry Andric // Native, decimal.
653*0fca6ea1SDimitry Andric FTInfo<FT>::kCppTypeName, ValuePrinter::dec(Lhs).Buffer, PredicateName,
654*0fca6ea1SDimitry Andric ValuePrinter::dec(Rhs).Buffer, GetTruthValueName(result),
655*0fca6ea1SDimitry Andric // Shadow, decimal
656*0fca6ea1SDimitry Andric FTInfo<ShadowFT>::kCppTypeName, ShadowPrinter::dec(LhsShadow).Buffer,
657*0fca6ea1SDimitry Andric PredicateName, ShadowPrinter::dec(RhsShadow).Buffer,
658*0fca6ea1SDimitry Andric GetTruthValueName(ShadowResult),
659*0fca6ea1SDimitry Andric // Native, hex.
660*0fca6ea1SDimitry Andric FTInfo<FT>::kCppTypeName, ValuePrinter::hex(Lhs).Buffer, PredicateName,
661*0fca6ea1SDimitry Andric ValuePrinter::hex(Rhs).Buffer, GetTruthValueName(result),
662*0fca6ea1SDimitry Andric // Shadow, hex
663*0fca6ea1SDimitry Andric FTInfo<ShadowFT>::kCppTypeName, ShadowPrinter::hex(LhsShadow).Buffer,
664*0fca6ea1SDimitry Andric PredicateName, ShadowPrinter::hex(RhsShadow).Buffer,
665*0fca6ea1SDimitry Andric GetTruthValueName(ShadowResult), D.End());
666*0fca6ea1SDimitry Andric stack.Print();
667*0fca6ea1SDimitry Andric if (flags().halt_on_error) {
668*0fca6ea1SDimitry Andric Printf("Exiting\n");
669*0fca6ea1SDimitry Andric Die();
670*0fca6ea1SDimitry Andric }
671*0fca6ea1SDimitry Andric }
672*0fca6ea1SDimitry Andric
673*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__nsan_fcmp_fail_float_d(float lhs,float rhs,double lhs_shadow,double rhs_shadow,int predicate,bool result,bool shadow_result)674*0fca6ea1SDimitry Andric __nsan_fcmp_fail_float_d(float lhs, float rhs, double lhs_shadow,
675*0fca6ea1SDimitry Andric double rhs_shadow, int predicate, bool result,
676*0fca6ea1SDimitry Andric bool shadow_result) {
677*0fca6ea1SDimitry Andric fCmpFailFT(lhs, rhs, lhs_shadow, rhs_shadow, predicate, result,
678*0fca6ea1SDimitry Andric shadow_result);
679*0fca6ea1SDimitry Andric }
680*0fca6ea1SDimitry Andric
681*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__nsan_fcmp_fail_double_q(double lhs,double rhs,__float128 lhs_shadow,__float128 rhs_shadow,int predicate,bool result,bool shadow_result)682*0fca6ea1SDimitry Andric __nsan_fcmp_fail_double_q(double lhs, double rhs, __float128 lhs_shadow,
683*0fca6ea1SDimitry Andric __float128 rhs_shadow, int predicate, bool result,
684*0fca6ea1SDimitry Andric bool shadow_result) {
685*0fca6ea1SDimitry Andric fCmpFailFT(lhs, rhs, lhs_shadow, rhs_shadow, predicate, result,
686*0fca6ea1SDimitry Andric shadow_result);
687*0fca6ea1SDimitry Andric }
688*0fca6ea1SDimitry Andric
689*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__nsan_fcmp_fail_double_l(double lhs,double rhs,long double lhs_shadow,long double rhs_shadow,int predicate,bool result,bool shadow_result)690*0fca6ea1SDimitry Andric __nsan_fcmp_fail_double_l(double lhs, double rhs, long double lhs_shadow,
691*0fca6ea1SDimitry Andric long double rhs_shadow, int predicate, bool result,
692*0fca6ea1SDimitry Andric bool shadow_result) {
693*0fca6ea1SDimitry Andric fCmpFailFT(lhs, rhs, lhs_shadow, rhs_shadow, predicate, result,
694*0fca6ea1SDimitry Andric shadow_result);
695*0fca6ea1SDimitry Andric }
696*0fca6ea1SDimitry Andric
697*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__nsan_fcmp_fail_longdouble_q(long double lhs,long double rhs,__float128 lhs_shadow,__float128 rhs_shadow,int predicate,bool result,bool shadow_result)698*0fca6ea1SDimitry Andric __nsan_fcmp_fail_longdouble_q(long double lhs, long double rhs,
699*0fca6ea1SDimitry Andric __float128 lhs_shadow, __float128 rhs_shadow,
700*0fca6ea1SDimitry Andric int predicate, bool result, bool shadow_result) {
701*0fca6ea1SDimitry Andric fCmpFailFT(lhs, rhs, lhs_shadow, rhs_shadow, predicate, result,
702*0fca6ea1SDimitry Andric shadow_result);
703*0fca6ea1SDimitry Andric }
704*0fca6ea1SDimitry Andric
checkFTFromShadowStack(const FT value)705*0fca6ea1SDimitry Andric template <typename FT> void checkFTFromShadowStack(const FT value) {
706*0fca6ea1SDimitry Andric // Get the shadow 2FT value from the shadow stack. Note that
707*0fca6ea1SDimitry Andric // __nsan_check_{float,double,long double} is a function like any other, so
708*0fca6ea1SDimitry Andric // the instrumentation will have placed the shadow value on the shadow stack.
709*0fca6ea1SDimitry Andric using ShadowFT = typename FTInfo<FT>::shadow_type;
710*0fca6ea1SDimitry Andric ShadowFT Shadow;
711*0fca6ea1SDimitry Andric __builtin_memcpy(&Shadow, __nsan_shadow_args_ptr, sizeof(ShadowFT));
712*0fca6ea1SDimitry Andric checkFT(value, Shadow, CheckTypeT::kUser, 0);
713*0fca6ea1SDimitry Andric }
714*0fca6ea1SDimitry Andric
715*0fca6ea1SDimitry Andric // FIXME: Add suffixes and let the instrumentation pass automatically add
716*0fca6ea1SDimitry Andric // suffixes.
__nsan_check_float(float value)717*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_check_float(float value) {
718*0fca6ea1SDimitry Andric assert(__nsan_shadow_args_tag == (uptr)&__nsan_check_float &&
719*0fca6ea1SDimitry Andric "__nsan_check_float called from non-instrumented function");
720*0fca6ea1SDimitry Andric checkFTFromShadowStack(value);
721*0fca6ea1SDimitry Andric }
722*0fca6ea1SDimitry Andric
723*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__nsan_check_double(double value)724*0fca6ea1SDimitry Andric __nsan_check_double(double value) {
725*0fca6ea1SDimitry Andric assert(__nsan_shadow_args_tag == (uptr)&__nsan_check_double &&
726*0fca6ea1SDimitry Andric "__nsan_check_double called from non-instrumented function");
727*0fca6ea1SDimitry Andric checkFTFromShadowStack(value);
728*0fca6ea1SDimitry Andric }
729*0fca6ea1SDimitry Andric
730*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__nsan_check_longdouble(long double value)731*0fca6ea1SDimitry Andric __nsan_check_longdouble(long double value) {
732*0fca6ea1SDimitry Andric assert(__nsan_shadow_args_tag == (uptr)&__nsan_check_longdouble &&
733*0fca6ea1SDimitry Andric "__nsan_check_longdouble called from non-instrumented function");
734*0fca6ea1SDimitry Andric checkFTFromShadowStack(value);
735*0fca6ea1SDimitry Andric }
736*0fca6ea1SDimitry Andric
dumpFTFromShadowStack(const FT value)737*0fca6ea1SDimitry Andric template <typename FT> static void dumpFTFromShadowStack(const FT value) {
738*0fca6ea1SDimitry Andric // Get the shadow 2FT value from the shadow stack. Note that
739*0fca6ea1SDimitry Andric // __nsan_dump_{float,double,long double} is a function like any other, so
740*0fca6ea1SDimitry Andric // the instrumentation will have placed the shadow value on the shadow stack.
741*0fca6ea1SDimitry Andric using ShadowFT = typename FTInfo<FT>::shadow_type;
742*0fca6ea1SDimitry Andric ShadowFT shadow;
743*0fca6ea1SDimitry Andric __builtin_memcpy(&shadow, __nsan_shadow_args_ptr, sizeof(ShadowFT));
744*0fca6ea1SDimitry Andric using ValuePrinter = FTPrinter<FT>;
745*0fca6ea1SDimitry Andric using ShadowPrinter = FTPrinter<typename FTInfo<FT>::shadow_type>;
746*0fca6ea1SDimitry Andric printf("value dec:%s hex:%s\n"
747*0fca6ea1SDimitry Andric "shadow dec:%s hex:%s\n",
748*0fca6ea1SDimitry Andric ValuePrinter::dec(value).Buffer, ValuePrinter::hex(value).Buffer,
749*0fca6ea1SDimitry Andric ShadowPrinter::dec(shadow).Buffer, ShadowPrinter::hex(shadow).Buffer);
750*0fca6ea1SDimitry Andric }
751*0fca6ea1SDimitry Andric
__nsan_dump_float(float value)752*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_dump_float(float value) {
753*0fca6ea1SDimitry Andric assert(__nsan_shadow_args_tag == (uptr)&__nsan_dump_float &&
754*0fca6ea1SDimitry Andric "__nsan_dump_float called from non-instrumented function");
755*0fca6ea1SDimitry Andric dumpFTFromShadowStack(value);
756*0fca6ea1SDimitry Andric }
757*0fca6ea1SDimitry Andric
__nsan_dump_double(double value)758*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_dump_double(double value) {
759*0fca6ea1SDimitry Andric assert(__nsan_shadow_args_tag == (uptr)&__nsan_dump_double &&
760*0fca6ea1SDimitry Andric "__nsan_dump_double called from non-instrumented function");
761*0fca6ea1SDimitry Andric dumpFTFromShadowStack(value);
762*0fca6ea1SDimitry Andric }
763*0fca6ea1SDimitry Andric
764*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__nsan_dump_longdouble(long double value)765*0fca6ea1SDimitry Andric __nsan_dump_longdouble(long double value) {
766*0fca6ea1SDimitry Andric assert(__nsan_shadow_args_tag == (uptr)&__nsan_dump_longdouble &&
767*0fca6ea1SDimitry Andric "__nsan_dump_longdouble called from non-instrumented function");
768*0fca6ea1SDimitry Andric dumpFTFromShadowStack(value);
769*0fca6ea1SDimitry Andric }
770*0fca6ea1SDimitry Andric
__nsan_dump_shadow_ret()771*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_dump_shadow_ret() {
772*0fca6ea1SDimitry Andric printf("ret tag: %lx\n", __nsan_shadow_ret_tag);
773*0fca6ea1SDimitry Andric double v;
774*0fca6ea1SDimitry Andric __builtin_memcpy(&v, __nsan_shadow_ret_ptr, sizeof(double));
775*0fca6ea1SDimitry Andric printf("double value: %f\n", v);
776*0fca6ea1SDimitry Andric // FIXME: float128 value.
777*0fca6ea1SDimitry Andric }
778*0fca6ea1SDimitry Andric
__nsan_dump_shadow_args()779*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_dump_shadow_args() {
780*0fca6ea1SDimitry Andric printf("args tag: %lx\n", __nsan_shadow_args_tag);
781*0fca6ea1SDimitry Andric }
782*0fca6ea1SDimitry Andric
783*0fca6ea1SDimitry Andric bool __nsan::nsan_initialized;
784*0fca6ea1SDimitry Andric bool __nsan::nsan_init_is_running;
785*0fca6ea1SDimitry Andric
__nsan_init()786*0fca6ea1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_init() {
787*0fca6ea1SDimitry Andric CHECK(!nsan_init_is_running);
788*0fca6ea1SDimitry Andric if (nsan_initialized)
789*0fca6ea1SDimitry Andric return;
790*0fca6ea1SDimitry Andric nsan_init_is_running = true;
791*0fca6ea1SDimitry Andric
792*0fca6ea1SDimitry Andric InitializeFlags();
793*0fca6ea1SDimitry Andric InitializeSuppressions();
794*0fca6ea1SDimitry Andric InitializePlatformEarly();
795*0fca6ea1SDimitry Andric
796*0fca6ea1SDimitry Andric DisableCoreDumperIfNecessary();
797*0fca6ea1SDimitry Andric
798*0fca6ea1SDimitry Andric if (!MmapFixedNoReserve(TypesAddr(), UnusedAddr() - TypesAddr()))
799*0fca6ea1SDimitry Andric Die();
800*0fca6ea1SDimitry Andric
801*0fca6ea1SDimitry Andric InitializeInterceptors();
802*0fca6ea1SDimitry Andric
803*0fca6ea1SDimitry Andric InitializeStats();
804*0fca6ea1SDimitry Andric if (flags().print_stats_on_exit)
805*0fca6ea1SDimitry Andric Atexit(NsanAtexit);
806*0fca6ea1SDimitry Andric
807*0fca6ea1SDimitry Andric nsan_init_is_running = false;
808*0fca6ea1SDimitry Andric nsan_initialized = true;
809*0fca6ea1SDimitry Andric }
810