Thread

Commits

Same data as JSON: GET /api/v1/messages/:b64id/commits the thread's linked commits as JSON, with link sources. API reference →
  1. Avoid scribbling on input node tree in CREATE/ALTER DOMAIN.

  2. Centralize the logic for protective copying of utility statements.

  1. BUG #17053: Memory corruption in parser on prepared query reuse

    PG Bug reporting form <noreply@postgresql.org> — 2021-06-09T20:13:17Z

    The following bug has been logged on the website:
    
    Bug reference:      17053
    Logged by:          Charles Samborski
    Email address:      demurgos@demurgos.net
    PostgreSQL version: 13.3
    Operating system:   Linux 5.12 (Arch Linux)
    Description:        
    
    I found a bug in Postgres where I can reliably trigger the following error:
    "unrecognized node type: X", where X can be anything and changes across
    program executions. For example, I can get "unrecognized node type: 0",
    "nrecognized node type: 184", "unrecognized node type: 196608" and many
    others (including negative values). This implies that a node type is read
    from a corrupted memory location.
    
    The following repo has C and Rust programs exhibiting this behavior:
    https://github.com/demurgos/pg_unrecognized_node.
    
    Here is the C program:
    
    ```
    #include <stdio.h>
    #include <stdlib.h>
    #include "libpq-fe.h"
    
    int
    main(int argc, char **argv)
    {
    	PGconn        *conn;
    	PGresult      *res;
    
    	conn = PQconnectdb("");
    
    	PQexec(conn, "DROP DOMAIN IF EXISTS schema_meta");
    	PQexec(conn, "CREATE TYPE raw_schema_meta AS (version int4)");
    	PQprepare(conn, "q1", "CREATE DOMAIN schema_meta AS raw_schema_meta CHECK
    ((value).version IS NOT NULL AND (value).version >= 1)", 0, NULL);
    	PQexecPrepared(conn, "q1", 0, NULL, 0, 0, 0);
    	PQexec(conn, "DROP DOMAIN IF EXISTS schema_meta");
    	res = PQexecPrepared(conn, "q1", 0, NULL, 0, 0, 0);
    
    	fprintf(stdout, "%s", PQresultErrorMessage(res));
    
    	PQfinish(conn);
    
    	return 0;
    }
    ```
    
    You can compile it with `gcc -lpq -o main main.c` and run it on fresh DB by
    passing the credentials through the environment, e.g.: `PGUSER=test
    PGPASSWORD=test PGDATABASE=test ./main`
    
    I investigated this issue with the help of some people from IRC and would
    like to thank them: ioguix, johto and Zr40.
    
    The code is fairly short, the core of the issue is that the prepared query
    `q1` is executed twice and it somehow messes up with the parser because of
    the `CHECK` clause.
    
    
  2. Re: BUG #17053: Memory corruption in parser on prepared query reuse

    Tom Lane <tgl@sss.pgh.pa.us> — 2021-06-09T21:41:36Z

    PG Bug reporting form <noreply@postgresql.org> writes:
    > The code is fairly short, the core of the issue is that the prepared query
    > `q1` is executed twice and it somehow messes up with the parser because of
    > the `CHECK` clause.
    
    Thanks for the report!  The core of the problem is that where
    transformExpr does this:
    
            case T_NullTest:
                {
                    NullTest   *n = (NullTest *) expr;
    
                    n->arg = (Expr *) transformExprRecurse(pstate, (Node *) n->arg);
    
    in the case of a prepared statement, it's scribbling on the same NullTest
    node that's in the plan cache.  So the next time we try to execute that
    cache entry, the arg pointer is now pointing at garbage, or at least not
    at the untransformed argument it should be pointing at.
    
    Ideally, maybe, the parser wouldn't ever modify its input.  However,
    this code fragment has got LOTS of company, so making that happen has
    never seemed too practical.  So what we generally do, before invoking
    the parser (or planner), is a quick copyObject() on any node tree that
    might be coming from cache.
    
    The proximate cause of this problem is that CREATE/ALTER DOMAIN did
    not get that memo.  Looking around in typecmds.c, I noted that
    CREATE DOMAIN ... DEFAULT ... and ALTER DOMAIN SET DEFAULT have the
    same kind of bug.
    
    The attached patch seems to fix it.  I wonder though if we ought to
    move the copying to someplace more centralized.  I cannot escape the
    suspicion that there are more of these creepy-crawlies in other
    poorly-tested utility statements.
    
    BTW, a note for future testing: you can set up this failure using
    pgbench, no custom client code required.  I tested stuff like this:
    
    $ cat bug17053b.sql
    DROP DOMAIN IF EXISTS schema_meta;
    CREATE DOMAIN schema_meta AS bool DEFAULT (42 IS NOT NULL);
    $ pgbench -n -M prepared -f bug17053b.sql regression
    NOTICE:  type "schema_meta" does not exist, skipping
    pgbench: error: client 0 script 0 aborted in command 1 query 0: ERROR:  unrecognized node type: 2139062143
    
    			regards, tom lane
    
    
  3. Re: BUG #17053: Memory corruption in parser on prepared query reuse

    Charles Samborski <demurgos@demurgos.net> — 2021-08-19T13:07:35Z

    I am not familiar with how Postgres tracks its bugs. How can I check the
    status of this bug #17053? Is it still pending?
    
    > The attached patch seems to fix it.  I wonder though if we ought to
    > move the copying to someplace more centralized.  I cannot escape the
    > suspicion that there are more of these creepy-crawlies in other
    > poorly-tested utility statements.
    
    Is the quick-fix already applied or do you want to wait for these
    larger changes? I was hoping to drop my workarounds once the fixes for
    this bug land.
    
    Regards,
    Charles Samborski
    
    
    
    
  4. Re: BUG #17053: Memory corruption in parser on prepared query reuse

    Tom Lane <tgl@sss.pgh.pa.us> — 2021-08-19T14:34:54Z

    Charles Samborski <demurgos@demurgos.net> writes:
    > I am not familiar with how Postgres tracks its bugs. How can I check the
    > status of this bug #17053? Is it still pending?
    
    The fix was pushed in the releases made earlier this month.
    
    			regards, tom lane