Hi, > Here is the corrected patch v3. Changes since v2: > > ``` > for (con = all_connections; con != NULL; con = con->next) > { > - /* XXX strcmp() will segfault if con->name is NULL */ > - if (strcmp(connection_name, con->name) == 0) > + /* Check for NULL to prevent segfault */ > + if (con->name != NULL && > strcmp(connection_name, con->name) == 0) > break; > } > ret = con; > ``` > > I was tired or something and didn't think of this trivial fix. > > As a side note it looks like ecpg could use some refactoring, but this > is subject for another patch IMO.
Forgot the attachment. Sorry for the noise.
From 0ef7a6ba96dd8900ed5d34e3d3e8aa6dec53213b Mon Sep 17 00:00:00 2001 From: Aleksander Alekseev <aleksan...@timescale.com> Date: Fri, 11 Jul 2025 17:59:50 +0300 Subject: [PATCH v3] Add proper checks for ecpg_strdup() return value Evgeniy Gorbanev, Aleksander Alekseev. Reviewed by TODO FIXME. Discussion: https://postgr.es/m/a6b193c1-6994-4d9c-9059-aca4aaf41...@basealt.ru --- src/interfaces/ecpg/ecpglib/connect.c | 28 ++++++++++++++++++------ src/interfaces/ecpg/ecpglib/execute.c | 17 +++++++++++++++ src/interfaces/ecpg/ecpglib/prepare.c | 31 +++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 7 deletions(-) diff --git a/src/interfaces/ecpg/ecpglib/connect.c b/src/interfaces/ecpg/ecpglib/connect.c index 2bbb70333dc..a7b84f2d239 100644 --- a/src/interfaces/ecpg/ecpglib/connect.c +++ b/src/interfaces/ecpg/ecpglib/connect.c @@ -58,7 +58,8 @@ ecpg_get_connection_nr(const char *connection_name) for (con = all_connections; con != NULL; con = con->next) { - if (strcmp(connection_name, con->name) == 0) + /* Check for NULL to prevent segfault */ + if (con->name != NULL && strcmp(connection_name, con->name) == 0) break; } ret = con; @@ -460,7 +461,21 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p */ conn_keywords = (const char **) ecpg_alloc((connect_params + 1) * sizeof(char *), lineno); conn_values = (const char **) ecpg_alloc(connect_params * sizeof(char *), lineno); - if (conn_keywords == NULL || conn_values == NULL) + + /* Allocate memory for connection name */ + if (connection_name != NULL) + this->name = ecpg_strdup(connection_name, lineno); + else + this->name = ecpg_strdup(realname, lineno); + + /* + * Note that NULL is a correct value for realname and ecpg_strdup(NULL, + * ...) just returns NULL. For named reasons the ckecks for this->name are + * a bit complicated here. + */ + if (conn_keywords == NULL || conn_values == NULL || + (connection_name != NULL && this->name == NULL) || /* first call failed */ + (connection_name == NULL && realname != NULL && this->name == NULL)) /* second call failed */ { if (host) ecpg_free(host); @@ -476,6 +491,8 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p ecpg_free(conn_keywords); if (conn_values) ecpg_free(conn_values); + if (this->name) + ecpg_free(this->name); free(this); return false; } @@ -510,17 +527,14 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p ecpg_free(conn_keywords); if (conn_values) ecpg_free(conn_values); + if (this->name) + ecpg_free(this->name); free(this); return false; } } #endif - if (connection_name != NULL) - this->name = ecpg_strdup(connection_name, lineno); - else - this->name = ecpg_strdup(realname, lineno); - this->cache_head = NULL; this->prep_stmts = NULL; diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c index f52da06de9a..6524c646c13 100644 --- a/src/interfaces/ecpg/ecpglib/execute.c +++ b/src/interfaces/ecpg/ecpglib/execute.c @@ -2030,7 +2030,14 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator, statement_type = ECPGst_execute; } else + { stmt->command = ecpg_strdup(query, lineno); + if (!stmt->command) + { + ecpg_do_epilogue(stmt); + return false; + } + } stmt->name = NULL; @@ -2043,6 +2050,11 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator, { stmt->name = stmt->command; stmt->command = ecpg_strdup(command, lineno); + if (!stmt->command) + { + ecpg_do_epilogue(stmt); + return false; + } } else { @@ -2176,6 +2188,11 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator, if (!is_prepared_name_set && stmt->statement_type == ECPGst_prepare) { stmt->name = ecpg_strdup(var->value, lineno); + if (!stmt->name) + { + ecpg_do_epilogue(stmt); + return false; + } is_prepared_name_set = true; } } diff --git a/src/interfaces/ecpg/ecpglib/prepare.c b/src/interfaces/ecpg/ecpglib/prepare.c index ea1146f520f..7b6019deed7 100644 --- a/src/interfaces/ecpg/ecpglib/prepare.c +++ b/src/interfaces/ecpg/ecpglib/prepare.c @@ -86,8 +86,21 @@ ecpg_register_prepared_stmt(struct statement *stmt) prep_stmt->lineno = lineno; prep_stmt->connection = con; prep_stmt->command = ecpg_strdup(stmt->command, lineno); + if (!prep_stmt->command) + { + ecpg_free(prep_stmt); + ecpg_free(this); + return false; + } prep_stmt->inlist = prep_stmt->outlist = NULL; this->name = ecpg_strdup(stmt->name, lineno); + if (!this->name) + { + ecpg_free(prep_stmt->command); + ecpg_free(prep_stmt); + ecpg_free(this); + return false; + } this->stmt = prep_stmt; this->prepared = true; @@ -178,6 +191,12 @@ prepare_common(int lineno, struct connection *con, const char *name, const char stmt->lineno = lineno; stmt->connection = con; stmt->command = ecpg_strdup(variable, lineno); + if (!stmt->command) + { + ecpg_free(stmt); + ecpg_free(this); + return false; + } stmt->inlist = stmt->outlist = NULL; /* if we have C variables in our statement replace them with '?' */ @@ -185,6 +204,13 @@ prepare_common(int lineno, struct connection *con, const char *name, const char /* add prepared statement to our list */ this->name = ecpg_strdup(name, lineno); + if (!this->name) + { + ecpg_free(stmt->command); + ecpg_free(stmt); + ecpg_free(this); + return false; + } this->stmt = stmt; /* and finally really prepare the statement */ @@ -541,6 +567,8 @@ AddStmtToCache(int lineno, /* line # of statement */ entry = &stmtCacheEntries[entNo]; entry->lineno = lineno; entry->ecpgQuery = ecpg_strdup(ecpgQuery, lineno); + if (!entry->ecpgQuery) + return -1; entry->connection = connection; entry->execs = 0; memcpy(entry->stmtID, stmtID, sizeof(entry->stmtID)); @@ -595,6 +623,9 @@ ecpg_auto_prepare(int lineno, const char *connection_name, const int compat, cha *name = ecpg_strdup(stmtID, lineno); } + if (!*name) + return false; + /* increase usage counter */ stmtCacheEntries[entNo].execs++; -- 2.43.0