summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRemi Collet <remi@remirepo.net>2021-04-08 15:48:15 +0200
committerRemi Collet <remi@remirepo.net>2021-04-08 15:48:15 +0200
commit2fec2005aa6472c5bca9368d3a38cb3782a87a3c (patch)
treeafe175615058ca7e6c8efa00ed6752425b922d14
parentd24e9befae861b647e0f1e761ecd4cecd29fbbbb (diff)
add upstream patch for https://bugs.php.net/80783
PDO ODBC truncates BLOB records at every 256th byte use oracle client library version 21.1
-rw-r--r--php-bug80783.patch185
-rw-r--r--php.spec30
2 files changed, 197 insertions, 18 deletions
diff --git a/php-bug80783.patch b/php-bug80783.patch
new file mode 100644
index 0000000..2da9928
--- /dev/null
+++ b/php-bug80783.patch
@@ -0,0 +1,185 @@
+From bccca0b53aa60a62e2988c750fc73c02d109e642 Mon Sep 17 00:00:00 2001
+From: "Christoph M. Becker" <cmbecker69@gmx.de>
+Date: Thu, 25 Feb 2021 14:38:42 +0100
+Subject: [PATCH] Fix #80783: PDO ODBC truncates BLOB records at every 256th
+ byte
+
+It is not guaranteed, that the driver inserts only a single NUL byte at
+the end of the buffer. Apparently, there is no way to find out the
+actual data length in the buffer after calling `SQLGetData()`, so we
+adjust after the next `SQLGetData()` call.
+
+We also prevent PDO::ODBC_ATTR_ASSUME_UTF8 from fetching garbage, by
+fetching all chunks with the same C type.
+
+Closes GH-6716.
+---
+ NEWS | 4 ++++
+ ext/pdo_odbc/odbc_stmt.c | 14 +++++++++++--
+ ext/pdo_odbc/tests/bug80783.phpt | 32 ++++++++++++++++++++++++++++++
+ ext/pdo_odbc/tests/bug80783a.phpt | 33 +++++++++++++++++++++++++++++++
+ 4 files changed, 81 insertions(+), 2 deletions(-)
+ create mode 100644 ext/pdo_odbc/tests/bug80783.phpt
+ create mode 100644 ext/pdo_odbc/tests/bug80783a.phpt
+
+diff --git a/ext/pdo_odbc/odbc_stmt.c b/ext/pdo_odbc/odbc_stmt.c
+index 18abc475b9eb..7ce0bebdca0d 100644
+--- a/ext/pdo_odbc/odbc_stmt.c
++++ b/ext/pdo_odbc/odbc_stmt.c
+@@ -652,6 +652,7 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, zend_ulong
+
+ /* if it is a column containing "long" data, perform late binding now */
+ if (C->is_long) {
++ SQLLEN orig_fetched_len = SQL_NULL_DATA;
+ zend_ulong used = 0;
+ char *buf;
+ RETCODE rc;
+@@ -662,6 +663,7 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, zend_ulong
+
+ rc = SQLGetData(S->stmt, colno+1, C->is_unicode ? SQL_C_BINARY : SQL_C_CHAR, C->data,
+ 256, &C->fetched_len);
++ orig_fetched_len = C->fetched_len;
+
+ if (rc == SQL_SUCCESS) {
+ /* all the data fit into our little buffer;
+@@ -673,7 +675,8 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, zend_ulong
+ /* this is a 'long column'
+
+ read the column in 255 byte blocks until the end of the column is reached, reassembling those blocks
+- in order into the output buffer
++ in order into the output buffer; 255 bytes are an optimistic assumption, since the driver may assert
++ more or less NUL bytes at the end; we cater to that later, if actual length information is available
+
+ this loop has to work whether or not SQLGetData() provides the total column length.
+ calling SQLDescribeCol() or other, specifically to get the column length, then doing a single read
+@@ -687,7 +690,14 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, zend_ulong
+ do {
+ C->fetched_len = 0;
+ /* read block. 256 bytes => 255 bytes are actually read, the last 1 is NULL */
+- rc = SQLGetData(S->stmt, colno+1, SQL_C_CHAR, buf2, 256, &C->fetched_len);
++ rc = SQLGetData(S->stmt, colno+1, C->is_unicode ? SQL_C_BINARY : SQL_C_CHAR, buf2, 256, &C->fetched_len);
++
++ /* adjust `used` in case we have length info from the driver */
++ if (orig_fetched_len >= 0 && C->fetched_len >= 0) {
++ SQLLEN fixed_used = orig_fetched_len - C->fetched_len;
++ ZEND_ASSERT(fixed_used <= used + 1);
++ used = fixed_used;
++ }
+
+ /* resize output buffer and reassemble block */
+ if (rc==SQL_SUCCESS_WITH_INFO) {
+diff --git a/ext/pdo_odbc/tests/bug80783.phpt b/ext/pdo_odbc/tests/bug80783.phpt
+new file mode 100644
+index 000000000000..9794c25a30ec
+--- /dev/null
++++ b/ext/pdo_odbc/tests/bug80783.phpt
+@@ -0,0 +1,32 @@
++--TEST--
++Bug #80783 (PDO ODBC truncates BLOB records at every 256th byte)
++--SKIPIF--
++<?php
++if (!extension_loaded('pdo_odbc')) die('skip pdo_odbc extension not available');
++require 'ext/pdo/tests/pdo_test.inc';
++PDOTest::skip();
++?>
++--FILE--
++<?php
++require 'ext/pdo/tests/pdo_test.inc';
++$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
++$db->exec("CREATE TABLE bug80783 (name IMAGE)");
++
++$string = str_repeat("0123456789", 50);
++$db->exec("INSERT INTO bug80783 VALUES('$string')");
++
++$stmt = $db->prepare("SELECT name FROM bug80783");
++$stmt->bindColumn(1, $data, PDO::PARAM_LOB);
++$stmt->execute();
++$stmt->fetch(PDO::FETCH_BOUND);
++
++var_dump($data === bin2hex($string));
++?>
++--CLEAN--
++<?php
++require 'ext/pdo/tests/pdo_test.inc';
++$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
++$db->exec("DROP TABLE bug80783");
++?>
++--EXPECT--
++bool(true)
+diff --git a/ext/pdo_odbc/tests/bug80783a.phpt b/ext/pdo_odbc/tests/bug80783a.phpt
+new file mode 100644
+index 000000000000..f9e123ae5426
+--- /dev/null
++++ b/ext/pdo_odbc/tests/bug80783a.phpt
+@@ -0,0 +1,33 @@
++--TEST--
++Bug #80783 (PDO ODBC truncates BLOB records at every 256th byte)
++--SKIPIF--
++<?php
++if (!extension_loaded('pdo_odbc')) die('skip pdo_odbc extension not available');
++require 'ext/pdo/tests/pdo_test.inc';
++PDOTest::skip();
++?>
++--FILE--
++<?php
++require 'ext/pdo/tests/pdo_test.inc';
++$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
++$db->exec("CREATE TABLE bug80783a (name NVARCHAR(MAX))");
++
++$string = str_repeat("0123456789", 50);
++$db->exec("INSERT INTO bug80783a VALUES('$string')");
++
++$stmt = $db->prepare("SELECT name FROM bug80783a");
++$stmt->setAttribute(PDO::ODBC_ATTR_ASSUME_UTF8, true);
++$stmt->bindColumn(1, $data, PDO::PARAM_STR);
++$stmt->execute();
++$stmt->fetch(PDO::FETCH_BOUND);
++
++var_dump($data === $string);
++?>
++--CLEAN--
++<?php
++require 'ext/pdo/tests/pdo_test.inc';
++$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
++$db->exec("DROP TABLE bug80783a");
++?>
++--EXPECT--
++bool(true)
+From 25f5a1b2e15344e75d69a7140631d467e8b3f966 Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Thu, 8 Apr 2021 11:04:33 +0200
+Subject: [PATCH] Improve fix for #80783
+
+---
+ ext/pdo_odbc/odbc_stmt.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/ext/pdo_odbc/odbc_stmt.c b/ext/pdo_odbc/odbc_stmt.c
+index 7ce0bebdca0d..368648c36ae2 100644
+--- a/ext/pdo_odbc/odbc_stmt.c
++++ b/ext/pdo_odbc/odbc_stmt.c
+@@ -665,13 +665,13 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, zend_ulong
+ 256, &C->fetched_len);
+ orig_fetched_len = C->fetched_len;
+
+- if (rc == SQL_SUCCESS) {
++ if (rc == SQL_SUCCESS && C->fetched_len < 256) {
+ /* all the data fit into our little buffer;
+ * jump down to the generic bound data case */
+ goto in_data;
+ }
+
+- if (rc == SQL_SUCCESS_WITH_INFO) {
++ if (rc == SQL_SUCCESS_WITH_INFO || rc == SQL_SUCCESS) {
+ /* this is a 'long column'
+
+ read the column in 255 byte blocks until the end of the column is reached, reassembling those blocks
+@@ -700,7 +700,7 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, zend_ulong
+ }
+
+ /* resize output buffer and reassemble block */
+- if (rc==SQL_SUCCESS_WITH_INFO) {
++ if (rc==SQL_SUCCESS_WITH_INFO || (rc==SQL_SUCCESS && C->fetched_len > 255)) {
+ /* point 5, in section "Retrieving Data with SQLGetData" in http://msdn.microsoft.com/en-us/library/windows/desktop/ms715441(v=vs.85).aspx
+ states that if SQL_SUCCESS_WITH_INFO, fetched_len will be > 255 (greater than buf2's size)
+ (if a driver fails to follow that and wrote less than 255 bytes to buf2, this will AV or read garbage into buf) */
diff --git a/php.spec b/php.spec
index 842cb0c..9f98ac8 100644
--- a/php.spec
+++ b/php.spec
@@ -55,22 +55,8 @@
%global mysql_sock %(mysql_config --socket 2>/dev/null || echo /var/lib/mysql/mysql.sock)
-%if 0%{?rhel} == 6
-%ifarch x86_64
-%global oraclever 18.5
-%else
-%global oraclever 18.3
-%endif
-%global oraclelib 18.1
-
-%else
-%ifarch x86_64
-%global oraclever 19.9
-%else
-%global oraclever 19.6
-%endif
-%global oraclelib 19.1
-%endif
+%global oraclever 21.1
+%global oraclelib 21.1
# Build for LiteSpeed Web Server (LSAPI)
%global with_lsws 1
@@ -141,7 +127,7 @@
Summary: PHP scripting language for creating dynamic web sites
Name: %{?scl_prefix}php
Version: %{upver}%{?rcver:~%{rcver}}
-Release: 1%{?dist}
+Release: 2%{?dist}
# All files licensed under PHP version 3.01, except
# Zend is licensed under Zend
# TSRM is licensed under BSD
@@ -203,8 +189,10 @@ Patch49: php-7.3.24-fpm.patch
Patch91: php-7.2.0-oci8conf.patch
# Upstream fixes (100+)
-# Backported from 7.4.16
+# Backported from 7.4.16 - opcache and pcre.jit
Patch100: php-bug80682.patch
+# Backported from 7.4.18 - pdo_odbc
+Patch101: php-bug80783.patch
# Security fixes (200+)
@@ -975,6 +963,7 @@ sed -e 's/php-devel/%{?scl_prefix}php-devel/' -i scripts/phpize.in
# upstream patches
%patch100 -p1 -b .bug80682
+%patch101 -p1 -b .bug80783
# security patches
@@ -1928,6 +1917,11 @@ fi
%changelog
+* Thu Apr 8 2021 Remi Collet <remi@remirepo.net> - 7.3.27-2
+- add upstream patch for https://bugs.php.net/80783
+ PDO ODBC truncates BLOB records at every 256th byte
+- use oracle client library version 21.1
+
* Tue Feb 2 2021 Remi Collet <remi@remirepo.net> - 7.3.27-1
- Update to 7.3.27 - http://www.php.net/releases/7_3_27.php