1//===-- copyprof_state.h ----------------------------------------*- C++ -*-===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8///
9/// This file declares the per-thread and per-object state structures used to
10/// track special member function nesting and dynamic memory allocations.
11///
12//===----------------------------------------------------------------------===//
13
14#ifndef COPYPROF_STATE_H
15#define COPYPROF_STATE_H
16
17#include "sanitizer_common/sanitizer_internal_defs.h"
18
19namespace __copyprof {
20
21// Determines the special member function (SMF) execution context of a thread,
22// dictating how stores and allocations affect shadow memory.
23// The first time control flow reaches the entry point of a special member
24// function, the current SMF context is changed accordingly.
25// A copy c'tor or copy assignment operator sets the context to `COPY`, a c'tor
26// to `CTOR`, and a d'tor to `DTOR`.
27// In the `COPY` context, shadow memory is marked as copy.
28// In the `CTOR` context, shadow memory is marked as non-copy.
29// In the `DTOR` context, no shadow memory is updated at all (to
30// avoid false negatives during destruction). Once control flow leaves (any
31// nested) special member functions, the context is set to `NONE`. In this
32// state, any stores mark shadow memory as non-copy.
33enum class SmfContext : u8 {
34 NONE,
35 CTOR,
36 COPY,
37 DTOR,
38};
39
40// CopyProf uses per-thread state to figure out whether control flow is
41// currently inside a special member function, and adapts updating of shadow
42// memory accordingly (see SmfContext). Since special member functions can
43// nest arbitrarily, this state needs to be kept across function calls, so this
44// state is stored in TLS. The nesting level counters are used to determine
45// whether a top-level (i.e. the first in the call stack of special member
46// functions) special member function has been reached.
47struct PerThreadState {
48 u32 construct_nesting_level = 0;
49 u32 copy_nesting_level = 0;
50 u32 destruct_nesting_level = 0;
51 SmfContext smf_context = SmfContext::NONE;
52 // Whether all transitively reachable d'tors from the top-level d'tor have
53 // observed copies.
54 bool is_transitive_copy = false;
55 // When control flow enters a special member function, this is set to the
56 // `this` pointer of the current object. This is used to look up the
57 // per-object state outside of special member functions (e.g. when allocating
58 // memory).
59 const void* current_this_ptr = nullptr;
60};
61
62// The runtime is always linked into the main executable, so the state can be
63// reached with the initial-exec model instead of paying for a __tls_get_addr
64// call on every access.
65__attribute__((tls_model(
66 "initial-exec"))) extern THREADLOCAL PerThreadState __copyprof_state;
67
68} // namespace __copyprof
69
70#endif // COPYPROF_STATE_H
71