summaryrefslogtreecommitdiff
path: root/src/interfaces
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2020-01-19 19:15:15 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2020-01-19 19:15:15 -0500
commitc7c2cc67007741338a36a8d7aa86e23600aa5e18 (patch)
tree0ed354e2eb4154be3b0d4dbddfbe1a0beb5a16cb /src/interfaces
parentac2dcca5dfe62177fd871a8f4f71430a1c92382c (diff)
downloadpostgresql-c7c2cc67007741338a36a8d7aa86e23600aa5e18.tar.gz
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.
Diffstat (limited to 'src/interfaces')
-rw-r--r--src/interfaces/ecpg/ecpglib/execute.c37
1 files changed, 24 insertions, 13 deletions
diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c
index 0912d87c77..606aff6373 100644
--- a/src/interfaces/ecpg/ecpglib/execute.c
+++ b/src/interfaces/ecpg/ecpglib/execute.c
@@ -1502,26 +1502,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++;