mirror of
https://github.com/postgres/postgres.git
synced 2026-10-23 13:29:09 +03:00
plpython: Fix NULL pointer dereferences for broken sequence and mapping objects
PL/Python and its hstore and jsonb transforms build SQL values from Python containers by calling Python C API functions that can return NULL, and in several places the result was used without first checking it. On the sequence side, PySequence_GetItem() is used when converting a returned sequence into a SQL array or composite value, when reading the argument list passed to plpy.execute() or plpy.cursor(), and when reading the list of type names given to plpy.prepare(). On the mapping side, the hstore and jsonb transforms call PyMapping_Size() and PyMapping_Items() and then index the result with PyList_GetItem() and PyTuple_GetItem(). All of these return NULL (or -1), with a Python exception set, for a broken object: for example one whose __getitem__() or items() raises, or which reports a length that disagrees with what it actually yields. The unchecked result was then dereferenced, crashing the backend. Fix this by checking the result of each call and reporting a regular error if it failed, so that the underlying Python exception is surfaced instead of taking down the session. Author: Richard Guo <guofenglinux@gmail.com> Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com> Discussion: https://postgr.es/m/CAMbWs49BKM9wP6m8bCXEpHwQKp7usvOGV6Jf=J7FYr_BCpxLqg@mail.gmail.com Backpatch-through: 14
This commit is contained in:
@@ -38,6 +38,71 @@ $$;
|
||||
SELECT test1bad();
|
||||
|
||||
|
||||
-- A mapping whose items() raises should be reported as an error, not crash
|
||||
-- the backend
|
||||
CREATE FUNCTION test1broken() RETURNS hstore
|
||||
LANGUAGE plpython3u
|
||||
TRANSFORM FOR TYPE hstore
|
||||
AS $$
|
||||
class C(dict):
|
||||
def items(self):
|
||||
raise ValueError('items failed')
|
||||
d = C()
|
||||
d['x'] = 1
|
||||
return d
|
||||
$$;
|
||||
|
||||
SELECT test1broken();
|
||||
|
||||
|
||||
-- Likewise for a mapping whose items() does not return key/value pairs
|
||||
CREATE FUNCTION test1malformed() RETURNS hstore
|
||||
LANGUAGE plpython3u
|
||||
TRANSFORM FOR TYPE hstore
|
||||
AS $$
|
||||
class C(dict):
|
||||
def items(self):
|
||||
return [42]
|
||||
d = C()
|
||||
d['x'] = 1
|
||||
return d
|
||||
$$;
|
||||
|
||||
SELECT test1malformed();
|
||||
|
||||
|
||||
-- Likewise for a mapping whose items() yields fewer pairs than its length
|
||||
CREATE FUNCTION test1short() RETURNS hstore
|
||||
LANGUAGE plpython3u
|
||||
TRANSFORM FOR TYPE hstore
|
||||
AS $$
|
||||
class C(dict):
|
||||
def items(self):
|
||||
return []
|
||||
d = C()
|
||||
d['x'] = 1
|
||||
return d
|
||||
$$;
|
||||
|
||||
SELECT test1short();
|
||||
|
||||
|
||||
-- Likewise for a mapping whose __len__() raises
|
||||
CREATE FUNCTION test1brokenlen() RETURNS hstore
|
||||
LANGUAGE plpython3u
|
||||
TRANSFORM FOR TYPE hstore
|
||||
AS $$
|
||||
class C(dict):
|
||||
def __len__(self):
|
||||
raise ValueError('len failed')
|
||||
d = C()
|
||||
d['x'] = 1
|
||||
return d
|
||||
$$;
|
||||
|
||||
SELECT test1brokenlen();
|
||||
|
||||
|
||||
-- test hstore[] -> python
|
||||
CREATE FUNCTION test1arr(val hstore[]) RETURNS int
|
||||
LANGUAGE plpython3u
|
||||
|
||||
Reference in New Issue
Block a user