Skip to content

Commit

Permalink
Fix array overflow for function argument types in orca
Browse files Browse the repository at this point in the history
In function “CTranslatorUtils::ResolvePolymorphicTypes()”, the
size of array arg_types is num_args, and it is smaller than
total_args, this causes a memory corruption and a backend crash.
Fixed by correcting the array size "total_args"(num_args +
num_return_args). Then copy the first 'num_args' function
argument types for arrary arg_types, the copying number can not
exceed num_args.

Fixes GitHub issue #11880

(cherry picked from commit 2f45387)
  • Loading branch information
shenfowang authored and chrishajas committed Jun 17, 2021
1 parent f6f46db commit 2888fcc
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 15 deletions.
26 changes: 14 additions & 12 deletions src/backend/gpopt/translate/CTranslatorUtils.cpp
Expand Up @@ -357,35 +357,37 @@ CTranslatorUtils::ConvertToCDXLLogicalTVF(CMemoryPool *mp,
//---------------------------------------------------------------------------
IMdIdArray *
CTranslatorUtils::ResolvePolymorphicTypes(CMemoryPool *mp,
IMdIdArray *mdid_array,
List *arg_types_list,
IMdIdArray *return_arg_mdids,
List *input_arg_types,
FuncExpr *funcexpr)
{
ULONG arg_index = 0;

const ULONG num_arg_types = gpdb::ListLength(arg_types_list);
const ULONG num_arg_types = gpdb::ListLength(input_arg_types);
const ULONG num_args_from_query = gpdb::ListLength(funcexpr->args);
const ULONG num_return_args = mdid_array->Size();
const ULONG num_args = num_arg_types < num_args_from_query
? num_arg_types
: num_args_from_query;
const ULONG num_return_args = return_arg_mdids->Size();
const ULONG num_args = std::min(num_arg_types, num_args_from_query);
const ULONG total_args = num_args + num_return_args;

OID arg_types[num_args];
OID arg_types[total_args];
char arg_modes[total_args];

// copy function argument types
// copy the first 'num_args' function argument types
ListCell *arg_type = nullptr;
ForEach(arg_type, arg_types_list)
ForEach(arg_type, input_arg_types)
{
if (arg_index >= num_args)
{
break;
}
arg_types[arg_index] = lfirst_oid(arg_type);
arg_modes[arg_index++] = PROARGMODE_IN;
}

// copy function return types
for (ULONG ul = 0; ul < num_return_args; ul++)
{
IMDId *mdid = (*mdid_array)[ul];
IMDId *mdid = (*return_arg_mdids)[ul];
arg_types[arg_index] = CMDIdGPDB::CastMdid(mdid)->Oid();
arg_modes[arg_index++] = PROARGMODE_TABLE;
}
Expand All @@ -399,7 +401,7 @@ CTranslatorUtils::ResolvePolymorphicTypes(CMemoryPool *mp,
"could not determine actual argument/return type for polymorphic function"));
}

// generate a new array of mdids based on the resolved types
// generate a new array of mdids based on the resolved return types
IMdIdArray *resolved_types = GPOS_NEW(mp) IMdIdArray(mp);

// get the resolved return types
Expand Down
6 changes: 3 additions & 3 deletions src/include/gpopt/translate/CTranslatorUtils.h
Expand Up @@ -94,9 +94,9 @@ class CTranslatorUtils
// resolve polymorphic types in the given array of type ids, replacing
// them with the actual types obtained from the query
static IMdIdArray *ResolvePolymorphicTypes(CMemoryPool *mp,
IMdIdArray *mdid_array,
List *arg_types,
FuncExpr *func_expr);
IMdIdArray *return_arg_mdids,
List *input_arg_types,
FuncExpr *funcexpr);

// update grouping col position mappings
static void UpdateGrpColMapping(CMemoryPool *mp,
Expand Down
10 changes: 10 additions & 0 deletions src/test/regress/expected/gporca.out
Expand Up @@ -10813,6 +10813,16 @@ SELECT * FROM func_array_nonarray_enum(ARRAY['blue'::rainbow, 'red'::rainbow], '
(1 row)

DROP FUNCTION IF EXISTS func_array_nonarray_enum(ANYARRAY, ANYNONARRAY, ANYENUM);
--TVF accepts ANYENUM, ANYELEMENT, ANYELEMENT return ANYENUM, ANYARRAY
CREATE FUNCTION return_enum_as_array(ANYENUM, ANYELEMENT, ANYELEMENT) RETURNS TABLE (ae ANYENUM, aa ANYARRAY)
AS $$ SELECT $1, array[$2, $3] $$ LANGUAGE SQL STABLE;
SELECT * FROM return_enum_as_array('red'::rainbow, 'yellow'::rainbow, 'blue'::rainbow);
ae | aa
-----+---------------
red | {yellow,blue}
(1 row)

DROP FUNCTION IF EXISTS return_enum_as_array(ANYENUM, ANYELEMENT, ANYELEMENT);
-- start_ignore
drop table foo;
-- end_ignore
Expand Down
13 changes: 13 additions & 0 deletions src/test/regress/expected/gporca_optimizer.out
Expand Up @@ -10989,6 +10989,19 @@ CONTEXT: SQL function "func_array_nonarray_enum" during startup
(1 row)

DROP FUNCTION IF EXISTS func_array_nonarray_enum(ANYARRAY, ANYNONARRAY, ANYENUM);
--TVF accepts ANYENUM, ANYELEMENT, ANYELEMENT return ANYENUM, ANYARRAY
CREATE FUNCTION return_enum_as_array(ANYENUM, ANYELEMENT, ANYELEMENT) RETURNS TABLE (ae ANYENUM, aa ANYARRAY)
AS $$ SELECT $1, array[$2, $3] $$ LANGUAGE SQL STABLE;
SELECT * FROM return_enum_as_array('red'::rainbow, 'yellow'::rainbow, 'blue'::rainbow);
INFO: GPORCA failed to produce a plan, falling back to planner
DETAIL: GPDB Expression type: Query Parameter not supported in DXL
CONTEXT: SQL function "return_enum_as_array" during startup
ae | aa
-----+---------------
red | {yellow,blue}
(1 row)

DROP FUNCTION IF EXISTS return_enum_as_array(ANYENUM, ANYELEMENT, ANYELEMENT);
-- start_ignore
drop table foo;
-- end_ignore
Expand Down
6 changes: 6 additions & 0 deletions src/test/regress/sql/gporca.sql
Expand Up @@ -2053,6 +2053,12 @@ AS $$ SELECT $1[1]; $$ LANGUAGE SQL STABLE;
SELECT * FROM func_array_nonarray_enum(ARRAY['blue'::rainbow, 'red'::rainbow], 'red'::rainbow, 'yellow'::rainbow);
DROP FUNCTION IF EXISTS func_array_nonarray_enum(ANYARRAY, ANYNONARRAY, ANYENUM);

--TVF accepts ANYENUM, ANYELEMENT, ANYELEMENT return ANYENUM, ANYARRAY
CREATE FUNCTION return_enum_as_array(ANYENUM, ANYELEMENT, ANYELEMENT) RETURNS TABLE (ae ANYENUM, aa ANYARRAY)
AS $$ SELECT $1, array[$2, $3] $$ LANGUAGE SQL STABLE;
SELECT * FROM return_enum_as_array('red'::rainbow, 'yellow'::rainbow, 'blue'::rainbow);
DROP FUNCTION IF EXISTS return_enum_as_array(ANYENUM, ANYELEMENT, ANYELEMENT);

-- start_ignore
drop table foo;
-- end_ignore
Expand Down

0 comments on commit 2888fcc

Please sign in to comment.