问题概述
对 GeneralUpdate.Bowl 组件进行代码审查后,发现以下架构层面和功能层面的问题。
🔴 严重问题
1. UpgradeFail 版本排除机制自毁
IpcEncryption.DecryptFromFile 在每次读取后自动删除文件:
finally {
try { File.Delete(filePath); } catch { }
}
流程:
- Bowl 检测到崩溃 →
SetVariable("UpgradeFail", "2.0.0") → 写入 %TEMP%/GeneralUpdate/ipc/UpgradeFail.enc
- Core
CheckFail() 调用 GetEnvironmentVariable("UpgradeFail") → 解密 → 返回 "2.0.0" → 文件被删除
- 再次调用
CheckFail() → 文件不存在 → 返回空字符串 → 跳过版本排除 → 再次安装已知崩溃版本
而 WindowStrategy.SetEnvironment() 注释声明:
"Once this version number is set, it will not be removed, and updates will not proceed until a version greater than the exception version number is obtained."
这是一个 永久性版本排除机制,但实现上只能工作一次。
2. Bowl 与 Core 之间 Environments + IpcEncryption 源码完全重复
| Bowl |
Core |
Bowl/Ipc/IpcEncryption.cs |
Core/Ipc/IpcEncryption.cs |
Bowl/Ipc/Environments.cs |
Core/Configuration/Environments.cs |
相同的 AES 密钥、相同的文件路径、逐字复制的代码。任何一方的密钥/路径变更未同步都会导致 IPC 静默失败。
3. Bowl 启动时读不到 ProcessInfo
WindowsStrategy.StartAppAsync() 直接 Process.Start(bowlAppPath),没有先写入 ProcessInfo 环境变量。Bowl 的 CreateParameter() 读取 ProcessInfo 失败 → ArgumentNullException → Bowl 进程直接退出。
🟡 中等问题
4. macOS 策略 (MacBowlStrategy) 在生产环境不可用
策略自身注释承认:
"lldb requires the process being debugged to allow debugging (SIP / task_for_pid restrictions). For production macOS crash capture, consider using Crashpad instead."
which lldb 检查只能确认 lldb 存在,不能确认它能 attach 目标进程。在生产 macOS 启用了 SIP 的情况下策略是一个空壳。
5. Linux 策略仅支持部分发行版
- 仅支持 6 个发行版:
ubuntu/debian/rhel/centos/fedora/clearos
- 所有包名只有
x86_64,ARM64(树莓派、AWS Graviton)全不支持
install.sh 依赖 sudo 且无密码提示处理 — 挂起 60s 直到超时
6. Linux 策略 -p 仅接受 PID
Linux procdump -p 只接受数字 PID,但参数名叫 ProcessNameOrId。开发者传进程名时静默失败。
7. 未使用的 CrashJsonContext 源码生成器
CrashJsonContext 定义了 [JsonSerializable(typeof(Crash))],但 CrashReporter 使用的是 JsonSerializer.Serialize(obj)(反射模式),源码生成器完全未用。
8. WindowsSystemInfoProvider 同步阻塞无取消支持
ExportAsync(string outputDirectory, CancellationToken ct) 方法内 process.WaitForExit(30_000) 同步阻塞,ct 从未被检查或使用。
9. ProcessRunner 输出竞态条件
OutputDataReceived 在 ThreadPool 线程触发,进程退出后可能仍有事件未完成。Exited 事件触发和 lock 拿快照之间有窗漏。
🔵 低优先级
10. Strategies/ vs Strategys/ 命名空间混淆
新 API(Strategies/IBowlStrategy)和旧 [Obsolete] API(Strategys/IStrategy)并存,"Strategys" 拼写错误。
11. TextTraceListener 位于全局命名空间
public class TextTraceListener : TraceListener — 没有 namespace 声明,污染所有消费者的全局命名空间。
12. StorageHelper 暴露为 public
内部文件系统工具类作为 public static class 暴露,应改为 internal。
13. GeneralTracer.Fatal 使用错误的 TraceLevel
public static void Fatal(string message) => WriteTraceMessage(TraceLevel.Off, message);
TraceLevel.Off 意为"不输出任何消息",对 Fatal 日志语义错误。
审查结论
- Windows: 完整功能可用
- Linux: 仅在满足 4 个条件时可工作(发行版在支持列表、sudo 免密、目标为 PID、procdump 版本兼容),无系统诊断导出
- macOS: 实际不可用
修复 PR
PR #491 解决了上述问题中的 1–8, 10–12。
问题概述
对
GeneralUpdate.Bowl组件进行代码审查后,发现以下架构层面和功能层面的问题。🔴 严重问题
1.
UpgradeFail版本排除机制自毁IpcEncryption.DecryptFromFile在每次读取后自动删除文件:流程:
SetVariable("UpgradeFail", "2.0.0")→ 写入%TEMP%/GeneralUpdate/ipc/UpgradeFail.encCheckFail()调用GetEnvironmentVariable("UpgradeFail")→ 解密 → 返回 "2.0.0" → 文件被删除CheckFail()→ 文件不存在 → 返回空字符串 → 跳过版本排除 → 再次安装已知崩溃版本而
WindowStrategy.SetEnvironment()注释声明:这是一个 永久性版本排除机制,但实现上只能工作一次。
2. Bowl 与 Core 之间
Environments+IpcEncryption源码完全重复Bowl/Ipc/IpcEncryption.csCore/Ipc/IpcEncryption.csBowl/Ipc/Environments.csCore/Configuration/Environments.cs相同的 AES 密钥、相同的文件路径、逐字复制的代码。任何一方的密钥/路径变更未同步都会导致 IPC 静默失败。
3. Bowl 启动时读不到
ProcessInfoWindowsStrategy.StartAppAsync()直接Process.Start(bowlAppPath),没有先写入ProcessInfo环境变量。Bowl 的CreateParameter()读取ProcessInfo失败 →ArgumentNullException→ Bowl 进程直接退出。🟡 中等问题
4. macOS 策略 (
MacBowlStrategy) 在生产环境不可用策略自身注释承认:
which lldb检查只能确认 lldb 存在,不能确认它能 attach 目标进程。在生产 macOS 启用了 SIP 的情况下策略是一个空壳。5. Linux 策略仅支持部分发行版
ubuntu/debian/rhel/centos/fedora/clearosx86_64,ARM64(树莓派、AWS Graviton)全不支持install.sh依赖sudo且无密码提示处理 — 挂起 60s 直到超时6. Linux 策略
-p仅接受 PIDLinux procdump
-p只接受数字 PID,但参数名叫ProcessNameOrId。开发者传进程名时静默失败。7. 未使用的
CrashJsonContext源码生成器CrashJsonContext定义了[JsonSerializable(typeof(Crash))],但CrashReporter使用的是JsonSerializer.Serialize(obj)(反射模式),源码生成器完全未用。8.
WindowsSystemInfoProvider同步阻塞无取消支持ExportAsync(string outputDirectory, CancellationToken ct)方法内process.WaitForExit(30_000)同步阻塞,ct从未被检查或使用。9.
ProcessRunner输出竞态条件OutputDataReceived在 ThreadPool 线程触发,进程退出后可能仍有事件未完成。Exited事件触发和lock拿快照之间有窗漏。🔵 低优先级
10.
Strategies/vsStrategys/命名空间混淆新 API(
Strategies/IBowlStrategy)和旧[Obsolete]API(Strategys/IStrategy)并存,"Strategys" 拼写错误。11.
TextTraceListener位于全局命名空间public class TextTraceListener : TraceListener— 没有namespace声明,污染所有消费者的全局命名空间。12.
StorageHelper暴露为public内部文件系统工具类作为
public static class暴露,应改为internal。13.
GeneralTracer.Fatal使用错误的TraceLevelTraceLevel.Off意为"不输出任何消息",对 Fatal 日志语义错误。审查结论
修复 PR
PR #491 解决了上述问题中的 1–8, 10–12。