<title>EasyLogger Flash 插件异常掉电后地址对齐缺陷报告</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
line-height: 1.6;
max-width: 900px;
margin: 0 auto;
padding: 20px;
color: #333;
}
h1 {
color: #2c3e50;
border-bottom: 3px solid #3498db;
padding-bottom: 10px;
}
h2 {
color: #34495e;
border-left: 4px solid #3498db;
padding-left: 10px;
margin-top: 30px;
}
h3 {
color: #555;
}
code {
background: #f4f4f4;
padding: 2px 6px;
border-radius: 3px;
font-family: "Consolas", "Monaco", monospace;
}
pre {
background: #282c34;
color: #abb2bf;
padding: 15px;
border-radius: 5px;
overflow-x: auto;
}
pre code {
background: none;
padding: 0;
color: #abb2bf;
}
table {
border-collapse: collapse;
width: 100%;
margin: 20px 0;
}
th, td {
border: 1px solid #ddd;
padding: 12px;
text-align: left;
}
th {
background: #3498db;
color: white;
}
tr:nth-child(even) {
background: #f9f9f9;
}
.warning {
background: #fff3cd;
border-left: 4px solid #ffc107;
padding: 15px;
margin: 20px 0;
}
.danger {
background: #f8d7da;
border-left: 4px solid #dc3545;
padding: 15px;
margin: 20px 0;
}
.info {
background: #d1ecf1;
border-left: 4px solid #17a2b8;
padding: 15px;
margin: 20px 0;
}
.meta {
color: #666;
font-size: 14px;
}
</style>
EasyLogger Flash 插件异常掉电后地址对齐缺陷报告
报告编号: ELOG-2024-001
发现日期: 2024年
严重程度: 严重 (Critical)
影响版本: EasyLogger v2.x + EasyFlash v3.x
影响组件: EasyLogger Flash 插件 (easylogger/plugins/flash/)
目标平台: STM32F10x 系列 (已验证)
1. 摘要
EasyLogger 的 Flash 插件在与 EasyFlash 库配合使用时,当 Flash 擦除过程中发生异常掉电,重新上电后日志系统可能无法正常工作。根因是日志区地址计算过程中未正确处理 4 字节对齐,导致后续 Flash 写入操作触发断言失败或硬件异常。此问题在掉电场景下有 75% 的触发概率。
受影响模块:
- EasyLogger Flash 插件 (elog_flash.c)
- EasyLogger 缓冲区模式 (ELOG_FLASH_USING_BUF_MODE)
- EasyFlash 日志功能 (ef_log.c, ef_utils.c)
2. 问题描述
2.1 问题现象
当系统在 Flash 页擦除过程中意外掉电,重新上电后:
- 系统启动正常,日志系统初始化可能返回成功
- 后续日志写入操作失败
- 可能触发
EF_ASSERT 断言失败导致程序停止
- 严重情况下系统无法正常输出日志
2.2 触发条件
| 条件 |
说明 |
| 必要条件 |
使用 EasyLogger Flash 插件 |
| 必要条件 |
启用缓冲区模式 (ELOG_FLASH_USING_BUF_MODE) |
| 必要条件 |
Flash 擦除单位为 Page 模式 |
| 触发条件 |
Flash 擦除过程中发生异常掉电 |
| 概率 |
已擦除字节数非 4 的整数倍时触发 (约 75%) |
2.3 根本原因
STM32 Flash 擦除机制为逐字节执行,掉电时可能导致部分字节已擦除 (0xFF) 而部分字节未擦除。EasyFlash 通过统计连续 0xFF 字节数 (continue_ff) 来计算下次写入地址,但未对结果进行 4 字节对齐处理。
EasyLogger Flash 插件调用链:
elog_flash_write() → elog_flash_flush() → ef_log_write() → ef_port_write()
↓
地址未对齐 → 触发 EF_ASSERT 或硬件错误
3. 技术分析
3.1 EasyLogger Flash 插件架构
┌─────────────────────────────────────────────────────────────┐
│ EasyLogger Core │
│ (elog.c) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Flash Plugin (elog_flash.c) │
│ - elog_flash_init() │
│ - elog_flash_write(log, size) │
│ - elog_flash_flush() ◄── 缓冲区模式入口 │
│ - elog_flash_output() │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ EasyFlash Library (ef_log.c) │
│ - ef_log_init() │
│ - ef_log_write(log, size) │
│ - ef_log_read() │
│ - ef_log_clean() │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Platform Port (ef_port.c) │
│ - ef_port_write(addr, buf, size) ◄── 断言检查在此 │
│ - ef_port_erase(addr, size) │
│ - ef_port_read() │
└─────────────────────────────────────────────────────────────┘
3.2 缓冲区模式配置
// easylogger/plugins/flash/elog_flash_cfg.h
#define ELOG_FLASH_USING_BUF_MODE // 启用缓冲区模式
#define ELOG_FLASH_BUF_SIZE 1024 // 缓冲区大小 1KB
3.3 问题代码定位
文件 1: easylogger/plugins/flash/elog_flash.c
问题: 插件将数据传递给 EasyFlash 时,未验证地址对齐
void elog_flash_flush(void) {
// ...
/* 写入所有缓冲的日志到 Flash */
ef_log_write((uint32_t *) log_buf, cur_buf_size + write_overage_size);
// ↑ 返回的地址可能未对齐
}
文件 2: easyflash/src/ef_utils.c
问题: 地址计算未强制对齐
uint32_t ef_find_sec_using_end_addr(uint32_t addr, size_t sec_size) {
// ... 逐字节扫描连续 0xFF ...
if (continue_ff >= 4) {
/* ⚠️ 问题所在: 未对齐处理 */
return (addr + sec_size - continue_ff) * 4 / 4 - 4;
/*
* 当 continue_ff = 5 时:
* 返回值 = addr + sec_size - 9 (非 4 字节对齐)
*/
}
}
文件 3: easyflash/port/ef_port.c
问题: 断言检查不完整
EfErrCode ef_port_write(uint32_t addr, const uint32_t *buf, size_t size) {
EF_ASSERT(size % 4 == 0); // ✓ size 检查
// EF_ASSERT(addr % 4 == 0); // ✗ 缺少地址对齐检查!
// 后续写入操作可能失败
}
3.4 问题传播路径
- 用户调用
log_e("message") 或其他日志接口
elog_output() → 写入 RAM 缓冲区
- 缓冲区满 →
elog_flash_flush()
ef_log_write() 内部调用 ef_find_sec_using_end_addr() ← 可能返回非对齐地址
ef_port_write() 执行写入 → 触发 EF_ASSERT 或硬件错误
3.5 概率分析
假设掉电时刻均匀分布在擦除过程中:
擦除页大小: 2048 字节 (STM32F107 大容量系列)
continue_ff % 4 的分布:
- continue_ff % 4 == 0: 概率 25% (地址对齐 ✓)
- continue_ff % 4 != 0: 概率 75% (地址非对齐 ✗)
触发故障概率: 约 75%
4. 修复建议
方案 A: EasyFlash 层修复 (根本解决)
修改 easyflash/src/ef_utils.c:
uint32_t ef_find_sec_using_end_addr(uint32_t addr, size_t sec_size) {
// ... 现有代码 ...
if (continue_ff >= 4) {
uint32_t base_addr = addr + sec_size - continue_ff - 4;
/* ✅ FIX: 强制 4 字节对齐 */
base_addr = (base_addr / 4) * 4;
return base_addr;
}
}
方案 B: 平台移植层防御
修改 easyflash/port/ef_port.c:
EfErrCode ef_port_write(uint32_t addr, const uint32_t *buf, size_t size) {
EF_ASSERT(size % 4 == 0);
/* ✅ FIX: 防御性地址对齐 */
if (addr % 4 != 0) {
EF_DEBUG("Warning: Adjusting unaligned address\n");
addr = (addr / 4) * 4;
}
// ... 后续代码 ...
}
5. 相关源文件
| 文件 |
路径 |
说明 |
| elog_flash.c |
easylogger/plugins/flash/ |
EasyLogger Flash 插件 |
| elog_flash_cfg.h |
easylogger/plugins/flash/ |
插件配置 |
| ef_utils.c |
easyflash/src/ |
地址计算 (问题所在) |
| ef_log.c |
easyflash/src/ |
日志功能 |
| ef_port.c |
easyflash/port/ |
平台移植层 |
6. 联系信息
报告提交者: [您的姓名/组织]
联系方式: [邮箱地址]
日期: 2024年
GitHub Issues 链接:
本报告可提交给 EasyLogger 作者,建议同时提交给 EasyFlash 作者以便同步修复。
EasyFlash_Alignment_Bug_Report.pdf
EasyLogger Flash 插件异常掉电后地址对齐缺陷报告
报告编号: ELOG-2024-001
发现日期: 2024年
严重程度: 严重 (Critical)
影响版本: EasyLogger v2.x + EasyFlash v3.x
影响组件: EasyLogger Flash 插件 (easylogger/plugins/flash/)
目标平台: STM32F10x 系列 (已验证)
1. 摘要
EasyLogger 的 Flash 插件在与 EasyFlash 库配合使用时,当 Flash 擦除过程中发生异常掉电,重新上电后日志系统可能无法正常工作。根因是日志区地址计算过程中未正确处理 4 字节对齐,导致后续 Flash 写入操作触发断言失败或硬件异常。此问题在掉电场景下有 75% 的触发概率。
受影响模块:
2. 问题描述
2.1 问题现象
当系统在 Flash 页擦除过程中意外掉电,重新上电后:
EF_ASSERT断言失败导致程序停止2.2 触发条件
2.3 根本原因
STM32 Flash 擦除机制为逐字节执行,掉电时可能导致部分字节已擦除 (0xFF) 而部分字节未擦除。EasyFlash 通过统计连续 0xFF 字节数 (
continue_ff) 来计算下次写入地址,但未对结果进行 4 字节对齐处理。EasyLogger Flash 插件调用链:
elog_flash_write() → elog_flash_flush() → ef_log_write() → ef_port_write() ↓ 地址未对齐 → 触发 EF_ASSERT 或硬件错误3. 技术分析
3.1 EasyLogger Flash 插件架构
┌─────────────────────────────────────────────────────────────┐ │ EasyLogger Core │ │ (elog.c) │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Flash Plugin (elog_flash.c) │ │ - elog_flash_init() │ │ - elog_flash_write(log, size) │ │ - elog_flash_flush() ◄── 缓冲区模式入口 │ │ - elog_flash_output() │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ EasyFlash Library (ef_log.c) │ │ - ef_log_init() │ │ - ef_log_write(log, size) │ │ - ef_log_read() │ │ - ef_log_clean() │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Platform Port (ef_port.c) │ │ - ef_port_write(addr, buf, size) ◄── 断言检查在此 │ │ - ef_port_erase(addr, size) │ │ - ef_port_read() │ └─────────────────────────────────────────────────────────────┘3.2 缓冲区模式配置
3.3 问题代码定位
文件 1:
easylogger/plugins/flash/elog_flash.c问题: 插件将数据传递给 EasyFlash 时,未验证地址对齐
void elog_flash_flush(void) { // ... /* 写入所有缓冲的日志到 Flash */ ef_log_write((uint32_t *) log_buf, cur_buf_size + write_overage_size); // ↑ 返回的地址可能未对齐 }文件 2:
easyflash/src/ef_utils.c问题: 地址计算未强制对齐
uint32_t ef_find_sec_using_end_addr(uint32_t addr, size_t sec_size) { // ... 逐字节扫描连续 0xFF ... if (continue_ff >= 4) { /* ⚠️ 问题所在: 未对齐处理 */ return (addr + sec_size - continue_ff) * 4 / 4 - 4; /* * 当 continue_ff = 5 时: * 返回值 = addr + sec_size - 9 (非 4 字节对齐) */ } }文件 3:
easyflash/port/ef_port.c问题: 断言检查不完整
EfErrCode ef_port_write(uint32_t addr, const uint32_t *buf, size_t size) { EF_ASSERT(size % 4 == 0); // ✓ size 检查 // EF_ASSERT(addr % 4 == 0); // ✗ 缺少地址对齐检查! // 后续写入操作可能失败 }3.4 问题传播路径
log_e("message")或其他日志接口elog_output()→ 写入 RAM 缓冲区elog_flash_flush()ef_log_write()内部调用ef_find_sec_using_end_addr()← 可能返回非对齐地址ef_port_write()执行写入 → 触发 EF_ASSERT 或硬件错误3.5 概率分析
假设掉电时刻均匀分布在擦除过程中:
4. 修复建议
方案 A: EasyFlash 层修复 (根本解决)
修改
easyflash/src/ef_utils.c:uint32_t ef_find_sec_using_end_addr(uint32_t addr, size_t sec_size) { // ... 现有代码 ... if (continue_ff >= 4) { uint32_t base_addr = addr + sec_size - continue_ff - 4; /* ✅ FIX: 强制 4 字节对齐 */ base_addr = (base_addr / 4) * 4; return base_addr; } }方案 B: 平台移植层防御
修改
easyflash/port/ef_port.c:EfErrCode ef_port_write(uint32_t addr, const uint32_t *buf, size_t size) { EF_ASSERT(size % 4 == 0); /* ✅ FIX: 防御性地址对齐 */ if (addr % 4 != 0) { EF_DEBUG("Warning: Adjusting unaligned address\n"); addr = (addr / 4) * 4; } // ... 后续代码 ... }5. 相关源文件
6. 联系信息
报告提交者: [您的姓名/组织]
联系方式: [邮箱地址]
日期: 2024年
GitHub Issues 链接:
本报告可提交给 EasyLogger 作者,建议同时提交给 EasyFlash 作者以便同步修复。
EasyFlash_Alignment_Bug_Report.pdf