@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.
- package/README.md +169 -0
- package/SKILL.md +518 -0
- package/bin/install.js +165 -0
- package/config/rules.yaml +445 -0
- package/config/whitelist.yaml +52 -0
- package/package.json +40 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_001.md +275 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_002.md +273 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_003.md +305 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_004.md +350 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_005.md +301 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_006.md +320 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_007.md +432 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_008.md +394 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_009.md +425 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_010.md +472 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_011.md +204 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_012.md +210 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_013.md +226 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_014.md +222 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_015.md +256 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_016.md +269 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_017.md +222 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_018.md +336 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_001.md +414 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_002.md +335 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_003.md +284 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_004.md +313 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_005.md +364 -0
- package/references/ExceptionHandling/StabilityCodeReview_ExceptionHandling_001.md +142 -0
- package/references/ExceptionHandling/StabilityCodeReview_ExceptionHandling_002.md +222 -0
- package/references/ExceptionHandling/StabilityCodeReview_ExceptionHandling_003.md +383 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_001.md +258 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_002.md +131 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_003.md +220 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_004.md +224 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_005.md +250 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_006.md +153 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_007.md +169 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_008.md +153 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_009.md +144 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_010.md +152 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_011.md +221 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_012.md +318 -0
- package/references/InitializationOrder/StabilityCodeReview_InitializationOrder_001.md +411 -0
- package/references/Lifecycle/StabilityCodeReview_Lifecycle_001.md +255 -0
- package/references/Lifecycle/StabilityCodeReview_Lifecycle_002.md +177 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_001.md +332 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_002.md +261 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_003.md +428 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_004.md +400 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_005.md +364 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_006.md +359 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_007.md +279 -0
- package/references/PROBLEM_TEMPLATE.md +65 -0
- package/references/PerformanceStability/StabilityCodeReview_PerformanceStability_001.md +380 -0
- package/references/PerformanceStability/StabilityCodeReview_PerformanceStability_002.md +437 -0
- package/references/REPORT_TEMPLATE.csv +5 -0
- package/references/REPORT_TEMPLATE.md +132 -0
- package/references/RULE_DEVELOPMENT_GUIDE.md +711 -0
- package/references/RULE_INDEX.md +101 -0
- package/references/RULE_TEMPLATE.md +192 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_001.md +334 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_002.md +425 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_003.md +420 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_004.md +409 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_005.md +445 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_006.md +384 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_007.md +395 -0
- package/scripts/add-rule.py +423 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# 稳定性规则总索引
|
|
2
|
+
|
|
3
|
+
本文件列出所有可用的稳定性规则及其配置信息。
|
|
4
|
+
|
|
5
|
+
## 规则统计
|
|
6
|
+
|
|
7
|
+
| 大类 | 规则数量 | 严重程度分布 |
|
|
8
|
+
|------|----------|--------------|
|
|
9
|
+
| 异常处理 | 3 | HIGH: 1, MEDIUM: 2 |
|
|
10
|
+
| 并发稳定性 | 5 | HIGH: 4, MEDIUM: 1 |
|
|
11
|
+
| 性能稳定性 | 2 | HIGH: 2 |
|
|
12
|
+
| 资源管理 | 7 | CRITICAL: 2, HIGH: 3, MEDIUM: 2 |
|
|
13
|
+
| 初始化顺序 | 1 | MEDIUM: 1 |
|
|
14
|
+
| 边界条件 | 18 | CRITICAL: 4, HIGH: 10, MEDIUM: 4 |
|
|
15
|
+
| 生命周期 | 2 | CRITICAL: 1, HIGH: 1 |
|
|
16
|
+
| 内存稳定性 | 7 | CRITICAL: 5, HIGH: 2 |
|
|
17
|
+
| 图形稳定性 | 12 | HIGH: 12 |
|
|
18
|
+
| **总计** | **57** | CRITICAL: 12, HIGH: 35, MEDIUM: 10 |
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 规则列表
|
|
23
|
+
|
|
24
|
+
### CRITICAL (12)
|
|
25
|
+
|
|
26
|
+
| 规则 ID | 名称 | 分类 | 描述 |
|
|
27
|
+
|---------|------|------|------|
|
|
28
|
+
| StabilityCodeReview_ResourceManagement_003 | 禁止智能指针get初始化另一个智能指针 | 资源管理 | 智能指针get()返回裸指针初始化另一个智能指针导致 double-free |
|
|
29
|
+
| StabilityCodeReview_ResourceManagement_007 | 智能指针与裸指针混用 | 资源管理 | 智能指针与裸指针混用导致生命周期管理混乱 |
|
|
30
|
+
| StabilityCodeReview_BoundaryCondition_001 | Parcel数据不可作为循环或递归条件 | 边界条件 | Parcel 数据作为循环条件可能导致无限循环或拒绝服务 |
|
|
31
|
+
| StabilityCodeReview_BoundaryCondition_002 | Parcel数据不可直接作为数组下标 | 边界条件 | Parcel 数据直接作为数组下标可能导致内存越界访问 |
|
|
32
|
+
| StabilityCodeReview_BoundaryCondition_006 | 除法和模运算需做除零保护 | 边界条件 | 除法和模运算未做除零保护可能导致 SIGFPE 崩溃 |
|
|
33
|
+
| StabilityCodeReview_BoundaryCondition_016 | 内存操作越界风险 | 边界条件 | 外部可控参数进行内存操作时未做边界校验可能导致内存越界 |
|
|
34
|
+
| StabilityCodeReview_Lifecycle_001 | 返回引用的函数返回局部变量 | 生命周期 | 函数返回局部变量的引用导致悬垂引用和 use-after-free |
|
|
35
|
+
| StabilityCodeReview_MemoryStability_001 | 内存分配失败判空检查 | 内存稳定性 | 内存分配后未检查 nullptr 就直接使用导致空指针解引用 |
|
|
36
|
+
| StabilityCodeReview_MemoryStability_002 | 指针解引用前判空 | 内存稳定性 | 指针未判空直接解引用导致空指针解引用崩溃 |
|
|
37
|
+
| StabilityCodeReview_MemoryStability_005 | double-free问题 | 内存稳定性 | 同一指针在多条路径上被释放导致 double-free |
|
|
38
|
+
| StabilityCodeReview_MemoryStability_006 | use-after-free问题 | 内存稳定性 | 指针释放后继续使用导致 use-after-free |
|
|
39
|
+
| StabilityCodeReview_MemoryStability_007 | 函数返回指针未检查NULL | 内存稳定性 | 函数返回空指针后未检查直接解引用导致崩溃 |
|
|
40
|
+
|
|
41
|
+
### HIGH (35)
|
|
42
|
+
|
|
43
|
+
| 规则 ID | 名称 | 分类 | 描述 |
|
|
44
|
+
|---------|------|------|------|
|
|
45
|
+
| StabilityCodeReview_ExceptionHandling_003 | 需校验函数返回值 | 异常处理 | 关键函数返回值未校验导致错误处理遗漏 |
|
|
46
|
+
| StabilityCodeReview_ConcurrencyStability_001 | 多线程场景线程安全设计缺失 | 并发稳定性 | 多线程访问共享变量时未做线程安全保护导致数据竞争 |
|
|
47
|
+
| StabilityCodeReview_ConcurrencyStability_002 | 智能指针线程安全问题 | 并发稳定性 | 智能指针引用计数操作非原子性导致线程安全问题 |
|
|
48
|
+
| StabilityCodeReview_ConcurrencyStability_004 | 加锁后返回引用或裸指针问题 | 并发稳定性 | 加锁后返回引用或裸指针导致锁外访问风险 |
|
|
49
|
+
| StabilityCodeReview_ConcurrencyStability_005 | RenderNodeDrawable全局变量写入问题 | 并发稳定性 | RenderNodeDrawable全局变量在多线程场景写入未加锁保护 |
|
|
50
|
+
| StabilityCodeReview_PerformanceStability_001 | 递归条件未考虑充分导致无限递归 | 性能稳定性 | 递归终止条件未充分考虑导致无限递归和栈溢出 |
|
|
51
|
+
| StabilityCodeReview_PerformanceStability_002 | 间接递归风险 | 性能稳定性 | 函数间相互调用形成的间接递归可能导致栈溢出 |
|
|
52
|
+
| StabilityCodeReview_ResourceManagement_001 | 反序列化内存泄漏 | 资源管理 | 反序列化过程中的内存泄漏风险 |
|
|
53
|
+
| StabilityCodeReview_ResourceManagement_002 | dlopen需配对dlclose | 赿源管理 | dlopen 后未配对调用 dlclose 导致动态库资源泄漏 |
|
|
54
|
+
| StabilityCodeReview_ResourceManagement_005 | 文件描述符泄漏 | 资源管理 | open/socket/epoll 等文件描述符在错误路径上未关闭 |
|
|
55
|
+
| StabilityCodeReview_BoundaryCondition_003 | Parcel数据不可直接作为内存申请大小 | 边界条件 | Parcel 数据直接作为内存申请大小可能导致 OOM 或整数溢出 |
|
|
56
|
+
| StabilityCodeReview_BoundaryCondition_004 | 容器size增长的对外接口应限制上限 | 边界条件 | 容器 size 增长的对外接口未限制上限可能导致 OOM |
|
|
57
|
+
| StabilityCodeReview_BoundaryCondition_007 | Parcel序列化和反序列化必须匹配 | 边界条件 | Parcel 序列化和反序列化不匹配导致数据处理错误 |
|
|
58
|
+
| StabilityCodeReview_BoundaryCondition_008 | 容器erase后需正确更新迭代器 | 边界条件 | 容器 erase 后未正确更新迭代器导致迭代器失效 |
|
|
59
|
+
| StabilityCodeReview_BoundaryCondition_009 | 外部数据类型转换需范围检查 | 边界条件 | 外部数据类型转换未做范围检查导致数据截断或溢出 |
|
|
60
|
+
| StabilityCodeReview_BoundaryCondition_010 | 容器find返回迭代器需校验有效性 | 边界条件 | 容器 find 返回迭代器未校验有效性直接访问导致崩溃 |
|
|
61
|
+
| StabilityCodeReview_BoundaryCondition_011 | 加减乘除运算应避免类型溢出或回绕 | 边界条件 | 加减乘除运算未考虑类型溢出或回绕导致计算错误 |
|
|
62
|
+
| StabilityCodeReview_BoundaryCondition_014 | 类型强制转换未校验,可能导致越界读 | 边界条件 | 类型强制转换未校验范围导致越界读取 |
|
|
63
|
+
| StabilityCodeReview_BoundaryCondition_015 | 数组下标的计算应避免整数回绕导致内存越界访问 | 边界条件 | 数组下标计算发生整数回绕导致内存越界访问 |
|
|
64
|
+
| StabilityCodeReview_BoundaryCondition_018 | JSON解析安全风险 | 边界条件 | JSON 解析过程中的安全风险 |
|
|
65
|
+
| StabilityCodeReview_Lifecycle_002 | 获取临时变量指针 | 生命周期 | 获取临时变量的指针或引用导致悬垂指针 |
|
|
66
|
+
| StabilityCodeReview_MemoryStability_003 | 异常分支内存未及时释放 | 内存稳定性 | 异常分支、早返回路径上分配的内存未及时释放 |
|
|
67
|
+
| StabilityCodeReview_MemoryStability_004 | 多返回路径资源泄漏 | 内存稳定性 | 多返回路径上的内存泄漏风险 |
|
|
68
|
+
| StabilityCodeReview_GraphicsStability_001 | VulkanCleanupHelper引用计数管理 | 图形稳定性 | VulkanCleanupHelper 引用计数管理不当导致资源泄漏 |
|
|
69
|
+
| StabilityCodeReview_GraphicsStability_002 | VulkanCleanUpHelper与SharedContext引用计数混用 | 图形稳定性 | VulkanCleanUpHelper 与 SharedContext 引用计数混用导致资源管理混乱 |
|
|
70
|
+
| StabilityCodeReview_GraphicsStability_003 | RS主线程禁止使用RenderNodeDrawable | 图形稳定性 | RS 主线程使用 RenderNodeDrawable 导致线程安全风险 |
|
|
71
|
+
| StabilityCodeReview_GraphicsStability_004 | RSUniRenderThread禁止访问RenderNode | 图形稳定性 | RSUniRenderThread 访问 RenderNode 导致线程安全风险 |
|
|
72
|
+
| StabilityCodeReview_GraphicsStability_005 | RS主线程禁止GPU Context操作 | 图形稳定性 | RS 主线程执行 GPU Context 操作导致线程安全风险 |
|
|
73
|
+
| StabilityCodeReview_GraphicsStability_006 | Surface/Image跨线程跨Context操作风险 | 图形稳定性 | Surface/Image 跨线程跨 Context 操作导致资源管理混乱 |
|
|
74
|
+
| StabilityCodeReview_GraphicsStability_007 | Surface/Image创建和释放线程一致性 | 图形稳定性 | Surface/Image 创建和释放线程不一致导致资源泄漏 |
|
|
75
|
+
| StabilityCodeReview_GraphicsStability_008 | GetBackendTexture线程限制 | 图形稳定性 | GetBackendTexture 在非创建线程调用导致线程安全风险 |
|
|
76
|
+
| StabilityCodeReview_GraphicsStability_009 | RSRenderNodeMap线程访问限制 | 图形稳定性 | RSRenderNodeMap 在多线程访问未加锁保护 |
|
|
77
|
+
| StabilityCodeReview_GraphicsStability_010 | 回调函数执行进程限制 | 图形稳定性 | 回调函数在错误进程执行导致功能异常 |
|
|
78
|
+
| StabilityCodeReview_GraphicsStability_011 | Vulkan信号量导出fd生命周期管理 | 图形稳定性 | Vulkan 信号量导出 fd 生命周期管理不当导致 fd 泄漏 |
|
|
79
|
+
| StabilityCodeReview_GraphicsStability_012 | SyncFence智能指针缓存管理 | 图形稳定性 | SyncFence 智能指针缓存管理不当导致资源泄漏 |
|
|
80
|
+
|
|
81
|
+
### MEDIUM (10)
|
|
82
|
+
|
|
83
|
+
| 规则 ID | 名称 | 分类 | 描述 |
|
|
84
|
+
|---------|------|------|------|
|
|
85
|
+
| StabilityCodeReview_ExceptionHandling_001 | 禁止异常处理机制 | 异常处理 | 使用 C++ 异常处理机制(try/catch/throw)违反编码规范 |
|
|
86
|
+
| StabilityCodeReview_ExceptionHandling_002 | 异常分支应正确处理 | 异常处理 | 异常分支处理不当导致错误传播或状态不一致 |
|
|
87
|
+
| StabilityCodeReview_ConcurrencyStability_003 | std::atomic时序问题 | 并发稳定性 | std::atomic 操作时序问题导致数据竞争 |
|
|
88
|
+
| StabilityCodeReview_ResourceManagement_004 | 谨慎使用static_pointer_cast | 资源管理 | static_pointer_cast 使用不当导致类型安全问题 |
|
|
89
|
+
| StabilityCodeReview_ResourceManagement_006 | JSON对象未关闭泄漏 | 资源管理 | JSON 对象未正确关闭导致资源泄漏 |
|
|
90
|
+
| StabilityCodeReview_InitializationOrder_001 | 类的数据成员需要显式初始化 | 初始化顺序 | 类数据成员未显式初始化导致未定义行为 |
|
|
91
|
+
| StabilityCodeReview_BoundaryCondition_005 | Parcel整数转枚举需校验有效性 | 边界条件 | Parcel 整数转枚举未校验有效性导致无效枚举值 |
|
|
92
|
+
| StabilityCodeReview_BoundaryCondition_012 | 使用json库获取键值内容前应先判断类型是否匹配、键值是否存在 | 边界条件 | 使用 json 库获取键值内容前未判断类型或键值是否存在导致解析失败 |
|
|
93
|
+
| StabilityCodeReview_BoundaryCondition_013 | 使用json库获取键值后,在进行类型转换前应先校验参数类型 | 边界条件 | 使用 json 库获取键值后未校验参数类型导致类型转换失败 |
|
|
94
|
+
| StabilityCodeReview_BoundaryCondition_017 | 返回值类型不匹配风险 | 边界条件 | 返回值类型不匹配导致数据截断或溢出 |
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 规则模板与开发指南
|
|
99
|
+
|
|
100
|
+
- 新增规则模板请参考 [RULE_TEMPLATE.md](./RULE_TEMPLATE.md)
|
|
101
|
+
- 完整开发指南请参考 [RULE_DEVELOPMENT_GUIDE.md](./RULE_DEVELOPMENT_GUIDE.md)
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
---
|
|
2
|
+
rule_id: "{RULE_ID}"
|
|
3
|
+
name: "{RULE_NAME}"
|
|
4
|
+
category: "{CATEGORY}"
|
|
5
|
+
severity: "{SEVERITY}"
|
|
6
|
+
language: ["cpp", "c++"]
|
|
7
|
+
author: "OH-Department7 Stability Team"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# {RULE_NAME}
|
|
11
|
+
|
|
12
|
+
## 问题描述
|
|
13
|
+
|
|
14
|
+
{一句话描述该规则检测的稳定性问题及其危害。}
|
|
15
|
+
|
|
16
|
+
{可选:补充详细背景说明,如OpenHarmony特定要求、实际项目中的常见错误模式等}
|
|
17
|
+
|
|
18
|
+
## 检测示例
|
|
19
|
+
|
|
20
|
+
### ❌ 问题代码
|
|
21
|
+
|
|
22
|
+
```cpp
|
|
23
|
+
// 场景1:{具体问题描述}
|
|
24
|
+
{问题代码示例}
|
|
25
|
+
|
|
26
|
+
// 场景2:{具体问题描述}
|
|
27
|
+
{问题代码示例}
|
|
28
|
+
|
|
29
|
+
// 场景3:{具体问题描述}
|
|
30
|
+
{问题代码示例}
|
|
31
|
+
|
|
32
|
+
// 场景4:{具体问题描述}
|
|
33
|
+
{问题代码示例}
|
|
34
|
+
|
|
35
|
+
// 场景5:{具体问题描述}
|
|
36
|
+
{问题代码示例}
|
|
37
|
+
|
|
38
|
+
// 建议:提供5-10个典型错误场景,覆盖常见变体和实际代码模式
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### ✅ 修复方案
|
|
42
|
+
|
|
43
|
+
```cpp
|
|
44
|
+
// 修复场景1:{修复方法说明}
|
|
45
|
+
{修复后的代码}
|
|
46
|
+
|
|
47
|
+
// 修复场景2:{修复方法说明}
|
|
48
|
+
{修复后的代码}
|
|
49
|
+
|
|
50
|
+
// 修复场景3:{修复方法说明}
|
|
51
|
+
{修复后的代码}
|
|
52
|
+
|
|
53
|
+
// 修复场景4:{修复方法说明}
|
|
54
|
+
{修复后的代码}
|
|
55
|
+
|
|
56
|
+
// 修复场景5:{修复方法说明}
|
|
57
|
+
{修复后的代码}
|
|
58
|
+
|
|
59
|
+
// 建议:提供5-10个修复方案,包括最佳实践、RAII模式、实际代码中的标准写法
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 检测范围
|
|
63
|
+
|
|
64
|
+
检查以下{API/函数/模式/场景}:
|
|
65
|
+
|
|
66
|
+
1. {检测目标1}
|
|
67
|
+
2. {检测目标2}
|
|
68
|
+
3. {检测目标3}
|
|
69
|
+
4. {检测目标4}
|
|
70
|
+
5. {检测目标5}
|
|
71
|
+
|
|
72
|
+
## 检测要点
|
|
73
|
+
|
|
74
|
+
1. {检测步骤1:如何识别目标}
|
|
75
|
+
2. {检测步骤2:如何检查问题}
|
|
76
|
+
3. {检测步骤3:如何判断风险}
|
|
77
|
+
4. {检测步骤4:如何排除误报}
|
|
78
|
+
5. {检测步骤5:特殊情况处理}
|
|
79
|
+
|
|
80
|
+
### {可选:扩展说明章节}
|
|
81
|
+
|
|
82
|
+
{根据规则特点添加以下可选章节:}
|
|
83
|
+
|
|
84
|
+
#### 最佳实践说明
|
|
85
|
+
|
|
86
|
+
{说明该类问题的最佳实践模式,如:}
|
|
87
|
+
- **推荐方式1**:{说明}
|
|
88
|
+
- 适用场景:{场景}
|
|
89
|
+
- 示例:`{代码片段}`
|
|
90
|
+
|
|
91
|
+
- **推荐方式2**:{说明}
|
|
92
|
+
- 适用场景:{场景}
|
|
93
|
+
- 示例:`{代码片段}`
|
|
94
|
+
|
|
95
|
+
#### 实际代码参考
|
|
96
|
+
|
|
97
|
+
{引用实际项目中的具体函数、常量、模式}
|
|
98
|
+
- **实际常量值**:`MAX_NESTING_DEPTH = 800`, `RECORD_CMD_MAX_DEPTH = 800`
|
|
99
|
+
- **实际函数名**:`RSCanvasDrawingRenderNodeDrawable::CreateGpuSurface`
|
|
100
|
+
- **实际日志函数**:`ROSEN_LOGE()`, `RS_LOGE()`
|
|
101
|
+
|
|
102
|
+
#### 特殊技术说明
|
|
103
|
+
|
|
104
|
+
{针对复杂技术点提供详细说明}
|
|
105
|
+
- **memory_order使用**:{详细说明不同memory_order的适用场景}
|
|
106
|
+
- **thread_local最佳实践**:{说明何时使用thread_local}
|
|
107
|
+
- **C++11/20特性**:{说明新标准特性如何改进代码}
|
|
108
|
+
- **POD vs 非POD类型**:{说明类型差异和初始化要求}
|
|
109
|
+
|
|
110
|
+
#### 分类处理策略
|
|
111
|
+
|
|
112
|
+
{针对不同场景提供不同的处理方式}
|
|
113
|
+
- **场景A**:{处理方式1}
|
|
114
|
+
- **场景B**:{处理方式2}
|
|
115
|
+
- **场景C**:{处理方式3}
|
|
116
|
+
|
|
117
|
+
## 风险流分析(RiskFlow)
|
|
118
|
+
|
|
119
|
+
- **RISK_SOURCE**: {稳定性风险来源描述,具体到代码元素}
|
|
120
|
+
- **RISK_TYPE**: {具体的稳定性风险类型,如空指针解引用、UAF、数据竞争等}
|
|
121
|
+
- **RISK_PATH**: {风险传播的完整路径,从来源到影响点}
|
|
122
|
+
- **IMPACT_POINT**: {最终影响系统稳定性的点,如崩溃、资源耗尽等}
|
|
123
|
+
|
|
124
|
+
## 影响分析(ImpactAnalysis)
|
|
125
|
+
|
|
126
|
+
- **Trigger**: {触发条件,具体场景描述}
|
|
127
|
+
- **Propagation**: {风险传播方式,具体机制}
|
|
128
|
+
- **Consequence**: {稳定性后果,具体表现}
|
|
129
|
+
- **Mitigation**: {缓解建议,具体修复方案}
|
|
130
|
+
|
|
131
|
+
## 误报排除
|
|
132
|
+
|
|
133
|
+
| 场景 | 识别特征 | 处理方式 |
|
|
134
|
+
|------|----------|----------|
|
|
135
|
+
| NOPROTECT标记 | 有 // NOPROTECT 注释 | 不报 |
|
|
136
|
+
| 已有安全防护 | {具体识别方法} | 不报 |
|
|
137
|
+
| 使用最佳实践 | {具体识别方法} | 不报 |
|
|
138
|
+
| 第三方库 | 位于 third_party 目录 | 白名单排除 |
|
|
139
|
+
| 测试代码 | 位于 test 目录或 _test.cpp 文件 | 自动跳过 |
|
|
140
|
+
| {其他场景} | {识别方法} | {处理方式} |
|
|
141
|
+
|
|
142
|
+
## 测试用例
|
|
143
|
+
|
|
144
|
+
### 触发用例(应该报)
|
|
145
|
+
|
|
146
|
+
```cpp
|
|
147
|
+
// test_{RULE_ID}_trigger.cpp
|
|
148
|
+
void trigger_bad_1()
|
|
149
|
+
{
|
|
150
|
+
// {触发场景1的代码}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
void trigger_bad_2()
|
|
154
|
+
{
|
|
155
|
+
// {触发场景2的代码}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
void trigger_bad_3()
|
|
159
|
+
{
|
|
160
|
+
// {触发场景3的代码}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// 建议:提供5-10个触发用例,覆盖典型错误模式和边界情况
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### 安全用例(不应该报)
|
|
167
|
+
|
|
168
|
+
```cpp
|
|
169
|
+
// test_{RULE_ID}_safe.cpp
|
|
170
|
+
void safe_good_1()
|
|
171
|
+
{
|
|
172
|
+
// {安全写法1的代码}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
void safe_good_2()
|
|
176
|
+
{
|
|
177
|
+
// {安全写法2的代码}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
void safe_good_3()
|
|
181
|
+
{
|
|
182
|
+
// {安全写法3的代码}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
void noprotect_case()
|
|
186
|
+
{
|
|
187
|
+
// NOPROTECT: {特殊场景说明}
|
|
188
|
+
// {有NOPROTECT标记的代码}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// 建议:提供5-10个安全用例,覆盖正确做法和误报排除场景
|
|
192
|
+
```
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
---
|
|
2
|
+
rule_id: "StabilityCodeReview_ResourceManagement_001"
|
|
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
|
+
Data* DeserializeData(Parcel& parcel)
|
|
23
|
+
{
|
|
24
|
+
Data* data = new Data(); // 申请内存
|
|
25
|
+
int count = parcel.ReadInt32();
|
|
26
|
+
if (count < 0 || count > MAX_COUNT) {
|
|
27
|
+
LOGE("Invalid count: %d", count);
|
|
28
|
+
return nullptr; // 错误:返回nullptr,data内存泄漏
|
|
29
|
+
}
|
|
30
|
+
data->count = count;
|
|
31
|
+
data->name = parcel.ReadString();
|
|
32
|
+
return data;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 场景2:嵌套反序列化内存泄漏
|
|
36
|
+
TreeNode* DeserializeTree(Parcel& parcel)
|
|
37
|
+
{
|
|
38
|
+
TreeNode* node = new TreeNode(); // 申请内存
|
|
39
|
+
node->id = parcel.ReadInt32();
|
|
40
|
+
int childCount = parcel.ReadInt32();
|
|
41
|
+
|
|
42
|
+
if (childCount < 0) {
|
|
43
|
+
LOGE("Invalid childCount");
|
|
44
|
+
return nullptr; // 错误:node内存泄漏
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
for (int i = 0; i < childCount; i++) {
|
|
48
|
+
TreeNode* child = DeserializeTree(parcel);
|
|
49
|
+
if (child == nullptr) {
|
|
50
|
+
// 错误:child反序列化失败,但node已创建
|
|
51
|
+
// 未清理其他已添加的children
|
|
52
|
+
return nullptr; // node和已添加的children全部泄漏
|
|
53
|
+
}
|
|
54
|
+
node->children.push_back(child);
|
|
55
|
+
}
|
|
56
|
+
return node;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 场景3:数组反序列化部分失败泄漏
|
|
60
|
+
int* DeserializeArray(Parcel& parcel, int& size)
|
|
61
|
+
{
|
|
62
|
+
size = parcel.ReadInt32();
|
|
63
|
+
if (size < 0 || size > MAX_SIZE) {
|
|
64
|
+
return nullptr; // 此处正确,内存未申请
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
int* arr = new int[size]; // 申请内存
|
|
68
|
+
for (int i = 0; i < size; i++) {
|
|
69
|
+
int value = parcel.ReadInt32();
|
|
70
|
+
if (value < 0) { // 业务校验失败
|
|
71
|
+
LOGE("Invalid value at index %d", i);
|
|
72
|
+
return nullptr; // 错误:arr内存泄漏
|
|
73
|
+
}
|
|
74
|
+
arr[i] = value;
|
|
75
|
+
}
|
|
76
|
+
return arr;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// 场景4:对象成员反序列化失败泄漏
|
|
80
|
+
class Config {
|
|
81
|
+
public:
|
|
82
|
+
char* buffer_;
|
|
83
|
+
int bufferSize_;
|
|
84
|
+
|
|
85
|
+
bool Deserialize(Parcel& parcel) {
|
|
86
|
+
bufferSize_ = parcel.ReadInt32();
|
|
87
|
+
if (bufferSize_ <= 0 || bufferSize_ > MAX_BUFFER) {
|
|
88
|
+
return false; // 正确:buffer_未申请
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
buffer_ = new char[bufferSize_]; // 申请内存
|
|
92
|
+
if (!parcel.ReadBuffer(buffer_, bufferSize_)) {
|
|
93
|
+
LOGE("ReadBuffer failed");
|
|
94
|
+
return false; // 错误:buffer_内存泄漏
|
|
95
|
+
}
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### ✅ 修复方案
|
|
102
|
+
|
|
103
|
+
```cpp
|
|
104
|
+
// 修复场景1:使用智能指针自动管理
|
|
105
|
+
Data* DeserializeData(Parcel& parcel)
|
|
106
|
+
{
|
|
107
|
+
std::unique_ptr<Data> data(new Data()); // 使用unique_ptr管理
|
|
108
|
+
int count = parcel.ReadInt32();
|
|
109
|
+
if (count < 0 || count > MAX_COUNT) {
|
|
110
|
+
LOGE("Invalid count: %d", count);
|
|
111
|
+
return nullptr; // unique_ptr自动释放
|
|
112
|
+
}
|
|
113
|
+
data->count = count;
|
|
114
|
+
data->name = parcel.ReadString();
|
|
115
|
+
return data.release(); // 成功时释放所有权
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// 修复场景2:嵌套反序列化安全清理
|
|
119
|
+
TreeNode* DeserializeTree(Parcel& parcel)
|
|
120
|
+
{
|
|
121
|
+
std::unique_ptr<TreeNode> node(new TreeNode());
|
|
122
|
+
node->id = parcel.ReadInt32();
|
|
123
|
+
int childCount = parcel.ReadInt32();
|
|
124
|
+
|
|
125
|
+
if (childCount < 0) {
|
|
126
|
+
LOGE("Invalid childCount");
|
|
127
|
+
return nullptr; // unique_ptr自动释放node
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
for (int i = 0; i < childCount; i++) {
|
|
131
|
+
TreeNode* child = DeserializeTree(parcel);
|
|
132
|
+
if (child == nullptr) {
|
|
133
|
+
// unique_ptr会自动清理node和已添加的children
|
|
134
|
+
return nullptr;
|
|
135
|
+
}
|
|
136
|
+
node->children.push_back(child);
|
|
137
|
+
}
|
|
138
|
+
return node.release();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// 修复场景3:数组反序列化安全清理
|
|
142
|
+
int* DeserializeArray(Parcel& parcel, int& size)
|
|
143
|
+
{
|
|
144
|
+
size = parcel.ReadInt32();
|
|
145
|
+
if (size < 0 || size > MAX_SIZE) {
|
|
146
|
+
return nullptr;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
std::unique_ptr<int[]> arr(new int[size]);
|
|
150
|
+
for (int i = 0; i < size; i++) {
|
|
151
|
+
int value = parcel.ReadInt32();
|
|
152
|
+
if (value < 0) {
|
|
153
|
+
LOGE("Invalid value at index %d", i);
|
|
154
|
+
return nullptr; // unique_ptr自动释放
|
|
155
|
+
}
|
|
156
|
+
arr[i] = value;
|
|
157
|
+
}
|
|
158
|
+
return arr.release();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// 修复场景4:对象成员使用智能指针
|
|
162
|
+
class Config {
|
|
163
|
+
public:
|
|
164
|
+
std::unique_ptr<char[]> buffer_;
|
|
165
|
+
int bufferSize_;
|
|
166
|
+
|
|
167
|
+
bool Deserialize(Parcel& parcel) {
|
|
168
|
+
bufferSize_ = parcel.ReadInt32();
|
|
169
|
+
if (bufferSize_ <= 0 || bufferSize_ > MAX_BUFFER) {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
buffer_.reset(new char[bufferSize_]); // unique_ptr管理
|
|
174
|
+
if (!parcel.ReadBuffer(buffer_.get(), bufferSize_)) {
|
|
175
|
+
LOGE("ReadBuffer failed");
|
|
176
|
+
buffer_.reset(); // 或自动清理
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
// 修复场景5:手动释放内存
|
|
184
|
+
Data* DeserializeDataManual(Parcel& parcel)
|
|
185
|
+
{
|
|
186
|
+
Data* data = new Data();
|
|
187
|
+
int count = parcel.ReadInt32();
|
|
188
|
+
if (count < 0 || count > MAX_COUNT) {
|
|
189
|
+
LOGE("Invalid count: %d", count);
|
|
190
|
+
delete data; // 手动释放
|
|
191
|
+
return nullptr;
|
|
192
|
+
}
|
|
193
|
+
data->count = count;
|
|
194
|
+
data->name = parcel.ReadString();
|
|
195
|
+
return data;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// 修复场景6:使用goto统一清理(C风格)
|
|
199
|
+
int* DeserializeArrayGoto(Parcel& parcel, int& size)
|
|
200
|
+
{
|
|
201
|
+
int* arr = nullptr;
|
|
202
|
+
|
|
203
|
+
size = parcel.ReadInt32();
|
|
204
|
+
if (size < 0 || size > MAX_SIZE) {
|
|
205
|
+
goto error;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
arr = new int[size];
|
|
209
|
+
for (int i = 0; i < size; i++) {
|
|
210
|
+
int value = parcel.ReadInt32();
|
|
211
|
+
if (value < 0) {
|
|
212
|
+
LOGE("Invalid value");
|
|
213
|
+
goto error;
|
|
214
|
+
}
|
|
215
|
+
arr[i] = value;
|
|
216
|
+
}
|
|
217
|
+
return arr;
|
|
218
|
+
|
|
219
|
+
error:
|
|
220
|
+
if (arr) {
|
|
221
|
+
delete[] arr;
|
|
222
|
+
}
|
|
223
|
+
size = 0;
|
|
224
|
+
return nullptr;
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## 检测范围
|
|
229
|
+
|
|
230
|
+
检查以下模式:
|
|
231
|
+
|
|
232
|
+
- `new/delete` 在反序列化函数中的使用
|
|
233
|
+
- `malloc/free` 在反序列化函数中的使用
|
|
234
|
+
- 异常分支(`return nullptr`, `return false`, `return -1`等)前未释放内存
|
|
235
|
+
- 反序列化函数中多个内存申请点的清理
|
|
236
|
+
|
|
237
|
+
## 检测要点
|
|
238
|
+
|
|
239
|
+
1. 识别反序列化函数(包含`Parcel`, `Deserialize`, `Unmarshal`, `Read`等关键字)
|
|
240
|
+
2. 检测内存申请操作(`new`, `malloc`, `calloc`)
|
|
241
|
+
3. 检测异常返回分支
|
|
242
|
+
4. 检查异常分支前是否有对应的释放操作
|
|
243
|
+
5. 排除使用智能指针的情况
|
|
244
|
+
|
|
245
|
+
## 风险流分析(RiskFlow)
|
|
246
|
+
|
|
247
|
+
- **RISK_SOURCE**:反序列化函数中申请的内存
|
|
248
|
+
- **RISK_TYPE**:内存泄漏
|
|
249
|
+
- **RISK_PATH**:申请内存 -> 异常分支 -> 未释放返回 -> 内存泄漏
|
|
250
|
+
- **IMPACT_POINT**:内存资源耗尽、程序稳定性下降
|
|
251
|
+
|
|
252
|
+
## 影响分析(ImpactAnalysis)
|
|
253
|
+
|
|
254
|
+
- **Trigger**:反序列化过程中遇到异常数据或读取失败
|
|
255
|
+
- **Propagation**:异常分支返回时未释放已申请内存
|
|
256
|
+
- **Consequence**:内存泄漏累积、系统内存耗尽、性能下降
|
|
257
|
+
- **Mitigation**:使用智能指针自动管理或手动释放内存
|
|
258
|
+
|
|
259
|
+
## 误报排除
|
|
260
|
+
|
|
261
|
+
| 场景 | 识别特征 | 处理方式 |
|
|
262
|
+
|------|----------|----------|
|
|
263
|
+
| 使用智能指针 | unique_ptr/shared_ptr | 不报 |
|
|
264
|
+
| 有delete释放 | 异常分支前有delete/free | 不报 |
|
|
265
|
+
| 使用RAII类 | 封装了清理的类对象 | 不报 |
|
|
266
|
+
| NOPROTECT标记 | 有 // NOPROTECT 注释 | 不报 |
|
|
267
|
+
| 第三方库 | 位于 third_party 目录 | 白名单排除 |
|
|
268
|
+
## 测试用例
|
|
269
|
+
|
|
270
|
+
### 触发用例(应该报)
|
|
271
|
+
|
|
272
|
+
```cpp
|
|
273
|
+
// test_ResourceManagement_001_trigger.cpp
|
|
274
|
+
Data* trigger_bad_1(Parcel& parcel)
|
|
275
|
+
{
|
|
276
|
+
Data* data = new Data(); // 应该报:new后异常返回未释放
|
|
277
|
+
int count = parcel.ReadInt32();
|
|
278
|
+
if (count < 0) {
|
|
279
|
+
return nullptr; // 内存泄漏
|
|
280
|
+
}
|
|
281
|
+
data->count = count;
|
|
282
|
+
return data;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
int* trigger_bad_2(Parcel& parcel)
|
|
286
|
+
{
|
|
287
|
+
int* arr = (int*)malloc(100 * sizeof(int)); // 应该报:malloc后异常返回未释放
|
|
288
|
+
int value = parcel.ReadInt32();
|
|
289
|
+
if (value < 0) {
|
|
290
|
+
return nullptr; // 内存泄漏
|
|
291
|
+
}
|
|
292
|
+
arr[0] = value;
|
|
293
|
+
return arr;
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### 安全用例(不应该报)
|
|
298
|
+
|
|
299
|
+
```cpp
|
|
300
|
+
// test_ResourceManagement_001_safe.cpp
|
|
301
|
+
Data* safe_good_1(Parcel& parcel)
|
|
302
|
+
{
|
|
303
|
+
std::unique_ptr<Data> data(new Data()); // 安全:使用智能指针
|
|
304
|
+
int count = parcel.ReadInt32();
|
|
305
|
+
if (count < 0) {
|
|
306
|
+
return nullptr; // unique_ptr自动释放
|
|
307
|
+
}
|
|
308
|
+
data->count = count;
|
|
309
|
+
return data.release();
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
Data* safe_good_2(Parcel& parcel)
|
|
313
|
+
{
|
|
314
|
+
Data* data = new Data();
|
|
315
|
+
int count = parcel.ReadInt32();
|
|
316
|
+
if (count < 0) {
|
|
317
|
+
delete data; // 安全:手动释放
|
|
318
|
+
return nullptr;
|
|
319
|
+
}
|
|
320
|
+
data->count = count;
|
|
321
|
+
return data;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// NOPROTECT: 特殊场景
|
|
325
|
+
// NOPROTECT: 测试代码
|
|
326
|
+
Data* noprotect_case(Parcel& parcel)
|
|
327
|
+
{
|
|
328
|
+
Data* data = new Data();
|
|
329
|
+
if (parcel.ReadInt32() < 0) {
|
|
330
|
+
return nullptr;
|
|
331
|
+
}
|
|
332
|
+
return data;
|
|
333
|
+
}
|
|
334
|
+
```
|