Thread

Commits

  1. In hstore_plpython, avoid crashing when return value isn't a mapping.

  1. BUG #17908: plpython_to_hstore() crashes with a non-dict argument

    The Post Office <noreply@postgresql.org> — 2023-04-25T13:00:02Z

    The following bug has been logged on the website:
    
    Bug reference:      17908
    Logged by:          Alexander Lakhin
    Email address:      exclusion@gmail.com
    PostgreSQL version: 15.2
    Operating system:   Ubuntu 22.04
    Description:        
    
    When executing the following query:
    CREATE EXTENSION hstore_plpython3u CASCADE;
    CREATE FUNCTION test_transform() RETURNS hstore
    LANGUAGE plpython3u
    TRANSFORM FOR TYPE hstore AS 'return "a"';
    SELECT test_transform();
    
    The server crashes with the stack trace:
    Core was generated by `postgres: law regression [local] SELECT              
                            '.
    Program terminated with signal SIGABRT, Aborted.
    
    warning: Section `.reg-xstate/3829693' in core file too small.
    #0  __pthread_kill_implementation (no_tid=0, signo=6,
    threadid=140451453683648) at ./nptl/pthread_kill.c:44
    44      ./nptl/pthread_kill.c: No such file or directory.
    (gdb) bt
    #0  __pthread_kill_implementation (no_tid=0, signo=6,
    threadid=140451453683648) at ./nptl/pthread_kill.c:44
    #1  __pthread_kill_internal (signo=6, threadid=140451453683648) at
    ./nptl/pthread_kill.c:78
    #2  __GI___pthread_kill (threadid=140451453683648, signo=signo@entry=6) at
    ./nptl/pthread_kill.c:89
    #3  0x00007fbd66427476 in __GI_raise (sig=sig@entry=6) at
    ../sysdeps/posix/raise.c:26
    #4  0x00007fbd6640d7f3 in __GI_abort () at ./stdlib/abort.c:79
    #5  0x000055eb85f693d7 in __sanitizer::Abort() ()
    #6  0x000055eb85f67271 in __sanitizer::Die() ()
    #7  0x000055eb85f49707 in
    __asan::ScopedInErrorReport::~ScopedInErrorReport() ()
    #8  0x000055eb85f490b6 in
    __asan::ReportDeadlySignal(__sanitizer::SignalContext const&) ()
    #9  0x000055eb85f48702 in __asan::AsanOnDeadlySignal(int, void*, void*) ()
    #10 <signal handler called>
    #11 0x00007fbd1b2c15c8 in PyList_GetItem () from
    /usr/lib/x86_64-linux-gnu/libpython3.10.so.1.0
    #12 0x00007fbd6410ed7f in plpython_to_hstore (fcinfo=0x7ffdc25d0460) at
    hstore_plpython.c:154
    #13 0x000055eb88fcf3a6 in FunctionCall1Coll (flinfo=0x625000177268,
    collation=0, arg1=140450178140016) at fmgr.c:1124
    #14 0x00007fbd1b8194b4 in PLyObject_ToTransform (arg=0x625000177248,
    plrv=0x7fbd1afa0770, isnull=0x625000184174, inarray=false) at
    plpy_typeio.c:1124
    #15 0x00007fbd1b80be9d in PLy_output_convert (arg=0x625000177248,
    val=0x7fbd1afa0770, isnull=0x625000184174) at plpy_typeio.c:122
    #16 0x00007fbd1b7e06fd in PLy_exec_function (fcinfo=0x625000184158,
    proc=0x625000177220) at plpy_exec.c:235
    #17 0x00007fbd1b7efa3a in plpython3_call_handler (fcinfo=0x625000184158) at
    plpy_main.c:247
    #18 0x000055eb872ab667 in ExecInterpExpr (state=0x625000184070,
    econtext=0x625000183d70, isnull=0x7ffdc25d48a0) at execExprInterp.c:727
    #19 0x000055eb872a3a4a in ExecInterpExprStillValid (state=0x625000184070,
    econtext=0x625000183d70, isNull=0x7ffdc25d48a0) at execExprInterp.c:1826
    #20 0x000055eb875a34cd in ExecEvalExprSwitchContext (state=0x625000184070,
    econtext=0x625000183d70, isNull=0x7ffdc25d48a0) at
    ../../../src/include/executor/executor.h:341
    #21 0x000055eb875a3024 in ExecProject (projInfo=0x625000184068) at
    ../../../src/include/executor/executor.h:375
    #22 0x000055eb875a1f5c in ExecResult (pstate=0x625000183c58) at
    nodeResult.c:136
    #23 0x000055eb87376877 in ExecProcNodeFirst (node=0x625000183c58) at
    execProcnode.c:464
    #24 0x000055eb873393a4 in ExecProcNode (node=0x625000183c58) at
    ../../../src/include/executor/executor.h:259
    #25 0x000055eb8731c58c in ExecutePlan (estate=0x625000183a20,
    planstate=0x625000183c58, use_parallel_mode=false, operation=CMD_SELECT,
    sendTuples=true, numberTuples=0, direction=ForwardScanDirection,
    dest=0x625000181968, 
        execute_once=true) at execMain.c:1636
    #26 0x000055eb8731bd92 in standard_ExecutorRun (queryDesc=0x6190000015a0,
    direction=ForwardScanDirection, count=0, execute_once=true) at
    execMain.c:363
    #27 0x000055eb8731adb3 in ExecutorRun (queryDesc=0x6190000015a0,
    direction=ForwardScanDirection, count=0, execute_once=true) at
    execMain.c:307
    #28 0x000055eb8843a4c9 in PortalRunSelect (portal=0x62500002aa20,
    forward=true, count=0, dest=0x625000181968) at pquery.c:924
    #29 0x000055eb8843887c in PortalRun (portal=0x62500002aa20,
    count=9223372036854775807, isTopLevel=true, run_once=true,
    dest=0x625000181968, altdest=0x625000181968, qc=0x7ffdc25d5900) at
    pquery.c:768
    #30 0x000055eb88422fff in exec_simple_query (query_string=0x625000005220
    "SELECT test_transform();") at postgres.c:1250
    #31 0x000055eb884205c9 in PostgresMain (dbname=0x629000011278 "regression",
    username=0x629000011258 "law") at postgres.c:4593
    #32 0x000055eb87ed06f1 in BackendRun (port=0x615000002b00) at
    postmaster.c:4511
    #33 0x000055eb87ece7f0 in BackendStartup (port=0x615000002b00) at
    postmaster.c:4239
    #34 0x000055eb87ec9c10 in ServerLoop () at postmaster.c:1806
    #35 0x000055eb87ec41d7 in PostmasterMain (argc=3, argv=0x6030000006d0) at
    postmaster.c:1478
    #36 0x000055eb8770321b in main (argc=3, argv=0x6030000006d0) at main.c:202
    
    (gdb) frame 12
    #12 0x00007fbd6410ed7f in plpython_to_hstore (fcinfo=0x7ffdc25d0460) at
    hstore_plpython.c:154
    154                             tuple = PyList_GetItem(items, i);
    (gdb) print items
    $1 = (PyObject * volatile) 0x0
    
    Here plpython_to_hstore() has got a string as an argument, but failed to
    detect that it's not a dictionary.
    With plpython2 (on REL_14_STABLE) I get:
    ERROR:  not a Python mapping
    CONTEXT:  while creating return value
    PL/Python function "test_transform"
    
    As noted in https://bugs.python.org/issue5945, the behaviour of
    PyMapping_Check() changed in Python 3, so it can't be used anymore to
    differentiate real dictionaries from strings or alike.
    
    
  2. Re: BUG #17908: plpython_to_hstore() crashes with a non-dict argument

    Dmitry Dolgov <9erthalion6@gmail.com> — 2023-04-27T08:27:27Z

    > On Tue, Apr 25, 2023 at 01:00:02PM +0000, PG Bug reporting form wrote:
    > The following bug has been logged on the website:
    >
    > Bug reference:      17908
    > Logged by:          Alexander Lakhin
    > Email address:      exclusion@gmail.com
    > PostgreSQL version: 15.2
    > Operating system:   Ubuntu 22.04
    > Description:
    >
    > When executing the following query:
    > CREATE EXTENSION hstore_plpython3u CASCADE;
    > CREATE FUNCTION test_transform() RETURNS hstore
    > LANGUAGE plpython3u
    > TRANSFORM FOR TYPE hstore AS 'return "a"';
    > SELECT test_transform();
    >
    > Here plpython_to_hstore() has got a string as an argument, but failed to
    > detect that it's not a dictionary.
    > With plpython2 (on REL_14_STABLE) I get:
    > ERROR:  not a Python mapping
    > CONTEXT:  while creating return value
    > PL/Python function "test_transform"
    >
    > As noted in https://bugs.python.org/issue5945, the behaviour of
    > PyMapping_Check() changed in Python 3, so it can't be used anymore to
    > differentiate real dictionaries from strings or alike.
    
    Thanks for finding this! That's indeed very annoying. After a quick
    investigation looks like a proposed solution from [1] is to use
    PyType_HasFeature with Py_TPFLAGS_MAPPING:
    
        -       if (!PyMapping_Check(dict))
        +       dict_type = Py_TYPE(dict);
        +       if (!PyType_HasFeature(dict_type, Py_TPFLAGS_MAPPING))
    
    But this flag is available only starting from Python 3.10, so not
    backward compatible :(
    
    [1]: https://bugs.python.org/issue46376
    
    
    
    
  3. Re: BUG #17908: plpython_to_hstore() crashes with a non-dict argument

    Tom Lane <tgl@sss.pgh.pa.us> — 2023-04-27T14:46:29Z

    Dmitry Dolgov <9erthalion6@gmail.com> writes:
    >> On Tue, Apr 25, 2023 at 01:00:02PM +0000, PG Bug reporting form wrote:
    >> As noted in https://bugs.python.org/issue5945, the behaviour of
    >> PyMapping_Check() changed in Python 3, so it can't be used anymore to
    >> differentiate real dictionaries from strings or alike.
    
    > Thanks for finding this! That's indeed very annoying.
    
    Yuck.
    
    > After a quick
    > investigation looks like a proposed solution from [1] is to use
    > PyType_HasFeature with Py_TPFLAGS_MAPPING:
    >     -       if (!PyMapping_Check(dict))
    >     +       dict_type = Py_TYPE(dict);
    >     +       if (!PyType_HasFeature(dict_type, Py_TPFLAGS_MAPPING))
    > But this flag is available only starting from Python 3.10, so not
    > backward compatible :(
    
    Yeah, doesn't sound hugely workable; I don't think we can require 3.10
    yet.  The issue5945 discussion suggested
    
    >>> And recommend `PyMapping_Check() && !PySequence_Check()` for true mapping test?
    
    I haven't verified this but will go test it shortly.  If it's true,
    it would explain why our other uses of PyMapping_Check haven't
    failed, because (whether by chance or not I dunno) they are not
    reached if PySequence_Check is true.
    
    			regards, tom lane