From 9c6fe6b0ffbd21bf8580ce00114f83b996577ffe Mon Sep 17 00:00:00 2001 From: David Carlier Date: Wed, 26 Mar 2025 12:47:57 +0000 Subject: [PATCH] Fix GH-18148: pg_copy_from() wrong \n offset check. Close GH-18149 --- NEWS | 4 ++++ ext/pgsql/pgsql.c | 6 ++++-- ext/pgsql/tests/gh18148.phpt | 24 ++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 ext/pgsql/tests/gh18148.phpt diff --git a/NEWS b/NEWS index f629af3a622..d747ba1b07b 100644 --- a/NEWS +++ b/NEWS @@ -75,6 +75,10 @@ PHP NEWS - PDO: . Fix memory leak when destroying PDORow. (nielsdos) +- PGSQL: + . Fixed bug GH-18148 (pg_copy_from() regression with explicit \n terminator + due to wrong offset check). (David Carlier) + - Standard: . Fix memory leaks in array_any() / array_all(). (nielsdos) diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index 4b03bfc3c9d..c0d4a5117ae 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -3451,11 +3451,13 @@ PHP_FUNCTION(pg_copy_from) if (UNEXPECTED(!tmp)) { return; } - zend_string *zquery = zend_string_alloc(ZSTR_LEN(tmp) + 1, false); + // we give allocation room for a potential command line `\n` terminator addition + zend_string *zquery = zend_string_alloc(ZSTR_LEN(tmp) + 2, false); memcpy(ZSTR_VAL(zquery), ZSTR_VAL(tmp), ZSTR_LEN(tmp) + 1); ZSTR_LEN(zquery) = ZSTR_LEN(tmp); - if (ZSTR_LEN(tmp) > 0 && ZSTR_VAL(zquery)[ZSTR_LEN(tmp)] != '\n') { + if (ZSTR_LEN(tmp) > 0 && ZSTR_VAL(zquery)[ZSTR_LEN(tmp) - 1] != '\n') { ZSTR_VAL(zquery)[ZSTR_LEN(tmp)] = '\n'; + ZSTR_VAL(zquery)[ZSTR_LEN(tmp) + 1] = '\0'; ZSTR_LEN(zquery) ++; } if (PQputCopyData(pgsql, ZSTR_VAL(zquery), ZSTR_LEN(zquery)) != 1) { diff --git a/ext/pgsql/tests/gh18148.phpt b/ext/pgsql/tests/gh18148.phpt new file mode 100644 index 00000000000..6cc2a254208 --- /dev/null +++ b/ext/pgsql/tests/gh18148.phpt @@ -0,0 +1,24 @@ +--TEST-- +Fix GH-18148 pg_copy_from() command position offset when giving explicit \n terminator +--EXTENSIONS-- +pgsql +--SKIPIF-- + +--FILE-- + +--EXPECT-- +bool(true)