1
0
mirror of https://github.com/postgres/postgres.git synced 2026-10-23 13:29:09 +03:00

test_extensible: Improve handling of incorrect inputs

The SQL wrappers of the module relied on stringToNode(), that trusts
its input.  When specifying node strings that to not match with the
expected ExtensibleNode "TestExtNode", the module would crash.

This adds a simple set of sanity checks to check the input, ensuring
that only an ExtensibleNode "TestExtNode" goes through.  Though far
from critical, it's always nice to make these test modules not crash
when used.

Oversight in 0e944fe357.

Author: Zsolt Parragi <zsolt.parragi@percona.com>
Reviewed-by: Greg Burd <greg@burd.me>
Discussion: https://postgr.es/m/CAN4CZFOTQXMZvuPxweO4Fm7+sjrPJUqU-JvYKETLBxuhqgbPjw@mail.gmail.com
This commit is contained in:
Michael Paquier
2026-09-10 11:02:21 +09:00
parent 895c1b5fe1
commit 7ac0c2d058
3 changed files with 44 additions and 12 deletions

View File

@@ -91,6 +91,13 @@ SELECT test_ext_node_equal(test_ext_node_make('1234'::oid, 2),
-- correct node type, missing field
SELECT test_ext_node_get_relid('{EXTENSIBLENODE :extnodename TestExtNode}');
ERROR: unexpected end of "TestExtNode"
-- incorrect node patterns
SELECT test_ext_node_get_relid('{QUERY}');
ERROR: argument is not a serialized "TestExtNode"
SELECT test_ext_node_get_relid('{EXTENSIBLENODE :extnodename NoSuchExtNode}');
ERROR: argument is not a serialized "TestExtNode"
SELECT test_ext_node_get_relid('42');
ERROR: argument is not a serialized "TestExtNode"
-- CustomScan tests
CREATE TABLE test_extensible_tbl (id integer, val text);
INSERT INTO test_extensible_tbl VALUES (1, 'one'), (2, 'two'), (3, 'three');

View File

@@ -33,6 +33,10 @@ SELECT test_ext_node_equal(test_ext_node_make('1234'::oid, 2),
-- correct node type, missing field
SELECT test_ext_node_get_relid('{EXTENSIBLENODE :extnodename TestExtNode}');
-- incorrect node patterns
SELECT test_ext_node_get_relid('{QUERY}');
SELECT test_ext_node_get_relid('{EXTENSIBLENODE :extnodename NoSuchExtNode}');
SELECT test_ext_node_get_relid('42');
-- CustomScan tests
CREATE TABLE test_extensible_tbl (id integer, val text);

View File

@@ -99,13 +99,16 @@ test_ext_node_out_cb(StringInfo str, const ExtensibleNode *node)
}
/*
* Fetch the next token, erroring out instead of returning NULL.
* Fetch the next token of the string being read.
*
* Unlike anything in readfuncs.c, this callback is reachable with arbitrary
* strings through SQL function calls, so we need this check.
* Unlike anything in readfuncs.c, this is reachable with arbitrary strings
* through SQL function calls, so the tokens need to be checked.
*
* If "expected" is specified, check that the token fetched matches with
* the input expected. Running out of tokens is a failure.
*/
static const char *
test_ext_node_next_token(ReadNodeContext *ctx)
test_ext_node_next_token(ReadNodeContext *ctx, const char *expected)
{
int length;
const char *token = pg_strtok(ctx, &length);
@@ -115,6 +118,14 @@ test_ext_node_next_token(ReadNodeContext *ctx)
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("unexpected end of \"%s\"", TEST_EXT_NODE_NAME)));
if (expected != NULL)
{
if (length != (int) strlen(expected))
return NULL;
if (memcmp(token, expected, length) != 0)
return NULL;
}
return token;
}
@@ -123,11 +134,11 @@ test_ext_node_read_cb(ReadNodeContext *ctx, ExtensibleNode *node)
{
TestExtNode *tnode = (TestExtNode *) node;
(void) test_ext_node_next_token(ctx); /* skip :relid */
tnode->relid = atooid(test_ext_node_next_token(ctx));
(void) test_ext_node_next_token(ctx, NULL); /* skip :relid */
tnode->relid = atooid(test_ext_node_next_token(ctx, NULL));
(void) test_ext_node_next_token(ctx); /* skip :repeat_count */
tnode->repeat_count = atoi(test_ext_node_next_token(ctx));
(void) test_ext_node_next_token(ctx, NULL); /* skip :repeat_count */
tnode->repeat_count = atoi(test_ext_node_next_token(ctx, NULL));
}
static const ExtensibleNodeMethods test_ext_node_methods =
@@ -469,16 +480,26 @@ test_get_custom_scan_methods(PG_FUNCTION_ARGS)
static TestExtNode *
text_to_test_ext_node(text *txt)
{
Node *node = stringToNode(text_to_cstring(txt));
char *str = text_to_cstring(txt);
ReadNodeContext ctx;
TestExtNode *tnode;
if (node == NULL || !IsA(node, ExtensibleNode) ||
strcmp(((ExtensibleNode *) node)->extnodename, TEST_EXT_NODE_NAME) != 0)
ctx.str = str;
if (test_ext_node_next_token(&ctx, "{") == NULL ||
test_ext_node_next_token(&ctx, "EXTENSIBLENODE") == NULL ||
test_ext_node_next_token(&ctx, ":extnodename") == NULL ||
test_ext_node_next_token(&ctx, TEST_EXT_NODE_NAME) == NULL)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("argument is not a serialized \"%s\"",
TEST_EXT_NODE_NAME)));
return (TestExtNode *) node;
tnode = (TestExtNode *) stringToNode(str);
Assert(IsA(tnode, ExtensibleNode) &&
strcmp(tnode->base.extnodename, TEST_EXT_NODE_NAME) == 0);
return tnode;
}
/*