]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Bounds-check access to TupleDescAttr with an Assert.
authorRobert Haas <rhaas@postgresql.org>
Tue, 24 Mar 2026 12:58:50 +0000 (08:58 -0400)
committerRobert Haas <rhaas@postgresql.org>
Tue, 24 Mar 2026 12:58:50 +0000 (08:58 -0400)
The second argument to TupleDescAttr should always be at least zero
and less than natts; otherwise, we index outside of the attribute
array. Assert that this is the case.

Various violations, or possible violations, of this rule that are
currently in the tree are actually harmless, because while
we do call TupleDescAttr() before verifying that the argument is
within range, we don't actually dereference it unless the argument
was within range all along. Nonetheless, the Assert means we
should be more careful, so tidy up accordingly.

Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: http://postgr.es/m/CA+TgmoacixUZVvi00hOjk_d9B4iYKswWP1gNqQ8Vfray-AcOCA@mail.gmail.com

src/backend/access/common/tupdesc.c
src/include/access/tupdesc.h
src/pl/plperl/plperl.c
src/pl/plpgsql/src/pl_exec.c

index d771a265b34168d7ee4b1e744cc20f258b546c03..196472c05d0664c5952665b7b24132bbe2c2b91b 100644 (file)
@@ -246,10 +246,11 @@ CreateTupleDescCopy(TupleDesc tupdesc)
 
        desc = CreateTemplateTupleDesc(tupdesc->natts);
 
-       /* Flat-copy the attribute array */
-       memcpy(TupleDescAttr(desc, 0),
-                  TupleDescAttr(tupdesc, 0),
-                  desc->natts * sizeof(FormData_pg_attribute));
+       /* Flat-copy the attribute array (unless there are no attributes) */
+       if (desc->natts > 0)
+               memcpy(TupleDescAttr(desc, 0),
+                          TupleDescAttr(tupdesc, 0),
+                          desc->natts * sizeof(FormData_pg_attribute));
 
        /*
         * Since we're not copying constraints and defaults, clear fields
@@ -294,10 +295,11 @@ CreateTupleDescTruncatedCopy(TupleDesc tupdesc, int natts)
 
        desc = CreateTemplateTupleDesc(natts);
 
-       /* Flat-copy the attribute array */
-       memcpy(TupleDescAttr(desc, 0),
-                  TupleDescAttr(tupdesc, 0),
-                  desc->natts * sizeof(FormData_pg_attribute));
+       /* Flat-copy the attribute array (unless there are no attributes) */
+       if (desc->natts > 0)
+               memcpy(TupleDescAttr(desc, 0),
+                          TupleDescAttr(tupdesc, 0),
+                          desc->natts * sizeof(FormData_pg_attribute));
 
        /*
         * Since we're not copying constraints and defaults, clear fields
@@ -339,10 +341,11 @@ CreateTupleDescCopyConstr(TupleDesc tupdesc)
 
        desc = CreateTemplateTupleDesc(tupdesc->natts);
 
-       /* Flat-copy the attribute array */
-       memcpy(TupleDescAttr(desc, 0),
-                  TupleDescAttr(tupdesc, 0),
-                  desc->natts * sizeof(FormData_pg_attribute));
+       /* Flat-copy the attribute array (unless there are no attributes) */
+       if (desc->natts > 0)
+               memcpy(TupleDescAttr(desc, 0),
+                          TupleDescAttr(tupdesc, 0),
+                          desc->natts * sizeof(FormData_pg_attribute));
 
        for (i = 0; i < desc->natts; i++)
        {
index 62ef6b384973b4a80f56f6b89ca85bbf14f43844..d26287271e937b10ccd3347c3a16f958e402ff7c 100644 (file)
@@ -179,6 +179,8 @@ TupleDescAttr(TupleDesc tupdesc, int i)
 {
        FormData_pg_attribute *attrs = TupleDescAttrAddress(tupdesc);
 
+       Assert(i >= 0 && i < tupdesc->natts);
+
        return &attrs[i];
 }
 
index c5f11b874c7d928669a9d0d0c63bfa4e2e5bd326..06ebffa111cf6170654a2d9d0515c861c5f0f912 100644 (file)
@@ -1093,7 +1093,7 @@ plperl_build_tuple_result(HV *perlhash, TupleDesc td)
                SV                 *val = HeVAL(he);
                char       *key = hek2cstr(he);
                int                     attn = SPI_fnumber(td, key);
-               Form_pg_attribute attr = TupleDescAttr(td, attn - 1);
+               Form_pg_attribute attr;
 
                if (attn == SPI_ERROR_NOATTRIBUTE)
                        ereport(ERROR,
@@ -1106,6 +1106,7 @@ plperl_build_tuple_result(HV *perlhash, TupleDesc td)
                                         errmsg("cannot set system attribute \"%s\"",
                                                        key)));
 
+               attr = TupleDescAttr(td, attn - 1);
                values[attn - 1] = plperl_sv_to_datum(val,
                                                                                          attr->atttypid,
                                                                                          attr->atttypmod,
@@ -1799,7 +1800,7 @@ plperl_modify_tuple(HV *hvTD, TriggerData *tdata, HeapTuple otup)
                char       *key = hek2cstr(he);
                SV                 *val = HeVAL(he);
                int                     attn = SPI_fnumber(tupdesc, key);
-               Form_pg_attribute attr = TupleDescAttr(tupdesc, attn - 1);
+               Form_pg_attribute attr;
 
                if (attn == SPI_ERROR_NOATTRIBUTE)
                        ereport(ERROR,
@@ -1811,6 +1812,8 @@ plperl_modify_tuple(HV *hvTD, TriggerData *tdata, HeapTuple otup)
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                         errmsg("cannot set system attribute \"%s\"",
                                                        key)));
+
+               attr = TupleDescAttr(tupdesc, attn - 1);
                if (attr->attgenerated)
                        ereport(ERROR,
                                        (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
index 45d667428f46723dd13aa3707e858d38a7e5a1d3..65b0fd0790f2eac0483c5be7653d0aad8f2cf067 100644 (file)
@@ -3401,7 +3401,7 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
                                        PLpgSQL_var *var = (PLpgSQL_var *) retvar;
                                        Datum           retval = var->value;
                                        bool            isNull = var->isnull;
-                                       Form_pg_attribute attr = TupleDescAttr(tupdesc, 0);
+                                       Form_pg_attribute attr;
 
                                        if (natts != 1)
                                                ereport(ERROR,
@@ -3414,6 +3414,7 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
                                                                                                                var->datatype->typlen);
 
                                        /* coerce type if needed */
+                                       attr = TupleDescAttr(tupdesc, 0);
                                        retval = exec_cast_value(estate,
                                                                                         retval,
                                                                                         &isNull,
@@ -3532,7 +3533,7 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
                }
                else
                {
-                       Form_pg_attribute attr = TupleDescAttr(tupdesc, 0);
+                       Form_pg_attribute attr;
 
                        /* Simple scalar result */
                        if (natts != 1)
@@ -3541,6 +3542,7 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
                                                 errmsg("wrong result type supplied in RETURN NEXT")));
 
                        /* coerce type if needed */
+                       attr = TupleDescAttr(tupdesc, 0);
                        retval = exec_cast_value(estate,
                                                                         retval,
                                                                         &isNull,