Skip to content

Commit 9252098

Browse files
tglsfdcreshke
authored andcommitted
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
1 parent 944f789 commit 9252098

1 file changed

Lines changed: 14 additions & 2 deletions

File tree

contrib/pg_stat_statements/pg_stat_statements.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,8 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
10801080
{
10811081
Node *parsetree = pstmt->utilityStmt;
10821082
uint64 saved_queryId = pstmt->queryId;
1083+
int saved_stmt_location = pstmt->stmt_location;
1084+
int saved_stmt_len = pstmt->stmt_len;
10831085

10841086
/*
10851087
* Force utility statements to get queryId zero. We do this even in cases
@@ -1145,6 +1147,16 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
11451147
}
11461148
PG_END_TRY();
11471149

1150+
/*
1151+
* CAUTION: do not access the *pstmt data structure again below here.
1152+
* If it was a ROLLBACK or similar, that data structure may have been
1153+
* freed. We must copy everything we still need into local variables,
1154+
* which we did above.
1155+
*
1156+
* For the same reason, we can't risk restoring pstmt->queryId to its
1157+
* former value, which'd otherwise be a good idea.
1158+
*/
1159+
11481160
INSTR_TIME_SET_CURRENT(duration);
11491161
INSTR_TIME_SUBTRACT(duration, start);
11501162

@@ -1170,8 +1182,8 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
11701182

11711183
pgss_store(queryString,
11721184
saved_queryId,
1173-
pstmt->stmt_location,
1174-
pstmt->stmt_len,
1185+
saved_stmt_location,
1186+
saved_stmt_len,
11751187
PGSS_EXEC,
11761188
INSTR_TIME_GET_MILLISEC(duration),
11771189
rows,

0 commit comments

Comments
 (0)