fix(ui,db): harden NULL handling and resource lifecycle across UI and SQLite
ui/window: fix subwindow lifecycle (safe delwin on recreate), clamp widths, add fallback timestamp when loading history to avoid NULL deref ui/buffer: add GSList bounds checks; assert non-NULL timestamps when creating entries ui/titlebar: guard newwin failures; make draw/resize/free no-ops when window is NULL ui/statusbar: guard window creation/resize/close; clamp columns; fallback display name if JID parsing fails ui/inputwin: check newpad result; guard resize/getters/close on NULL; safe delwin ui/chatwin: guard buffer_get_entry/time before ISO8601 formatting ui/window_list: validate win_create_* results; don’t insert NULL windows; fix barejid leak in wins_get_by_string db/database: ensure cleanup on sqlite init/open failures; use sqlite3_close_v2 and warn if busy; always return a ProfMessage from log_database_get_limits_info and set current UTC timestamp when is_last with no row; initialize err_msg and free consistently; improve error messages Prevents crashes from NULL dereferences (e.g., during MAM history) and closes small leaks; improves robustness under OOM and allocation failures.
This commit is contained in:
@@ -98,17 +98,23 @@ log_database_init(ProfAccount* account)
|
||||
|
||||
auto_char char* filename = _get_db_filename(account);
|
||||
if (!filename) {
|
||||
sqlite3_shutdown();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ret = sqlite3_open(filename, &g_chatlog_database);
|
||||
if (ret != SQLITE_OK) {
|
||||
const char* err_msg = sqlite3_errmsg(g_chatlog_database);
|
||||
const char* err_msg = g_chatlog_database ? sqlite3_errmsg(g_chatlog_database) : "(no handle)";
|
||||
log_error("Error opening SQLite database: %s", err_msg);
|
||||
if (g_chatlog_database) {
|
||||
sqlite3_close(g_chatlog_database);
|
||||
g_chatlog_database = NULL;
|
||||
}
|
||||
sqlite3_shutdown();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
char* err_msg;
|
||||
char* err_msg = NULL;
|
||||
|
||||
int db_version = _get_db_version();
|
||||
if (db_version == latest_version) {
|
||||
@@ -216,6 +222,11 @@ out:
|
||||
} else {
|
||||
log_error("Unknown SQLite error in log_database_init().");
|
||||
}
|
||||
if (g_chatlog_database) {
|
||||
sqlite3_close(g_chatlog_database);
|
||||
g_chatlog_database = NULL;
|
||||
}
|
||||
sqlite3_shutdown();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -224,7 +235,10 @@ log_database_close(void)
|
||||
{
|
||||
log_debug("log_database_close() called");
|
||||
if (g_chatlog_database) {
|
||||
sqlite3_close(g_chatlog_database);
|
||||
int rc = sqlite3_close_v2(g_chatlog_database);
|
||||
if (rc != SQLITE_OK) {
|
||||
log_warning("sqlite3_close_v2 returned %d; database may still have active statements.", rc);
|
||||
}
|
||||
sqlite3_shutdown();
|
||||
g_chatlog_database = NULL;
|
||||
}
|
||||
@@ -281,8 +295,15 @@ log_database_get_limits_info(const gchar* const contact_barejid, gboolean is_las
|
||||
{
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
const Jid* myjid = connection_get_jid();
|
||||
if (!myjid->str)
|
||||
return NULL;
|
||||
// Always return a valid ProfMessage to avoid NULL dereferences in callers
|
||||
ProfMessage* msg = message_init();
|
||||
if (!myjid || !myjid->str) {
|
||||
// If caller requested the last message and we have no context, fall back to now
|
||||
if (is_last) {
|
||||
msg->timestamp = g_date_time_new_now_utc();
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
const char* order = is_last ? "DESC" : "ASC";
|
||||
auto_sqlite char* query = sqlite3_mprintf("SELECT `archive_id`, `timestamp` FROM `ChatLogs` WHERE "
|
||||
@@ -293,17 +314,21 @@ log_database_get_limits_info(const gchar* const contact_barejid, gboolean is_las
|
||||
|
||||
if (!query) {
|
||||
log_error("Could not allocate memory for SQL query in log_database_get_limits_info()");
|
||||
return NULL;
|
||||
if (is_last) {
|
||||
msg->timestamp = g_date_time_new_now_utc();
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
int rc = sqlite3_prepare_v2(g_chatlog_database, query, -1, &stmt, NULL);
|
||||
if (rc != SQLITE_OK) {
|
||||
log_error("Unknown SQLite error in log_database_get_last_info().");
|
||||
return NULL;
|
||||
log_error("Unknown SQLite error in log_database_get_limits_info().");
|
||||
if (is_last) {
|
||||
msg->timestamp = g_date_time_new_now_utc();
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
ProfMessage* msg = message_init();
|
||||
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
char* archive_id = (char*)sqlite3_column_text(stmt, 0);
|
||||
char* date = (char*)sqlite3_column_text(stmt, 1);
|
||||
@@ -313,6 +338,11 @@ log_database_get_limits_info(const gchar* const contact_barejid, gboolean is_las
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
// If nothing was found and caller expects the last message, provide a sane default
|
||||
if (!msg->timestamp && is_last) {
|
||||
msg->timestamp = g_date_time_new_now_utc();
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user