Skip to content

Only treat oversized ErrorResponse as plain text during startup#1326

Open
momomuchu wants to merge 1 commit into
lib:masterfrom
momomuchu:fix/1324-oversized-error-response
Open

Only treat oversized ErrorResponse as plain text during startup#1326
momomuchu wants to merge 1 commit into
lib:masterfrom
momomuchu:fix/1324-oversized-error-response

Conversation

@momomuchu

Copy link
Copy Markdown

Fixes #1324

Since #1249, recvMessage treats any ErrorResponse over MaxErrlen (30000) as a pre-protocol plain-text error. libpq only applies that heuristic while awaiting the startup response (fe-connect.c, PQconnectPoll); after the handshake an ErrorResponse is explicitly allowed to exceed 30000 bytes (fe-protocol3.c, VALID_LONG_MESSAGE_TYPE).

Applying it in steady state does two things to a legitimate large error, e.g. RAISE EXCEPTION '%', repeat('x', 40000): the error comes back garbled (the raw length bytes plus the first field instead of the parsed message), and the connection is left desynced, since the early return never drains the message body or the trailing ReadyForQuery. inProgress stays stuck, the conn is not marked bad, and the pool hands it back out, so the next query fails with "there is already a query being processed on this connection" (see the second comment on #1324 for the full trace).

This gates the heuristic on a new startup parameter to recvMessage, true only from conn.recv, which is only used during the startup/auth sequence. recv1Buf and the direct callers in copy.go and notify.go pass false and parse large ErrorResponses normally, matching libpq. The pre-handshake "could not fork" case from #1249 keeps working as before.

This is unrelated to #1320/#1321, which is an EOF-handling bug in the extended-protocol cleanup paths; same end symptom, different cause and code path.

Test uses pqtest.Fake to send a MaxErrlen+10000 ErrorResponse and asserts the message and SQLSTATE parse intact and that a second query on the same pooled connection still works.

recvMessage treated any ErrorResponse over MaxErrlen as a pre-protocol
plain-text error (from PR lib#1249). libpq only applies that heuristic
while awaiting the startup response; post-handshake an ErrorResponse
is allowed to exceed MaxErrlen. Applying it in steady state garbled
legitimate large errors and left the connection desynced: the message
body and the following ReadyForQuery were never drained, so inProgress
stayed stuck and the poisoned connection went back into the pool.

Gate the check on a new startup bool, true only for conn.recv (used
exclusively during the handshake). recv1Buf and the direct callers in
copy.go and notify.go now pass false and parse large ErrorResponse
messages normally.

Fixes lib#1324
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ErrorResponse > 30000 bytes is misparsed as a pre-protocol plain-text error

1 participant