| 赛题 | proj248-heap_detection |
|---|---|
| 队伍名称 | 我重生了这一世我要夺回属于我的OS赛冠军 |
| 小组成员 | 李紫剑、冯锦坤、郑旭晖 |
| 项目导师 | 勇健 |
| 指导老师 | 夏文、李诗逸 |
MIAYC项目是一个轻量级堆内存异常检测工具,专注于内存安全领域,旨在解决静态检测器检测率不足、动态检测器性能开销过高导致生产环境部署困难等问题。该项目通过融合静态程序分析、动态智能插桩与操作系统级资源监控,构建了新型内存问题检测框架。
静态分析模块基于LLVM IR实现,通过整合分层内存缓存技术、最小路径覆盖(MPC)算法与函数摘要技术优化符号执行过程,有效缓解路径爆炸导致的检测精度与效率失衡问题,为系统奠定技术基础。其在Juliet Test Suite内存错误测试集上,相比Clang Static Analyzer平均准确率提升15%,性能提升达93%;与初赛基准相比,准确率提升25%,性能提升70%。
动态检测器在Asan框架上进行扩展,对原有Asan进行去冗余优化,合并和删除不必要的插桩检测并且根据不同的静态flag插入含不同程度检测的代码,优化运行时性能,提升生产环境部署可行性。其在Juliet Test Suite内存错误测试集上以 5% 的准确率降低为代价,减少了Asan 80% 的插桩。在SPEC Benchmark中相比Asan达到了平均85% 的动态性能提升。决赛阶段相比初赛阶段的效果提升了196%。
内存采样器基于eBPF技术实现,通过多线程技术加速数据处理过程;同时将eBPF技术与机器学习技术有机结合,采用滑动窗口法提取时序特征,选取LightGBM分类模型进行时序预测,构建采样数据与内存泄漏的检测模型,为大型在线程序提供高效的内存泄漏监控与实时修复方案。在模型训练阶段,1000, 000条原始分配事件数据处理到模型训练仅需25~30秒左右,在SPEC CPU2006测试集上,模型的预测精度高达0.93。
目前,我们的赛题完成度如下:
| 目标 | 完成情况 | 说明 |
|---|---|---|
| 实现静态分析模块,在编译期对程序进行符号执行并分析出可能存在的内存问题 | 全部完成 | 基于LLVM IR实现符号执行静态分析器,在编译期检测程序内存问题 |
| 优化静态分析模块在大规模程序的表现,解决传统符号执行技术痛点(决赛阶段完成) | 全部完成 | 通过优化符号内存模型、约束求解策略及分层调用机制,采用启发式MPC路径搜索策略有效缓解路径爆炸问题;结合LLM分析技术降低误报率 |
| 设计并实现可以基于静态分析报告动态插桩的动态分析程序 | 全部完成 | 扩展Asan实现基于静态分析报告的智能插桩,通过动静结合策略减少插桩数量及运行时开销 |
| 进一步提高动态分析效率,继续降低动态资源消耗(决赛阶段完成) | 全部完成 | 针对影子内存访问开销及循环访问冗余问题实施优化,降低Asan运行时开销 |
| 在操作系统方面设置资源检测程序,在运行中动态触发内存泄漏检测程序(决赛阶段完成) | 全部完成 | 基于eBPF构建无感知内存泄漏监控框架,利用lsan标注数据训练时序模型实现泄漏预测,并设计应对方案 |
| 分析知名开源工具与往年参赛作品,验证项目分析能力(决赛阶段完成) | 全部完成 | 通过分析知名开源工具及往年参赛作品,验证系统检测能力 |
- 整体设计:在初赛的基础上,决赛更加明确了MIAYC项目的全栈内存检测覆盖的设计定位,贯穿了从开发,测试到部署的整个程序生命周期。通过静态分析器,动态分析器与系统采样器的动静结合,提供了一个完整的内存异常检测解决方案。
- 静态分析器:在初赛基础上,进一步优化符号执行引擎,采用分层符号缓存、约束树构建等技术并且创新优化传统MPC算法,自主设计出启发式MPC算法,大幅提升了静态分析的精度与效率与面对路径爆炸的能力。通过对LLVM IR的深度解析,实现了对多种内存问题的高覆盖率检测。
- 动态分析器:在初赛的基础上,采用路径合并,基本块合并,循环合并等更深层次去冗余优化技术,大幅度减少了动态分析器的插桩数量,提升了运行时性能。并且通过对静态分析结果的解析,针对不同的内存指令插入不同的检测代码,进一步提升了动态分析器的检测精度。
- 系统采样器:在初赛的基础上,采用多线程技术加速数据处理过程;同时将eBPF技术与机器学习技术有机结合,采用滑动窗口法提取时序特征,选取LightGBM分类模型进行时序预测,构建采样数据与内存泄漏的检测模型,为大型在线程序提供高效的内存泄漏监控与实时修复方案。
| 成员 | 主要分工 |
|---|---|
| 李紫剑 | 负责设计项目框架,实现静态检测器,参与动态检测器设计,参与系统采样器设计,编写测试,编写文档 |
| 冯锦坤 | 负责设计与实现动态检测器,编写测试,编写文档 |
| 郑旭晖 | 负责设计与实现系统采样器,编写测试,编写文档 |
详细分工情况请参考项目分工
- Memory is all you check : 贯通程序开发,测试与部署的高性能内存异常检测工具
内存安全漏洞持续构成软件系统安全的重大威胁。根据MITRE通用缺陷枚举(CWE)2024年度报告,内存安全相关漏洞占据C/C++程序高危漏洞的相当大一部分,其中缓冲区错误(CWE-119)和释放后使用(CWE-416)以及出界读取(CWE-125)位列最危险漏洞前十位。
基于对当前内存安全检测技术现状的分析,本项目需要应对以下关键挑战:
-
当前内存安全检测工具链存在显著的覆盖断层问题。现有代表性工具(如开发阶段的 Coverity、Clang Static Analyzer (CSA),测试阶段的 AddressSanitizer (ASan),以及部署阶段的 eBPF 技术,在技术栈上相互割裂,导致检测上下文无法有效衔接,难以覆盖软件项目的完整生命周期。因此,本项目需设计并实现一个统一的内存安全检测工具链,该工具链应集成静态分析、动态分析与系统级程序分析能力,并贯穿程序开发、测试与部署运行的全过程。
-
在检测精度与执行效率的协调方面存在显著困难。现有静态分析工具(如 CSA, KLEE, Cppcheck)普遍面临难以平衡分析精度与性能开销的挑战。例如,CSA 在遭遇路径爆炸问题时检测精度会显著下降,Cppcheck 的分析深度通常较浅,而 KLEE 的分析时长往往难以接受。因此,本项目需实现一个静态分析器,该分析器需具备高效的分析速度、较高的检测精度,并能够在路径爆炸等复杂情况下,在有限的时间内达到可接受的精度水平。
类似的精度与效率协调困境也存在于动态分析工具中。即使如 AddressSanitizer (ASan) 这类相对轻量级的工具,通常也会引入 2 倍的程序性能开销,使其难以在生产部署环境中实际应用。Valgrind 等工具的开销则更为显著。因此,本项目需实现一个动态内存问题检测组件,其核心目标是显著降低运行时开销,以期在部分对性能约束相对宽松的软件部署环境中支持实时的内存问题检测。
-
对于部署阶段对性能有严格要求的软件,需要采用运行时开销极低的内存分析方案。现有的基于 eBPF 的系统级内存泄漏检测工具(如 memleak)虽然运行时开销极低,但其分析深度有限,未能充分利用操作系统层提供的丰富上下文信息,亦难以深入解析程序内存访问的时序特征。因此,本项目需实现一个基于 eBPF 技术的内存泄漏检测器,该检测器在维持极低性能开销的同时,应具备深度获取并分析程序内存行为关键信息(包括时序信息)的能力,从而为高性能场景下的内存泄漏检测提供新的技术路径。
具体详细的背景调研参考调研概要
MIAYC 的整体架构如整体架构图所示,其核心由静态分析器、动态检测器和内存采样器三大模块构成。这三个模块依次贯穿程序开发的开发、测试与部署三个阶段,形成一套连续的分析流程。以下对各模块的设计思路与架构进行阐述。
-
MIAYC静态分析器:静态分析器作为 MIAYC 的前端模块,主要服务于开发与测试阶段。该模块的设计核心在于对用户代码实施深度符号执行,并采用保守的分析策略,旨在实现内存错误的高召回率与程序代码的高覆盖率。这一设计确保了静态分析结果指导动态分析器的高可靠性,从而最小化潜在错误遗漏的风险。此外,静态分析器为动态检测器提供必要的元数据,同时为开发者输出详细的错误信息,包括出错指令位置、完整调用栈等关键数据,以辅助漏洞复现与分析。该模块还集成了大型语言模型(LLM)技术,以增强开发者对有用信息的筛选能力。
-
MIAYC动态检测器:动态检测器作为 MIAYC 的中间层模块,贯穿开发、测试与部署全过程。与 AddressSanitizer (Asan) 等传统动态分析工具相比,后者通常引入显著的运行时开销,限制了其在生产环境的应用。本项目通过结合静态分析结果与插桩去冗余技术,大幅减少了 Asan 所需的插桩数量,从而显著降低动态检测的运行时开销。这使得动态检测器能够在性能约束相对宽松的项目部署环境中支持实时内存漏洞检测。对于性能要求严格的部署场景,动态检测器进一步与内存采样器协同工作,以提升整体检测方案的效率与准确性。
-
MIAYC内存采样器:内存采样器作为 MIAYC 的后端模块,专注于为大型、高性能项目部署提供内存泄漏检测解决方案。该模块基于eBPF技术构建,实现了实时、低开销且无侵入性的程序内存分配监控。与传统内存泄漏检测方法相比,本项目通过整合 LeakSanitizer (Lsan) 的检测数据,训练了一个机器学习模型。该模型利用程序内存变化趋势预测泄漏发生概率,并配套提供了一套完整的错误处理机制
MIAYC静态分析器采用分层架构设计,其核心流程包含以下五个逻辑层次,以确保模块化与可扩展性:
-
IR读取与预处理层(IR Module Reader Layer)负责解析输入的LLVM中间表示(IR),构建控制流图(CFG)、调用图(CG)、支配树及类型信息表等核心数据结构,为后续分析阶段提供完整的程序结构信息。该层同时处理用户配置参数,用于指导静态分析器的具体执行策略。
-
符号执行层(ExprEngine Layer)作为静态分析的核心引擎,实现了基于符号执行的分析机制。引擎从CFG中按序提取指令,并通过
TransferVisitor组件对各类指令进行语义处理。决赛阶段为应对路径爆炸问题,该层集成了深度优先搜索(DFS)、广度优先搜索(BFS)及启发式最小路径算法(MPC)等路径探索算法。该层定义的关键数据结构ProgramState表征符号执行过程中的程序状态,具体包括:- 环境映射表(Env map):建立程序变量(
llvm::Value*)到符号表达式(SymExpr)的映射关系,表征变量语义; - 存储映射表(Store map):建立内存区域(
MemoryRegion)到符号表达式的映射关系,表征存储语义; - 父状态指针(ParentNode):维护状态继承关系,在函数调用时创建子状态,返回时通过副作用分析将状态更新传递至父状态,有效缓解状态空间膨胀;
- 约束头节点(ConstraintHead):管理符号约束集合,通过树形结构组织约束关系以提升求解效率;
- 内存操作记录(Free & Malloc map):追踪内存分配与释放操作,支持内存生命周期分析与泄漏检测;
- 逃逸集合(Escaped set):标识跨过程传递的内存指针,为生命周期分析与副作用计算提供关键依据。
- 环境映射表(Env map):建立程序变量(
-
符号求解层(Symbol Execution Layer)为符号执行提供基础支持。在初赛实现仅支持Z3求解器的基础上,后续迭代中引入了表达式化简机制与缓存体系,确保语义等价符号表达式在分析过程中保持统一表示,从而提升符号分析的执行效率与结果准确性。
-
函数摘要层(Function Summary Layer)通过分层调用机制与函数摘要技术,高效处理内联函数调用及外部函数调用。该设计既保障了过程间分析的可行性,也实现了对外部运行环境的有效建模,显著提升了跨函数分析的效率。
-
检查与报告层(Checker & Report Layer)提供可扩展的检查器模板框架,并实现了针对内存安全问题的专用检测器(PointerChecker)。该层同时构建了完整的错误报告体系,可输出包含错误位置、调用栈信息及源码上下文(调试模式下)的诊断结果,支持控制台与JSON两种输出格式。集成的大型语言模型(LLM)组件为开发者提供错误信息分析与验证的辅助功能。
具体详细的开发报告参考决赛静态分析开发报告
以及初赛时开发报告初赛静态分析开发报告
MIAYC动态检测器作为项目的动态分析组件,基于AddressSanitizer(Asan)框架进行功能扩展与优化。其架构设计包含以下逻辑层次:
-
IR预处理层(IR Preprocess Layer)负责解析静态分析阶段输出的标记化LLVM中间表示(IR),完成动态检测的初始化流程,为后续插桩操作奠定基础。
-
插桩优化层(ASAN Optimization)在决赛阶段时,本项目通过静态分析提供的元数据实施插桩冗余消除。核心优化策略包括:移除重复内存检查指令、合并相邻内存操作检测点、优化循环结构内的检测逻辑,从而显著降低插桩引入的指令开销。
-
插桩调度层(Instrumentation Top Layer)依据静态分析结果与IR语义信息,动态确定内存操作的检测策略。该层支持差异化检测机制,包括概率抽样检测、限定次数检测及全量检测模式,实现检测粒度的自适应调整。
-
内联插桩层(Inline Instrument Layer)针对内存操作密度较低的函数,直接在IR指令流中插入检测逻辑。该方案通过消除运行时函数调用开销,优化检测过程的执行效率。
-
运行时回调层(Runtime Call/Callback Layer)适用于内存操作密集的函数,将检测逻辑转化为对运行时库函数的调用。此设计通过减少IR指令膨胀,维持代码结构的简洁性,同时确保检测功能的完整性。
-
报告处理层(Crash & Report Handler)在运行时生成结构化诊断日志,包含详细错误上下文与调用栈回溯信息,为内存问题定位提供关键依据。
该检测器通过对Asan框架的定向改造,核心目标在于利用静态分析生成的程序语义信息,为不同风险等级的内存操作实施差异化检测策略,从而在保证检测精度的前提下优化动态分析的执行效率。
具体详细的开发报告参考决赛动态开发报告以及 具体详细的开发报告参考初赛动态开发报告
系统采样器作为MIAYC的部署阶段组件,其核心功能在于实时采集目标程序的内存分配数据,通过机器学习模型预测内存泄漏发生概率,并触发诊断数据采集机制以供后续分析。该组件架构包含以下核心模块:
-
用户程序组件 为目标程序提供集成化支持,涵盖通信接口与内存监控功能,实现采样器与目标程序的协同工作。
-
eBPF内核态采样器 基于uprobe与kprobe技术,监控libc库的内存分配函数(如malloc/free)。该模块对内存操作事件进行采样,并将原始数据提交至用户态组件,同时承担部分中间数据的临时存储功能。
-
eBPF用户态采样器 以高频率从内核态组件获取采样数据,构建原始数据管道并传输至数据处理模块。
-
数据处理器 核心分析单元,负责通过时序分析方法从原始数据中提取特征。其处理流程分为三个阶段:
- 构建内存分配事件模型(AllocEvent)
- 提取初级特征并组织结构化数据
- 基于滑动窗口机制生成瞬时特征与窗口聚合特征作为最终模型输入
-
机器学习模型 采用LightGBM分类算法,对时序特征进行内存泄漏概率预测。当检测到泄漏风险超过阈值时,主动触发信号机制通知用户程序组件保存堆栈快照,为后续诊断提供关键上下文。
System Sampler的源码均位于./system目录下。
System Sampler的详细开发报告参考系统采样器开发文档
System Sampler的详细测试文档参考系统采样器设计文档
- 目标1:实现高精度静态分析引擎:构建一个基于符号执行与Worklist算法的静态分析器,实现对多种内存安全问题的路径敏感检测。
- 目标2:优化静态分析性能:应对初赛中遇到的分析精度不足,符号执行效率不高,路径爆炸严重等问题。
- 目标3:构建动静结合的智能插桩框架:设计并实现一个由静态分析报告指导的动态分析程序,实现智能化、低开销的动态插桩。
- 目标4:优化动态分析性能:通过消除冗余插桩、优化影子内存管理等技术,进一步降低动态分析的运行时资源消耗。
- 目标5:实现系统级内存监控:在操作系统层面部署资源监控探针,实现对内存分配行为的高覆盖度实时监控。
- 目标6:实现快速轻量内存泄露预测:通过对运行时数据处理和模型预测逻辑进行优化,实现对内存泄漏等问题的运行时动态触发式检测。
项目小组基于对赛题的深度解读、相关技术背景的调研,并与项目导师充分交流后,确定了以下详细技术实施路径:
- 行动项1:标准化开发环境搭建。选用RockyOS v9.6与LLVM-21.0.0作为基准环境,采用CMake & Ninja构建系统,确保开发与编译环境的一致性。
- 行动项1:程序结构信息提取。基于LLVM API,实现对CFG、CG、支配树及循环信息的自动化解析与缓存,为分析提供结构化视图。
- 行动项2:过程内符号执行框架构建。设计并实现以
ExprEngine为调度核心、以持久化数据结构ProgramState为状态载体的过程内分析引擎。 - 行动项3:过程间分析能力扩展。通过函数内联分析与上下文敏感的调用栈(Call Stack)管理,实现跨函数的过程间分析;并构建可扩展的函数摘要(Function Summary)机制,对外部库函数进行行为建模。
- 行动项4:路径敏感的内存缺陷检测器。实现
Checker模块,集成Z3 SMT求解器,对空指针解引用、堆溢出、释放后使用(UAF)、双重释放等多种内存缺陷进行路径敏感检测。 - 行动项5:跨路径缺陷聚合与报告。设计
InstructionStateManager以聚合多路径多调用栈分析结果,并由Analyzer模块生成人类可读的详细分析报告。 - 行动项5.5(决赛完成):接入LLM提供更准确可读的错误报告。实现Json输出并且接入LLM分析错误报告。
- 行动项6:高级静态分析算法优化(决赛完成)。引入分层符号缓存,约束树构建,MPC算法等高级技术,以应对路径爆炸问题,提升分析的精度与效率。
- 行动项7:动静结合接口协议设计。定义了基于LLVM元数据的通信协议,规定了风险等级(如
Dangerous,Dubious)的语义,实现静态分析结果到动态插桩的精确指导。 - 行动项8:静态分析模块验证。利用Juliet Test Suite等标准测试集,对静态分析器的检测准确性与召回率进行系统性测试。
- 行动项8.5(决赛完成):实际项目漏洞检测。检测更多开源项目,以及OS赛历届作品以验证静态分析器的可用性。
- 行动项9:用户自定义配置系统。开发灵活的配置接口,允许用户自定义分析深度、循环边界、报告规则等参数。
- 行动项1:增量式编译环境优化。配置Ninja构建系统,实现对AddressSanitizer项目的增量编译,大幅提升开发迭代效率。
- 行动项2:智能化插桩逻辑扩展。改造AddressSanitizer的插桩Pass,使其能够解析上游传入的LLVM元数据,并根据风险等级执行差异化插桩策略。
- 行动项3:定制化运行时库(Runtime Library)。修改
compiler-rt,为不同风险等级的指令提供专用的运行时处理函数,实现更细粒度的检测行为控制。 - 行动项4:动态分析性能深度优化(决赛完成)。实现路径合并,基本块合并,循环合并等高级去冗余技术,进一步提升动态分析器性能。
- 行动项5:与系统采样器接口设计(决赛完成)。定义动态分析器与系统内存采样器之间的通信协议,实现信息联动。
- 行动项6:动态分析模块验证(决赛完成)。对智能插桩的正确性、性能开销及检测能力进行基准测试与评估。
本部分均为决赛完成
- 行动项1:内核态内存行为监控设计。研究并设计基于eBPF的内核探针,以极低开销捕获进程的
malloc/free等内存分配行为。 - 行动项2:eBPF探针性能优化。对eBPF程序进行优化,确保在生产环境中的采样开销足够低。
- 行动项3:内存泄漏特征工程。对采集的内存分配/释放时序数据进行特征工程,构建能够表征内存泄漏时序行为的特征向量。
- 行动项4:智能化泄漏检测算法研究。探索应用机器学习或统计模型,对特征向量进行分析,以高精度、低延迟地判断内存泄漏发生的概率。
- 行动项5:实际部署适配。将系统采样器与内存泄漏分析器集成到实际部署环境中,验证其在生产环境中的有效性与可靠性。
- 核心分析框架搭建:完成了标准化的开发环境配置,并成功构建了静态分析器与动态分析器的核心框架。
- 静态分析能力完备:实现了功能完备的过程内与过程间符号执行分析,能够对多种关键内存安全问题进行路径敏感的检测。
- 动静结合协议实现:设计并实现了基于LLVM元数据的动静结合通信协议,打通了从静态分析到动态智能插桩的技术链路。
- 智能插桩原型验证:完成了对AddressSanitizer的改造,实现了可根据静态分析报告进行差异化插桩的原型系统。
- 关键模块测试:对静态分析的准确性和动态分析的有效性进行了初步的单元测试与集成测试。
- 系统采样方案确立:完成了对基于eBPF的系统级内存监控方案的技术预研与详细设计。
- 大幅提高静态分析检测效率与精度:通过对内存模型,约束求解,函数调用,路径探索等符号执行关键技术的优化和创新,大幅度提高了静态分析器的检测效率和精度。
- 实际验证静态分析效果:通过检测分析开源项目和历届OS赛作品,证明了静态分析器的可用性。
- 动态分析性能优化:通过优化影子内存,合并冗余路径和基本块等技术,与静态分析工作相辅相成实现更高效的优化策略。
- 搭建了基于eBPF的系统态内存采样器架构。将eBPF与机器学习技术创新性结合,构建出了eBPF -> 数据处理器 -> 机器学习模型的全新框架,提出了Epoch和滑动窗口法等提取特征的核心方案,大幅提高了采样器的数据分析速度与模型预测的精度,实现了系统采样器的轻量化设计,构造了一套完备、便利的内存检测系统。
- 对云平台进行深度适配与部署:通过采样器实时检测部署的项目内存泄漏情况,并提供了一套泄漏应对措施。
- 展望1:进一步完善静态分析器:完善静态分析器:优化核心算法性能;扩展语言库函数支持范围;构建完整的用户交互与异常处理体系;使用多线程技术进一步提升静态分析器的分析效率。
- 展望2:进一步完善动态分析其: 开发更高效的动静协同机制,实现动态检测开销的深度优化。
- 展望3:系统采样器的进一步优化:应用深度学习技术挖掘进程内存特征与内存泄漏的关联性,寻找覆盖更多内存分配模式的训练集,使用更高级的技术增加模型泛化能力;设计更加可靠的特征工程以提升系统采样器检测精度;强化采样器错误应急机制以增强部署可靠性;开发内存监控面板以直观展示程序内存趋势;为采样器寻找更加有效的预测后处理机制。
- 展望4:系统集成与部署:将静态分析器、动态检测器与系统采样器整合为一体化的内存安全检测平台,提供统一的用户界面与API接口,支持多种编程语言与开发环境。
- 展望5:系统适配与移植:将MIAYC平台适配到更多操作系统与编程语言环境,支持更广泛的应用场景。
本节中所有测试数据均在测试结果目录下。
| 环境指标 | 环境参数 |
|---|---|
| Linux发行版 | Rocky Linux 9.5 |
| Linux内核 | 5.14.0-503.40.1.el9_5.x86_64 |
| CPU | Intel Xeon W-2123 (8) @ 3.900GHz |
| 核心数 | 8 |
| 内存 | 64GB |
| LLVM版本 | 21.0.0 |
我们构建了一个包含多种高复杂度、路径敏感和跨函数场景的测试集(irtest),覆盖了二次释放、堆溢出、释放后使用和内存泄漏等关键问题,主要测试的功能需求包括:
- 正确识别基本形式的内存安全问题
- 正确识别复杂的指针别名和内存别名
- 正确处理多分支和多循环
- 正确处理函数调用,实际参数的传递和返回值的处理
- 正确处理间接函数调用
- 正确处理库函数调用
- 正确处理数组结构体等聚合类型
- 正确处理全局变量的处理
- 正确处理链表等数据结构中的内存问题
我们针对不同的测试点和以上的测试需求,编写了系列测试用例,对MIAYC静态分析器的功能与正确性进行了全面验证。测试用例覆盖了从简单的内存分配到复杂的多层嵌套函数调用场景,测试结果如下:
MIAYC测试结果
| 测试用例 | 主要测试点 | 通过情况 |
|---|---|---|
| 基础测试 | 基本形式的内存安全问题 | PASS |
| 指针别名测试 | 复杂的指针别名和内存别名 | PASS |
| 分支测试 | 多分支和多循环 | PASS |
| 函数调用测试 | 函数调用、实际参数传递和返回值处理 | PASS |
| 间接调用测试 | 间接函数调用 | PASS |
| 库函数测试 | 库函数调用 | PASS |
| 聚合类型测试 | 数组、结构体等聚合类型 | PASS |
| 全局变量测试 | 全局变量的处理 | PASS |
| 链表测试 | 链表等数据结构中的内存问题 | PASS |
同样的,我们也对Cppcheck和Clang Static Analyzer (CSA)进行了相同的测试,结果如下:
测试结果汇总:
| 工具 | 精确率 (Precision) | 召回率 (Recall) | F1-Score | 总耗时 (s) | 最大内存 (MB) |
|---|---|---|---|---|---|
| MIAYC | 100% | 100% | 1.000 | 0.32 | 41.86 |
| Cppcheck | 100% | 22.4% | 0.366 | 0.10 | 9.50 |
| Clang Static Analyzer | 96.0% | 82.8% | 0.889 | 1.62 | 92.13 |
结论分析: 在此专项测试集上,MIAYC表现出完美的检测能力,实现了100%的精确率与召回率,且无任何误报。相较之下,Cppcheck虽性能极高,但漏报了大量复杂场景;CSA虽精度较高,但存在少量误报且性能开销显著大于MIAYC。
为了对分析器进行大规模、标准化的评估,我们使用美国国家标准与技术研究院 (NIST) 的 Juliet Test Suite for C/C++。这是一个包含数万个测试用例的大型代码库,覆盖了上百种CWE(Common Weakness Enumeration)漏洞类型。 我们选取了:
- CWE121_Stack_Based_Buffer_Overflow
- CWE122_Heap_Based_Buffer_Overflow
- CWE401_Memory_Leak
- CWE415_Double_Free
- CWE416_Use_After_Free 等总计数万个测试用例进行标准化评估。在本节中我们将MIAYC的三个循环分析等级(l1,l2,l3)与现有成熟静态分析工具Clang static Analyzer与Cppcheck进行横向分析,并且与初赛阶段的MIAYC进行纵向对比,旨在与体现出本项目的性能与准确度优势。
Juliet测试集综合评估结果:
从以上结果可以看出:
- Cppcheck虽然在性能表现上极好,但由于其为源代码级分析工具,很难分析复杂的漏洞场景,导致其召回率极低,漏报严重。
- Clang Static Analyzer在检测精度上表现较好,但性能欠佳,尤其在处理复杂漏洞时耗时较长,并且在CWE416(use-after-free)测试集中表现欠佳。
- MIAYC Static Analyzer在所有内存问题测试用例中表现极佳,不仅精确度(Precision , Recall , Accuracy)上表现强于前两者.相比Clang Static Analyzer平均准确率提升15%,性能提升达93%。
同时我们对MIAYC初赛和决赛结果进行了纵向分析如下表所示:
Juliet测试集纵向对比
| 测试集 | 用例数 | 初赛精度 | 决赛精度 | 初赛耗时 | 决赛耗时 |
|---|---|---|---|---|---|
| CWE121 | 5016 | 93% | 98% | 82.3s | 24.9s |
| CWE122 | 3340 | 91% | 91% | 57.1s | 17.0s |
| CWE401 | 1396 | 82% | 87% | 5.2s | 4.9s |
| CWE415 | 380 | 100% | 100% | 1.3s | 1.4s |
| CWE416 | 236 | 100% | 100% | 7.2s | 2.0s |
| Total | 10368 | 91% | 95% | 59.1s | 18.3s |
经过决赛时期的创新优化,静态分析器的精度与效率都得到了大幅度提升,尤其是对于大规模高消耗的程序优化效果更优,总体精度提升达到44%,总体效率提升达到69%。
我们对测试中出现的少量误报(False Positives)与漏报(False Negatives)案例进行了深度剖析。分析表明,这些案例主要涉及对特定库函数(如realloc)失败路径的保守假设、宽字符与普通字符的隐式类型转换,以及对strlen等函数返回值的处理策略。这些发现为我们下一阶段的优化指明了清晰的方向。详细的错误用例分析请参见静态分析测试文档。
在前文的两个测试用例中,我们已经对MIAYC的静态分析性能进行了初步评估。
为科学且全面评估MIAYC在不同负载下的性能表现与可扩展性,我们设计了一套系统的、可量化的深度性能测试方案。此方案的核心是控制变量法,通过自动化的基准程序生成器,精确控制输入代码的各项复杂度指标,从而独立地观察每个因素对分析器性能的影响。
1. 性能评估维度
为实现对分析器性能的全面刻画,我们定义了以下三个关键评估维度,并量化其对应的自变量与因变量。
| 评估维度 | 自变量 (Independent Variables) | 因变量 (Dependent Variables) |
|---|---|---|
| 控制流复杂度 | 分支嵌套深度 (branch_depth) |
CPU时间 (s): 进程消耗的用户态CPU时间 |
| 代码规模 | 函数数量 (num_functions) |
峰值内存 (MB): 进程占用的最大物理内存 |
| 数据流复杂度 | 指针别名数量 (num_aliases) |
吞吐量 (行/s): 每秒分析的代码行数 |
为确保测试的科学性、可重复性与高效性,我们构建了一套由代码生成、测试执行、性能度量和结果聚合组成的自动化测试流程。详细代码请参考static/test/CGener。
2. 测试结果概览
分支深度代表了程序的控制流复杂度,在初赛时,我们因为没有一个行之有效的方式来处理路径爆炸,导致此项数据出现指数递增的情况,效果极差。而决赛时期我们采用的启发式MPC算法很好的解决了这个问题,我们能在短时间内探索绝大多数基本块,同时保证错误的覆盖率。
从上两图可以清晰看出,决赛时期的MIAYC受到分支数目的影响大幅度下降,虽然仍然不可避免地随着分支深度的增加而导致效率降低,但是应对路径爆炸能力已达到先进水准。

函数数量代表了程序的调用栈与状态复杂度,决赛时期的分层函数调用优化很好的解决了因为频繁函数调用带来的巨额开销,其横向纵向对比图如下几图所示:

从上图中我们可以很明显看出来,初赛时期在函数数量不断变多的影响下,静态检测器不管是时间还是空间效率都在不断变低,并且观察图像斜率可以发现,这一问题是非常显著的。而决赛时期引入的种种优化机制(尤其是函数分层调用机制),极大缓解了因为函数调用带来的性能开销,从图16可以看出,随着函数数量的变化,系统分析效率几乎不发生变化(只有小幅度波动)。
指针别名数量代表了程序的数据流复杂度,指针别名数越多,带给静态分析器的数据分析压力越高,如何处理层层叠叠的指针指向关系也是静态分析器的一大难题。

从上图中我们可以发现:数据流复杂度对不同工具的影响呈现显著分化。Cppcheck的性能对指针别名数量极为敏感,其CPU时间随别名数量增加而急剧上升。与之形成鲜明对比的是,MIAYC与CSA均表现出优异的鲁棒性,其性能曲线非常平缓。尤其是MIAYC,其CPU时间和内存消耗相比其他两个工具更低,这证明了MIAYC的内存模型和符号执行引擎能够高效地处理复杂的指针别名场景,而不会导致状态过度膨胀或分析效率下降。
在本次测试中,我们将基于代码生成框架定量分析我们决赛期间所做的两项重要优化分层函数调用与MPC路径算法的优化效果。
- 分层函数调用,我们运行不同负载的程序,每个程序都限定分析步数为6000次,在每次执行程序状态时记录其内部符号总数,并观察其分布趋势。
| 测试名称 | 代码行数 | 优化前耗时(s) | 优化后耗时(s) | 优化比率 |
|---|---|---|---|---|
| Small | 6544 | 10.08 | 9.19 | 8% |
| Medium | 17390 | 27.32 | 17.40 | 36% |
| Large | 33526 | 65.56 | 25.80 | 60% |
可以发现随着代码行数上升,有没有进行分层函数调用优化的差距正在迅速拉开。以下图表为两者运行时状态变化:
三个测试集优化后的程序相比优化前的平均符号消耗量均降低98% 以上。
- MPC路径选择算法,我们构造了一个分支深度较大,且带有循环的大型测试用例来模拟真实大型程序,我们分别测试使用DFS,BFS 和MPC算法进行路径选择,在限制执行步数的情况下分别能覆盖多少不同的基本块。
测试集参数
| 函数数量 | 函数负载 | 分支深度 | 指针别名数 | 代码行数 | 基本块个数 |
|---|---|---|---|---|---|
| 100 | 100 | 6 | 10 | 91230 | 5579 |
我们收集了三种路径选择算法在限定执行步数为1000 - 10000(步长为1000)的耗时与覆盖基本块数量,结果如下图所示:
由上图可以看出,MPC算法基本块覆盖率上表现卓越,仅需要不到6000步就可以几乎探索完5579个基本块的程序,在达到饱和前对探索步数的利用率超过95%,在达到饱和后时间资源消耗也同步降低。同时,其探索基本块 - 时间比也是三种算法中最优秀的,面对路径爆炸时,仅仅需要很低的步数与更低的时间便可以完成大部分程序基本块的探索。相比之下,BFS的步数利用率,时间利用率均逊色于MPC,而DFS算法虽然有极高的时间效率,但是其很容易陷入循环,基本块覆盖率非常低,只适合在中小型程序中进行全路径探索,面对大型路径爆炸的程序无法达到有效的覆盖率。
经过了上述测试,已成功证明了MIAYC静态分析器相对于传统符号执行分析器的创新优势以及可用性,其在Juliet Test Suite上大幅度领先传统静态分析器的同时,面对大型路径爆炸程序的能力也显著由于同类型工具。同时也证明了决赛时期所做的创新与优化均行之有效且效果显著。
本次测试我们一共选取了6个知名开源项目与一个往年优秀作品JunkMalloc作为实际情况的测试,成功检测出了多个内存安全问题,并提供了详细的分析报告与路径分析。
以下为相关检测信息:
| 项目名称 | 版本 | 二进制大小 | 基本块数量 | 可疑指令数量 | CSA检测可疑内存问题数目 |
|---|---|---|---|---|---|
| GNU bc | 1.07.1 | 169KB | 2383 | 31 | 12 |
| GNU bison | 3.8.2 | 1585KB | 20653 | 39 | 12 |
| GNU grep | 3.11 | 448KB | 6085 | 47 | 11 |
| GNU make | 4.4.1 | 610KB | 9196 | 38 | 20 |
| FLVMeta | 1.2.2 | 376KB | 5065 | 9 | 0 |
| libtiff | 4.6.0 | 1221KB | 15587 | 163 | 31 |
| JunkMalloc | - | 50KB | 391 | 22 | 3 |
相比于Clang Static Analyzer (CSA)的检测结果,MIAYC静态分析器在多个项目中均表现出更高的检测精度,尤其在GNU bc和GNU bison等复杂项目中,MIAYC能够识别出更多的内存安全问题。
以下为MIAYC静态分析器在上述项目中的检测结果示例:
"bc_malloc": {
"function_name": "bc_malloc",
"issues": [
...
{
"execution_count": 1,
"instruction": " %5 = call noalias ptr @malloc(i64 noundef %4) #12, !dbg !1256 // util.c:652",
"issues": [
{
"call_stack": [
"rl_input"
],
"error_type": "Memory Leak"
}
],
"source_code": "ptr = (void *) malloc (size);"
}
],
...
以下为调用链与相关代码:
// scan.l
rl_input((char *)buf, &result, max_size){
...
yylval.s_value = strcopyof(yytext);
...
}
// util.c
char * strcopyof(const char * str){
...
temp = bc_malloc(strlen(str) + 1);
...
}
void * bc_malloc(size_t size){
void * ptr;
ptr = (void *) malloc(size);
// Detect Memory leak allocated here
}可以看见MIAYC静态分析器成功检测到了bc_malloc函数中的内存泄漏问题,并提供了详细的调用链与源代码位置。
以下为更多MIAYC检测到的内存问题示例:
static uint8 get_bit(bit_buffer * bb) {
uint8 ret;
ret = (*(bb->current) >> (7 - bb->read_bits)) & 0x1; // Heap Overflow May occur at here
if (bb->read_bits == 7) {
bb->read_bits = 0;
bb->current++;
}
else {
bb->read_bits++;
}
return ret;
}grep错误示例:
"add_exclude": {
"function_name": "add_exclude",
"issues": [
{
"execution_count": 10,
"instruction": " store i32 %80, ptr %82, align 8, !dbg !3017 // exclude.c:534",
"issues": [
{
"call_stack": [
"main",
" call void @add_exclude(ptr noundef %361, ptr noundef %362, i32 noundef %370), !dbg !3316 // grep.c:2777"
],
"error_type": "Heap Overflow"
},
{
"call_stack": [
"main",
" call void @add_exclude(ptr noundef %431, ptr noundef %432, i32 noundef %435), !dbg !3380 // grep.c:2800"
],
"error_type": "Heap Overflow"
}
],
"source_code": "patopts->options = options;"
},
],
},以及LLM分析结果示例:
python ../../static/scripts/llm_filter.py --function_name add_exclude --stack grep.json
Adding call stack information to the prompt.
--- Analyzing function: add_exclude ---
Issue #1: patopts->options = options;
Verdict: PATH EXISTS
Confidence: High
Reasoning: The issue arises when 'patopts->options = options;' is executed. A feasible path exists if 'ex->head' is not NULL, 'ex->head->type' is 'exclude_pattern', and the options match, leading to the allocation and assignment without proper bounds checking. This can cause a heap overflow if 'pat->exclude_alloc' is not sufficiently large to accommodate 'pat->exclude_count++'.
Issue #2: patopts->v.pattern = pattern;
Verdict: PATH EXISTS
Confidence: Medium
Reasoning: The issue occurs with 'patopts->v.pattern = pattern;'. A feasible path exists when 'options & EXCLUDE_ALLOC' is true, leading to 'pattern' being duplicated and assigned without checking the allocated memory's bounds. This can result in a heap overflow if the duplicated pattern exceeds the allocated memory size.
--------------------------------------------------
> python ../../../scripts/llm_filter.py --function_name TIFFAppendToStrip --stack libtiff.json
--- Analyzing function: TIFFAppendToStrip ---
Issue #1: if (td->td_stripoffset_p[strip] == 0 || tif->tif_curoff == 0)
Verdict: PATH EXISTS
Confidence: High
Reasoning: The condition checks if 'td->td_stripoffset_p[strip]' is 0 or 'tif->tif_curoff' is 0. If 'strip' is out of bounds, it could lead to a heap overflow. Given that 'strip' is passed as a parameter, an attacker could provide a value that exceeds the array bounds.
Issue #2: if (td->td_stripbytecount_p[strip] != 0 &&
Verdict: PATH EXISTS
Confidence: High
Reasoning: Similar to issue #1, accessing 'td->td_stripbytecount_p[strip]' without bounds checking on 'strip' could lead to a heap overflow if 'strip' is out of bounds.
Issue #3: td->td_stripoffset_p[strip] != 0 &&
Verdict: PATH EXISTS
Confidence: High
Reasoning: Accessing 'td->td_stripoffset_p[strip]' without bounds checking on 'strip' could lead to a heap overflow if 'strip' is out of bounds.LLM会分析MIAYC报告中的可信程度,并且结合源代码分析是否存在可能的路径导致这些问题。以上示例中,LLM分析了TIFFAppendToStrip函数中的三个潜在问题,并给出了高置信度的判断,认为这些问题在使用不当的情况下确实可能导致堆溢出。
在往届优秀作品中同样存在类似问题:
> python ../../../scripts/llm_filter.py --function_name triple_read --stack JunkMalloc.json
Adding call stack information to the prompt.
--- Analyzing function: triple_read ---
Issue #1: memcpy(tar, source, size);
Verdict: PATH EXISTS
Confidence: High
Reasoning: The function 'triple_read' copies 'size' bytes from 'source' to 'tar' without checking if 'tar' has enough allocated memory. If 'size' exceeds the allocated memory for 'tar', a heap overflow occurs. This can happen if the function is called with a 'size' larger than the memory allocated for 'tar'.
Issue #2: memcpy(ptr_2, source, size);
Verdict: PATH EXISTS
Confidence: High
Reasoning: Similar to issue #1, copying 'size' bytes from 'source' to 'ptr_2' without bounds checking can lead to a heap overflow if 'ptr_2' plus 'size' exceeds allocated memory. This scenario is feasible if 'size' is inappropriately large or 'ptr_2' is not properly allocated.
Issue #3: memcpy(ptr_1, source, size);
Verdict: PATH EXISTS
Confidence: High
Reasoning: Copying 'size' bytes from 'source' to 'ptr_1' without verifying the bounds of 'ptr_1' can cause a heap overflow. This is possible under the same conditions as issues #1 and #2, where 'size' is too large or memory allocation is insufficient.
更多详细测试过程请见决赛静态测试文档,更多具体的检测报考请参考测试结果
与静态分析器类似,我们首先测试动态分析器在Juliet Test Suite的表现来验证其效果与准确性。由于Juliet Test Suite中的代码多为程序片段,使用运行时间作为参考标准不能体现出动态分析器在减少Asan插桩数量上的贡献。因此,本测试将使用插桩数目评判动态检测器性能,使用正确检测到错误的个数评判动态检测器的准确性。
我们将Juliet Test Suite中的每个错误类型的所有文件先编译成IR,随后分别使用原版Clang与动态分析器中的Clang开启Asan进行编译,随后对比两份经过Asan插桩后的IR文件中Asan的插桩数目。同时,我们还会将每个测试用例编译成可执行文件并执行,通过检测是否触发Asan报告来验证动态检测器的正确性。
运行时输出示例如下:
MERGED ANALYSIS RESULTS
================================================================================
Total files analyzed: 5016
- Bad samples: 2508
- Good samples: 2508
- Unclassified samples: 0
INSTRUMENTATION STATISTICS:
Total Standard ASan instrumentations: 100950
Total MIAYC + ASan instrumentations: 24831
Total instrumentation reduction: 76119 calls (75.40%)
ERROR DETECTION STATISTICS:
Standard ASan Performance Metrics:
- True Positives (TP): 2249
- False Positives (FP): 0
- True Negatives (TN): 2508
- False Negatives (FN): 259
- Accuracy: 0.9484
- Precision: 1.0000
- Recall: 0.8967
- F1 Score: 0.9456
MIAYC ASan Performance Metrics:
- True Positives (TP): 2006
- False Positives (FP): 0
- True Negatives (TN): 2508
- False Negatives (FN): 502
- Accuracy: 0.8999
- Precision: 1.0000
- Recall: 0.7998
- F1 Score: 0.8888
Overall Detection Accuracy:
Standard ASan correct detections: 4757/5016 (94.84%)
MIAYC ASan correct detections: 4514/5016 (89.99%)
DETAILED DETECTION ANALYSIS:
Bad samples (should detect errors):
- Standard ASan: 2249/2508 (89.67%)
- MIAYC ASan: 2006/2508 (79.98%)
Good samples (should NOT detect errors):
- Standard ASan: 2508/2508 (100.00%)
- MIAYC ASan: 2508/2508 (100.00%)整合成表格如下表所示:
| 测试集 | 用例数 | 插桩减少率 | Asan F1 | MIAYC F1 |
|---|---|---|---|---|
| CWE121 | 5016 | 75.4% | 0.94 | 0.88 |
| CWE122 | 3340 | 79.7% | 0.88 | 0.84 |
| CWE401 | 1396 | 78.61% | 0.69 | 0.81 |
| CWE415 | 380 | 79.11% | 0.99 | 0.99 |
| CWE416 | 236 | 80.42% | 0.97 | 0.97 |
由上表所示,MIAYC动态检测器相对原版Asan的插桩减少量达到了80%,而精度损失几乎只有5%,甚至在CWE401(内存泄漏)的测试集中,精度比原版Asan还要高。
详细测试请参考决赛动态测试文档。
SPEC是标准性能评估公司(Standard Performance Evaluation Corporation)的简称。SPEC是由计算机厂商、系统集成商、大学、研究机构、咨询等多家公司组成的非营利性组织,这个组织的目标是建立、维护一套用于评估计算机系统的标准。其中包含两套测试套件:CINT2006和CFP2006。其中CINT2006共有12个测试项目,用于评测CPU整型运算的性能;CFP2006共有17个测试项目,用于评测CPU浮点运算的性能。这29个测试项目使用了C、C++、Fortran共三种语言。
我们将选用以下测试用例进行测试:
SPEC测试用例
| 测试集 | Basic Block | 用例含义 |
|---|---|---|
| 401.bzip2 | 2708 | 压缩程序 |
| 429.mcf | 514 | 用于大型公共交通中的单站车辆调度的程序 |
| 456.hmmer | 11245 | 使用HMMS基因识别方法进行基因序列搜索 |
| 458.sjeng | 5759 | 人工智能象棋算法 |
测试方式与Juliet Test Suite类似,我们将会通过Asan与MIAYC分别对测试程序进行插桩,并且通过分析插桩减少数目与实际运行时间来验证MIAYC动态分析器的性能效果。
编译结果如下:
| 测试集 | 原始插桩数 | 现有插桩数 | 插桩减少率 |
|---|---|---|---|
| 401.bzip2 | 3659 | 319 | 91.28% |
| 429.mcf | 594 | 56 | 90.57% |
| 456.hmmer | 12021 | 1396 | 88.39% |
| 458.sjeng | 2447 | 417 | 82.96% |
对于正常程序,可疑的内存访问数量是远远要小于Asan插桩数量的,即使是经过了采取保守分析的MIAYC静态分析器筛选后,也能有80% 以上的插桩数目优化能力。可见动静结合减少程序插桩方法的强大。
我们分别使用原始程序,Asan插桩,MIAYC插桩三个可执行文件对SPEC负载展开性能测试,详细数据请见下图:
由上图可见,MIAYC不仅显著降低了程序插桩数目,也显著降低了Asan带来的运行时开销,达到了平均85% 以上的提升。
此部分测试旨在确保MIAYC系统采样模块(MIAYC System Sampler)的核心功能按预期工作,且其设计能够在生产环境中以低开销实时监控内存分配行为。
- 训练效果评估: 利用数据集分割的测试集,对MIAYC系统采样模块的内存泄漏检测模型进行了多指标综合评估以及可视化。
- 实际部署功能展示: 运行实际部署脚本和测试,通过日志文件展示系统采样模块在生产环境中的实时内存监控能力。
为了方便且准确地评估模型的预测精度,我们在模型训练时按照0.2的比例分割出了测试集,并进行了训练后评估。
在system/trainntest.py中,通过设置参数实现自动化批量训练分类模型:
[system] $ sudo python3 trainntest.py --filter-best-params --auto-stop-trace我们设置了如下参数组合:
# all combinations
PARAMS_COMBINATIONS = {
# first layer: n factor
16: {
# second layer: milc hmmer ratio
6: [6, 7, 8], # third layer: window sizes
7: [6, 7, 8], # third layer: window sizes
8: [6, 7, 8], # third layer: window sizes
},
24: {
6: [6, 7, 8],
7: [6, 7, 8], # third layer: window sizes
8: [6, 7, 8],
},
32: {
6: [6, 7, 8],
7: [6, 7, 8], # third layer: window sizes
8: [6, 7, 8],
},
}它们涵盖了所有可能训练出优质模型的参数组合,共包含了三个参数:
-
n_factor: 随机free()的N因子。我们通过替换目标中的free()函数来人为制造内存泄漏,获取足够多的泄漏数据。 -
milc_hmmer_ratio: 我们使用了SPEC中如下testbench的内存数据作为训练集:测试集 程序功能 433.milc 用于在MIMD上模拟四维SU(3)晶格规范理论 456.hmmer 使用HMMS基因识别方法进行基因序列搜索 由于两个程序的内存_分配模式和程序规模_差别较大,我们需要按照一定比例运行两个程序产生数据集,以保证True和False标签的均衡。
-
window_size: 特征提取使用的滑动窗口大小,影响到最终特征的时序性。
我们根据n_factor分组,绘制出了模型的训练效果对比图:

从图中可以看出,三个不同的n_factor均表现出优良的训练效果,整体指标在0.9左右浮动。这说明我们的特征工程可靠性极强,能够稳定训练出高精度的模型。
其中n_factor == 16训练效果最佳,五个指标平均数值均在0.9以上。
同时,为了能够直观展现模型的分析效果,我们截取部分epoch绘制了模型预测行为的趋势图:
,
,
,
在我们训练过的所有模型中,精度最佳的为:
| Metrics | precision | recall | f1-score | support |
|---|---|---|---|---|
| False | 0.9280 | 0.9495 | 0.9386 | 733.0000 |
| True | 0.9411 | 0.9163 | 0.9285 | 645.0000 |
| macro avg | 0.9345 | 0.9329 | 0.9336 | 1378.0000 |
| weighted avg | 0.9341 | 0.9340 | 0.9339 | 1378.0000 |
| accuracy | 0.9340 |
该模型参数组合为:
MILC_HMMER_RATIO: 6
窗口大小: 7
随机释放N因子: 16由表可知训练精度高达0.9340,几乎不会出现漏判或者误判。
[system] $ sudo python3 sampler.py
[test] $ run_test.py <testname>Sampler输出日志如下:
2025-08-16 13:52:42,758 - INFO - Found 447 alloc events for PID: 1332605, start extracting features...
2025-08-16 13:52:42,758 - INFO - AllocEvent构造完成,开始提取特征,PID: 1332605, AllocEvent数量: 447
2025-08-16 13:52:42,759 - INFO - 提取初级特征完成,PID: 1332605, Epoch数量:10,开始提取最终特征...
2025-08-16 13:52:42,760 - INFO - 提取最终特征完成,PID: 1332605, Epoch数量:10,插入到最终特征Queue中...
2025-08-16 13:52:42,760 - INFO - 从队列中获取到PID: 1332605的最终特征,开始执行模型分析...
2025-08-16 13:52:42,763 - INFO - Model prediction for PID 1332605: False
2025-08-16 13:52:42,843 - INFO - Found 772 alloc events for PID: 1332605, start extracting features...
2025-08-16 13:52:42,843 - INFO - AllocEvent构造完成,开始提取特征,PID: 1332605, AllocEvent数量: 772
2025-08-16 13:52:42,844 - INFO - 提取初级特征完成,PID: 1332605, Epoch数量:9,开始提取最终特征...
2025-08-16 13:52:42,844 - INFO - 提取最终特征完成,PID: 1332605, Epoch数量:9,插入到最终特征Queue中...
2025-08-16 13:52:42,845 - INFO - 从队列中获取到PID: 1332605的最终特征,开始执行模型分析...
2025-08-16 13:52:42,849 - INFO - 检测到内存泄漏,向进程 1332605 发送信号...
2025-08-16 13:52:42,849 - INFO - Model prediction for PID 1332605: True
2025-08-16 13:52:42,928 - INFO - Found 752 alloc events for PID: 1332605, start extracting features...
2025-08-16 13:52:42,928 - INFO - AllocEvent构造完成,开始提取特征,PID: 1332605, AllocEvent数量: 752
2025-08-16 13:52:42,929 - INFO - 提取初级特征完成,PID: 1332605, Epoch数量:10,开始提取最终特征...
2025-08-16 13:52:42,930 - INFO - 提取最终特征完成,PID: 1332605, Epoch数量:10,插入到最终特征Queue中...
2025-08-16 13:52:42,930 - INFO - 从队列中获取到PID: 1332605的最终特征,开始执行模型分析...
2025-08-16 13:52:42,934 - INFO - 检测到内存泄漏,向进程 1332605 发送信号...
2025-08-16 13:52:42,934 - INFO - Model prediction for PID 1332605: True由日志可知,Sampler定时进行了取样,提取初级特征和最终特征并预测了内存泄漏,最后向用户组件发送了信号,实现了最后的部署功能。
本项目创新性地构建了静态检测、动态监测与系统态监控相融合的内存问题检测架构,主要工作与创新点如下:
- 设计并实现了基于LLVM IR的符号执行检测工具,开发了优化的内存模型、类型系统、约束求解及分层函数调用机制,提出启发式MPC算法以提升路径爆炸场景下的检测精度与性能,接入大语言模型帮助开发者减少筛选误报的成本。该模块已通过完备测试体系验证其技术优势。
- 优化了基于Asan的动态检测器,提出通过静态分析结果指导Asan插桩的协同框架,并实施路径合并、基本块合并与循环合并等优化策略,实现动态开销降低85% 的同时保持95% 的检测精度,几乎达到部署标准。
- 搭建了基于eBPF的系统态内存采样器架构。将eBPF与机器学习技术创新性结合,构建出了eBPF -> 数据处理器 -> 机器学习模型的全新框架,提出了Epoch和滑动窗口法等提取特征的核心方案,大幅提高了采样器的数据分析速度与模型预测的精度,实现了系统采样器的轻量化设计,构造了一套完备、便利的内存检测系统。
- 静态分析器虽经测试验证具备先进性能,并采用启发式MPC算法缓解路径爆炸问题,但仍存在误报/漏报现象。受限于开发周期,当前实现仅聚焦核心框架,尚未构建完整的用户交互逻辑与异常处理机制,暂未达到工业级检测工具链标准。
- 动态检测器对静态分析元数据的利用率有待提升,需设计更精细的动静协同机制以深化检测调控,进一步降低动态开销并提升准确率。
- 系统采样器的功能实现尚未完成。尽管系统采样器的核心框架已经全部搭建完成,但在泄漏预测后如何处理的部分仍然没有明确有效的方案;受限于开发周期,我们尚未能为分类模型提供更加具有广泛性的训练集;分类模型针对不同内存分配模式的程序适应性较差,泛化能力一般。
当前成果为后续研究奠定基础,后续工作将聚焦以下方向:
- 完善静态分析器:优化核心算法性能;扩展语言库函数支持范围;构建完整的用户交互与异常处理体系;使用多线程技术进一步提升静态分析器的分析效率。
- 开发更高效的动静协同机制,实现动态检测开销的深度优化。
- 应用深度学习技术挖掘进程内存特征与内存泄漏的关联性,寻找覆盖更多内存分配模式的训练集,使用更高级的技术增加模型泛化能力;设计更加可靠的特征工程以提升系统采样器检测精度;强化采样器错误应急机制以增强部署可靠性;开发内存监控面板以直观展示程序内存趋势;为采样器寻找更加有效的预测后处理机制。
由于功能展示视频较大,只能在此展示压缩过码率与分辨率的视频:(可能需要加载一会)
原版未压缩视频请通过以下链接下载:MIAYC决赛功能展示视频
由于项目PPT较大,无法直接上传至仓库,请通过以下链接下载: MIAYC初赛PPT
MIAYC决赛PPT请见决赛答辩文件提交部分。
以下为更多本文档未覆盖的项目细节,请参考对应的Markdown文档:
- 3.1 调研概要 - 项目背景与技术调研
- 3.2 环境配置 - 开发环境与依赖配置
- 3.3 项目分工 - 团队成员分工与职责
- 3.4 进度同步 - 项目进度与分工记录
- 3.5 项目遇到的困难 - 项目开发中的挑战与解决方案
- 3.6 项目收获 - 团队成员的学习与成长
- 4.1 静态开发文档 - 静态分析器的设计与实现
- 4.2 决赛静态开发文档 - 决赛阶段静态分析器的设计与实现
- 4.3 静态测试文档 - 静态分析器的测试与评估
- 4.4 决赛静态测试文档 - 决赛阶段静态分析器的测试与评估
- 5.1 动态开发文档 - 动态检测器的设计与实现
- 5.2 决赛动态开发文档 - 动态检测器的设计与实现
- 5.3 动态测试文档 - 动态检测器的测试与评估
- 5.4 决赛动态测试文档 - 决赛阶段动态检测器的测试与评估
- 6.1 系统采样器开发文档 - 系统采样器的设计与实现
- 6.2 系统采样器测试文档 - 系统采样器的测试与评估
本项目静态分析器模块在系统架构设计层面,主要参考了开源项目Clang Static Analyzer(以下简称CSA)与KLEE的核心实现机制。在关键组件设计中:
-
内存模型与状态管理
继承自CSA框架的内存模型和程序状态管理机制,针对路径敏感分析需求进行深度优化与创新性改进 -
符号执行引擎
综合CSA的上下文敏感约束求解能力与KLEE的动态符号执行优势,实现协同优化 -
路径规划算法
借鉴Empc论文提出的状态空间缩减策略。 -
开源依赖库
a.cxxopts(MIT License)
b.nlohmann/json(MIT License)
c.tomlplusplus(MIT License) -
基础框架许可
a. CSA:采用Apache License v2.0
b. KLEE:采用University of Illinois/NCSA Open Source License
动态检测模块主要基于开源项目Address Sanitizer(以下简称ASAN):
- 检测机制
继承ASAN的影子内存机制,新增静态分析接口并优化多类型指令插桩策略 - 去冗余优化
参考论文Debloating Address Sanitizer的创新算法 - 开源许可
a. ASAN采用Apache License v2.0
系统采样器模块主要参考以下技术:
-
Epoch设计
核心概念源自论文Detection of Memory Leaks in C/C++ Code via Machine Learning的内存管理模型 -
eBPF实现
探针开发参考eBPF Tutorial的实践指南
见BibLaTeX.bib文件。
.
├── CMakeLists.txt # CMake配置文件
├── doc # 文档目录
├── dynamic # 动态分析器目录
├── external # 外部依赖目录
├── image # 图片目录
├── LICENSE # 许可证文件
├── MIAYC初赛设计开发文档.pdf # 初赛设计开发文档
├── MIAYC决赛设计开发文档.pdf # 决赛设计开发文档
├── README.md # 项目主文档
├── Reference # 参考文献目录
├── static # 静态分析器目录
├── system # 系统采样器目录
├── test # 测试结果目录
└── video # 视频目录












