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