Skip to content

Commit b088747

Browse files
committed
LifetimeSanitizer changes.
1 parent 50b2544 commit b088747

File tree

7 files changed

+115
-90
lines changed

7 files changed

+115
-90
lines changed

Common/Cpp/LifetimeSanitizer.cpp

Lines changed: 80 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,12 @@ SpinLock sanitizer_lock;
3333
std::set<const LifetimeSanitizer*> sanitizer_map;
3434

3535

36-
std::atomic<bool> LifetimeSanitizer_enabled(true);
37-
bool LifetimeSanitizer_has_been_disabled = false;
36+
std::atomic<bool> LifetimeSanitizer_disabled(false);
3837

39-
void LifetimeSanitizer::set_enabled(bool enabled){
40-
if (enabled){
41-
LifetimeSanitizer_enabled.store(true, std::memory_order_relaxed);
42-
return;
43-
}
38+
void LifetimeSanitizer::disable(){
4439
WriteSpinLock lg(sanitizer_lock);
45-
LifetimeSanitizer_has_been_disabled = true;
46-
LifetimeSanitizer_enabled.store(false, std::memory_order_relaxed);
40+
LifetimeSanitizer_disabled.store(true, std::memory_order_relaxed);
41+
sanitizer_map.clear();
4742
}
4843

4944
PA_NO_INLINE void LifetimeSanitizer::terminate_with_dump(){
@@ -60,53 +55,40 @@ PA_NO_INLINE void LifetimeSanitizer::terminate_with_dump(){
6055

6156

6257

63-
LifetimeSanitizer::LifetimeSanitizer(const char* name)
64-
: m_token(SANITIZER_TOKEN)
65-
, m_self(this)
66-
, m_name(name)
67-
{
68-
if (!LifetimeSanitizer_enabled.load(std::memory_order_relaxed)){
58+
LifetimeSanitizer::LifetimeSanitizer(const char* name){
59+
if (LifetimeSanitizer_disabled.load(std::memory_order_relaxed)){
6960
return;
7061
}
71-
internal_construct();
62+
internal_construct(name);
7263
}
7364
LifetimeSanitizer::~LifetimeSanitizer(){
74-
if (!LifetimeSanitizer_enabled.load(std::memory_order_relaxed)){
75-
m_self = nullptr;
65+
if (LifetimeSanitizer_disabled.load(std::memory_order_relaxed)){
7666
return;
7767
}
7868
internal_destruct();
7969
}
8070

8171

82-
LifetimeSanitizer::LifetimeSanitizer(LifetimeSanitizer&& x)
83-
: m_token(SANITIZER_TOKEN)
84-
, m_self(this)
85-
, m_name(x.m_name)
86-
{
87-
if (!LifetimeSanitizer_enabled.load(std::memory_order_relaxed)){
72+
LifetimeSanitizer::LifetimeSanitizer(LifetimeSanitizer&& x){
73+
if (LifetimeSanitizer_disabled.load(std::memory_order_relaxed)){
8874
return;
8975
}
9076
x.check_usage();
91-
internal_construct();
77+
internal_construct(x.m_name);
9278
}
9379
void LifetimeSanitizer::operator=(LifetimeSanitizer&& x){
94-
if (!LifetimeSanitizer_enabled.load(std::memory_order_relaxed)){
80+
if (LifetimeSanitizer_disabled.load(std::memory_order_relaxed)){
9581
return;
9682
}
9783
check_usage();
9884
x.check_usage();
9985
}
100-
LifetimeSanitizer::LifetimeSanitizer(const LifetimeSanitizer& x)
101-
: m_token(SANITIZER_TOKEN)
102-
, m_self(this)
103-
, m_name(x.m_name)
104-
{
105-
if (!LifetimeSanitizer_enabled.load(std::memory_order_relaxed)){
86+
LifetimeSanitizer::LifetimeSanitizer(const LifetimeSanitizer& x){
87+
if (LifetimeSanitizer_disabled.load(std::memory_order_relaxed)){
10688
return;
10789
}
10890
x.check_usage();
109-
internal_construct();
91+
internal_construct(x.m_name);
11092
}
11193
void LifetimeSanitizer::operator=(const LifetimeSanitizer& x){
11294
check_usage();
@@ -116,72 +98,102 @@ void LifetimeSanitizer::operator=(const LifetimeSanitizer& x){
11698

11799

118100
void LifetimeSanitizer::check_usage() const{
119-
if (!LifetimeSanitizer_enabled.load(std::memory_order_relaxed)){
101+
if (LifetimeSanitizer_disabled.load(std::memory_order_relaxed)){
120102
return;
121103
}
122-
123-
if (m_token != SANITIZER_TOKEN || m_self != this){
104+
ReadSpinLock lg(sanitizer_lock);
105+
if (SANITIZER_FILTER.contains(m_name)){
106+
std::cout << "LifetimeSanitizer - Using: " << this << " : " << m_name << std::endl;
107+
}
108+
auto iter = sanitizer_map.find(this);
109+
if (iter == sanitizer_map.end()){
124110
std::cerr << "Use non-existant: " << this << " : " << m_name << std::endl;
125111
terminate_with_dump();
126112
}
127-
128-
if (LifetimeSanitizer_has_been_disabled){
113+
if (m_token != SANITIZER_TOKEN || m_self != this){
114+
std::cerr << "Use corrupted: " << this << " : " << m_name << std::endl;
115+
terminate_with_dump();
116+
}
117+
}
118+
void LifetimeSanitizer::start_using() const{
119+
if (LifetimeSanitizer_disabled.load(std::memory_order_relaxed)){
129120
return;
130121
}
131-
132122
ReadSpinLock lg(sanitizer_lock);
133123
if (SANITIZER_FILTER.contains(m_name)){
134-
std::cout << "LifetimeSanitizer - Using: " << this << " : " << m_name << std::endl;
124+
std::cout << "LifetimeSanitizer - Start using: " << this << " : " << m_name << std::endl;
135125
}
136126
auto iter = sanitizer_map.find(this);
137-
if (iter != sanitizer_map.end()){
138-
return;
127+
if (iter == sanitizer_map.end()){
128+
std::cerr << "Start using non-existant: " << this << " : " << m_name << std::endl;
129+
terminate_with_dump();
139130
}
140-
std::cerr << "Use non-existant: " << this << " : " << m_name << std::endl;
141-
terminate_with_dump();
131+
if (m_token != SANITIZER_TOKEN || m_self != this){
132+
std::cerr << "Start using corrupted: " << this << " : " << m_name << std::endl;
133+
terminate_with_dump();
134+
}
135+
m_use_counter++;
142136
}
143-
144-
145-
void LifetimeSanitizer::internal_construct(){
146-
WriteSpinLock lg(sanitizer_lock);
137+
void LifetimeSanitizer::done_using() const{
138+
if (LifetimeSanitizer_disabled.load(std::memory_order_relaxed)){
139+
return;
140+
}
141+
ReadSpinLock lg(sanitizer_lock);
147142
if (SANITIZER_FILTER.contains(m_name)){
148-
std::cout << "LifetimeSanitizer - Allocating: " << this << " : " << m_name << std::endl;
143+
std::cout << "LifetimeSanitizer - Done using: " << this << " : " << m_name << std::endl;
149144
}
150145
auto iter = sanitizer_map.find(this);
151146
if (iter == sanitizer_map.end()){
152-
sanitizer_map.insert(this);
153-
return;
147+
std::cerr << "Done using non-existant: " << this << " : " << m_name << std::endl;
148+
terminate_with_dump();
149+
}
150+
if (m_token != SANITIZER_TOKEN || m_self != this){
151+
std::cerr << "Done using corrupted: " << this << " : " << m_name << std::endl;
152+
terminate_with_dump();
154153
}
155-
std::cerr << "LifetimeSanitizer - Double allocation: " << this << " : " << m_name << std::endl;
156-
terminate_with_dump();
154+
m_use_counter--;
157155
}
158-
void LifetimeSanitizer::internal_destruct(){
159-
void* self = m_self;
160-
m_self = nullptr;
161156

157+
158+
void LifetimeSanitizer::internal_construct(const char* name){
162159
WriteSpinLock lg(sanitizer_lock);
163-
if (m_token != SANITIZER_TOKEN || self != this){
164-
std::cerr << "LifetimeSanitizer - Free non-existant: " << this << " : " << m_name << std::endl;
160+
if (SANITIZER_FILTER.contains(name)){
161+
std::cout << "LifetimeSanitizer - Allocating: " << this << " : " << name << std::endl;
162+
}
163+
164+
auto iter = sanitizer_map.find(this);
165+
if (iter != sanitizer_map.end()){
166+
std::cerr << "LifetimeSanitizer - Double allocation: " << this << " : " << name << std::endl;
165167
terminate_with_dump();
166168
}
169+
sanitizer_map.insert(this);
167170

171+
m_token = SANITIZER_TOKEN;
172+
m_self = this;
173+
m_name = name;
174+
}
175+
void LifetimeSanitizer::internal_destruct(){
176+
WriteSpinLock lg(sanitizer_lock);
168177
if (SANITIZER_FILTER.contains(m_name)){
169178
std::cout << "LifetimeSanitizer - Freeing: " << this << " : " << m_name << std::endl;
170179
}
180+
171181
auto iter = sanitizer_map.find(this);
172-
if (iter != sanitizer_map.end()){
173-
sanitizer_map.erase(this);
174-
return;
182+
if (iter == sanitizer_map.end()){
183+
std::cerr << "LifetimeSanitizer - Free non-existant: " << this << " : " << m_name << std::endl;
184+
terminate_with_dump();
175185
}
186+
sanitizer_map.erase(this);
176187

177-
// Skip this check if we've been disabled before in case there's stuff we
178-
// haven't tracked.
179-
if (LifetimeSanitizer_has_been_disabled){
180-
return;
188+
if (m_token != SANITIZER_TOKEN || m_self != this){
189+
std::cerr << "LifetimeSanitizer - Free non-existant: " << this << " : " << m_name << std::endl;
190+
terminate_with_dump();
181191
}
182-
183-
std::cerr << "LifetimeSanitizer - Free non-existant: " << this << " : " << m_name << std::endl;
184-
terminate_with_dump();
192+
if (m_use_counter != 0){
193+
std::cerr << "LifetimeSanitizer - Freeing while in-use: " << this << " : " << m_name << std::endl;
194+
terminate_with_dump();
195+
}
196+
m_self = nullptr;
185197
}
186198

187199

Common/Cpp/LifetimeSanitizer.h

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,31 +56,39 @@ class LifetimeSanitizer{
5656
};
5757

5858
void check_usage() const;
59+
void start_using() const;
60+
void done_using() const;
5961
CheckScope check_scope() const{
6062
return CheckScope(*this);
6163
}
6264

63-
static void set_enabled(bool enabled);
64-
static void terminate_with_dump();
65-
65+
static void disable();
6666

6767

6868
private:
69-
void internal_construct();
69+
static void terminate_with_dump();
70+
void internal_construct(const char* name);
7071
void internal_destruct();
7172

73+
7274
private:
7375
uint64_t m_token;
7476
void* m_self;
7577
const char* m_name;
78+
mutable size_t m_use_counter = 0;
7679
};
7780

7881

7982
#else
8083
class LifetimeSanitizer{
8184
public:
8285
void check_usage() const{}
83-
static void set_enabled(bool enabled){}
86+
static void disable(){}
87+
88+
using CheckScope = bool;
89+
CheckScope check_scope() const{
90+
return false;
91+
}
8492
};
8593
#endif
8694

Common/Cpp/Options/ConfigOption.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,17 +63,17 @@ ConfigOption::ConfigOption(ConfigOptionState visibility)
6363
{}
6464

6565
void ConfigOption::add_listener(Listener& listener){
66-
m_lifetime_sanitizer.check_usage();
66+
auto scope = m_lifetime_sanitizer.check_scope();
6767
Data& data = *m_data;
6868
data.listeners.add(listener);
6969
}
7070
void ConfigOption::remove_listener(Listener& listener){
71-
m_lifetime_sanitizer.check_usage();
71+
auto scope = m_lifetime_sanitizer.check_scope();
7272
Data& data = *m_data;
7373
data.listeners.remove(listener);
7474
}
7575
size_t ConfigOption::total_listeners() const{
76-
m_lifetime_sanitizer.check_usage();
76+
auto scope = m_lifetime_sanitizer.check_scope();
7777
const Data& data = *m_data;
7878
return data.listeners.count_unique();
7979
}
@@ -105,25 +105,25 @@ ConfigOptionState ConfigOption::visibility() const{
105105
return m_data->visibility.load(std::memory_order_relaxed);
106106
}
107107
void ConfigOption::set_visibility(ConfigOptionState visibility){
108-
m_lifetime_sanitizer.check_usage();
108+
auto scope = m_lifetime_sanitizer.check_scope();
109109
if (m_data->set_visibility(visibility)){
110110
report_visibility_changed();
111111
}
112112
}
113113

114114

115115
void ConfigOption::report_visibility_changed(){
116-
m_lifetime_sanitizer.check_usage();
116+
auto scope = m_lifetime_sanitizer.check_scope();
117117
Data& data = *m_data;
118118
data.listeners.run_method_unique(&Listener::visibility_changed);
119119
}
120120
void ConfigOption::report_program_state(bool program_is_running){
121-
m_lifetime_sanitizer.check_usage();
121+
auto scope = m_lifetime_sanitizer.check_scope();
122122
Data& data = *m_data;
123123
data.listeners.run_method_unique(&Listener::program_state_changed, program_is_running);
124124
}
125125
void ConfigOption::report_value_changed(void* object){
126-
m_lifetime_sanitizer.check_usage();
126+
auto scope = m_lifetime_sanitizer.check_scope();
127127
Data& data = *m_data;
128128
data.listeners.run_method_unique(&Listener::value_changed, object);
129129
}

Common/Cpp/Options/ConfigOption.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ class ConfigOption{
7373
void check_usage() const{
7474
m_lifetime_sanitizer.check_usage();
7575
}
76+
LifetimeSanitizer::CheckScope check_scope() const{
77+
return m_lifetime_sanitizer.check_scope();
78+
}
7679

7780
public:
7881
LockMode lock_mode() const;

Common/Qt/Options/ConfigWidget.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ ConfigWidget::ConfigWidget(ConfigOption& m_value, QWidget& widget)
3232
m_value.add_listener(*this);
3333
}
3434
void ConfigWidget::update_visibility(){
35+
auto scope = m_value.check_scope();
3536
m_value.check_usage();
3637
if (m_widget == nullptr){
3738
return;
@@ -59,24 +60,24 @@ void ConfigWidget::update_visibility(){
5960
}
6061
}
6162
void ConfigWidget::update_visibility(bool program_is_running){
62-
m_value.check_usage();
63+
auto scope = m_value.check_scope();
6364
m_program_is_running = program_is_running;
6465
update_visibility();
6566
}
6667
void ConfigWidget::update_all(bool program_is_running){
67-
m_value.check_usage();
68+
auto scope = m_value.check_scope();
6869
update_value();
6970
update_visibility(program_is_running);
7071
}
7172

7273
void ConfigWidget::visibility_changed(){
73-
m_value.check_usage();
74+
auto scope = m_value.check_scope();
7475
QMetaObject::invokeMethod(m_widget, [this]{
7576
update_visibility();
7677
}, Qt::QueuedConnection);
7778
}
7879
void ConfigWidget::program_state_changed(bool program_is_running){
79-
m_value.check_usage();
80+
auto scope = m_value.check_scope();
8081
QMetaObject::invokeMethod(m_widget, [this, program_is_running]{
8182
update_visibility(program_is_running);
8283
}, Qt::QueuedConnection);

SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ GlobalSettings::GlobalSettings()
166166
, VIDEO_PIPELINE(CONSTRUCT_TOKEN)
167167
, ENABLE_LIFETIME_SANITIZER0(
168168
"<b>Enable Lifetime Sanitizer: (for debugging)</b><br>"
169-
"Check for C++ object lifetime violations. Terminate program with stack dump if violations are found.",
169+
"Check for C++ object lifetime violations. Terminate program with stack dump if violations are found. "
170+
"If enabling, you must restart the program for it to take effect.",
170171
LockMode::UNLOCK_WHILE_RUNNING,
171172
true
172173
// IS_BETA_VERSION
@@ -337,11 +338,11 @@ JsonValue GlobalSettings::to_json() const{
337338

338339
void GlobalSettings::value_changed(void* object){
339340
bool enabled = ENABLE_LIFETIME_SANITIZER0;
340-
LifetimeSanitizer::set_enabled(enabled);
341341
if (enabled){
342342
global_logger_tagged().log("LifeTime Sanitizer: Enabled", COLOR_BLUE);
343343
}else{
344344
global_logger_tagged().log("LifeTime Sanitizer: Disabled", COLOR_BLUE);
345+
LifetimeSanitizer::disable();
345346
}
346347
}
347348

0 commit comments

Comments
 (0)