Segfault-Inc / Multicorn

Data Access Library
https://multicorn.org/
PostgreSQL License
700 stars 145 forks source link

Seg fault 11 when use DISTINCT, MAX or MIN functions with Postgres 11? #228

Open johnmudd opened 5 years ago

johnmudd commented 5 years ago

I get a seg fault when use DISTINCT, MAX or MIN after upgrading to Postgres 11. My question for now is whether anyone running Multicorn with Postgres 11 gets the same sort of error. It doesn't matter if the column is indexed or not.

I build Postgres and Python from source using musl C library. I've used Multicorn w/o issue on Postgres 9 & 10. I can also use the functions w/o error using Postgres 11 on regular (non-FDW) tables. Linux psql example and traceback below.

$ echo "select distinct(patstoreid) from shipping" | psql rx30
server closed the connection unexpectedly
        This probably means the server terminated abnormally
        before or while processing the request.
connection to server was lost
$
$ gdb /usr/rx30/musl/postgresql-11.3.install/bin/postgres core
(gdb) bt
#0  0xf770c103 in strlen () from /usr/rx30/musl/lib/ld-musl-i386.so.1
#1  0xf770be3b in strdup () from /usr/rx30/musl/lib/ld-musl-i386.so.1
#2  0xf770be2c in strdup () from /usr/rx30/musl/lib/ld-musl-i386.so.1
#3  0xee4da0be in deparse_sortgroup () from /home/mudd/musl.11.3/postgresql-11.3.install/lib/multicorn.so
#4  0xee4db254 in multicornGetForeignPaths () from /home/mudd/musl.11.3/postgresql-11.3.install/lib/multicorn.so
#5  0x082e6506 in set_rel_pathlist ()
#6  0x082e72d9 in make_one_rel ()
#7  0x083130d5 in query_planner ()
#8  0x080b0ac8 in build_minmax_path ()
#9  0x08312e48 in preprocess_minmax_aggregates ()
#10 0x083178fc in grouping_planner ()
#11 0x0831a954 in subquery_planner ()
#12 0x0831b93b in standard_planner ()
#13 0x083e1275 in exec_simple_query ()
#14 0x083e29b6 in PostgresMain ()
#15 0x080b3392 in ServerLoop ()
#16 0x0835e2f7 in PostmasterMain ()
#17 0x080b5153 in main ()
(gdb) 
johnmudd commented 5 years ago

The seg fault occurs in src/query.c when get_collation_name(collid) returns 0 (zero) and this is passed to strdup().

Here's a code change to src/query.c that seems to bypass the problem.

BEFORE

            /* ORDER BY clauses having a COLLATE option will be RelabelType */
            else if (IsA(expr, RelabelType) &&
                    IsA(((RelabelType *) expr)->arg, Var))
            {   
                Var *var = (Var *)((RelabelType *) expr)->arg;
                Oid collid = ((RelabelType *) expr)->resultcollid;

                if (collid == DEFAULT_COLLATION_OID)
                    md->collate = NULL;
                else
                    md->collate = (Name) strdup(get_collation_name(collid));  // Seg fault here.
                md->attname = (Name) strdup(get_attname(foreigntableid, var->varattno, false));
                md->attnum = var->varattno;
                found = true;
            }

AFTER

            /* ORDER BY clauses having a COLLATE option will be RelabelType */
            else if (IsA(expr, RelabelType) &&
                    IsA(((RelabelType *) expr)->arg, Var))
            {   
                Var *var = (Var *)((RelabelType *) expr)->arg;
                Oid collid = ((RelabelType *) expr)->resultcollid;

                if (collid == DEFAULT_COLLATION_OID)
                {   
                    found = true;
                    md->collate = NULL;
                }
                else
                {   
                    if (get_collation_name(collid))
                    {   
                        found = true;
                        md->collate = (Name) strdup(get_collation_name(collid));
                    }
                }
                if (found)
                {   
                    md->attname = (Name) strdup(get_attname(foreigntableid, var->varattno, false));
                    md->attnum = var->varattno;
                }
            }