//===-- msan_origin.h ----------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Origin id utils. //===----------------------------------------------------------------------===// #ifndef MSAN_ORIGIN_H #define MSAN_ORIGIN_H #include "sanitizer_common/sanitizer_stackdepot.h" #include "msan_chained_origin_depot.h" namespace __msan { // Origin handling. // // Origin is a 32-bit identifier that is attached to any uninitialized value in // the program and describes, more or less exactly, how this memory came to be // uninitialized. // // There are 3 kinds of origin ids: // 1xxx xxxx xxxx xxxx heap origin id // 0000 xxxx xxxx xxxx stack origin id // 0zzz xxxx xxxx xxxx chained origin id // // Heap origin id describes a heap memory allocation and contains (in the xxx // part) a value of StackDepot. // // Stack origin id describes a stack memory allocation and contains (in the xxx // part) an index into StackOriginDescr and StackOriginPC. We don't store a // stack trace for such origins for performance reasons. // // Chained origin id describes an event of storing an uninitialized value to // memory. The xxx part is a value of ChainedOriginDepot, which is a mapping of // (stack_id, prev_id) -> id, where // * stack_id describes the event. // StackDepot keeps a mapping between those and corresponding stack traces. // * prev_id is another origin id that describes the earlier part of the // uninitialized value history. // Following a chain of prev_id provides the full recorded history of an // uninitialized value. // // This, effectively, defines a tree (or 2 trees, see below) where nodes are // points in value history marked with origin ids, and edges are events that are // marked with stack_id. // // The "zzz" bits of chained origin id are used to store the length (or depth) // of the origin chain. class Origin { public: static bool isValidId(u32 id) { return id != 0 && id != (u32)-1; } u32 raw_id() const { return raw_id_; } bool isHeapOrigin() const { // 1xxx xxxx xxxx xxxx return raw_id_ >> kHeapShift == 0; } bool isStackOrigin() const { // 1000 xxxx xxxx xxxx return (raw_id_ >> kDepthShift) == (1 << kDepthBits); } bool isChainedOrigin() const { // 1zzz xxxx xxxx xxxx, zzz != 000 return (raw_id_ >> kDepthShift) > (1 << kDepthBits); } u32 getChainedId() const { CHECK(isChainedOrigin()); return raw_id_ & kChainedIdMask; } u32 getStackId() const { CHECK(isStackOrigin()); return raw_id_ & kChainedIdMask; } u32 getHeapId() const { CHECK(isHeapOrigin()); return raw_id_ & kHeapIdMask; } // Returns the next origin in the chain and the current stack trace. Origin getNextChainedOrigin(StackTrace *stack) const { CHECK(isChainedOrigin()); u32 prev_id; u32 stack_id = ChainedOriginDepotGet(getChainedId(), &prev_id); if (stack) *stack = StackDepotGet(stack_id); return Origin(prev_id); } StackTrace getStackTraceForHeapOrigin() const { return StackDepotGet(getHeapId()); } static Origin CreateStackOrigin(u32 id) { CHECK((id & kStackIdMask) == id); return Origin((1 << kHeapShift) | id); } static Origin CreateHeapOrigin(StackTrace *stack) { u32 stack_id = StackDepotPut(*stack); CHECK(stack_id); CHECK((stack_id & kHeapIdMask) == stack_id); return Origin(stack_id); } static Origin CreateChainedOrigin(Origin prev, StackTrace *stack) { int depth = prev.isChainedOrigin() ? prev.depth() : 0; // depth is the length of the chain minus 1. // origin_history_size of 0 means unlimited depth. if (flags()->origin_history_size > 0) { if (depth + 1 >= flags()->origin_history_size) { return prev; } else { ++depth; CHECK(depth < (1 << kDepthBits)); } } StackDepotHandle h = StackDepotPut_WithHandle(*stack); if (!h.valid()) return prev; if (flags()->origin_history_per_stack_limit > 0) { int use_count = h.use_count(); if (use_count > flags()->origin_history_per_stack_limit) return prev; } u32 chained_id; bool inserted = ChainedOriginDepotPut(h.id(), prev.raw_id(), &chained_id); CHECK((chained_id & kChainedIdMask) == chained_id); if (inserted && flags()->origin_history_per_stack_limit > 0) h.inc_use_count_unsafe(); return Origin((1 << kHeapShift) | (depth << kDepthShift) | chained_id); } static Origin FromRawId(u32 id) { return Origin(id); } private: static const int kDepthBits = 3; static const int kDepthShift = 32 - kDepthBits - 1; static const int kHeapShift = 31; static const u32 kChainedIdMask = ((u32)-1) >> (32 - kDepthShift); static const u32 kStackIdMask = ((u32)-1) >> (32 - kDepthShift); static const u32 kHeapIdMask = ((u32)-1) >> (32 - kHeapShift); u32 raw_id_; explicit Origin(u32 raw_id) : raw_id_(raw_id) {} int depth() const { CHECK(isChainedOrigin()); return (raw_id_ >> kDepthShift) & ((1 << kDepthBits) - 1); } public: static const int kMaxDepth = (1 << kDepthBits) - 1; }; } // namespace __msan #endif // MSAN_ORIGIN_H