Skip to content

Commit 87f8355

Browse files
authored
Merge pull request #5006 from sysown/v3.0-4976
Fix memory leak in 'ProxySQL_Admin::stats___mysql_global' - Closes #4976
2 parents b78e8e2 + 25d5681 commit 87f8355

File tree

3 files changed

+71
-17
lines changed

3 files changed

+71
-17
lines changed

include/sqlite3db.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
#undef min
77
#undef max
88
#include <cstdint>
9+
#include <memory>
910
#include <vector>
11+
#include <utility>
1012
#define PROXYSQL_SQLITE3DB_PTHREAD_MUTEX
1113

1214
#ifndef SAFE_SQLITE3_STEP2
@@ -40,6 +42,7 @@ extern int (*proxy_sqlite3_close_v2)(sqlite3*);
4042
extern int (*proxy_sqlite3_get_autocommit)(sqlite3*);
4143
extern void (*proxy_sqlite3_free)(void*);
4244
extern int (*proxy_sqlite3_status)(int op, int *pCurrent, int *pHighwater, int resetFlag);
45+
extern int (*proxy_sqlite3_status64)(int op, long long *pCurrent, long long *pHighwater, int resetFlag);
4346
extern int (*proxy_sqlite3_changes)(sqlite3*);
4447
extern int (*proxy_sqlite3_step)(sqlite3_stmt*);
4548
extern int (*proxy_sqlite3_config)(int, ...);
@@ -87,6 +90,8 @@ int (*proxy_sqlite3_close_v2)(sqlite3*);
8790
int (*proxy_sqlite3_get_autocommit)(sqlite3*);
8891
void (*proxy_sqlite3_free)(void*);
8992
int (*proxy_sqlite3_status)(int op, int *pCurrent, int *pHighwater, int resetFlag);
93+
int (*proxy_sqlite3_status64)(int op, long long *pCurrent, long long *pHighwater, int resetFlag);
94+
9095
int (*proxy_sqlite3_changes)(sqlite3*);
9196
int (*proxy_sqlite3_step)(sqlite3_stmt*);
9297
int (*proxy_sqlite3_config)(int, ...);
@@ -165,6 +170,18 @@ class SQLite3_result {
165170
void dump_to_stderr();
166171
};
167172

173+
/**
174+
* @brief Helper type for finalizing 'sqlite3_stmt' managed by smart pointers.
175+
*/
176+
struct stmt_deleter_t {
177+
void operator()(sqlite3_stmt* x) const;
178+
};
179+
180+
/**
181+
* @brief Safe type for automatically deallocation of 'sqlite3_stmt'.
182+
*/
183+
using stmt_unique_ptr = std::unique_ptr<sqlite3_stmt, stmt_deleter_t>;
184+
168185
class SQLite3DB {
169186
private:
170187
char *url;
@@ -191,7 +208,14 @@ class SQLite3DB {
191208
int check_table_structure(char *table_name, char *table_def);
192209
bool build_table(char *table_name, char *table_def, bool dropit);
193210
bool check_and_build_table(char *table_name, char *table_def);
211+
[[deprecated("Use safer alternative 'prepare_v2(const char *)'")]]
194212
int prepare_v2(const char *, sqlite3_stmt **);
213+
/**
214+
* @brief Prepares a query as a statement in the SQLite3DB.
215+
* @param query The query to be prepared as an 'sqlite3_stmt'.
216+
* @return A pair of with shape { err_code, stmt_unique_ptr }.
217+
*/
218+
std::pair<int,stmt_unique_ptr> prepare_v2(const char* query);
195219
static void LoadPlugin(const char *);
196220
};
197221

lib/ProxySQL_Admin_Stats.cpp

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,9 @@ void ProxySQL_Admin::p_stats___memory_metrics() {
109109
this->metrics.p_gauge_array[p_admin_gauge::connpool_memory_bytes]->Set(connpool_mem);
110110

111111
// proxysql_sqlite3_memory_bytes metric
112-
int highwater = 0;
113-
int current = 0;
114-
(*proxy_sqlite3_status)(SQLITE_STATUS_MEMORY_USED, &current, &highwater, 0);
112+
long long highwater = 0;
113+
long long current = 0;
114+
(*proxy_sqlite3_status64)(SQLITE_STATUS_MEMORY_USED, &current, &highwater, 0);
115115
this->metrics.p_gauge_array[p_admin_gauge::sqlite3_memory_bytes]->Set(current);
116116

117117
// proxysql_jemalloc_* memory metrics
@@ -206,8 +206,8 @@ void ProxySQL_Admin::stats___memory_metrics() {
206206
if (!GloMTH) return;
207207
SQLite3_result * resultset = NULL;
208208

209-
int highwater;
210-
int current;
209+
long long highwater = 0;
210+
long long current = 0;
211211
char bu[32];
212212
char *vn=NULL;
213213
char *query=NULL;
@@ -218,9 +218,9 @@ void ProxySQL_Admin::stats___memory_metrics() {
218218
delete resultset;
219219
resultset=NULL;
220220
}
221-
(*proxy_sqlite3_status)(SQLITE_STATUS_MEMORY_USED, &current, &highwater, 0);
221+
(*proxy_sqlite3_status64)(SQLITE_STATUS_MEMORY_USED, &current, &highwater, 0);
222222
vn=(char *)"SQLite3_memory_bytes";
223-
sprintf(bu,"%d",current);
223+
sprintf(bu,"%lld",current);
224224
query=(char *)malloc(strlen(a)+strlen(vn)+strlen(bu)+16);
225225
sprintf(query,a,vn,bu);
226226
statsdb->execute(query);
@@ -492,6 +492,8 @@ const void sqlite3_global_stats_row_step(
492492
sprintf(buf, "%lu", val);
493493
} else if constexpr (std::is_same_v<T, unsigned long long>) {
494494
sprintf(buf, "%llu", val);
495+
} else if constexpr (std::is_same_v<T, long long>) {
496+
sprintf(buf, "%lld", val);
495497
} else if constexpr (std::is_same_v<T, bool>) {
496498
sprintf(buf, "%s", val ? "true" : "false");
497499
} else {
@@ -521,12 +523,17 @@ void ProxySQL_Admin::stats___mysql_global() {
521523
"INSERT INTO stats_mysql_global VALUES " + generate_multi_rows_query(32, 2)
522524
};
523525

524-
sqlite3_stmt* row_stmt = nullptr;
525-
int rc = statsdb->prepare_v2(q_row_insert.c_str(), &row_stmt);
526+
int rc = 0;
527+
528+
stmt_unique_ptr u_row_stmt { nullptr };
529+
std::tie(rc, u_row_stmt) = statsdb->prepare_v2(q_row_insert.c_str());
526530
ASSERT_SQLITE_OK(rc, statsdb);
527-
sqlite3_stmt* bulk_stmt = nullptr;
528-
rc = statsdb->prepare_v2(q_bulk_insert.c_str(), &bulk_stmt);
531+
sqlite3_stmt* const row_stmt { u_row_stmt.get() };
532+
533+
stmt_unique_ptr u_bulk_stmt { nullptr };
534+
std::tie(rc, u_bulk_stmt) = statsdb->prepare_v2(q_bulk_insert.c_str());
529535
ASSERT_SQLITE_OK(rc, statsdb);
536+
sqlite3_stmt* const bulk_stmt { u_bulk_stmt.get() };
530537

531538
sqlite3_bulk_step(statsdb, row_stmt, bulk_stmt, resultset, stats_mysql_global___bind_row);
532539

@@ -542,8 +549,8 @@ void ProxySQL_Admin::stats___mysql_global() {
542549
}
543550

544551
{
545-
int highwater, current = 0;
546-
(*proxy_sqlite3_status)(SQLITE_STATUS_MEMORY_USED, &current, &highwater, 0);
552+
long long highwater, current = 0;
553+
(*proxy_sqlite3_status64)(SQLITE_STATUS_MEMORY_USED, &current, &highwater, 0);
547554
sqlite3_global_stats_row_step(statsdb, row_stmt, "SQLite3_memory_bytes", current);
548555
}
549556

@@ -647,14 +654,14 @@ void ProxySQL_Admin::stats___pgsql_global() {
647654
resultset = NULL;
648655
}
649656

650-
int highwater;
651-
int current;
652-
(*proxy_sqlite3_status)(SQLITE_STATUS_MEMORY_USED, &current, &highwater, 0);
657+
long long highwater = 0;
658+
long long current = 0;
659+
(*proxy_sqlite3_status64)(SQLITE_STATUS_MEMORY_USED, &current, &highwater, 0);
653660
char bu[32];
654661
char* vn = NULL;
655662
char* query = NULL;
656663
vn = (char*)"SQLite3_memory_bytes";
657-
sprintf(bu, "%d", current);
664+
sprintf(bu, "%lld", current);
658665
query = (char*)malloc(strlen(a) + strlen(vn) + strlen(bu) + 16);
659666
sprintf(query, a, vn, bu);
660667
statsdb->execute(query);

lib/sqlite3db.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,26 @@ int SQLite3DB::prepare_v2(const char *str, sqlite3_stmt **statement) {
260260
return rc;
261261
}
262262

263+
void stmt_deleter_t::operator()(sqlite3_stmt* x) const {
264+
proxy_sqlite3_finalize(x);
265+
}
266+
267+
std::pair<int,stmt_unique_ptr> SQLite3DB::prepare_v2(const char* query) {
268+
int rc { 0 };
269+
sqlite3_stmt* stmt { nullptr };
270+
271+
do {
272+
rc = (*proxy_sqlite3_prepare_v2)(db, query, -1, &stmt, nullptr);
273+
274+
if (rc==SQLITE_LOCKED || rc==SQLITE_BUSY) {
275+
struct timespec ts { .tv_sec = 0, .tv_nsec = USLEEP_SQLITE_LOCKED * 1000 };
276+
nanosleep(&ts, nullptr);
277+
}
278+
} while (rc==SQLITE_LOCKED || rc==SQLITE_BUSY);
279+
280+
return { rc, stmt_unique_ptr(stmt) };
281+
}
282+
263283
/**
264284
* @brief Executes a SQL statement and returns the result set.
265285
*
@@ -988,6 +1008,7 @@ void SQLite3DB::LoadPlugin(const char *plugin_name) {
9881008
proxy_sqlite3_get_autocommit = NULL;
9891009
proxy_sqlite3_free = NULL;
9901010
proxy_sqlite3_status = NULL;
1011+
proxy_sqlite3_status64 = NULL;
9911012
proxy_sqlite3_changes = NULL;
9921013
proxy_sqlite3_step = NULL;
9931014
proxy_sqlite3_shutdown = NULL;
@@ -1066,6 +1087,7 @@ void SQLite3DB::LoadPlugin(const char *plugin_name) {
10661087
proxy_sqlite3_get_autocommit = sqlite3_get_autocommit;
10671088
proxy_sqlite3_free = sqlite3_free;
10681089
proxy_sqlite3_status = sqlite3_status;
1090+
proxy_sqlite3_status64 = sqlite3_status64;
10691091
proxy_sqlite3_changes = sqlite3_changes;
10701092
proxy_sqlite3_step = sqlite3_step;
10711093
proxy_sqlite3_shutdown = sqlite3_shutdown;
@@ -1094,6 +1116,7 @@ void SQLite3DB::LoadPlugin(const char *plugin_name) {
10941116
assert(proxy_sqlite3_get_autocommit);
10951117
assert(proxy_sqlite3_free);
10961118
assert(proxy_sqlite3_status);
1119+
assert(proxy_sqlite3_status64);
10971120
assert(proxy_sqlite3_changes);
10981121
assert(proxy_sqlite3_step);
10991122
assert(proxy_sqlite3_shutdown);

0 commit comments

Comments
 (0)