题目重点:Nvidia NG SDE onsite 面经描述大 C++ 项目分阶段排查逻辑、内存与竞态问题;本文给出可复现的定位流程、验证顺序和屏幕共享表达。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 文章给出排查流程和合成示例,不把 use-after-free、double free 或某个 race 说成原题的真实缺陷;题目只明确缺陷类别。
- 训练环境可本地编译、运行单测、使用 AddressSanitizer/UndefinedBehaviorSanitizer/ThreadSanitizer;实际可用工具取决于面试环境。
- 每个 stage 先固定输入、预期输出与失败症状;一次只改一类根因,并为新发现的行为补最小回归例。
解题路线
- 先让项目在原配置下可重复失败:记录编译命令、输入、stage、退出码、日志和预期行为。若失败不稳定,固定随机种子、并发度和环境;先确认是否为逻辑错误还是未定义行为。
- 按证据选工具:输出错误先追输入到输出的数据路径、加断言和缩小输入;崩溃或内存异常用 ASan/UBSan 看首次违规读写与所有权链;竞态嫌疑用 TSan、重复运行和线程交错日志。不同 sanitizer 的可用组合需按编译器核对。
- 把失败缩到最小函数或最少事件序列,提出可证伪的根因假设。例如训练案例中一个异步任务捕获已销毁对象引用,先用 ASan 确认生命周期,再改为明确所有权,最后用任务完成后的断言验证。该案例不是题目源码。
- 修复后运行该 stage 的原失败输入、相邻边界输入与前面 stages 的回归集;并发问题还要多次重复与压力运行。屏幕共享时口述假设、证据、修改和验证,不只展示最后能跑通的代码。
- 若使用 AI 辅助,先提供最小代码段、错误输出和当前假设,要求给可验证的候选原因;逐条在本地证实。题目只说明允许使用 AI,没有规定提示词或评分标准。
手动走一遍
合成训练例:stage 2 在重复 100 次中偶发输出少一个元素。先固定线程数和输入;在写入共享 vector 的位置加线程 ID 日志,观察两线程同时修改;TSan 若报告冲突,再比较加锁、分线程缓冲区后合并两种修法的正确性和成本。修完后重跑原输入及 stage 1,避免只修表面输出。
规模与取舍
这里没有一个可推导的单一算法复杂度。实际成本来自复现次数、编译/测试周期、插桩开销与项目规模。修复方案若加全局锁会改变吞吐和尾延迟;若分线程缓冲区会增加 O(T×B) 级别的临时内存,T 为线程数、B 为每线程缓冲容量。面试中需针对具体缺陷量测。
易错点与追问
容易失分的边界
- 看到最终错误输出就直接改输出路径,不追首次违反不变量的位置;内存破坏常在更早发生。
- 把每个随机失败都归为 race;未初始化内存、非确定性输入与未定义行为也可能导致不稳定症状。
- 一次修改多处并跳过回归,无法确认哪个改动修复了根因,也可能让早期 stage 退化。
- 把 AI 给出的建议直接粘贴为修复,而没有运行最小复现、sanitizer 或边界验证。
继续深挖
- 若 sanitizer 改变时序导致 race 不再复现,保留日志与压力测试,控制线程调度并检查共享状态的同步约定。
- 若修复需要改 API 所有权,比较 unique_ptr/shared_ptr、值语义和生命周期约束,而不是只把裸指针替换成 shared_ptr。
- 若时间有限,优先建立可重复复现和最小根因证据,再说明剩余验证计划;不要声称已修复无法复现的问题。
