postgres.git / summary / log / commit / refs

commit    44f1fc8df5dadbc5e80661660903aab4076d868f
Author:   Tom Lane <tgl@sss.pgh.pa.us>
Date:     Mon Jan 20 00:15:15 2020 +0000
First released in: 13.0, 12.2

    Fix out-of-memory handling in ecpglib.
    
    ecpg_build_params() would crash on a null pointer dereference if
    realloc() failed, due to updating the persistent "stmt" struct
    too aggressively.  (Even without the crash, this would've leaked
    the old storage that we were trying to realloc.)
    
    Per Coverity.  This seems to have been broken in commit 0cc050794,
    so back-patch into v12.


src/interfaces/ecpg/ecpglib/execute.c | 37 +++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c index e261cf91671..59e8e3a8258 100644 --- a/src/interfaces/ecpg/ecpglib/execute.c +++ b/src/interfaces/ecpg/ecpglib/execute.c @@ -1499,26 +1499,37 @@ ecpg_build_params(struct statement *stmt) } else { - if (!(stmt->paramvalues = (char **) ecpg_realloc(stmt->paramvalues, sizeof(char *) * (stmt->nparams + 1), stmt->lineno))) + bool realloc_failed = false; + char **newparamvalues; + int *newparamlengths; + int *newparamformats; + + /* enlarge all the param arrays */ + if ((newparamvalues = (char **) ecpg_realloc(stmt->paramvalues, sizeof(char *) * (stmt->nparams + 1), stmt->lineno))) + stmt->paramvalues = newparamvalues; + else + realloc_failed = true; + + if ((newparamlengths = (int *) ecpg_realloc(stmt->paramlengths, sizeof(int) * (stmt->nparams + 1), stmt->lineno))) + stmt->paramlengths = newparamlengths; + else + realloc_failed = true; + + if ((newparamformats = (int *) ecpg_realloc(stmt->paramformats, sizeof(int) * (stmt->nparams + 1), stmt->lineno))) + stmt->paramformats = newparamformats; + else + realloc_failed = true; + + if (realloc_failed) { ecpg_free_params(stmt, false); ecpg_free(tobeinserted); return false; } - stmt->paramvalues[stmt->nparams] = tobeinserted; - if (!(stmt->paramlengths = (int *) ecpg_realloc(stmt->paramlengths, sizeof(int) * (stmt->nparams + 1), stmt->lineno))) - { - ecpg_free_params(stmt, false); - return false; - } + /* only now can we assign ownership of "tobeinserted" to stmt */ + stmt->paramvalues[stmt->nparams] = tobeinserted; stmt->paramlengths[stmt->nparams] = binary_length; - - if (!(stmt->paramformats = (int *) ecpg_realloc(stmt->paramformats, sizeof(int) * (stmt->nparams + 1), stmt->lineno))) - { - ecpg_free_params(stmt, false); - return false; - } stmt->paramformats[stmt->nparams] = (binary_format ? 1 : 0); stmt->nparams++; [parent: 9c679a08f0cd]