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:
@@ -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');
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user