aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2022-11-01 12:48:01 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2022-11-01 12:48:01 -0400
commit149e00192fa1314ca26c47e7620d470681fea502 (patch)
tree02bf7fd22c74bb467f46988cc9a3c4ec4fb54703
parent341fba2a6291f6f1c5f801c308b72fa62e46e5c8 (diff)
downloadpostgresql-149e00192fa1314ca26c47e7620d470681fea502.tar.gz
postgresql-149e00192fa1314ca26c47e7620d470681fea502.zip
pg_stat_statements: fetch stmt location/length before it disappears.
When executing a utility statement, we must fetch everything we need out of the PlannedStmt data structure before calling standard_ProcessUtility. In certain cases (possibly only ROLLBACK in extended query protocol), that data structure will get freed during command execution. The situation is probably often harmless in production builds, but in debug builds we intentionally overwrite the freed memory with garbage, leading to picking up garbage values of statement location and length, typically causing an assertion failure later in pg_stat_statements. In non-debug builds, if something did go wrong it would likely lead to storing garbage for the query string. Report and fix by zhaoqigui (with cosmetic adjustments by me). It's an old problem, so back-patch to all supported versions. Discussion: https://postgr.es/m/17663-a344fd0675f92128@postgresql.org Discussion: https://postgr.es/m/1667307420050.56657@hundsun.com
-rw-r--r--contrib/pg_stat_statements/pg_stat_statements.c13
1 files changed, 11 insertions, 2 deletions
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 5d7aa859227..3e9cf3de143 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -965,6 +965,8 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
DestReceiver *dest, char *completionTag)
{
Node *parsetree = pstmt->utilityStmt;
+ int saved_stmt_location = pstmt->stmt_location;
+ int saved_stmt_len = pstmt->stmt_len;
/*
* If it's an EXECUTE statement, we don't track it and don't increment the
@@ -1014,6 +1016,13 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
}
PG_END_TRY();
+ /*
+ * CAUTION: do not access the *pstmt data structure again below here.
+ * If it was a ROLLBACK or similar, that data structure may have been
+ * freed. We must copy everything we still need into local variables,
+ * which we did above.
+ */
+
INSTR_TIME_SET_CURRENT(duration);
INSTR_TIME_SUBTRACT(duration, start);
@@ -1052,8 +1061,8 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
pgss_store(queryString,
0, /* signal that it's a utility stmt */
- pstmt->stmt_location,
- pstmt->stmt_len,
+ saved_stmt_location,
+ saved_stmt_len,
INSTR_TIME_GET_MILLISEC(duration),
rows,
&bufusage,