W19: plugin_loader hardening — ABI try/catch, path validation, atomic IDs, CLI exit codes (W19.1-W19.5)
Some checks failed
CI / Determine matrix (push) Has been cancelled
CI / ${{ matrix.os }} / ${{ matrix.build_type }} (push) Has been cancelled

Fixes: F-18.3-1 through F-18.3-5 (all CLOSED, findings registry at zero)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-27 19:34:43 +08:00
parent c545d16120
commit 3250b5a8bf
15 changed files with 273 additions and 30 deletions

View File

@@ -35,10 +35,11 @@
#define CLR_BOLD "\033[1m"
// ---- 退出码 ----
// 0=正常退出 1=用户中断(SIGINT/Ctrl+C) 2=致命错误 3=配置错误
#define EXIT_OK 0
#define EXIT_INIT_FAIL 1
#define EXIT_AI_ERROR 2
#define EXIT_SVC_UNAVAIL 3
#define EXIT_INTERRUPT 1
#define EXIT_FATAL 2
#define EXIT_CONFIG 3
// ---- 服务 vtable 指针 ----
static const dstalk_ai_service_t* g_ai = nullptr;
@@ -48,12 +49,14 @@ static const dstalk_file_io_service_t* g_file_io = nullptr;
// ---- 运行时状态 ----
static std::string g_current_model;
static std::atomic<bool> g_quit_requested{false};
static std::atomic<bool> g_quit_via_signal{false};
// ---- Ctrl+C 信号处理 ----
#ifdef _WIN32
static BOOL WINAPI on_console_event(DWORD event)
{
if (event == CTRL_C_EVENT || event == CTRL_BREAK_EVENT) {
g_quit_via_signal = true;
g_quit_requested = true;
return TRUE;
}
@@ -62,6 +65,7 @@ static BOOL WINAPI on_console_event(DWORD event)
#else
static void on_signal(int /*sig*/)
{
g_quit_via_signal = true;
g_quit_requested = true;
}
#endif
@@ -154,7 +158,6 @@ static void handle_command(const char* line)
// /quit —— 设置退出标志,让控制流自然回到 main 末尾
if (std::strcmp(line, "/quit") == 0 || std::strcmp(line, "/q") == 0) {
g_quit_requested = true;
std::printf("再见!\n");
return;
}
@@ -442,7 +445,7 @@ int main(int argc, char* argv[])
// 初始化主机(加载配置 + 自动扫描 plugins/ 目录加载插件)
if (dstalk_init(config_path) != 0) {
std::fprintf(stderr, CLR_RED "[dstalk] 初始化失败\n" CLR_RESET);
return EXIT_INIT_FAIL;
return EXIT_CONFIG;
}
// 查询插件服务
@@ -486,12 +489,12 @@ int main(int argc, char* argv[])
if (input.empty()) {
std::fprintf(stderr, "empty prompt\n");
dstalk_shutdown();
return 1;
return EXIT_FATAL;
}
if (!g_ai || !g_session) {
std::fprintf(stderr, CLR_RED "[ERROR] AI or session service unavailable\n" CLR_RESET);
dstalk_shutdown();
return EXIT_SVC_UNAVAIL;
return EXIT_CONFIG;
}
int history_count = 0;
const dstalk_message_t* history = g_session->history(&history_count);
@@ -506,14 +509,17 @@ int main(int argc, char* argv[])
result.error ? result.error : "unknown");
g_ai->free_result(&result);
dstalk_shutdown();
return EXIT_AI_ERROR;
return EXIT_FATAL;
}
}
char buffer[8192];
while (true) {
// B1: 检查退出标志
if (g_quit_requested) break;
if (g_quit_requested) {
std::printf("再见!\n");
break;
}
// A1: 提示符带模型名batch 模式不打印)
if (!batch_mode) {
@@ -574,7 +580,7 @@ int main(int argc, char* argv[])
g_ai->free_result(&result);
}
// B2: 单一退出点dstalk_shutdown 只在此调用
// B2: 单一退出点dstalk_shutdown 只在此调用(交互模式下)
dstalk_shutdown();
return EXIT_OK;
return g_quit_via_signal ? EXIT_INTERRUPT : EXIT_OK;
}