Skip to content

EasyLogger Flash 插件异常掉电后地址对齐缺陷问题 #174

@Sundy925

Description

@Sundy925
<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 页擦除过程中意外掉电,重新上电后:

  1. 系统启动正常,日志系统初始化可能返回成功
  2. 后续日志写入操作失败
  3. 可能触发 EF_ASSERT 断言失败导致程序停止
  4. 严重情况下系统无法正常输出日志

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 问题传播路径

  1. 用户调用 log_e("message") 或其他日志接口
  2. elog_output() → 写入 RAM 缓冲区
  3. 缓冲区满 → elog_flash_flush()
  4. ef_log_write() 内部调用 ef_find_sec_using_end_addr() ← 可能返回非对齐地址
  5. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions