Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Handle zero-length sublist correctly in Python -> SQL array conversion.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 28 Apr 2023 16:24:29 +0000 (12:24 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 28 Apr 2023 16:24:29 +0000 (12:24 -0400)
If PLySequence_ToArray came across a zero-length sublist, it'd compute
the overall array size as zero, possibly leading to a memory clobber.
(This would likely qualify as a security bug, were it not that plpython
is an untrusted language already.)

I think there are other corner-case issues in this code as well, notably
that the error messages don't match the core code and for some ranges
of array sizes you'd get "invalid memory alloc request size" rather than
the intended message about array size.

Really this code has no business doing its own array size calculation
at all, so remove the faulty code in favor of using ArrayGetNItems().

Per bug #17912 from Alexander Lakhin.  Bug seems to have come in with
commit 94aceed31, so back-patch to all supported branches.

Discussion: https://postgr.es/m/17912-82ceed78731d9cdc@postgresql.org

src/pl/plpython/expected/plpython_types.out
src/pl/plpython/expected/plpython_types_3.out
src/pl/plpython/plpy_typeio.c
src/pl/plpython/sql/plpython_types.sql

index 0a2659fe29297142ba9a728931fe9d95ed4b9449..052b53cd4c93f62e4b719e80607f8e7e148b8744 100644 (file)
@@ -687,6 +687,15 @@ SELECT * FROM test_type_conversion_array_mixed2();
 ERROR:  invalid input syntax for type integer: "abc"
 CONTEXT:  while creating return value
 PL/Python function "test_type_conversion_array_mixed2"
+CREATE FUNCTION test_type_conversion_array_mixed3() RETURNS text[] AS $$
+return [[], 'a']
+$$ LANGUAGE plpythonu;
+SELECT * FROM test_type_conversion_array_mixed3();
+ test_type_conversion_array_mixed3 
+-----------------------------------
+ {[],a}
+(1 row)
+
 CREATE FUNCTION test_type_conversion_mdarray_malformed() RETURNS int[] AS $$
 return [[1,2,3],[4,5]]
 $$ LANGUAGE plpythonu;
index a6ec10d5e1821f00381e719ca811c3bd9dac454c..4f72a626e181d49f513f2a674335b643fbf61e18 100644 (file)
@@ -687,6 +687,15 @@ SELECT * FROM test_type_conversion_array_mixed2();
 ERROR:  invalid input syntax for type integer: "abc"
 CONTEXT:  while creating return value
 PL/Python function "test_type_conversion_array_mixed2"
+CREATE FUNCTION test_type_conversion_array_mixed3() RETURNS text[] AS $$
+return [[], 'a']
+$$ LANGUAGE plpython3u;
+SELECT * FROM test_type_conversion_array_mixed3();
+ test_type_conversion_array_mixed3 
+-----------------------------------
+ {[],a}
+(1 row)
+
 CREATE FUNCTION test_type_conversion_mdarray_malformed() RETURNS int[] AS $$
 return [[1,2,3],[4,5]]
 $$ LANGUAGE plpython3u;
index 5e807b139f16d2707bfe2a41c1b98c3c11367a6d..8572bd86a1e8635af364bbe8a41889330d3b76e8 100644 (file)
@@ -1144,7 +1144,7 @@ PLySequence_ToArray(PLyObToDatum *arg, PyObject *plrv,
    int         i;
    Datum      *elems;
    bool       *nulls;
-   int64       len;
+   int         len;
    int         ndim;
    int         dims[MAXDIM];
    int         lbs[MAXDIM];
@@ -1163,7 +1163,6 @@ PLySequence_ToArray(PLyObToDatum *arg, PyObject *plrv,
     * Determine the number of dimensions, and their sizes.
     */
    ndim = 0;
-   len = 1;
 
    Py_INCREF(plrv);
 
@@ -1182,17 +1181,6 @@ PLySequence_ToArray(PLyObToDatum *arg, PyObject *plrv,
        if (dims[ndim] < 0)
            PLy_elog(ERROR, "could not determine sequence length for function return value");
 
-       if (dims[ndim] > MaxAllocSize)
-           ereport(ERROR,
-                   (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
-                    errmsg("array size exceeds the maximum allowed")));
-
-       len *= dims[ndim];
-       if (len > MaxAllocSize)
-           ereport(ERROR,
-                   (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
-                    errmsg("array size exceeds the maximum allowed")));
-
        if (dims[ndim] == 0)
        {
            /* empty sequence */
@@ -1222,15 +1210,18 @@ PLySequence_ToArray(PLyObToDatum *arg, PyObject *plrv,
                     errmsg("return value of function with array return type is not a Python sequence")));
 
        ndim = 1;
-       len = dims[0] = PySequence_Length(plrv);
+       dims[0] = PySequence_Length(plrv);
    }
 
+   /* Allocate space for work arrays, after detecting array size overflow */
+   len = ArrayGetNItems(ndim, dims);
+   elems = palloc(sizeof(Datum) * len);
+   nulls = palloc(sizeof(bool) * len);
+
    /*
     * Traverse the Python lists, in depth-first order, and collect all the
     * elements at the bottom level into 'elems'/'nulls' arrays.
     */
-   elems = palloc(sizeof(Datum) * len);
-   nulls = palloc(sizeof(bool) * len);
    currelem = 0;
    PLySequence_ToArray_recurse(arg->u.array.elm, plrv,
                                dims, ndim, 0,
index 0d207d9c0158c265a36de8a63991404940e07e35..065d887f431181261b7e2134f5fd97e4e0ffe073 100644 (file)
@@ -328,6 +328,13 @@ $$ LANGUAGE plpythonu;
 
 SELECT * FROM test_type_conversion_array_mixed2();
 
+CREATE FUNCTION test_type_conversion_array_mixed3() RETURNS text[] AS $$
+return [[], 'a']
+$$ LANGUAGE plpythonu;
+
+SELECT * FROM test_type_conversion_array_mixed3();
+
+
 CREATE FUNCTION test_type_conversion_mdarray_malformed() RETURNS int[] AS $$
 return [[1,2,3],[4,5]]
 $$ LANGUAGE plpythonu;