@ohos-graphics/stability-code-review 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +169 -0
  2. package/SKILL.md +518 -0
  3. package/bin/install.js +165 -0
  4. package/config/rules.yaml +445 -0
  5. package/config/whitelist.yaml +52 -0
  6. package/package.json +40 -0
  7. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_001.md +275 -0
  8. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_002.md +273 -0
  9. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_003.md +305 -0
  10. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_004.md +350 -0
  11. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_005.md +301 -0
  12. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_006.md +320 -0
  13. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_007.md +432 -0
  14. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_008.md +394 -0
  15. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_009.md +425 -0
  16. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_010.md +472 -0
  17. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_011.md +204 -0
  18. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_012.md +210 -0
  19. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_013.md +226 -0
  20. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_014.md +222 -0
  21. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_015.md +256 -0
  22. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_016.md +269 -0
  23. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_017.md +222 -0
  24. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_018.md +336 -0
  25. package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_001.md +414 -0
  26. package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_002.md +335 -0
  27. package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_003.md +284 -0
  28. package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_004.md +313 -0
  29. package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_005.md +364 -0
  30. package/references/ExceptionHandling/StabilityCodeReview_ExceptionHandling_001.md +142 -0
  31. package/references/ExceptionHandling/StabilityCodeReview_ExceptionHandling_002.md +222 -0
  32. package/references/ExceptionHandling/StabilityCodeReview_ExceptionHandling_003.md +383 -0
  33. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_001.md +258 -0
  34. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_002.md +131 -0
  35. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_003.md +220 -0
  36. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_004.md +224 -0
  37. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_005.md +250 -0
  38. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_006.md +153 -0
  39. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_007.md +169 -0
  40. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_008.md +153 -0
  41. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_009.md +144 -0
  42. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_010.md +152 -0
  43. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_011.md +221 -0
  44. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_012.md +318 -0
  45. package/references/InitializationOrder/StabilityCodeReview_InitializationOrder_001.md +411 -0
  46. package/references/Lifecycle/StabilityCodeReview_Lifecycle_001.md +255 -0
  47. package/references/Lifecycle/StabilityCodeReview_Lifecycle_002.md +177 -0
  48. package/references/MemoryStability/StabilityCodeReview_MemoryStability_001.md +332 -0
  49. package/references/MemoryStability/StabilityCodeReview_MemoryStability_002.md +261 -0
  50. package/references/MemoryStability/StabilityCodeReview_MemoryStability_003.md +428 -0
  51. package/references/MemoryStability/StabilityCodeReview_MemoryStability_004.md +400 -0
  52. package/references/MemoryStability/StabilityCodeReview_MemoryStability_005.md +364 -0
  53. package/references/MemoryStability/StabilityCodeReview_MemoryStability_006.md +359 -0
  54. package/references/MemoryStability/StabilityCodeReview_MemoryStability_007.md +279 -0
  55. package/references/PROBLEM_TEMPLATE.md +65 -0
  56. package/references/PerformanceStability/StabilityCodeReview_PerformanceStability_001.md +380 -0
  57. package/references/PerformanceStability/StabilityCodeReview_PerformanceStability_002.md +437 -0
  58. package/references/REPORT_TEMPLATE.csv +5 -0
  59. package/references/REPORT_TEMPLATE.md +132 -0
  60. package/references/RULE_DEVELOPMENT_GUIDE.md +711 -0
  61. package/references/RULE_INDEX.md +101 -0
  62. package/references/RULE_TEMPLATE.md +192 -0
  63. package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_001.md +334 -0
  64. package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_002.md +425 -0
  65. package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_003.md +420 -0
  66. package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_004.md +409 -0
  67. package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_005.md +445 -0
  68. package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_006.md +384 -0
  69. package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_007.md +395 -0
  70. package/scripts/add-rule.py +423 -0
@@ -0,0 +1,313 @@
1
+ ---
2
+ rule_id: "StabilityCodeReview_ConcurrencyStability_004"
3
+ name: "加锁后返回引用或裸指针问题"
4
+ category: "并发稳定性"
5
+ severity: "HIGH"
6
+ language: ["cpp", "c++"]
7
+ author: "OH-Department7 Stability Team"
8
+ ---
9
+
10
+ # 加锁后返回引用或裸指针问题
11
+
12
+ ## 问题描述
13
+
14
+ 加锁后返回引用类型或裸指针类型极易引入并发风险或内存风险,应避免使用。当函数在持有锁的情况下返回受保护数据的引用或裸指针时,锁会在函数返回后立即释放,而返回的引用或指针却可以让外部代码无锁访问受保护的数据,导致数据竞争或内存安全问题。
15
+
16
+ ## 检测示例
17
+
18
+ ### ❌ 问题代码
19
+
20
+ ```cpp
21
+ // 错误示例1:加锁后返回引用
22
+ class ThreadSafeContainer {
23
+ public:
24
+ Data& GetData() {
25
+ std::lock_guard<std::mutex> lock(mutex_);
26
+ return data_; // 危险:锁释放后,外部可通过引用无锁访问
27
+ }
28
+ private:
29
+ Data data_;
30
+ std::mutex mutex_;
31
+ };
32
+
33
+ // 错误示例2:加锁后返回指针
34
+ class ProtectedResource {
35
+ public:
36
+ Resource* GetResource() {
37
+ std::lock_guard<std::mutex> lock(mutex_);
38
+ return &resource_; // 危险:锁释放后,外部可通过指针无锁访问
39
+ }
40
+ private:
41
+ Resource resource_;
42
+ std::mutex mutex_;
43
+ };
44
+
45
+ // 错误示例3:加锁范围内返回容器元素的引用
46
+ class SafeMap {
47
+ public:
48
+ std::string& GetValue(int key) {
49
+ std::lock_guard<std::mutex> lock(mutex_);
50
+ auto it = map_.find(key);
51
+ if (it != map_.end()) {
52
+ return it->second; // 危险:返回map元素的引用
53
+ }
54
+ static std::string empty;
55
+ return empty;
56
+ }
57
+ private:
58
+ std::map<int, std::string> map_;
59
+ std::mutex mutex_;
60
+ };
61
+
62
+ // 错误示例4:返回内部数组的指针
63
+ class BufferManager {
64
+ public:
65
+ char* GetBuffer() {
66
+ std::lock_guard<std::mutex> lock(mutex_);
67
+ return buffer_; // 危险:返回内部buffer的指针
68
+ }
69
+ private:
70
+ char buffer_[1024];
71
+ std::mutex mutex_;
72
+ };
73
+
74
+ // 错误示例5:Getter返回成员指针
75
+ class SharedData {
76
+ public:
77
+ Data* GetData() const {
78
+ std::lock_guard<std::mutex> lock(mutex_);
79
+ return data_; // 危险:data_可能在锁释放后被其他线程修改
80
+ }
81
+ private:
82
+ Data* data_;
83
+ mutable std::mutex mutex_;
84
+ };
85
+
86
+ // 错误示例6:返回迭代器
87
+ class ThreadSafeList {
88
+ public:
89
+ std::list<int>::iterator GetIterator() {
90
+ std::lock_guard<std::mutex> lock(mutex_);
91
+ return list_.begin(); // 危险:迭代器在锁释放后使用可能导致崩溃
92
+ }
93
+ private:
94
+ std::list<int> list_;
95
+ std::mutex mutex_;
96
+ };
97
+ ```
98
+
99
+ ### ✅ 修复方案
100
+
101
+ ```cpp
102
+ // 正确示例1:返回值拷贝而非引用
103
+ class ThreadSafeContainer {
104
+ public:
105
+ Data GetData() { // 返回拷贝
106
+ std::lock_guard<std::mutex> lock(mutex_);
107
+ return data_; // 安全:返回副本,外部无法修改内部数据
108
+ }
109
+ private:
110
+ Data data_;
111
+ std::mutex mutex_;
112
+ };
113
+
114
+ // 正确示例2:返回智能指针
115
+ class ProtectedResource {
116
+ public:
117
+ std::shared_ptr<Resource> GetResource() {
118
+ std::lock_guard<std::mutex> lock(mutex_);
119
+ return resourcePtr_; // 安全:引用计数原子增加,资源生命周期延长
120
+ }
121
+ private:
122
+ std::shared_ptr<Resource> resourcePtr_;
123
+ std::mutex mutex_;
124
+ };
125
+
126
+ // 正确示例3:返回字符串副本
127
+ class SafeMap {
128
+ public:
129
+ std::string GetValue(int key) {
130
+ std::lock_guard<std::mutex> lock(mutex_);
131
+ auto it = map_.find(key);
132
+ if (it != map_.end()) {
133
+ return it->second; // 安全:返回副本
134
+ }
135
+ return "";
136
+ }
137
+ private:
138
+ std::map<int, std::string> map_;
139
+ std::mutex mutex_;
140
+ };
141
+
142
+ // 正确示例4:提供带锁的访问接口
143
+ class ThreadSafeContainer {
144
+ public:
145
+ template<typename Func>
146
+ void WithData(Func func) {
147
+ std::lock_guard<std::mutex> lock(mutex_);
148
+ func(data_); // 安全:在整个回调期间持有锁
149
+ }
150
+ private:
151
+ Data data_;
152
+ std::mutex mutex_;
153
+ };
154
+
155
+ // 使用示例:
156
+ container.WithData([](Data& data) {
157
+ data.Process(); // 在锁保护下操作
158
+ });
159
+
160
+ // 正确示例5:返回const引用配合外部锁管理
161
+ class SharedData {
162
+ public:
163
+ const Data& GetData(std::unique_lock<std::mutex>& lock) {
164
+ lock = std::unique_lock<std::mutex>(mutex_);
165
+ return data_; // 安全:调用者持有锁
166
+ }
167
+ private:
168
+ Data data_;
169
+ std::mutex mutex_;
170
+ };
171
+
172
+ // 使用示例:
173
+ std::unique_lock<std::mutex> lock;
174
+ const Data& data = sharedData.GetData(lock);
175
+ data.Process(); // lock仍然持有
176
+
177
+ // 正确示例6:使用pimpl模式隐藏实现
178
+ class ThreadSafeData {
179
+ public:
180
+ DataAccessor Access();
181
+ private:
182
+ class Impl;
183
+ std::unique_ptr<Impl> impl_;
184
+ };
185
+
186
+ // DataAccessor在析构时自动释放锁
187
+ class DataAccessor {
188
+ public:
189
+ Data& Get() { return *data_; }
190
+ ~DataAccessor() { lock_.unlock(); }
191
+ private:
192
+ std::unique_lock<std::mutex> lock_;
193
+ Data* data_;
194
+ };
195
+ ```
196
+
197
+ ## 检测范围
198
+
199
+ 检查以下场景:
200
+
201
+ 1. 加锁范围内返回引用
202
+ 2. 加锁范围内返回裸指针
203
+ 3. Getter函数返回受保护数据的引用/指针
204
+ 4. 返回容器元素的引用/指针
205
+ 5. 返回迭代器
206
+
207
+ ## 检测要点
208
+
209
+ 1. 识别lock_guard、unique_lock等锁的使用
210
+ 2. 检测return语句返回引用(&)或指针(*)
211
+ 3. 分析返回值是否指向受保护的数据
212
+ 4. 检查Getter函数的返回类型
213
+ 5. 识别返回容器元素引用的模式
214
+
215
+ ## 风险流分析(RiskFlow)
216
+
217
+ - **RISK_SOURCE**: 加锁后返回引用或裸指针绕过锁保护
218
+ - **RISK_TYPE**: 锁失效、数据竞争
219
+ - **RISK_PATH**: 返回引用/指针 -> 锁释放 -> 外部无锁访问 -> 数据竞争
220
+ - **IMPACT_POINT**: 数据损坏、内存错误、程序崩溃
221
+
222
+ ## 影响分析(ImpactAnalysis)
223
+
224
+ - **Trigger**: 外部代码通过返回的引用/指针访问数据
225
+ - **Propagation**: 锁已释放,数据无保护
226
+ - **Consequence**: 数据竞争、内存损坏、程序崩溃
227
+ - **Mitigation**: 返回值拷贝或使用智能指针,或将锁管理权转移给调用者
228
+
229
+ ## 误报排除
230
+
231
+ | 场景 | 识别特征 | 处理方式 |
232
+ |------|----------|----------|
233
+ | NOPROTECT 标记 | 有 // NOPROTECT 注释 | 不报 |
234
+ | 返回值拷贝 | 返回非引用/指针类型 | 不报 |
235
+ | 返回智能指针 | 返回 shared_ptr 等 | 不报 |
236
+ | 锁转移设计 | 返回 unique_lock 等 | 不报 |
237
+ | 返回局部变量 | 返回函数内局部变量引用 | 不报(不同问题) |
238
+ ## 测试用例
239
+
240
+ ### 触发用例(应该报)
241
+
242
+ ```cpp
243
+ class ThreadSafeContainer {
244
+ public:
245
+ Data& GetData() {
246
+ std::lock_guard<std::mutex> lock(mutex_);
247
+ return data_; // 应该报:加锁后返回引用
248
+ }
249
+ private:
250
+ Data data_;
251
+ std::mutex mutex_;
252
+ };
253
+
254
+ class ProtectedResource {
255
+ public:
256
+ Resource* GetResource() {
257
+ std::lock_guard<std::mutex> lock(mutex_);
258
+ return &resource_; // 应该报:加锁后返回指针
259
+ }
260
+ private:
261
+ Resource resource_;
262
+ std::mutex mutex_;
263
+ };
264
+
265
+ class SafeMap {
266
+ public:
267
+ std::string& GetValue(int key) {
268
+ std::lock_guard<std::mutex> lock(mutex_);
269
+ return map_[key]; // 应该报:返回map元素引用
270
+ }
271
+ private:
272
+ std::map<int, std::string> map_;
273
+ std::mutex mutex_;
274
+ };
275
+ ```
276
+
277
+ ### 安全用例(不应该报)
278
+
279
+ ```cpp
280
+ class ThreadSafeContainer {
281
+ public:
282
+ Data GetData() {
283
+ std::lock_guard<std::mutex> lock(mutex_);
284
+ return data_; // 安全:返回值拷贝
285
+ }
286
+ private:
287
+ Data data_;
288
+ std::mutex mutex_;
289
+ };
290
+
291
+ class ProtectedResource {
292
+ public:
293
+ std::shared_ptr<Resource> GetResource() {
294
+ std::lock_guard<std::mutex> lock(mutex_);
295
+ return resourcePtr_; // 安全:返回智能指针
296
+ }
297
+ private:
298
+ std::shared_ptr<Resource> resourcePtr_;
299
+ std::mutex mutex_;
300
+ };
301
+
302
+ template<typename Func>
303
+ void WithData(Func func) {
304
+ std::lock_guard<std::mutex> lock(mutex_);
305
+ func(data_); // 安全:回调期间持有锁
306
+ }
307
+
308
+ // NOPROTECT: 数据本身不可变,返回引用安全
309
+ const Data& GetDataConst() {
310
+ std::lock_guard<std::mutex> lock(mutex_);
311
+ return constData_; // 不报:明确标记
312
+ }
313
+ ```
@@ -0,0 +1,364 @@
1
+ ---
2
+ rule_id: "StabilityCodeReview_ConcurrencyStability_005"
3
+ name: "RenderNodeDrawable全局变量写入问题"
4
+ category: "并发稳定性"
5
+ severity: "HIGH"
6
+ language: ["cpp", "c++"]
7
+ author: "OH-Department7 Stability Team"
8
+ ---
9
+
10
+ # RenderNodeDrawable全局变量写入问题
11
+
12
+ ## 问题描述
13
+
14
+ RenderNodeDrawable是渲染系统中的关键组件,在多线程渲染场景下,应避免写入全局变量。若必须使用全局变量,则应加锁保护避免并发问题。渲染线程可能并发执行,对全局变量的无锁写入会导致数据竞争、渲染异常、画面闪烁等严重问题。
15
+
16
+ ## 检测示例
17
+
18
+ ### ❌ 问题代码
19
+
20
+ ```cpp
21
+ // 错误示例1:RenderNodeDrawable中写入全局变量
22
+ class RenderNodeDrawable {
23
+ public:
24
+ void Draw() {
25
+ g_renderCount++; // 危险:多线程并发写入全局计数
26
+ ProcessDraw();
27
+ }
28
+ private:
29
+ void ProcessDraw() {
30
+ g_currentDrawable = this; // 危险:多线程并发设置全局指针
31
+ }
32
+ };
33
+
34
+ // 错误示例2:修改全局容器
35
+ class RenderNodeDrawable {
36
+ public:
37
+ void Draw() {
38
+ g_drawableList.push_back(this); // 危险:多线程并发push
39
+ Render();
40
+ }
41
+
42
+ void Clear() {
43
+ g_drawableList.clear(); // 危险:多线程并发clear
44
+ }
45
+ };
46
+
47
+ // 错误示例3:写入静态成员变量
48
+ class RenderNodeDrawable {
49
+ public:
50
+ static int s_totalNodes;
51
+
52
+ void Draw() {
53
+ s_totalNodes++; // 危险:多线程并发修改静态成员
54
+ }
55
+ };
56
+
57
+ // 错误示例4:全局缓存写入
58
+ class RenderNodeDrawable {
59
+ public:
60
+ void Draw() {
61
+ g_cache[key] = value; // 危险:多线程并发写入全局缓存
62
+ UseCache();
63
+ }
64
+ };
65
+
66
+ // 错误示例5:回调中写入全局状态
67
+ class RenderNodeDrawable {
68
+ public:
69
+ void OnRenderComplete() {
70
+ g_lastRenderTime = GetCurrentTime(); // 危险:回调可能并发执行
71
+ g_renderStatus = "completed"; // 危险:多线程并发写入
72
+ }
73
+ };
74
+
75
+ // 错误示例6:全局资源池修改
76
+ class RenderNodeDrawable {
77
+ public:
78
+ void AllocateResource() {
79
+ g_resourcePool.erase(id); // 危险:多线程并发erase
80
+ allocated_ = true;
81
+ }
82
+ };
83
+ ```
84
+
85
+ ### ✅ 修复方案
86
+
87
+ ```cpp
88
+ // 正确示例1:使用成员变量替代全局变量
89
+ class RenderNodeDrawable {
90
+ public:
91
+ void Draw() {
92
+ renderCount_++; // 安全:使用成员变量
93
+ ProcessDraw();
94
+ }
95
+ private:
96
+ int renderCount_ = 0; // 每个实例独立计数
97
+ };
98
+
99
+ // 正确示例2:使用mutex保护全局变量
100
+ class RenderNodeDrawable {
101
+ public:
102
+ void Draw() {
103
+ {
104
+ std::lock_guard<std::mutex> lock(g_renderMutex);
105
+ g_renderCount++; // 安全:有锁保护
106
+ }
107
+ ProcessDraw();
108
+ }
109
+ };
110
+
111
+ // 正确示例3:使用atomic计数器
112
+ std::atomic<int> g_atomicRenderCount{0};
113
+
114
+ class RenderNodeDrawable {
115
+ public:
116
+ void Draw() {
117
+ g_atomicRenderCount.fetch_add(1, std::memory_order_relaxed); // 安全:atomic操作
118
+ ProcessDraw();
119
+ }
120
+ };
121
+
122
+ // 正确示例4:使用thread_local变量
123
+ thread_local int t_localCounter = 0;
124
+
125
+ class RenderNodeDrawable {
126
+ public:
127
+ void Draw() {
128
+ t_localCounter++; // 安全:thread_local变量
129
+ ProcessDraw();
130
+ }
131
+ };
132
+
133
+ // 正确示例5:使用线程安全容器
134
+ class RenderNodeDrawable {
135
+ public:
136
+ void Draw() {
137
+ std::lock_guard<std::mutex> lock(g_listMutex);
138
+ g_drawableList.push_back(this); // 安全:有锁保护
139
+ Render();
140
+ }
141
+ };
142
+
143
+ // 正确示例6:使用局部变量和返回值
144
+ class RenderNodeDrawable {
145
+ public:
146
+ RenderStats GetStats() const {
147
+ return stats_; // 安全:返回局部状态
148
+ }
149
+ private:
150
+ RenderStats stats_; // 成员变量,线程安全
151
+ };
152
+
153
+ // 正确示例7:避免全局状态,使用参数传递
154
+ class RenderNodeDrawable {
155
+ public:
156
+ void Draw(RenderContext& context) {
157
+ context.nodeCount++; // 安全:context由调用者管理
158
+ ProcessDraw(context);
159
+ }
160
+ };
161
+
162
+ // 正确示例8:静态atomic成员是线程安全的
163
+ class RenderNodeDrawable {
164
+ public:
165
+ static inline std::atomic<int> totalProcessedNodeCount_{0};
166
+
167
+ static void TotalProcessedNodeCountInc()
168
+ {
169
+ totalProcessedNodeCount_++; // 安全:静态atomic成员,无需额外锁
170
+ }
171
+
172
+ static int GetTotalProcessedNodeCount()
173
+ {
174
+ return totalProcessedNodeCount_.load();
175
+ }
176
+ };
177
+
178
+ // 正确示例9:静态成员使用mutex保护
179
+ class RenderNodeDrawable {
180
+ public:
181
+ static inline std::mutex drawingCacheInfoMutex_;
182
+ static inline std::unordered_map<NodeId, std::pair<RectI, int32_t>> drawingCacheInfos_;
183
+
184
+ void UpdateCacheInfo(NodeId id, const RectI& rect)
185
+ {
186
+ std::lock_guard<std::mutex> lock(drawingCacheInfoMutex_);
187
+ drawingCacheInfos_[id] = {rect, 0}; // 安全:静态mutex保护静态数据
188
+ }
189
+ };
190
+
191
+ // 正确示例10:thread_local静态成员,每个线程独立
192
+ class RenderNodeDrawable {
193
+ public:
194
+ static thread_local bool isOpDropped_;
195
+ static thread_local bool occlusionCullingEnabled_;
196
+ static thread_local inline int processedNodeCount_ = 0;
197
+
198
+ void Draw() {
199
+ processedNodeCount_++; // 安全:thread_local,每个渲染线程独立计数
200
+ isOpDropped_ = false; // 安全:thread_local
201
+ ProcessDraw();
202
+ }
203
+ };
204
+ ```
205
+
206
+ ## 检测范围
207
+
208
+ 检查以下场景:
209
+
210
+ 1. RenderNodeDrawable类中写入全局变量(g_开头)
211
+ 2. RenderNodeDrawable类中写入静态成员变量(s_开头)
212
+ 3. RenderNodeDrawable修改全局容器
213
+ 4. 渲染回调函数中写入全局状态
214
+ 5. RenderNodeDrawable::Draw等渲染函数中的全局写入
215
+
216
+ ## 检测要点
217
+
218
+ 1. 识别RenderNodeDrawable类/结构体
219
+ 2. 检测全局变量写入(g_变量赋值、++等)
220
+ 3. 检测静态成员变量写入
221
+ 4. 检测全局容器修改操作
222
+ 5. 检查是否有mutex保护
223
+
224
+ ### 静态成员变量处理方式
225
+
226
+ 静态成员变量需要与全局变量同等对待,根据类型选择保护策略:
227
+
228
+ - **静态atomic成员**:线程安全,无需额外锁
229
+ ```cpp
230
+ static inline std::atomic<int> totalProcessedNodeCount_{0};
231
+ totalProcessedNodeCount_++; // 安全
232
+ ```
233
+
234
+ - **静态普通成员**:需要静态mutex保护
235
+ ```cpp
236
+ static inline std::mutex drawingCacheInfoMutex_;
237
+ static inline std::unordered_map<NodeId, ...> drawingCacheInfos_;
238
+ // 使用静态mutex保护静态数据
239
+ ```
240
+
241
+ - **thread_local静态成员**:每个线程独立,无需同步
242
+ ```cpp
243
+ static thread_local int processedNodeCount_ = 0;
244
+ processedNodeCount_++; // 安全,每个线程独立
245
+ ```
246
+
247
+ ### thread_local作为最佳实践
248
+
249
+ thread_local在渲染系统中的典型应用:
250
+
251
+ - **渲染线程独立状态**:
252
+ - 每个渲染线程的计数器
253
+ - 渲染线程的配置标志
254
+ - 性能追踪的临时数据
255
+
256
+ - **优势**:
257
+ - 完全避免同步开销
258
+ - 性能与普通变量相同
259
+ - 适用于高频访问的数据
260
+
261
+ - **适用数据类型**:
262
+ - bool:状态标志(如isOpDropped_)
263
+ - int:计数器(如processedNodeCount_)
264
+ - 复杂类型:线程独立的缓存
265
+
266
+ ### 场景分类细化
267
+
268
+ - **实例成员**:默认线程安全(单线程访问该实例)
269
+ - **静态atomic成员**:线程安全,无需额外保护
270
+ - **静态普通成员**:需要静态mutex保护
271
+ - **thread_local静态成员**:每个线程独立,无需同步
272
+ - **全局变量**:需要全局mutex保护或使用atomic
273
+
274
+ ## 风险流分析(RiskFlow)
275
+
276
+ - **RISK_SOURCE**: RenderNodeDrawable中写入全局变量
277
+ - **RISK_TYPE**: 并发风险、数据竞争
278
+ - **RISK_PATH**: 多线程并发写入全局变量 -> 数据竞争 -> 渲染状态不一致
279
+ - **IMPACT_POINT**: 渲染错误、画面闪烁、程序崩溃
280
+
281
+ ## 影响分析(ImpactAnalysis)
282
+
283
+ - **Trigger**: 多个渲染线程同时写入全局变量
284
+ - **Propagation**: 数据竞争导致状态不一致
285
+ - **Consequence**: 渲染错误、画面闪烁、程序崩溃
286
+ - **Mitigation**: 使用mutex保护,或改用thread_local/成员变量
287
+
288
+ ## 误报排除
289
+
290
+ | 场景 | 识别特征 | 处理方式 |
291
+ |------|----------|----------|
292
+ | NOPROTECT 标记 | 有 // NOPROTECT 注释 | 不报 |
293
+ | 已有锁保护 | 存在 lock_guard 等 | 不报 |
294
+ | 使用atomic | 变量类型为 std::atomic | 不报 |
295
+ | thread_local | thread_local 关键字 | 不报 |
296
+ | 只读全局变量 | 仅读取,不写入 | 不报 |
297
+ | 单线程场景 | 明确注释说明单线程 | 不报 |
298
+ ## 测试用例
299
+
300
+ ### 触发用例(应该报)
301
+
302
+ ```cpp
303
+ class RenderNodeDrawable {
304
+ public:
305
+ void Draw() {
306
+ g_renderCount++; // 应该报:全局变量无锁写入
307
+ }
308
+
309
+ void Process() {
310
+ g_drawableList.push_back(this); // 应该报:全局容器无锁修改
311
+ }
312
+
313
+ static int s_totalNodes;
314
+ void Count() {
315
+ s_totalNodes++; // 应该报:静态成员无锁写入
316
+ }
317
+ };
318
+
319
+ int g_renderCount = 0;
320
+ std::vector<RenderNodeDrawable*> g_drawableList;
321
+ ```
322
+
323
+ ### 安全用例(不应该报)
324
+
325
+ ```cpp
326
+ std::atomic<int> g_atomicRenderCount{0};
327
+
328
+ class RenderNodeDrawable {
329
+ public:
330
+ void Draw() {
331
+ g_atomicRenderCount++; // 安全:使用atomic
332
+ }
333
+ };
334
+
335
+ class RenderNodeDrawable {
336
+ public:
337
+ void Draw() {
338
+ std::lock_guard<std::mutex> lock(g_mutex);
339
+ g_renderCount++; // 安全:有锁保护
340
+ }
341
+ };
342
+
343
+ thread_local int t_localCounter = 0;
344
+ class RenderNodeDrawable {
345
+ public:
346
+ void Draw() {
347
+ t_localCounter++; // 安全:thread_local
348
+ }
349
+ };
350
+
351
+ class RenderNodeDrawable {
352
+ public:
353
+ void Draw() {
354
+ renderCount_++; // 安全:成员变量
355
+ }
356
+ private:
357
+ int renderCount_ = 0;
358
+ };
359
+
360
+ // NOPROTECT: 单线程渲染
361
+ void InitGlobal() {
362
+ g_renderCount = 0; // 不报:明确标记单线程
363
+ }
364
+ ```