From 7caeedb2bee58f383d181d62d9f92dfb2e78bd9c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 3 Feb 2026 12:24:07 -0500 Subject: [PATCH] fix: fix memory leaks in User::find() functions Previously, if zmDbFetch returned a result but mysql_num_rows != 1, the MYSQL_RES was not freed before returning nullptr, causing a memory leak. Now properly frees the result in all code paths. Co-Authored-By: Claude Opus 4.5 --- src/zm_user.cpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/zm_user.cpp b/src/zm_user.cpp index cfdfaf7f7..495317cfd 100644 --- a/src/zm_user.cpp +++ b/src/zm_user.cpp @@ -135,13 +135,16 @@ User *User::find(const std::string &username) { " FROM `Users` WHERE `Username` = '%s' AND `Enabled` = 1", escaped_username.c_str()); MYSQL_RES *result = zmDbFetch(sql); - if (result && mysql_num_rows(result) == 1 ) { - MYSQL_ROW dbrow = mysql_fetch_row(result); - User *user = new User(dbrow); + if (!result) + return nullptr; + if (mysql_num_rows(result) != 1) { mysql_free_result(result); - return user; + return nullptr; } - return nullptr; + MYSQL_ROW dbrow = mysql_fetch_row(result); + User *user = new User(dbrow); + mysql_free_result(result); + return user; } User *User::find(int id) { @@ -150,13 +153,16 @@ User *User::find(int id) { " FROM `Users` WHERE `Id` = %d AND `Enabled` = 1", id); MYSQL_RES *result = zmDbFetch(sql); - if (result && mysql_num_rows(result) == 1 ) { - MYSQL_ROW dbrow = mysql_fetch_row(result); - User *user = new User(dbrow); + if (!result) + return nullptr; + if (mysql_num_rows(result) != 1) { mysql_free_result(result); - return user; + return nullptr; } - return nullptr; + MYSQL_ROW dbrow = mysql_fetch_row(result); + User *user = new User(dbrow); + mysql_free_result(result); + return user; } std::string User::getAuthHash() {