BUG #19866: acldefault() emits invalid UTF-8 for a high-bit "char" value

From: PG Bug reporting form <noreply(at)postgresql(dot)org>
To: pgsql-bugs(at)lists(dot)postgresql(dot)org
Cc: 1548140642(at)qq(dot)com
Subject: BUG #19866: acldefault() emits invalid UTF-8 for a high-bit "char" value
Date: 2026-11-11 05:39:16
Message-ID: 19866-6c04f56db1b73ac6@postgresql.org
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

The following bug has been logged on the website:

Bug reference: 19866
Logged by: Milo
Email address: 1548140642(at)qq(dot)com
PostgreSQL version: 18.6
Operating system: Linux/amd64
Description:

In a UTF-8 database, pg_catalog.acldefault(char, oid) produces MESSAGE_TEXT
containing a raw, invalid UTF-8 byte when the invalid object type is the
one-byte value 0x80. A client that decodes server responses as UTF-8 can
therefore fail to decode the diagnostic.

The diagnostic should remain valid in the server encoding. The byte should
be rendered in an encoding-safe form such as \200, as charout() and the
setweight() diagnostic do, rather than inserted as a raw standalone byte.

How to repeat:

Save the following as reproducer.sql and run `psql -X -d postgres -f
reproducer.sql` against a UTF-8 database.

CREATE TEMP TABLE encoding_result
(tested_function text,
message_is_invalid_utf8 boolean,
validation_sqlstate text);

DO $test$
DECLARE
captured_message text;
invalid_utf8 boolean;
validation_state text;
BEGIN
BEGIN
PERFORM pg_catalog.acldefault('\200'::pg_catalog."char", 10::oid);
RAISE EXCEPTION 'expected acldefault() to reject the invalid object
type';
EXCEPTION WHEN OTHERS THEN
GET STACKED DIAGNOSTICS captured_message = MESSAGE_TEXT;
END;

invalid_utf8 := false;
validation_state := NULL;
BEGIN
-- Converting away from the database encoding forces validation of the
-- UTF-8 source bytes; UTF8-to-UTF8 conversion would be optimized away.
PERFORM pg_catalog.convert_to(captured_message, 'LATIN1');
EXCEPTION WHEN OTHERS THEN
invalid_utf8 := true;
GET STACKED DIAGNOSTICS validation_state = RETURNED_SQLSTATE;
END;
INSERT INTO encoding_result
VALUES ('acldefault', invalid_utf8, validation_state);

BEGIN
PERFORM pg_catalog.setweight('a'::pg_catalog.tsvector,
'\200'::pg_catalog."char");
RAISE EXCEPTION 'expected setweight() to reject the invalid weight';
EXCEPTION WHEN OTHERS THEN
GET STACKED DIAGNOSTICS captured_message = MESSAGE_TEXT;
END;

invalid_utf8 := false;
validation_state := NULL;
BEGIN
PERFORM pg_catalog.convert_to(captured_message, 'LATIN1');
EXCEPTION WHEN OTHERS THEN
invalid_utf8 := true;
GET STACKED DIAGNOSTICS validation_state = RETURNED_SQLSTATE;
END;
INSERT INTO encoding_result
VALUES ('setweight_control', invalid_utf8, validation_state);
END
$test$;

SELECT tested_function, message_is_invalid_utf8, validation_sqlstate
FROM encoding_result
ORDER BY tested_function;

DROP TABLE encoding_result;

The recorded output was:

CREATE TABLE
DO
tested_function | message_is_invalid_utf8 | validation_sqlstate
-------------------+-------------------------+---------------------
acldefault | t | 22021
setweight_control | f |
(2 rows)

DROP TABLE

The acldefault() message therefore fails UTF-8 source validation with
SQLSTATE 22021, while the diagnostic produced by setweight() for the same
one-byte value remains valid.

The issue was reproduced on PostgreSQL 18.6 and PostgreSQL 20devel on
Linux/amd64.

This occurs when acldefault() is called with the high-bit one-byte "char"
value 0x80 as an invalid object type.

Browse pgsql-bugs by date

  From Date Subject
Next Message PG Bug reporting form 2026-11-11 05:46:08 BUG #19867: pg_verifybackup accepts out-of-range Timeline in backup manifest
Previous Message PG Bug reporting form 2026-11-11 05:36:09 BUG #19865: WAL summary reader wraps block numbers for oversized chunk counts