xref: /freebsd/contrib/llvm-project/compiler-rt/lib/msan/msan_origin.h (revision e25152834cdf3b353892835a4f3b157e066a8ed4)
10b57cec5SDimitry Andric //===-- msan_origin.h ----------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // Origin id utils.
100b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
110b57cec5SDimitry Andric #ifndef MSAN_ORIGIN_H
120b57cec5SDimitry Andric #define MSAN_ORIGIN_H
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_stackdepot.h"
150b57cec5SDimitry Andric #include "msan_chained_origin_depot.h"
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric namespace __msan {
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric // Origin handling.
200b57cec5SDimitry Andric //
210b57cec5SDimitry Andric // Origin is a 32-bit identifier that is attached to any uninitialized value in
220b57cec5SDimitry Andric // the program and describes, more or less exactly, how this memory came to be
230b57cec5SDimitry Andric // uninitialized.
240b57cec5SDimitry Andric //
250b57cec5SDimitry Andric // There are 3 kinds of origin ids:
260b57cec5SDimitry Andric // 1xxx xxxx xxxx xxxx   heap origin id
270b57cec5SDimitry Andric // 0000 xxxx xxxx xxxx   stack origin id
280b57cec5SDimitry Andric // 0zzz xxxx xxxx xxxx   chained origin id
290b57cec5SDimitry Andric //
300b57cec5SDimitry Andric // Heap origin id describes a heap memory allocation and contains (in the xxx
310b57cec5SDimitry Andric // part) a value of StackDepot.
320b57cec5SDimitry Andric //
330b57cec5SDimitry Andric // Stack origin id describes a stack memory allocation and contains (in the xxx
340b57cec5SDimitry Andric // part) an index into StackOriginDescr and StackOriginPC. We don't store a
350b57cec5SDimitry Andric // stack trace for such origins for performance reasons.
360b57cec5SDimitry Andric //
370b57cec5SDimitry Andric // Chained origin id describes an event of storing an uninitialized value to
380b57cec5SDimitry Andric // memory. The xxx part is a value of ChainedOriginDepot, which is a mapping of
390b57cec5SDimitry Andric // (stack_id, prev_id) -> id, where
400b57cec5SDimitry Andric //  * stack_id describes the event.
410b57cec5SDimitry Andric //    StackDepot keeps a mapping between those and corresponding stack traces.
420b57cec5SDimitry Andric //  * prev_id is another origin id that describes the earlier part of the
430b57cec5SDimitry Andric //    uninitialized value history.
440b57cec5SDimitry Andric // Following a chain of prev_id provides the full recorded history of an
450b57cec5SDimitry Andric // uninitialized value.
460b57cec5SDimitry Andric //
470b57cec5SDimitry Andric // This, effectively, defines a tree (or 2 trees, see below) where nodes are
480b57cec5SDimitry Andric // points in value history marked with origin ids, and edges are events that are
490b57cec5SDimitry Andric // marked with stack_id.
500b57cec5SDimitry Andric //
510b57cec5SDimitry Andric // The "zzz" bits of chained origin id are used to store the length (or depth)
520b57cec5SDimitry Andric // of the origin chain.
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric class Origin {
550b57cec5SDimitry Andric  public:
isValidId(u32 id)560b57cec5SDimitry Andric   static bool isValidId(u32 id) { return id != 0 && id != (u32)-1; }
570b57cec5SDimitry Andric 
raw_id()580b57cec5SDimitry Andric   u32 raw_id() const { return raw_id_; }
isHeapOrigin()590b57cec5SDimitry Andric   bool isHeapOrigin() const {
60*5ffd83dbSDimitry Andric     // 0xxx xxxx xxxx xxxx
610b57cec5SDimitry Andric     return raw_id_ >> kHeapShift == 0;
620b57cec5SDimitry Andric   }
isStackOrigin()630b57cec5SDimitry Andric   bool isStackOrigin() const {
640b57cec5SDimitry Andric     // 1000 xxxx xxxx xxxx
650b57cec5SDimitry Andric     return (raw_id_ >> kDepthShift) == (1 << kDepthBits);
660b57cec5SDimitry Andric   }
isChainedOrigin()670b57cec5SDimitry Andric   bool isChainedOrigin() const {
680b57cec5SDimitry Andric     // 1zzz xxxx xxxx xxxx, zzz != 000
690b57cec5SDimitry Andric     return (raw_id_ >> kDepthShift) > (1 << kDepthBits);
700b57cec5SDimitry Andric   }
getChainedId()710b57cec5SDimitry Andric   u32 getChainedId() const {
720b57cec5SDimitry Andric     CHECK(isChainedOrigin());
730b57cec5SDimitry Andric     return raw_id_ & kChainedIdMask;
740b57cec5SDimitry Andric   }
getStackId()750b57cec5SDimitry Andric   u32 getStackId() const {
760b57cec5SDimitry Andric     CHECK(isStackOrigin());
770b57cec5SDimitry Andric     return raw_id_ & kChainedIdMask;
780b57cec5SDimitry Andric   }
getHeapId()790b57cec5SDimitry Andric   u32 getHeapId() const {
800b57cec5SDimitry Andric     CHECK(isHeapOrigin());
810b57cec5SDimitry Andric     return raw_id_ & kHeapIdMask;
820b57cec5SDimitry Andric   }
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric   // Returns the next origin in the chain and the current stack trace.
getNextChainedOrigin(StackTrace * stack)850b57cec5SDimitry Andric   Origin getNextChainedOrigin(StackTrace *stack) const {
860b57cec5SDimitry Andric     CHECK(isChainedOrigin());
870b57cec5SDimitry Andric     u32 prev_id;
880b57cec5SDimitry Andric     u32 stack_id = ChainedOriginDepotGet(getChainedId(), &prev_id);
890b57cec5SDimitry Andric     if (stack) *stack = StackDepotGet(stack_id);
900b57cec5SDimitry Andric     return Origin(prev_id);
910b57cec5SDimitry Andric   }
920b57cec5SDimitry Andric 
getStackTraceForHeapOrigin()930b57cec5SDimitry Andric   StackTrace getStackTraceForHeapOrigin() const {
940b57cec5SDimitry Andric     return StackDepotGet(getHeapId());
950b57cec5SDimitry Andric   }
960b57cec5SDimitry Andric 
CreateStackOrigin(u32 id)970b57cec5SDimitry Andric   static Origin CreateStackOrigin(u32 id) {
980b57cec5SDimitry Andric     CHECK((id & kStackIdMask) == id);
990b57cec5SDimitry Andric     return Origin((1 << kHeapShift) | id);
1000b57cec5SDimitry Andric   }
1010b57cec5SDimitry Andric 
CreateHeapOrigin(StackTrace * stack)1020b57cec5SDimitry Andric   static Origin CreateHeapOrigin(StackTrace *stack) {
1030b57cec5SDimitry Andric     u32 stack_id = StackDepotPut(*stack);
1040b57cec5SDimitry Andric     CHECK(stack_id);
1050b57cec5SDimitry Andric     CHECK((stack_id & kHeapIdMask) == stack_id);
1060b57cec5SDimitry Andric     return Origin(stack_id);
1070b57cec5SDimitry Andric   }
1080b57cec5SDimitry Andric 
CreateChainedOrigin(Origin prev,StackTrace * stack)1090b57cec5SDimitry Andric   static Origin CreateChainedOrigin(Origin prev, StackTrace *stack) {
1100b57cec5SDimitry Andric     int depth = prev.isChainedOrigin() ? prev.depth() : 0;
1110b57cec5SDimitry Andric     // depth is the length of the chain minus 1.
1120b57cec5SDimitry Andric     // origin_history_size of 0 means unlimited depth.
1130b57cec5SDimitry Andric     if (flags()->origin_history_size > 0) {
1140b57cec5SDimitry Andric       if (depth + 1 >= flags()->origin_history_size) {
1150b57cec5SDimitry Andric         return prev;
1160b57cec5SDimitry Andric       } else {
1170b57cec5SDimitry Andric         ++depth;
1180b57cec5SDimitry Andric         CHECK(depth < (1 << kDepthBits));
1190b57cec5SDimitry Andric       }
1200b57cec5SDimitry Andric     }
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric     StackDepotHandle h = StackDepotPut_WithHandle(*stack);
1230b57cec5SDimitry Andric     if (!h.valid()) return prev;
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric     if (flags()->origin_history_per_stack_limit > 0) {
1260b57cec5SDimitry Andric       int use_count = h.use_count();
1270b57cec5SDimitry Andric       if (use_count > flags()->origin_history_per_stack_limit) return prev;
1280b57cec5SDimitry Andric     }
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric     u32 chained_id;
1310b57cec5SDimitry Andric     bool inserted = ChainedOriginDepotPut(h.id(), prev.raw_id(), &chained_id);
1320b57cec5SDimitry Andric     CHECK((chained_id & kChainedIdMask) == chained_id);
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric     if (inserted && flags()->origin_history_per_stack_limit > 0)
1350b57cec5SDimitry Andric       h.inc_use_count_unsafe();
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric     return Origin((1 << kHeapShift) | (depth << kDepthShift) | chained_id);
1380b57cec5SDimitry Andric   }
1390b57cec5SDimitry Andric 
FromRawId(u32 id)1400b57cec5SDimitry Andric   static Origin FromRawId(u32 id) {
1410b57cec5SDimitry Andric     return Origin(id);
1420b57cec5SDimitry Andric   }
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric  private:
1450b57cec5SDimitry Andric   static const int kDepthBits = 3;
1460b57cec5SDimitry Andric   static const int kDepthShift = 32 - kDepthBits - 1;
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric   static const int kHeapShift = 31;
1490b57cec5SDimitry Andric   static const u32 kChainedIdMask = ((u32)-1) >> (32 - kDepthShift);
1500b57cec5SDimitry Andric   static const u32 kStackIdMask = ((u32)-1) >> (32 - kDepthShift);
1510b57cec5SDimitry Andric   static const u32 kHeapIdMask = ((u32)-1) >> (32 - kHeapShift);
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric   u32 raw_id_;
1540b57cec5SDimitry Andric 
Origin(u32 raw_id)1550b57cec5SDimitry Andric   explicit Origin(u32 raw_id) : raw_id_(raw_id) {}
1560b57cec5SDimitry Andric 
depth()1570b57cec5SDimitry Andric   int depth() const {
1580b57cec5SDimitry Andric     CHECK(isChainedOrigin());
1590b57cec5SDimitry Andric     return (raw_id_ >> kDepthShift) & ((1 << kDepthBits) - 1);
1600b57cec5SDimitry Andric   }
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric  public:
1630b57cec5SDimitry Andric   static const int kMaxDepth = (1 << kDepthBits) - 1;
1640b57cec5SDimitry Andric };
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric }  // namespace __msan
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric #endif  // MSAN_ORIGIN_H
169