fix(ai): add mutex to AISession for thread safety
Some checks failed
CI Code / Linux (debian) (pull_request) Failing after 3m27s
CI Code / Linux (arch) (pull_request) Failing after 5m14s
CI Code / Code Coverage (pull_request) Failing after 10m52s
CI Code / Check spelling (pull_request) Failing after 10m57s
CI Code / Check coding style (pull_request) Failing after 11m2s
CI Code / Linux (ubuntu) (pull_request) Failing after 11m8s

Introduce a pthread mutex to protect all AISession fields from
concurrent access between the main thread and background request
worker.

- Initialize and destroy mutex during session lifecycle
- Lock session state when modifying or reading history, model, and
  provider fields
- Snapshot session state under lock in the request worker thread to
  prevent UAF races during API calls
- Refactor _build_json_payload to accept direct parameters for safe
  usage under lock
- Update command handlers to safely switch provider/model under lock
This commit is contained in:
2026-05-11 23:26:14 +00:00
parent 6fe8c370df
commit 9f4621883a
3 changed files with 131 additions and 26 deletions

View File

@@ -51,6 +51,7 @@
#include <unistd.h>
#include <langinfo.h>
#include <ctype.h>
#include <pthread.h>
// fork / execl
#include <sys/types.h>
@@ -11096,7 +11097,14 @@ cmd_ai_switch(ProfWin* window, const char* const command, gchar** args)
}
} else {
// arg1 is a model name, keep current provider
// Read provider_name under lock to prevent UAF on session->provider_name
pthread_mutex_lock(&aiwin->session->lock);
provider_name = aiwin->session->provider_name;
pthread_mutex_unlock(&aiwin->session->lock);
if (!provider_name) {
cons_show_error("Session has no provider name.");
return TRUE;
}
model = arg1;
}
@@ -11108,7 +11116,8 @@ cmd_ai_switch(ProfWin* window, const char* const command, gchar** args)
return TRUE;
}
// Update the existing session's provider and model
// Update the existing session's provider and model (all under lock)
pthread_mutex_lock(&aiwin->session->lock);
if (changed_provider) {
AIProvider* new_provider = ai_get_provider(provider_name);
g_free(aiwin->session->provider_name);
@@ -11121,6 +11130,7 @@ cmd_ai_switch(ProfWin* window, const char* const command, gchar** args)
aiwin->session->model = g_strdup(model);
g_free(aiwin->session->api_key);
aiwin->session->api_key = g_strdup(api_key);
pthread_mutex_unlock(&aiwin->session->lock);
// Update window title
win_println((ProfWin*)aiwin, THEME_DEFAULT, "-", "AI Chat: %s/%s", provider_name, model);