@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,335 @@
1
+ ---
2
+ rule_id: "StabilityCodeReview_ConcurrencyStability_002"
3
+ name: "智能指针线程安全问题"
4
+ category: "并发稳定性"
5
+ severity: "HIGH"
6
+ language: ["cpp", "c++"]
7
+ author: "OH-Department7 Stability Team"
8
+ ---
9
+
10
+ # 智能指针线程安全问题
11
+
12
+ ## 问题描述
13
+
14
+ 智能指针(shared_ptr/sptr)不是线程安全的。对于同一个shared_ptr或sptr对象,允许多线程同时读,但是不允许多线程又读又写。如果多个线程同时对同一个智能指针对象进行写操作(赋值、reset、swap等),会导致引用计数竞争,引发内存泄漏、悬空指针等问题。
15
+
16
+ ## 检测示例
17
+
18
+ ### ❌ 问题代码
19
+
20
+ ```cpp
21
+ // 错误示例1:多线程并发修改同一个shared_ptr
22
+ std::shared_ptr<Data> g_data;
23
+
24
+ void ThreadA()
25
+ {
26
+ g_data = std::make_shared<Data>(); // 危险:多线程并发赋值
27
+ }
28
+
29
+ void ThreadB()
30
+ {
31
+ g_data = std::make_shared<Data>(); // 危险:多线程并发赋值
32
+ }
33
+
34
+ // 错误示例2:多线程并发reset
35
+ std::shared_ptr<Resource> g_resource;
36
+
37
+ void ReleaseResource()
38
+ {
39
+ g_resource.reset(); // 危险:多线程并发reset
40
+ }
41
+
42
+ void UpdateResource()
43
+ {
44
+ g_resource.reset(new Resource()); // 危险:多线程并发reset
45
+ }
46
+
47
+ // 错误示例3:多线程并发swap
48
+ std::shared_ptr<Buffer> g_buffer;
49
+
50
+ void SwapBuffer(std::shared_ptr<Buffer> newBuffer)
51
+ {
52
+ g_buffer.swap(newBuffer); // 危险:多线程并发swap
53
+ }
54
+
55
+ // 错误示例4:sptr对象多线程写入
56
+ using namespace OHOS;
57
+ sptr<Service> g_service;
58
+
59
+ void UpdateService(sptr<Service> service)
60
+ {
61
+ g_service = service; // 危险:多线程并发写入sptr
62
+ }
63
+
64
+ // 错误示例5:回调中修改shared_ptr
65
+ class Handler {
66
+ public:
67
+ std::shared_ptr<Context> context_;
68
+
69
+ void OnCallback() {
70
+ context_ = std::make_shared<Context>(); // 危险:回调可能并发执行
71
+ }
72
+ };
73
+ ```
74
+
75
+ ### ✅ 修复方案
76
+
77
+ ```cpp
78
+ // 正确示例1:使用mutex保护shared_ptr写操作
79
+ std::shared_ptr<Data> g_data;
80
+ std::mutex g_dataMutex;
81
+
82
+ void ThreadA()
83
+ {
84
+ std::lock_guard<std::mutex> lock(g_dataMutex);
85
+ g_data = std::make_shared<Data>(); // 安全:有锁保护
86
+ }
87
+
88
+ void ThreadB()
89
+ {
90
+ std::lock_guard<std::mutex> lock(g_dataMutex);
91
+ g_data = std::make_shared<Data>(); // 安全:有锁保护
92
+ }
93
+
94
+ // 正确示例2:使用atomic<shared_ptr> (C++20)
95
+ std::atomic<std::shared_ptr<Data>> g_atomicData;
96
+
97
+ void ThreadA()
98
+ {
99
+ g_atomicData.store(std::make_shared<Data>()); // 安全:atomic操作
100
+ }
101
+
102
+ void ThreadB()
103
+ {
104
+ auto data = g_atomicData.load(); // 安全:atomic操作
105
+ }
106
+
107
+ // 正确示例3:返回shared_ptr副本而非修改全局变量
108
+ std::shared_ptr<Resource> GetResource()
109
+ {
110
+ std::lock_guard<std::mutex> lock(g_resourceMutex);
111
+ return g_resource; // 安全:返回副本,引用计数原子增加
112
+ }
113
+
114
+ // 正确示例4:使用call_once初始化
115
+ std::shared_ptr<Service> g_service;
116
+ std::once_flag g_serviceFlag;
117
+
118
+ void InitService()
119
+ {
120
+ std::call_once(g_serviceFlag, []() {
121
+ g_service = std::make_shared<Service>();
122
+ });
123
+ }
124
+
125
+ // 正确示例5:只读场景无需锁保护
126
+ std::shared_ptr<const Config> g_config;
127
+
128
+ void ReadConfig()
129
+ {
130
+ auto config = g_config; // 安全:多线程同时读是允许的
131
+ if (config) {
132
+ config->GetValue();
133
+ }
134
+ }
135
+
136
+ // 正确示例6:每个线程持有独立副本
137
+ class ThreadSafeHandler {
138
+ public:
139
+ void Process() {
140
+ auto localContext = context_; // 创建副本
141
+ localContext->DoWork(); // 安全:使用局部副本
142
+ }
143
+ private:
144
+ std::shared_ptr<Context> context_;
145
+ };
146
+
147
+ // 正确示例7:使用weak_ptr安全访问可能已销毁的对象
148
+ class RSRenderNodeDrawable {
149
+ public:
150
+ inline std::shared_ptr<const RSRenderNode> GetRenderNode()
151
+ {
152
+ return renderNode_.lock(); // 安全:weak_ptr::lock()是线程安全的原子操作
153
+ }
154
+
155
+ void Draw() {
156
+ auto node = renderNode_.lock(); // 创建shared_ptr副本
157
+ if (!node) {
158
+ return; // 对象已销毁,安全退出
159
+ }
160
+ node->Process(); // 安全:使用局部副本,避免并发问题
161
+ }
162
+ private:
163
+ std::weak_ptr<const RSRenderNode> renderNode_; // 使用weak_ptr避免循环引用
164
+ };
165
+
166
+ // 正确示例8:渲染树中的父子节点引用管理
167
+ class RSRenderNode {
168
+ public:
169
+ void RemoveExpiredChildren() {
170
+ children_.remove_if([&](const auto& child) -> bool {
171
+ auto existingChild = child.lock(); // 线程安全的lock()操作
172
+ if (existingChild == nullptr) {
173
+ return true; // 移除已过期节点
174
+ }
175
+ // 使用existingChild进行操作
176
+ return false;
177
+ });
178
+ }
179
+ private:
180
+ std::list<std::weak_ptr<RSRenderNode>> children_; // 使用weak_ptr存储子节点
181
+ std::weak_ptr<RSRenderNode> parent_; // 使用weak_ptr存储父节点引用
182
+ };
183
+ ```
184
+
185
+ ## 检测范围
186
+
187
+ 检查以下智能指针并发场景:
188
+
189
+ 1. 全局shared_ptr/sptr对象的写操作
190
+ 2. 成员shared_ptr在多线程环境下的写操作
191
+ 3. shared_ptr的reset、swap操作
192
+ 4. 回调/异步任务中修改shared_ptr
193
+ 5. shared_ptr的赋值操作
194
+
195
+ ## 检测要点
196
+
197
+ 1. 识别shared_ptr/sptr变量
198
+ 2. 识别写操作:赋值、reset、swap、move
199
+ 3. 检查多线程上下文:线程函数、回调、异步任务
200
+ 4. 检查是否有mutex保护
201
+ 5. 区分读操作(安全)和写操作(需保护)
202
+
203
+ ### weak_ptr线程安全特性
204
+
205
+ weak_ptr是线程安全的,常用于避免循环引用和安全访问可能已销毁的对象:
206
+
207
+ - **weak_ptr::lock()操作是原子且线程安全的**
208
+ - 返回一个shared_ptr,如果对象还存在则引用计数原子增加
209
+ - 如果对象已销毁则返回nullptr
210
+ - 无需额外锁保护
211
+
212
+ - **适用场景**:
213
+ - 渲染树中的父子节点引用(避免循环引用)
214
+ - 观察者模式中观察对象的引用
215
+ - 缓存中对象的弱引用
216
+
217
+ - **典型用法**:
218
+ ```cpp
219
+ // 线程安全的访问
220
+ auto node = weakNode_.lock();
221
+ if (!node) return; // 对象已销毁
222
+ node->Process(); // 使用局部副本,避免并发问题
223
+ ```
224
+
225
+ ### 智能指针操作分类
226
+
227
+ - **读操作(线程安全)**:
228
+ - `get()`:获取裸指针
229
+ - `use_count()`:获取引用计数
230
+ - `operator bool()`:检查是否有效
231
+ - `weak_ptr::lock()`:尝试获取shared_ptr
232
+
233
+ - **写操作(需要保护)**:
234
+ - `operator=`:赋值操作
235
+ - `reset()`:重置指针
236
+ - `swap()`:交换指针
237
+ - `operator*()`解引用后的修改操作
238
+
239
+ ### 参数传递的线程安全
240
+
241
+ 智能指针作为参数传递时引用计数原子增加,是线程安全的:
242
+
243
+ ```cpp
244
+ // 参数传递,引用计数原子增加
245
+ void ProcessNode(std::shared_ptr<Node> node) {
246
+ node->DoWork(); // 安全:参数传递时已增加引用计数
247
+ }
248
+
249
+ // 调用时
250
+ ProcessNode(globalNode); // 安全:传递过程中引用计数原子增加
251
+ ```
252
+
253
+ ## 风险流分析(RiskFlow)
254
+
255
+ - **RISK_SOURCE**: 智能指针对象在多线程环境下被并发写
256
+ - **RISK_TYPE**: 引用计数竞争、数据竞争
257
+ - **RISK_PATH**: 并发写操作 -> 引用计数更新冲突 -> 内存管理错误
258
+ - **IMPACT_POINT**: 内存泄漏、悬空指针、程序崩溃
259
+
260
+ ## 影响分析(ImpactAnalysis)
261
+
262
+ - **Trigger**: 多线程同时对同一智能指针执行写操作
263
+ - **Propagation**: 引用计数更新不同步导致计数错误
264
+ - **Consequence**: 内存泄漏、悬空指针访问、程序崩溃
265
+ - **Mitigation**: 使用mutex保护写操作,或使用atomic<shared_ptr>
266
+
267
+ ## 误报排除
268
+
269
+ | 场景 | 识别特征 | 处理方式 |
270
+ |------|----------|----------|
271
+ | NOPROTECT 标记 | 有 // NOPROTECT 注释 | 不报 |
272
+ | 已有锁保护 | 存在 lock_guard、unique_lock 等 | 不报 |
273
+ | 只读操作 | 仅使用 get、use_count 等 | 不报 |
274
+ | 创建副本 | 返回 shared_ptr 副本 | 不报 |
275
+ | atomic智能指针 | std::atomic<shared_ptr> | 不报 |
276
+ | 单线程场景 | 明确注释说明单线程 | 不报 |
277
+ ## 测试用例
278
+
279
+ ### 触发用例(应该报)
280
+
281
+ ```cpp
282
+ std::shared_ptr<Data> g_data;
283
+
284
+ void trigger_bad_1()
285
+ {
286
+ g_data = std::make_shared<Data>(); // 应该报:无锁保护的写操作
287
+ }
288
+
289
+ void trigger_bad_2()
290
+ {
291
+ g_data.reset(); // 应该报:无锁保护的reset
292
+ }
293
+
294
+ void trigger_bad_3()
295
+ {
296
+ g_data.swap(other); // 应该报:无锁保护的swap
297
+ }
298
+
299
+ sptr<Service> g_service;
300
+ void trigger_bad_4()
301
+ {
302
+ g_service = new Service(); // 应该报:sptr无锁写操作
303
+ }
304
+ ```
305
+
306
+ ### 安全用例(不应该报)
307
+
308
+ ```cpp
309
+ std::shared_ptr<Data> g_data;
310
+ std::mutex g_mutex;
311
+
312
+ void safe_good_1()
313
+ {
314
+ std::lock_guard<std::mutex> lock(g_mutex);
315
+ g_data = std::make_shared<Data>(); // 安全:有锁保护
316
+ }
317
+
318
+ void safe_good_2()
319
+ {
320
+ auto data = g_data; // 安全:只读操作(副本)
321
+ }
322
+
323
+ void safe_good_3()
324
+ {
325
+ if (g_data) { // 安全:只读检查
326
+ g_data->GetValue();
327
+ }
328
+ }
329
+
330
+ // NOPROTECT: 单线程初始化
331
+ void noprotect_init()
332
+ {
333
+ g_data = std::make_shared<Data>(); // 不报:明确标记单线程
334
+ }
335
+ ```
@@ -0,0 +1,284 @@
1
+ ---
2
+ rule_id: "StabilityCodeReview_ConcurrencyStability_003"
3
+ name: "std::atomic时序问题"
4
+ category: "并发稳定性"
5
+ severity: "MEDIUM"
6
+ language: ["cpp", "c++"]
7
+ author: "OH-Department7 Stability Team"
8
+ ---
9
+
10
+ # std::atomic时序问题
11
+
12
+ ## 问题描述
13
+
14
+ std::atomic可以保证操作的原子性,但是不能保证时序。使用std::atomic需要检验代码的时序是否正确。特别是使用memory_order_relaxed时,编译器和CPU可能对操作进行重排,导致数据可见性问题。对于同步标志,必须使用合适的内存序(acquire/release或seq_cst)保证时序正确。
15
+
16
+ ## 检测示例
17
+
18
+ ### ❌ 问题代码
19
+
20
+ ```cpp
21
+ // 错误示例1:使用relaxed内存序作为同步标志
22
+ std::atomic<bool> g_ready{false};
23
+ std::atomic<int> g_data{0};
24
+
25
+ void Producer()
26
+ {
27
+ g_data.store(42, std::memory_order_relaxed);
28
+ g_ready.store(true, std::memory_order_relaxed); // 危险:relaxed无法保证时序
29
+ }
30
+
31
+ void Consumer()
32
+ {
33
+ while (!g_ready.load(std::memory_order_relaxed)) { // 危险:可能看到ready但看不到data
34
+ ;
35
+ }
36
+ int value = g_data.load(std::memory_order_relaxed); // 危险:可能读到旧值
37
+ }
38
+
39
+ // 错误示例2:检查-执行模式的时序问题
40
+ std::atomic<bool> g_flag{false};
41
+
42
+ void ThreadA()
43
+ {
44
+ // 设置数据
45
+ data_ = 42;
46
+ g_flag.store(true, std::memory_order_relaxed); // 危险:数据设置可能被重排到flag之后
47
+ }
48
+
49
+ void ThreadB()
50
+ {
51
+ if (g_flag.load(std::memory_order_relaxed)) { // 危险:可能看到flag但数据未准备好
52
+ useData(data_); // 危险:可能使用未准备好的数据
53
+ }
54
+ }
55
+
56
+ // 错误示例3:多标志同步问题
57
+ std::atomic<bool> g_flag1{false};
58
+ std::atomic<bool> g_flag2{false};
59
+
60
+ void SetFlags()
61
+ {
62
+ g_flag1.store(true, std::memory_order_relaxed);
63
+ g_flag2.store(true, std::memory_order_relaxed); // 危险:两个标志的顺序无法保证
64
+ }
65
+
66
+ void CheckFlags()
67
+ {
68
+ if (g_flag2.load(std::memory_order_relaxed) &&
69
+ !g_flag1.load(std::memory_order_relaxed)) { // 危险:可能看到flag2但看不到flag1
70
+ // 异常状态
71
+ }
72
+ }
73
+
74
+ // 错误示例4:发布-订阅模式的时序问题
75
+ std::atomic<Object*> g_object{nullptr};
76
+
77
+ void PublishObject()
78
+ {
79
+ Object* obj = new Object();
80
+ obj->Init();
81
+ g_object.store(obj, std::memory_order_relaxed); // 危险:Init可能被重排到store之后
82
+ }
83
+
84
+ void SubscribeObject()
85
+ {
86
+ Object* obj = g_object.load(std::memory_order_relaxed);
87
+ if (obj) {
88
+ obj->Use(); // 危险:可能使用未完成初始化的对象
89
+ }
90
+ }
91
+
92
+ // 错误示例5:引用计数发布的时序问题
93
+ std::atomic<int> g_refCount{0};
94
+ std::atomic<bool> g_initialized{false};
95
+
96
+ void InitAndPublish()
97
+ {
98
+ g_refCount.store(1, std::memory_order_relaxed);
99
+ DoInitialization();
100
+ g_initialized.store(true, std::memory_order_relaxed); // 危险:时序无法保证
101
+ }
102
+ ```
103
+
104
+ ### ✅ 修复方案
105
+
106
+ ```cpp
107
+ // 正确示例1:使用release/acquire保证时序
108
+ std::atomic<bool> g_ready{false};
109
+ std::atomic<int> g_data{0};
110
+
111
+ void Producer()
112
+ {
113
+ g_data.store(42, std::memory_order_relaxed);
114
+ g_ready.store(true, std::memory_order_release); // 安全:release保证之前的操作可见
115
+ }
116
+
117
+ void Consumer()
118
+ {
119
+ while (!g_ready.load(std::memory_order_acquire)) { // 安全:acquire保证之后的操作看到release前的状态
120
+ ;
121
+ }
122
+ int value = g_data.load(std::memory_order_relaxed); // 安全:此时数据一定可见
123
+ }
124
+
125
+ // 正确示例2:使用seq_cst内存序
126
+ std::atomic<bool> g_flag{false};
127
+
128
+ void ThreadA()
129
+ {
130
+ data_ = 42;
131
+ g_flag.store(true, std::memory_order_seq_cst); // 安全:seq_cst保证全局顺序
132
+ }
133
+
134
+ void ThreadB()
135
+ {
136
+ if (g_flag.load(std::memory_order_seq_cst)) {
137
+ useData(data_); // 安全:数据一定准备好
138
+ }
139
+ }
140
+
141
+ // 正确示例3:使用mutex替代复杂同步
142
+ std::mutex g_mutex;
143
+ bool g_flag1 = false;
144
+ bool g_flag2 = false;
145
+
146
+ void SetFlags()
147
+ {
148
+ std::lock_guard<std::mutex> lock(g_mutex);
149
+ g_flag1 = true;
150
+ g_flag2 = true; // 安全:mutex保证顺序
151
+ }
152
+
153
+ // 正确示例4:发布时使用release
154
+ std::atomic<Object*> g_object{nullptr};
155
+
156
+ void PublishObject()
157
+ {
158
+ Object* obj = new Object();
159
+ obj->Init();
160
+ g_object.store(obj, std::memory_order_release); // 安全:Init一定在store之前完成
161
+ }
162
+
163
+ void SubscribeObject()
164
+ {
165
+ Object* obj = g_object.load(std::memory_order_acquire);
166
+ if (obj) {
167
+ obj->Use(); // 安全:Init一定已完成
168
+ }
169
+ }
170
+
171
+ // 正确示例5:一次性初始化使用call_once
172
+ std::once_flag g_initFlag;
173
+ Object* g_object = nullptr;
174
+
175
+ void InitObject()
176
+ {
177
+ std::call_once(g_initFlag, []() {
178
+ g_object = new Object();
179
+ g_object->Init();
180
+ });
181
+ }
182
+ ```
183
+
184
+ ## 检测范围
185
+
186
+ 检查以下atomic时序场景:
187
+
188
+ 1. atomic变量作为同步标志的使用
189
+ 2. memory_order_relaxed用于同步
190
+ 3. 检查-执行(check-then-act)模式
191
+ 4. 发布-订阅模式
192
+ 5. 多atomic变量的顺序依赖
193
+
194
+ ## 检测要点
195
+
196
+ 1. 识别std::atomic变量
197
+ 2. 检测memory_order_relaxed使用
198
+ 3. 分析同步标志的使用场景
199
+ 4. 检查检查-执行模式
200
+ 5. 验证发布操作的内存序
201
+
202
+ ## 风险流分析(RiskFlow)
203
+
204
+ - **RISK_SOURCE**: atomic变量使用不正确的内存序
205
+ - **RISK_TYPE**: 时序问题、可见性问题
206
+ - **RISK_PATH**: relaxed内存序 -> 操作重排 -> 数据可见性问题 -> 状态不一致
207
+ - **IMPACT_POINT**: 逻辑错误、状态异常、程序崩溃
208
+
209
+ ## 影响分析(ImpactAnalysis)
210
+
211
+ - **Trigger**: 一个线程设置标志后另一个线程读取到旧值
212
+ - **Propagation**: 内存序不正确导致编译器/CPU重排操作
213
+ - **Consequence**: 状态标志失效、逻辑错误、程序异常行为
214
+ - **Mitigation**: 对于同步标志使用acquire/release或seq_cst内存序
215
+
216
+ ## 误报排除
217
+
218
+ | 场景 | 识别特征 | 处理方式 |
219
+ |------|----------|----------|
220
+ | NOPROTECT 标记 | 有 // NOPROTECT 注释 | 不报 |
221
+ | 纯计数场景 | 仅用于计数,不用于同步 | 不报 |
222
+ | 使用release/acquire | 正确的内存序 | 不报 |
223
+ | 使用seq_cst | 默认内存序 | 不报 |
224
+ | 单线程场景 | 明确注释说明单线程 | 不报 |
225
+ ## 测试用例
226
+
227
+ ### 触发用例(应该报)
228
+
229
+ ```cpp
230
+ std::atomic<bool> g_ready{false};
231
+ std::atomic<int> g_data{0};
232
+
233
+ void trigger_bad_1()
234
+ {
235
+ g_data.store(42, std::memory_order_relaxed);
236
+ g_ready.store(true, std::memory_order_relaxed); // 应该报:relaxed用于同步标志
237
+ }
238
+
239
+ void trigger_bad_2()
240
+ {
241
+ while (!g_ready.load(std::memory_order_relaxed)) { // 应该报:relaxed用于同步等待
242
+ ;
243
+ }
244
+ }
245
+
246
+ std::atomic<bool> g_flag{false};
247
+ void trigger_bad_3()
248
+ {
249
+ if (g_flag.load(std::memory_order_relaxed)) { // 应该报:检查时序问题
250
+ useData(data_);
251
+ }
252
+ }
253
+ ```
254
+
255
+ ### 安全用例(不应该报)
256
+
257
+ ```cpp
258
+ std::atomic<bool> g_ready{false};
259
+ std::atomic<int> g_data{0};
260
+
261
+ void safe_good_1()
262
+ {
263
+ g_data.store(42, std::memory_order_relaxed);
264
+ g_ready.store(true, std::memory_order_release); // 安全:使用release
265
+ }
266
+
267
+ void safe_good_2()
268
+ {
269
+ while (!g_ready.load(std::memory_order_acquire)) { // 安全:使用acquire
270
+ ;
271
+ }
272
+ }
273
+
274
+ void safe_good_3()
275
+ {
276
+ g_counter.fetch_add(1, std::memory_order_relaxed); // 安全:纯计数场景
277
+ }
278
+
279
+ std::atomic<int> g_counter{0};
280
+ void safe_good_4()
281
+ {
282
+ g_counter++; // 安全:默认seq_cst
283
+ }
284
+ ```