Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit ac00ff1

Browse files
committed
Add test of various escape functions
As highlighted by the prior commit, writing correct escape functions is less trivial than one might hope. This test module tries to verify that different escaping functions behave reasonably. It e.g. tests: - Invalidly encoded input to an escape function leads to invalidly encoded output - Trailing incomplete multi-byte characters are handled sensibly - Escaped strings are parsed as single statement by psql's parser (which derives from the backend parser) There are further tests that would be good to add. But even in the current state it was rather useful for writing the fix in the prior commit. Reviewed-by: Noah Misch <noah@leadboat.com> Backpatch-through: 13 Security: CVE-2025-1094
1 parent 5dc1e42 commit ac00ff1

File tree

8 files changed

+921
-0
lines changed

8 files changed

+921
-0
lines changed

src/test/modules/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ SUBDIRS = \
1919
test_ddl_deparse \
2020
test_dsa \
2121
test_dsm_registry \
22+
test_escape \
2223
test_extensions \
2324
test_ginpostinglist \
2425
test_integerset \

src/test/modules/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ subdir('test_custom_rmgrs')
1818
subdir('test_ddl_deparse')
1919
subdir('test_dsa')
2020
subdir('test_dsm_registry')
21+
subdir('test_escape')
2122
subdir('test_extensions')
2223
subdir('test_ginpostinglist')
2324
subdir('test_integerset')
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/tmp_check/
2+
/test_escape

src/test/modules/test_escape/Makefile

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# src/test/modules/test_escape/Makefile
2+
3+
PGFILEDESC = "test escape program"
4+
PGAPPICON = win32
5+
6+
PROGRAM = test_escape
7+
OBJS = $(WIN32RES) test_escape.o
8+
9+
PG_CPPFLAGS = -I$(libpq_srcdir)
10+
PG_LIBS_INTERNAL += -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport)
11+
12+
NO_INSTALL = 1
13+
TAP_TESTS = 1
14+
15+
ifdef USE_PGXS
16+
PG_CONFIG = pg_config
17+
PGXS := $(shell $(PG_CONFIG) --pgxs)
18+
include $(PGXS)
19+
else
20+
subdir = src/test/modules/test_escape
21+
top_builddir = ../../../..
22+
include $(top_builddir)/src/Makefile.global
23+
include $(top_srcdir)/contrib/contrib-global.mk
24+
endif
25+
26+
test_escape$(X): | submake-libpgfeutils
27+
check: test_escape$(X)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
test_escape_sources = files(
2+
'test_escape.c',
3+
)
4+
5+
if host_system == 'windows'
6+
test_escape_sources += rc_bin_gen.process(win32ver_rc, extra_args: [
7+
'--NAME', 'test_escape',
8+
'--FILEDESC', 'test escape program',])
9+
endif
10+
11+
test_escape = executable('test_escape',
12+
test_escape_sources,
13+
dependencies: [frontend_code, libpq],
14+
kwargs: default_bin_args + {
15+
'install': false,
16+
}
17+
)
18+
testprep_targets += test_escape
19+
20+
21+
tests += {
22+
'name': 'test_escape',
23+
'sd': meson.current_source_dir(),
24+
'bd': meson.current_build_dir(),
25+
'tap': {
26+
'tests': [
27+
't/001_test_escape.pl',
28+
],
29+
'deps': [test_escape],
30+
},
31+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Copyright (c) 2023-2025, PostgreSQL Global Development Group
2+
use strict;
3+
use warnings FATAL => 'all';
4+
use Config;
5+
use PostgreSQL::Test::Utils;
6+
use PostgreSQL::Test::Cluster;
7+
use Test::More;
8+
9+
my $node = PostgreSQL::Test::Cluster->new('node');
10+
11+
$node->init();
12+
$node->start();
13+
14+
$node->safe_psql('postgres',
15+
q(CREATE DATABASE db_sql_ascii ENCODING "sql_ascii" TEMPLATE template0;));
16+
17+
my $cmd =
18+
[ 'test_escape', '--conninfo', $node->connstr . " dbname=db_sql_ascii" ];
19+
20+
# There currently is no good other way to transport test results from a C
21+
# program that requires just the node being set-up...
22+
my ($stderr, $stdout);
23+
my $result = IPC::Run::run $cmd, '>', \$stdout, '2>', \$stderr;
24+
25+
is($result, 1, "test_escape returns 0");
26+
is($stderr, '', "test_escape stderr is empty");
27+
28+
foreach my $line (split('\n', $stdout))
29+
{
30+
if ($line =~ m/^ok \d+ ?(.*)/)
31+
{
32+
ok(1, $1);
33+
}
34+
35+
elsif ($line =~ m/^not ok \d+ ?(.*)/)
36+
{
37+
ok(0, $1);
38+
}
39+
40+
elsif ($line =~ m/^# ?(.*)/)
41+
{
42+
note $1;
43+
}
44+
elsif ($line =~ m/^\d+..\d+$/)
45+
{
46+
}
47+
else
48+
{
49+
BAIL_OUT("no unmapped lines, got $line");
50+
}
51+
}
52+
53+
done_testing();

0 commit comments

Comments
 (0)