1 //===-- dfsan_origin.h ----------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file is a part of DataFlowSanitizer.
12 //===----------------------------------------------------------------------===//
14 #ifndef DFSAN_ORIGIN_H
15 #define DFSAN_ORIGIN_H
17 #include "dfsan_chained_origin_depot.h"
18 #include "dfsan_flags.h"
19 #include "sanitizer_common/sanitizer_stackdepot.h"
25 // Origin is a 32-bit identifier that is attached to any taint value in the
26 // program and describes how this memory came to be tainted.
28 // Chained origin id is like:
29 // zzzz xxxx xxxx xxxx
31 // Chained origin id describes an event of storing a taint value to
32 // memory. The xxx part is a value of ChainedOriginDepot, which is a mapping of
33 // (stack_id, prev_id) -> id, where
34 // * stack_id describes the event.
35 // StackDepot keeps a mapping between those and corresponding stack traces.
36 // * prev_id is another origin id that describes the earlier part of the
37 // taint value history. 0 prev_id indicates the start of a chain.
38 // Following a chain of prev_id provides the full recorded history of a taint
41 // This, effectively, defines a forest where nodes are points in value history
42 // marked with origin ids, and edges are events that are marked with stack_id.
44 // The "zzzz" bits of chained origin id are used to store the length of the
49 static bool isValidId(u32 id
) { return id
!= 0; }
51 u32
raw_id() const { return raw_id_
; }
53 bool isChainedOrigin() const { return Origin::isValidId(raw_id_
); }
55 u32
getChainedId() const {
56 CHECK(Origin::isValidId(raw_id_
));
57 return raw_id_
& kChainedIdMask
;
60 // Returns the next origin in the chain and the current stack trace.
62 // It scans a partition of StackDepot linearly, and is used only by origin
64 Origin
getNextChainedOrigin(StackTrace
*stack
) const {
65 CHECK(Origin::isValidId(raw_id_
));
67 u32 stack_id
= GetChainedOriginDepot()->Get(getChainedId(), &prev_id
);
69 *stack
= StackDepotGet(stack_id
);
70 return Origin(prev_id
);
73 static Origin
CreateChainedOrigin(Origin prev
, StackTrace
*stack
) {
74 int depth
= prev
.isChainedOrigin() ? prev
.depth() : -1;
75 // depth is the length of the chain minus 1.
76 // origin_history_size of 0 means unlimited depth.
77 if (flags().origin_history_size
> 0) {
79 if (depth
>= flags().origin_history_size
|| depth
> kMaxDepth
)
83 StackDepotHandle h
= StackDepotPut_WithHandle(*stack
);
87 if (flags().origin_history_per_stack_limit
> 0) {
88 int use_count
= h
.use_count();
89 if (use_count
> flags().origin_history_per_stack_limit
)
95 GetChainedOriginDepot()->Put(h
.id(), prev
.raw_id(), &chained_id
);
96 CHECK((chained_id
& kChainedIdMask
) == chained_id
);
98 if (inserted
&& flags().origin_history_per_stack_limit
> 0)
99 h
.inc_use_count_unsafe();
101 return Origin((depth
<< kDepthShift
) | chained_id
);
104 static Origin
FromRawId(u32 id
) { return Origin(id
); }
107 static const int kDepthBits
= 4;
108 static const int kDepthShift
= 32 - kDepthBits
;
110 static const u32 kChainedIdMask
= ((u32
)-1) >> kDepthBits
;
114 explicit Origin(u32 raw_id
) : raw_id_(raw_id
) {}
117 CHECK(isChainedOrigin());
118 return (raw_id_
>> kDepthShift
) & ((1 << kDepthBits
) - 1);
122 static const int kMaxDepth
= (1 << kDepthBits
) - 1;
125 } // namespace __dfsan
127 #endif // DFSAN_ORIGIN_H