@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,383 @@
1
+ ---
2
+ rule_id: "StabilityCodeReview_ExceptionHandling_003"
3
+ name: "需校验函数返回值"
4
+ category: "异常处理"
5
+ severity: "HIGH"
6
+ language: ["cpp", "c++"]
7
+ author: "OH-Department7 Stability Team"
8
+ ---
9
+
10
+ # 需校验函数返回值
11
+
12
+ ## 问题描述
13
+
14
+ 当函数的返回值表示操作成功与否时,必须校验返回值。忽略返回值可能导致错误未被发现,程序继续执行可能引发更严重的问题。常见的返回值类型包括:错误码、bool类型、指针类型等。
15
+
16
+ 代码调用会失败的 API(系统调用、第三方库、解码器、文件/网络/内存分配等)后,未检查其返回值或状态码即继续使用输出参数。失败场景下输出参数保持未初始化或处于无效状态,代码继续执行会读写未初始化内存、使用空指针、泄露资源或进入逻辑错误,最终可致崩溃或未定义行为。
17
+
18
+ ## 检测示例
19
+
20
+ ### ❌ 问题代码
21
+
22
+ ```cpp
23
+ // 场景1:忽略bool返回值
24
+ void ProcessFile(const std::string& path) {
25
+ bool success = ValidatePath(path); // 返回值被忽略
26
+ // 未检查success,继续执行
27
+ OpenFile(path); // 如果ValidatePath失败,可能导致问题
28
+ }
29
+
30
+ // 场景2:忽略错误码返回值
31
+ void HandleData(Data* data) {
32
+ int ret = InitializeData(data); // 返回值被忽略
33
+ // 未检查ret,继续使用data
34
+ ProcessData(data); // 如果初始化失败,可能导致问题
35
+ }
36
+
37
+ // 场景3:忽略指针返回值检查
38
+ void UseResource() {
39
+ Resource* res = CreateResource(); // 可能返回nullptr
40
+ res->DoSomething(); // 未检查res是否为nullptr
41
+ }
42
+
43
+ // 场景4:直接调用忽略返回值
44
+ void Execute() {
45
+ DoSomething(); // 返回ErrorCode但被忽略
46
+ ContinueProcess(); // 如果DoSomething失败,继续执行是危险的
47
+ }
48
+
49
+ // 场景5:系统调用返回值未检查
50
+ void WriteToFile(int fd, const char* data, size_t size) {
51
+ write(fd, data, size); // 错误:write可能失败,返回值被忽略
52
+ // 文件可能未成功写入,但代码继续执行
53
+ }
54
+
55
+ // 场景6:第三方库API返回值未检查
56
+ void DecodeData(const char* input) {
57
+ Data decoded;
58
+ int ret = Decoder_Decode(input, &decoded); // 返回错误码但被忽略
59
+ ProcessData(decoded); // 错误:如果解码失败,decoded可能未初始化
60
+ }
61
+
62
+ // 场景7:内存分配API返回值未检查
63
+ void AllocateBuffer() {
64
+ void* buffer;
65
+ int ret = AllocateMemory(1024, &buffer); // 返回错误码但被忽略
66
+ memcpy(buffer, source, 1024); // 错误:如果分配失败,buffer为nullptr
67
+ }
68
+
69
+ // 场景8:文件操作API返回值未检查
70
+ void ReadConfig() {
71
+ Config config;
72
+ bool success = LoadConfigFromFile("config.txt", &config); // 返回值被忽略
73
+ UseConfig(config); // 错误:如果加载失败,config未初始化
74
+ }
75
+ ```
76
+
77
+ ### ✅ 修复方案
78
+
79
+ ```cpp
80
+ // 修复场景1:校验bool返回值
81
+ void ProcessFile(const std::string& path) {
82
+ bool success = ValidatePath(path);
83
+ if (!success) {
84
+ LOGE("ValidatePath failed: %s", path.c_str());
85
+ return;
86
+ }
87
+ OpenFile(path);
88
+ }
89
+
90
+ // 修复场景2:校验错误码返回值
91
+ void HandleData(Data* data) {
92
+ int ret = InitializeData(data);
93
+ if (ret != ERR_SUCCESS) {
94
+ LOGE("InitializeData failed: %d", ret);
95
+ return;
96
+ }
97
+ ProcessData(data);
98
+ }
99
+
100
+ // 修复场景3:校验指针返回值
101
+ void UseResource() {
102
+ Resource* res = CreateResource();
103
+ if (res == nullptr) {
104
+ LOGE("CreateResource failed");
105
+ return;
106
+ }
107
+ res->DoSomething();
108
+ }
109
+
110
+ // 修复场景4:直接调用后立即校验
111
+ void Execute() {
112
+ ErrorCode err = DoSomething();
113
+ if (err != ErrorCode::SUCCESS) {
114
+ LOGE("DoSomething failed: %d", static_cast<int>(err));
115
+ return;
116
+ }
117
+ ContinueProcess();
118
+ }
119
+
120
+ // 修复场景5:系统调用返回值检查
121
+ void WriteToFile(int fd, const char* data, size_t size) {
122
+ ssize_t written = write(fd, data, size);
123
+ if (written < 0) { // 正确:检查write返回值
124
+ LOGE("write failed: %d", errno);
125
+ return;
126
+ }
127
+ if (static_cast<size_t>(written) != size) { // 正确:检查写入字节数
128
+ LOGE("partial write: %zd of %zu", written, size);
129
+ }
130
+ }
131
+
132
+ // 修复场景6:第三方库API返回值检查
133
+ void DecodeData(const char* input) {
134
+ Data decoded;
135
+ int ret = Decoder_Decode(input, &decoded);
136
+ if (ret != DECODER_SUCCESS) { // 正确:检查解码返回值
137
+ LOGE("Decoder_Decode failed: %d", ret);
138
+ return;
139
+ }
140
+ ProcessData(decoded); // 安全:解码成功,decoded已初始化
141
+ }
142
+
143
+ // 修复场景7:内存分配API返回值检查
144
+ void AllocateBuffer() {
145
+ void* buffer;
146
+ int ret = AllocateMemory(1024, &buffer);
147
+ if (ret != ALLOC_SUCCESS || buffer == nullptr) { // 正确:检查返回值和输出参数
148
+ LOGE("AllocateMemory failed: %d", ret);
149
+ return;
150
+ }
151
+ memcpy(buffer, source, 1024); // 安全:分配成功
152
+ }
153
+
154
+ // 修复场景8:文件操作API返回值检查
155
+ void ReadConfig() {
156
+ Config config;
157
+ bool success = LoadConfigFromFile("config.txt", &config);
158
+ if (!success) { // 正确:检查加载返回值
159
+ LOGE("LoadConfigFromFile failed");
160
+ return;
161
+ }
162
+ UseConfig(config); // 安全:加载成功,config已初始化
163
+ }
164
+
165
+ // 修复场景9:复杂链式调用每步校验
166
+ void ConnectToService() {
167
+ auto* manager = SystemManager::GetInstance();
168
+ if (manager == nullptr) { // 第1步:校验GetInstance
169
+ LOGE("SystemManager::GetInstance failed");
170
+ return;
171
+ }
172
+ auto* service = manager->GetService();
173
+ if (service == nullptr) { // 第2步:校验GetService
174
+ LOGE("GetService failed");
175
+ return;
176
+ }
177
+ auto conn = service->CreateConnection();
178
+ if (!conn) { // 第3步:校验CreateConnection
179
+ LOGE("CreateConnection failed");
180
+ return;
181
+ }
182
+ UseConnection(conn);
183
+ }
184
+
185
+ // 修复场景10:智能指针返回值检查
186
+ void ProcessImageData() {
187
+ std::shared_ptr<ImageData> img = LoadImageData("test.png");
188
+ if (img == nullptr || !img) { // 正确:检查智能指针
189
+ LOGE("LoadImageData failed");
190
+ return;
191
+ }
192
+ ProcessImage(*img); // 安全:img已验证有效
193
+ }
194
+
195
+ // 修复场景11:C++17结构化绑定校验
196
+ void SetupConnection() {
197
+ auto [conn, status] = CreateConnectionWithStatus();
198
+ if (status != ConnectionStatus::SUCCESS) { // 正确:校验结构化绑定的状态部分
199
+ LOGE("CreateConnection failed with status: %d", static_cast<int>(status));
200
+ return;
201
+ }
202
+ if (!conn) { // 正确:校验连接对象部分
203
+ LOGE("Connection object is null");
204
+ return;
205
+ }
206
+ UseConnection(conn); // 安全:conn和status都已验证
207
+ }
208
+ ```
209
+
210
+ ## 检测范围
211
+
212
+ 检查以下需要校验的返回值:
213
+
214
+ - `bool` 类型返回值
215
+ - `int/ErrorCode` 类型返回值(表示错误码)
216
+ - 指针类型返回值(可能返回nullptr)
217
+ - 返回值被赋值但未使用的变量
218
+ - 直接调用函数返回值被忽略的情况
219
+ - 系统调用返回值(write、read、open等)
220
+ - 第三方库API返回值
221
+ - 输出参数初始化状态(API调用失败时输出参数可能未初始化)
222
+
223
+ ## 检测要点
224
+
225
+ 1. **确认函数有返回值**:必须先确定函数确实有返回值(非void类型),对返回void的函数不应检测返回值校验
226
+ - 通过函数声明/定义确定返回值类型
227
+ - 若找不到函数定义,应参考同仓其余代码引用相同函数的写法来判断
228
+ 2. 识别函数返回值类型(bool、int、ErrorCode、指针等,不包括void)
229
+ 3. 检查返回值变量是否在后续代码中被使用
230
+ 4. 检查直接函数调用时返回值是否被忽略
231
+ 5. 检查API调用后是否在使用输出参数前校验返回值
232
+ 6. 排除明确标记为忽略返回值的情况(如(void)cast)
233
+
234
+ ### 复杂链式调用检测
235
+
236
+ 对于链式调用,每一步都需要校验返回值:
237
+
238
+ ```cpp
239
+ // ❌ 错误:链式调用中间步骤未校验
240
+ auto conn = SystemManager::GetInstance()->GetService()->CreateConnection();
241
+ // 任何一步失败都会导致后续空指针访问
242
+
243
+ // ✅ 正确:每步校验
244
+ auto* manager = SystemManager::GetInstance();
245
+ if (!manager) return;
246
+ auto* service = manager->GetService();
247
+ if (!service) return;
248
+ auto conn = service->CreateConnection();
249
+ if (!conn) return;
250
+ ```
251
+
252
+ ### 智能指针返回值检测
253
+
254
+ 智能指针(std::shared_ptr、std::unique_ptr)返回值同样需要校验:
255
+
256
+ - 使用 `if (ptr == nullptr)` 或 `if (!ptr)` 检查
257
+ - 使用 `if (ptr)` 检查有效性(隐式bool转换)
258
+ - 注意:`if (!ptr)` 利用了智能指针的bool转换操作符
259
+
260
+ ### C++17结构化绑定检测
261
+
262
+ 结构化绑定(`auto [a, b] = func()`)需要校验其中的状态/错误部分:
263
+
264
+ ```cpp
265
+ auto [result, error] = PerformOperation();
266
+ if (error != ErrorCode::SUCCESS) { // 校验错误状态部分
267
+ return;
268
+ }
269
+ UseResult(result); // 安全:result已验证有效
270
+ ```
271
+
272
+ ## 风险流分析(RiskFlow)
273
+
274
+ - **RISK_SOURCE**:函数返回值被忽略,错误状态未被发现
275
+ - **RISK_TYPE**:返回值校验缺失导致逻辑缺陷,输出参数未初始化
276
+ - **RISK_PATH**:错误未被发现,程序继续执行,使用非法状态、未初始化数据或无效资源
277
+ - **IMPACT_POINT**:可能引发空指针访问、未初始化内存读写、资源泄漏、功能异常等严重问题
278
+
279
+ ## 影响分析(ImpactAnalysis)
280
+
281
+ - **Trigger**:函数调用失败返回错误值,但被调用方忽略
282
+ - **Propagation**:程序继续执行,使用未正确初始化的数据、未初始化的输出参数或无效资源
283
+ - **Consequence**:空指针崩溃、未初始化内存读写、资源泄漏、数据损坏、功能异常
284
+ - **Mitigation**:校验返回值,根据返回值决定后续处理逻辑,确保输出参数有效后再使用
285
+
286
+ ## 误报排除
287
+
288
+ | 场景 | 识别特征 | 处理方式 |
289
+ |------|----------|----------|
290
+ | 故意忽略 | 有 (void) 强制转换 | 不报 |
291
+ | NOPROTECT 标记 | 有 // NOPROTECT 注释 | 不报 |
292
+ | 返回值用于条件 | 返回值在if条件中使用 | 不报 |
293
+ | 返回值用于逻辑运算 | 返回值参与逻辑运算 | 不报 |
294
+ | 输出型参数函数 | 函数名含Get/Create等 | 根据函数名判断 |
295
+ | void返回值函数 | 函数返回值为void | 不报(不适用此规则) |
296
+ | 函数定义未找到 | 无函数声明/定义 | 参考同仓其他调用处判断 |
297
+ ## 测试用例
298
+
299
+ ### 触发用例(应该报)
300
+
301
+ ```cpp
302
+ // test_ExceptionHandling_003_trigger.cpp
303
+ void trigger_bad_1() {
304
+ bool success = ValidateInput(); // 应该报:返回值未校验
305
+ ProcessData();
306
+ }
307
+
308
+ int trigger_bad_2() {
309
+ int ret = InitResource(); // 应该报:返回值未校验
310
+ return 0;
311
+ }
312
+
313
+ void trigger_bad_3() {
314
+ Resource* res = CreateResource(); // 应该报:指针未检查
315
+ res->Use(); // 可能空指针
316
+ }
317
+
318
+ void trigger_bad_4() {
319
+ DoSomething(); // 应该报:返回值被直接忽略
320
+ }
321
+
322
+ void trigger_bad_5(int fd, const char* data, size_t size) {
323
+ write(fd, data, size); // 应该报:系统调用返回值被忽略
324
+ // 继续使用文件,但可能写入失败
325
+ }
326
+
327
+ void trigger_bad_6(const char* input) {
328
+ Data decoded;
329
+ int ret = Decoder_Decode(input, &decoded); // 应该报:返回值未检查,使用未初始化输出参数
330
+ ProcessData(decoded);
331
+ }
332
+ ```
333
+
334
+ ### 安全用例(不应该报)
335
+
336
+ ```cpp
337
+ // test_ExceptionHandling_003_safe.cpp
338
+ void safe_good_1() {
339
+ bool success = ValidateInput();
340
+ if (!success) { // 正确:校验了返回值
341
+ LOGE("ValidateInput failed");
342
+ return;
343
+ }
344
+ ProcessData();
345
+ }
346
+
347
+ int safe_good_2() {
348
+ int ret = InitResource();
349
+ if (ret != ERR_SUCCESS) { // 正确:校验了错误码
350
+ LOGE("InitResource failed: %d", ret);
351
+ return -1;
352
+ }
353
+ return 0;
354
+ }
355
+
356
+ void safe_good_3() {
357
+ (void)DoSomething(); // 正确:明确标记忽略返回值
358
+ }
359
+
360
+ // NOPROTECT 标记
361
+ void noprotect_case() {
362
+ // NOPROTECT: 返回值不影响后续逻辑
363
+ int ret = MinorOperation();
364
+ }
365
+
366
+ void safe_good_6(int fd, const char* data, size_t size) {
367
+ ssize_t written = write(fd, data, size);
368
+ if (written < 0) { // 正确:检查系统调用返回值
369
+ LOGE("write failed");
370
+ return;
371
+ }
372
+ }
373
+
374
+ void safe_good_7(const char* input) {
375
+ Data decoded;
376
+ int ret = Decoder_Decode(input, &decoded);
377
+ if (ret != DECODER_SUCCESS) { // 正确:检查返回值后再使用输出参数
378
+ LOGE("decode failed");
379
+ return;
380
+ }
381
+ ProcessData(decoded); // 安全:decoded已初始化
382
+ }
383
+ ```
@@ -0,0 +1,258 @@
1
+ ---
2
+ rule_id: "StabilityCodeReview_GraphicsStability_001"
3
+ name: "VulkanCleanupHelper引用计数管理"
4
+ category: "图形稳定性"
5
+ severity: "HIGH"
6
+ language: ["cpp", "c++"]
7
+ author: "OH-Department7 Stability Team"
8
+ ---
9
+
10
+ # VulkanCleanupHelper引用计数管理
11
+
12
+ ## 问题描述
13
+
14
+ 使用`MakeFromBackendTexture`或`BuildFromTexture`创建GPU资源时,应正确使用`NativeBufferUtils::VulkanCleanupHelper`管理VkImage的引用计数。首次传入`vulkanCleanupHelper`,后续传入`vulkanCleanupHelper->Ref()`,配合`NativeBufferUtils::DeleteVkImage`函数,确保底层VkImage的生命周期正确管理,避免GPU发生UAF问题或资源泄漏。
15
+
16
+ 注意:`DeleteVkImage`函数指针接收void*参数,内部调用`VulkanCleanupHelper::UnRef()`减少引用计数。`VulkanCleanupHelper`是引用计数管理类,通过Ref()/UnRef()机制维护VkImage的生命周期。
17
+
18
+ ## 检测示例
19
+
20
+ ### 错误示例
21
+
22
+ ```cpp
23
+ // 错误示例1:首次和后续调用都传入vulkanCleanupHelper(引用计数错误)
24
+ void CreateSurfaceFromTexture(
25
+ Drawing::GPUContext* gpuContext,
26
+ const Drawing::BackendTexture& backendTexture,
27
+ NativeBufferUtils::VulkanCleanupHelper* vulkanCleanupHelper)
28
+ {
29
+ // 首次创建:正确传入vulkanCleanupHelper
30
+ auto surface1 = Drawing::Surface::MakeFromBackendTexture(
31
+ gpuContext, backendTexture.GetTextureInfo(), Drawing::TextureOrigin::TOP_LEFT,
32
+ 1, Drawing::COLORTYPE_RGBA_8888, nullptr,
33
+ NativeBufferUtils::DeleteVkImage, vulkanCleanupHelper);
34
+
35
+ // 后续创建:错误!应该传入vulkanCleanupHelper->Ref()
36
+ auto surface2 = Drawing::Surface::MakeFromBackendTexture(
37
+ gpuContext, backendTexture.GetTextureInfo(), Drawing::TextureOrigin::TOP_LEFT,
38
+ 1, Drawing::COLORTYPE_RGBA_8888, nullptr,
39
+ NativeBufferUtils::DeleteVkImage, vulkanCleanupHelper); // 错误:引用计数管理不当
40
+
41
+ // 当surface1和surface2都销毁时,引用计数会出错
42
+ }
43
+
44
+ // 错误示例2:未传入VulkanCleanupHelper
45
+ bool CreateImageFromTexture(
46
+ Drawing::GPUContext& gpuContext,
47
+ const Drawing::TextureInfo& textureInfo,
48
+ Drawing::VKTextureInfo* vkTextureInfo)
49
+ {
50
+ auto image = std::make_shared<Drawing::Image>();
51
+ // 错误:未传入vulkanCleanupHelper管理VkImage生命周期
52
+ bool ret = image->BuildFromTexture(gpuContext, textureInfo,
53
+ Drawing::TextureOrigin::TOP_LEFT, Drawing::BitmapFormat(), nullptr);
54
+ // 缺少生命周期管理,VkImage可能泄漏或提前释放
55
+
56
+ return ret;
57
+ }
58
+
59
+ // 错误示例3:deleteFunc传入错误函数
60
+ void WrongCleanupFunc(void* ptr) {
61
+ delete static_cast<int*>(ptr); // 错误:不是调用UnRef()
62
+ }
63
+
64
+ std::shared_ptr<Drawing::Image> CreateImageWrong(
65
+ Drawing::GPUContext& gpuContext,
66
+ const Drawing::TextureInfo& textureInfo,
67
+ NativeBufferUtils::VulkanCleanupHelper* vulkanCleanupHelper)
68
+ {
69
+ auto image = std::make_shared<Drawing::Image>();
70
+ // 错误:deleteFunc应传入NativeBufferUtils::DeleteVkImage
71
+ bool ret = image->BuildFromTexture(gpuContext, textureInfo,
72
+ Drawing::TextureOrigin::TOP_LEFT, Drawing::BitmapFormat(), nullptr,
73
+ WrongCleanupFunc, vulkanCleanupHelper); // 错误函数
74
+
75
+ return image;
76
+ }
77
+ ```
78
+
79
+ ### 正确示例
80
+
81
+ ```cpp
82
+ // 正确示例1:正确使用VulkanCleanupHelper引用计数(参考源码RSCanvasDrawingRenderNodeDrawable::CreateGpuSurface)
83
+ void CreateGpuSurface(
84
+ const Drawing::ImageInfo& imageInfo,
85
+ const std::shared_ptr<Drawing::GPUContext>& gpuContext,
86
+ bool& newVulkanCleanupHelper)
87
+ {
88
+ auto vkTextureInfo = backendTexture_.GetTextureInfo().GetVKTextureInfo();
89
+ if (vkTextureInfo == nullptr || gpuContext == nullptr) {
90
+ return;
91
+ }
92
+
93
+ // 判断是否需要新建VulkanCleanupHelper
94
+ newVulkanCleanupHelper = vulkanCleanupHelper_ == nullptr;
95
+ if (newVulkanCleanupHelper) {
96
+ // 首次创建VulkanCleanupHelper
97
+ vulkanCleanupHelper_ = new NativeBufferUtils::VulkanCleanupHelper(
98
+ RsVulkanContext::GetSingleton(), vkTextureInfo, pid);
99
+ }
100
+
101
+ // 正确:首次传入vulkanCleanupHelper_,后续传入vulkanCleanupHelper_->Ref()
102
+ surface_ = Drawing::Surface::MakeFromBackendTexture(
103
+ gpuContext.get(), backendTexture_.GetTextureInfo(),
104
+ Drawing::TextureOrigin::TOP_LEFT, 1, Drawing::COLORTYPE_RGBA_8888,
105
+ imageInfo.GetColorSpace(),
106
+ NativeBufferUtils::DeleteVkImage,
107
+ newVulkanCleanupHelper ? vulkanCleanupHelper_ : vulkanCleanupHelper_->Ref()); // 正确
108
+
109
+ // 当有多个Surface共享同一VkImage时,引用计数正确增加
110
+ }
111
+
112
+ // 正确示例2:BuildFromTexture正确管理引用计数
113
+ bool CreateImageFromTexture(
114
+ Drawing::GPUContext& gpuContext,
115
+ const Drawing::TextureInfo& textureInfo,
116
+ NativeBufferUtils::VulkanCleanupHelper* vulkanCleanupHelper,
117
+ bool isFirstTime)
118
+ {
119
+ auto image = std::make_shared<Drawing::Image>();
120
+ Drawing::BitmapFormat bitmapFormat;
121
+
122
+ // 正确:首次传入vulkanCleanupHelper,后续传入vulkanCleanupHelper->Ref()
123
+ bool ret = image->BuildFromTexture(
124
+ gpuContext, textureInfo, Drawing::TextureOrigin::TOP_LEFT,
125
+ bitmapFormat, nullptr,
126
+ NativeBufferUtils::DeleteVkImage,
127
+ isFirstTime ? vulkanCleanupHelper : vulkanCleanupHelper->Ref()); // 正确
128
+
129
+ if (!ret) {
130
+ RS_LOGE("BuildFromTexture failed");
131
+ NativeBufferUtils::DeleteVkImage(vulkanCleanupHelper);
132
+ return false;
133
+ }
134
+ return true;
135
+ }
136
+
137
+ // 正确示例3:清理失败时的资源释放
138
+ void CleanupOnFailure(
139
+ Drawing::GPUContext& gpuContext,
140
+ NativeBufferUtils::VulkanCleanupHelper* vulkanCleanupHelper)
141
+ {
142
+ auto image = std::make_shared<Drawing::Image>();
143
+ bool ret = image->BuildFromTexture(
144
+ gpuContext, textureInfo, Drawing::TextureOrigin::TOP_LEFT,
145
+ bitmapFormat, nullptr,
146
+ NativeBufferUtils::DeleteVkImage,
147
+ vulkanCleanupHelper->Ref());
148
+
149
+ if (!ret) {
150
+ // 正确:失败时需要手动释放引用计数
151
+ NativeBufferUtils::DeleteVkImage(vulkanCleanupHelper);
152
+ RS_LOGE("BuildFromTexture failed, cleanupHelper released");
153
+ }
154
+ }
155
+
156
+ // 正确示例4:不需要清理时传入nullptr(资源由其他机制管理)
157
+ // NOPROTECT: texture资源由NativeBuffer管理,不需要额外清理
158
+ std::shared_ptr<Drawing::Surface> CreateSurfaceNoCleanup(
159
+ Drawing::GPUContext* gpuContext,
160
+ const Drawing::TextureInfo& textureInfo)
161
+ {
162
+ // 正确:明确不需要清理时,传入nullptr(资源由其他地方管理)
163
+ auto surface = Drawing::Surface::MakeFromBackendTexture(
164
+ gpuContext, textureInfo, Drawing::TextureOrigin::TOP_LEFT,
165
+ 1, Drawing::COLORTYPE_RGBA_8888, nullptr, nullptr, nullptr);
166
+
167
+ return surface;
168
+ }
169
+ ```
170
+
171
+ ## 风险流分析(RiskFlow)
172
+
173
+ - **RISK_SOURCE**: VulkanCleanupHelper引用计数管理不当,首次和后续调用未正确使用Ref()
174
+ - **RISK_TYPE**: 引用计数错误
175
+ - **RISK_PATH**: 首次传入vulkanCleanupHelper后,后续未传入vulkanCleanupHelper->Ref() → 引用计数不一致 → VkImage生命周期管理失败 → UAF或资源泄漏
176
+ - **IMPACT_POINT**: GPU UAF问题、GPU崩溃、渲染异常
177
+
178
+ ## 影响分析(ImpactAnalysis)
179
+
180
+ - **Trigger**: MakeFromBackendTexture/BuildFromTexture调用时,后续调用未使用vulkanCleanupHelper->Ref()
181
+ - **Propagation**: VkImage引用计数错误,资源提前释放或泄漏
182
+ - **Consequence**: GPU释放后使用(UAF)、程序崩溃、渲染黑屏、内存泄漏
183
+ - **Mitigation**: 首次传入vulkanCleanupHelper,后续传入vulkanCleanupHelper->Ref(),deleteFunc传入NativeBufferUtils::DeleteVkImage
184
+
185
+ ## 误报排除
186
+
187
+ | 场景 | 识别特征 | 处理方式 |
188
+ |------|----------|----------|
189
+ | NOPROTECT 标记 | 有 // NOPROTECT 注释 | 不报 |
190
+ | 正确使用Ref() | 存在 vulkanCleanupHelper->Ref() | 不报 |
191
+ | 不需要清理 | deleteFunc和cleanupHelper都为nullptr,且有注释说明 | 不报 |
192
+ | deleteFunc正确 | NativeBufferUtils::DeleteVkImage | 不报 |
193
+
194
+ ## 测试用例
195
+
196
+ ### 触发用例(应该报)
197
+
198
+ ```cpp
199
+ // 错误:后续调用未使用vulkanCleanupHelper->Ref()
200
+ void CreateSurfaceWrong(
201
+ Drawing::GPUContext* gpuContext,
202
+ NativeBufferUtils::VulkanCleanupHelper* vulkanCleanupHelper)
203
+ {
204
+ // 首次创建正确
205
+ auto surface1 = Drawing::Surface::MakeFromBackendTexture(
206
+ gpuContext, textureInfo, Drawing::TextureOrigin::TOP_LEFT,
207
+ 1, Drawing::COLORTYPE_RGBA_8888, nullptr,
208
+ NativeBufferUtils::DeleteVkImage, vulkanCleanupHelper);
209
+
210
+ // 后续创建错误:应该传入vulkanCleanupHelper->Ref()
211
+ auto surface2 = Drawing::Surface::MakeFromBackendTexture(
212
+ gpuContext, textureInfo, Drawing::TextureOrigin::TOP_LEFT,
213
+ 1, Drawing::COLORTYPE_RGBA_8888, nullptr,
214
+ NativeBufferUtils::DeleteVkImage, vulkanCleanupHelper); // 应该报
215
+ }
216
+
217
+ // 错误:deleteFunc传入错误函数
218
+ auto surface = Drawing::Surface::MakeFromBackendTexture(
219
+ gpuContext, textureInfo, Drawing::TextureOrigin::TOP_LEFT,
220
+ 1, Drawing::COLORTYPE_RGBA_8888, nullptr,
221
+ WrongDeleteFunc, vulkanCleanupHelper); // 应该报:deleteFunc错误
222
+ ```
223
+
224
+ ### 安全用例(不应该报)
225
+
226
+ ```cpp
227
+ // 正确:后续调用使用vulkanCleanupHelper->Ref()
228
+ void CreateSurfaceCorrect(
229
+ Drawing::GPUContext* gpuContext,
230
+ NativeBufferUtils::VulkanCleanupHelper* vulkanCleanupHelper)
231
+ {
232
+ // 首次创建
233
+ auto surface1 = Drawing::Surface::MakeFromBackendTexture(
234
+ gpuContext, textureInfo, Drawing::TextureOrigin::TOP_LEFT,
235
+ 1, Drawing::COLORTYPE_RGBA_8888, nullptr,
236
+ NativeBufferUtils::DeleteVkImage, vulkanCleanupHelper);
237
+
238
+ // 后续创建正确:传入vulkanCleanupHelper->Ref()
239
+ auto surface2 = Drawing::Surface::MakeFromBackendTexture(
240
+ gpuContext, textureInfo, Drawing::TextureOrigin::TOP_LEFT,
241
+ 1, Drawing::COLORTYPE_RGBA_8888, nullptr,
242
+ NativeBufferUtils::DeleteVkImage, vulkanCleanupHelper->Ref()); // 不报
243
+ }
244
+
245
+ // 正确:明确不需要清理
246
+ // NOPROTECT: texture资源由buffer管理,不需要额外清理
247
+ auto surface = Drawing::Surface::MakeFromBackendTexture(
248
+ gpuContext, textureInfo, Drawing::TextureOrigin::TOP_LEFT,
249
+ 1, Drawing::COLORTYPE_RGBA_8888, nullptr, nullptr, nullptr); // 不报
250
+
251
+ // 正确:首次创建时使用三元运算符判断
252
+ bool newVulkanCleanupHelper = vulkanCleanupHelper_ == nullptr;
253
+ auto surface = Drawing::Surface::MakeFromBackendTexture(
254
+ gpuContext, textureInfo, Drawing::TextureOrigin::TOP_LEFT,
255
+ 1, Drawing::COLORTYPE_RGBA_8888, nullptr,
256
+ NativeBufferUtils::DeleteVkImage,
257
+ newVulkanCleanupHelper ? vulkanCleanupHelper_ : vulkanCleanupHelper_->Ref()); // 不报
258
+ ```