1 // Copyright 2021 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "Pragma.hpp"
16 #include "PragmaInternals.hpp"
17
18 #include "Debug.hpp"
19
20 // The CLANG_NO_SANITIZE_MEMORY macro suppresses MemorySanitizer checks for
21 // use-of-uninitialized-data. It is used to decorate functions with known
22 // false positives.
23 #ifdef __clang__
24 # define CLANG_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
25 #else
26 # define CLANG_NO_SANITIZE_MEMORY
27 #endif
28
29 namespace {
30
31 struct PragmaState
32 {
33 bool memorySanitizerInstrumentation = true;
34 bool initializeLocalVariables = false;
35 int optimizationLevel = 2; // Default
36 };
37
38 // The initialization of static thread-local data is not observed by MemorySanitizer
39 // when inside a shared library, leading to false-positive use-of-uninitialized-data
40 // errors: https://github.com/google/sanitizers/issues/1409
41 // We work around this by assigning an initial value to it ourselves on first use.
42 // Note that since the flag to check whether this initialization has already been
43 // done is itself a static thread-local, we must suppress the MemorySanitizer check
44 // with a function attribute.
getPragmaState()45 CLANG_NO_SANITIZE_MEMORY PragmaState &getPragmaState()
46 {
47 static thread_local bool initialized = false;
48 static thread_local PragmaState state;
49
50 if(!initialized)
51 {
52 state = {};
53
54 initialized = true;
55 }
56
57 return state;
58 }
59
60 } // namespace
61
62 namespace rr {
63
Pragma(BooleanPragmaOption option,bool enable)64 void Pragma(BooleanPragmaOption option, bool enable)
65 {
66 PragmaState &state = ::getPragmaState();
67
68 switch(option)
69 {
70 case MemorySanitizerInstrumentation:
71 state.memorySanitizerInstrumentation = enable;
72 break;
73 case InitializeLocalVariables:
74 state.initializeLocalVariables = enable;
75 break;
76 default:
77 UNSUPPORTED("Unknown Boolean pragma option %d", int(option));
78 }
79 }
80
Pragma(IntegerPragmaOption option,int value)81 void Pragma(IntegerPragmaOption option, int value)
82 {
83 PragmaState &state = ::getPragmaState();
84
85 switch(option)
86 {
87 case OptimizationLevel:
88 state.optimizationLevel = value;
89 break;
90 default:
91 UNSUPPORTED("Unknown integer pragma option %d", int(option));
92 }
93 }
94
getPragmaState(BooleanPragmaOption option)95 bool getPragmaState(BooleanPragmaOption option)
96 {
97 PragmaState &state = ::getPragmaState();
98
99 switch(option)
100 {
101 case MemorySanitizerInstrumentation:
102 return state.memorySanitizerInstrumentation;
103 case InitializeLocalVariables:
104 return state.initializeLocalVariables;
105 default:
106 UNSUPPORTED("Unknown Boolean pragma option %d", int(option));
107 return false;
108 }
109 }
110
getPragmaState(IntegerPragmaOption option)111 int getPragmaState(IntegerPragmaOption option)
112 {
113 PragmaState &state = ::getPragmaState();
114
115 switch(option)
116 {
117 case OptimizationLevel:
118 return state.optimizationLevel;
119 default:
120 UNSUPPORTED("Unknown integer pragma option %d", int(option));
121 return 0;
122 }
123 }
124
ScopedPragma(BooleanPragmaOption option,bool enable)125 ScopedPragma::ScopedPragma(BooleanPragmaOption option, bool enable)
126 {
127 oldState = BooleanPragma{ option, getPragmaState(option) };
128 Pragma(option, enable);
129 }
130
ScopedPragma(IntegerPragmaOption option,int value)131 ScopedPragma::ScopedPragma(IntegerPragmaOption option, int value)
132 {
133 oldState = IntegerPragma{ option, getPragmaState(option) };
134 Pragma(option, value);
135 }
136
~ScopedPragma()137 ScopedPragma::~ScopedPragma()
138 {
139 if(std::holds_alternative<BooleanPragma>(oldState))
140 {
141 auto &restore = std::get<BooleanPragma>(oldState);
142 Pragma(restore.option, restore.enable);
143 }
144 else
145 {
146 auto &restore = std::get<IntegerPragma>(oldState);
147 Pragma(restore.option, restore.value);
148 }
149 }
150
151 } // namespace rr