mirror of
https://git.jabber.space/devs/cproof.git
synced 2026-07-26 18:46:21 +00:00
Fix(ai): protect AI session state from concurrent access races
cmd_ai_switch() and cmd_ai_clear() mutated session fields (provider_name, provider, model, api_key, history) on the main thread without coordination, while _ai_request_thread() read the same fields concurrently in the worker thread. This caused use-after-free when: - g_free(session->model) was called between worker's read and g_strdup() - ai_provider_unref(session->provider) freed the provider struct while worker accessed session->provider->api_url - ai_session_clear_history() freed the history list while worker walked it Fix: 1. Add pthread_mutex_t lock to AISession struct to protect all session fields from concurrent access. 2. Introduce ai_session_switch() public API that atomically switches provider, model, and API key under the session lock. This encapsulates all session mutations within ai_client.c so cmd_funcs.c never touches session fields directly. 3. Have _ai_request_thread() snapshot all session state under the session lock before making requests, using local copies for the duration of the curl request. 4. Add ai_provider_ref()/ai_provider_unref() around _ai_generic_request_thread() to prevent provider UAF during model-fetch requests. 5. Protect ai_session_add_message(), ai_session_clear_history(), and ai_session_set_model() with the session lock. No pthread.h needed in cmd_funcs.c — all locking is encapsulated within ai_client.c via the public API. No deadlock risk from nested locks. Files changed: - src/ai/ai_client.h: Add lock field, ai_session_switch() declaration - src/ai/ai_client.c: Mutex init/destroy, session mutation protection, worker thread snapshot, provider ref management - src/command/cmd_funcs.c: Use ai_session_switch() API, remove pthread.h
This commit is contained in:
@@ -239,32 +239,6 @@ const gchar* ai_session_get_model(AISession* session);
|
||||
*/
|
||||
void ai_session_set_model(AISession* session, const gchar* model);
|
||||
|
||||
/**
|
||||
* Atomically switch session provider, model, and API key.
|
||||
* All mutations happen under the session lock to prevent races with
|
||||
* _ai_request_thread() which snapshots session state before making requests.
|
||||
*
|
||||
* @param session The session
|
||||
* @param provider_name New provider name
|
||||
* @param model New model identifier
|
||||
* @param api_key New API key (caller must free after calling this)
|
||||
*/
|
||||
void ai_session_switch(AISession* session, const gchar* provider_name,
|
||||
const gchar* model, gchar* api_key);
|
||||
|
||||
/**
|
||||
* Atomically switch session provider, model, and API key.
|
||||
* All mutations happen under the session lock to prevent races with
|
||||
* _ai_request_thread() which snapshots session state before making requests.
|
||||
*
|
||||
* @param session The session
|
||||
* @param provider_name New provider name
|
||||
* @param model New model identifier
|
||||
* @param api_key New API key (caller must free after calling this)
|
||||
*/
|
||||
void ai_session_switch(AISession* session, const gchar* provider_name,
|
||||
const gchar* model, gchar* api_key);
|
||||
|
||||
/**
|
||||
* Atomically switch session provider, model, and API key.
|
||||
* All mutations happen under the session lock to prevent races with
|
||||
|
||||
Reference in New Issue
Block a user