]> granicus.if.org Git - php/commitdiff
Fix #44618: Fetching may rely on uninitialized data
authorChristoph M. Becker <cmbecker69@gmx.de>
Thu, 29 Oct 2020 10:52:10 +0000 (11:52 +0100)
committerChristoph M. Becker <cmbecker69@gmx.de>
Thu, 29 Oct 2020 10:59:12 +0000 (11:59 +0100)
Unless `SQLGetData()` returns `SQL_SUCCESS` or `SQL_SUCCESS_WITH_INFO`,
the `StrLen_or_IndPtr` output argument is not guaranteed to be properly
set.  Thus we handle retrieval failure other than `SQL_ERROR` by
yielding `false` for those column values and raising a warning.

Closes GH-6281.

NEWS
ext/odbc/php_odbc.c
ext/odbc/tests/bug44618.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 6d74ead2b9801ce2f39fd29ef64207d29a01ab8b..72b47f29943ed81a2a07ffb31b139f683adbe1cc 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -22,6 +22,9 @@ PHP                                                                        NEWS
   . Fixed bug #80242 (imap_mail_compose() segfaults for multipart with rfc822).
     (cmb)
 
+- ODBC:
+  . Fixed bug #44618 (Fetching may rely on uninitialized data). (cmb)
+
 29 Oct 2020, PHP 7.3.24
 
 - Core:
index 1bb832553c52c0355cb148d971b30e92f013b5a7..cc0580fb83480e6f82705f5d6c4bd47b239f17f8 100644 (file)
@@ -1810,6 +1810,9 @@ static void php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type)
 
                                if (rc == SQL_SUCCESS_WITH_INFO) {
                                        ZVAL_STRINGL(&tmp, buf, result->longreadlen);
+                               } else if (rc != SQL_SUCCESS) {
+                                       php_error_docref(NULL, E_WARNING, "Cannot get data of column #%d (retcode %u)", i + 1, rc);
+                                       ZVAL_FALSE(&tmp);
                                } else if (result->values[i].vallen == SQL_NULL_DATA) {
                                        ZVAL_NULL(&tmp);
                                        break;
@@ -1962,6 +1965,9 @@ PHP_FUNCTION(odbc_fetch_into)
                                }
                                if (rc == SQL_SUCCESS_WITH_INFO) {
                                        ZVAL_STRINGL(&tmp, buf, result->longreadlen);
+                               } else if (rc != SQL_SUCCESS) {
+                                       php_error_docref(NULL, E_WARNING, "Cannot get data of column #%d (retcode %u)", i + 1, rc);
+                                       ZVAL_FALSE(&tmp);
                                } else if (result->values[i].vallen == SQL_NULL_DATA) {
                                        ZVAL_NULL(&tmp);
                                        break;
@@ -2199,12 +2205,13 @@ PHP_FUNCTION(odbc_result)
                                RETURN_FALSE;
                        }
 
-                       if (result->values[field_ind].vallen == SQL_NULL_DATA) {
-                               zend_string_efree(field_str);
-                               RETURN_NULL();
-                       } else if (rc == SQL_NO_DATA_FOUND) {
+                       if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
                                zend_string_efree(field_str);
+                               php_error_docref(NULL, E_WARNING, "Cannot get data of column #%d (retcode %u)", field_ind + 1, rc);
                                RETURN_FALSE;
+                       } else if (result->values[field_ind].vallen == SQL_NULL_DATA) {
+                               zend_string_efree(field_str);
+                               RETURN_NULL();
                        }
                        /* Reduce fieldlen by 1 if we have char data. One day we might
                           have binary strings... */
@@ -2250,6 +2257,12 @@ PHP_FUNCTION(odbc_result)
                        RETURN_FALSE;
                }
 
+               if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
+                       php_error_docref(NULL, E_WARNING, "Cannot get data of column #%d (retcode %u)", field_ind + 1, rc);
+                       efree(field);
+                       RETURN_FALSE;
+               }
+
                if (result->values[field_ind].vallen == SQL_NULL_DATA) {
                        efree(field);
                        RETURN_NULL();
@@ -2359,6 +2372,11 @@ PHP_FUNCTION(odbc_result_all)
                                        }
                                        if (rc == SQL_SUCCESS_WITH_INFO) {
                                                PHPWRITE(buf, result->longreadlen);
+                                       } else if (rc != SQL_SUCCESS) {
+                                               php_printf("</td></tr></table>");
+                                               php_error_docref(NULL, E_WARNING, "Cannot get data of column #%d (retcode %u)", i + 1, rc);
+                                               efree(buf);
+                                               RETURN_FALSE;
                                        } else if (result->values[i].vallen == SQL_NULL_DATA) {
                                                php_printf("<td>NULL</td>");
                                                break;
diff --git a/ext/odbc/tests/bug44618.phpt b/ext/odbc/tests/bug44618.phpt
new file mode 100644 (file)
index 0000000..668cee7
--- /dev/null
@@ -0,0 +1,62 @@
+--TEST--
+Bug #44618 (Fetching may rely on uninitialized data)
+--SKIPIF--
+<?php include 'skipif.inc'; ?>
+--FILE--
+<?php
+include __DIR__ . "/config.inc";
+$conn = odbc_connect($dsn, $user, $pass, SQL_CUR_USE_ODBC);
+
+odbc_exec($conn, "CREATE TABLE bug44618(ID INT, real1 REAL, text1 TEXT)");
+odbc_exec($conn, "INSERT INTO bug44618 VALUES (1, 10.0199995, 'testing 1,2,3')");
+
+$result = odbc_exec($conn, "SELECT * FROM bug44618");
+var_dump(odbc_fetch_array($result));
+$result = null;
+
+$result = odbc_exec($conn, "SELECT * FROM bug44618");
+odbc_fetch_into($result, $array);
+var_dump($array);
+$result = null;
+
+$result = odbc_exec($conn, "SELECT * FROM bug44618");
+odbc_fetch_row($result);
+var_dump(odbc_result($result, "text1"));
+$result = null;
+
+$result = odbc_exec($conn, "SELECT * FROM bug44618");
+odbc_result_all($result);
+$result = null;
+?>
+--CLEAN--
+<?php
+include __DIR__ . "/config.inc";
+$conn = odbc_connect($dsn, $user, $pass);
+odbc_exec($conn, "DROP TABLE bug44618");
+?>
+--EXPECTF--
+Warning: odbc_fetch_array(): Cannot get data of column #3 (retcode 100) in %s on line %d
+array(3) {
+  ["ID"]=>
+  string(1) "1"
+  ["real1"]=>
+  string(5) "10.02"
+  ["text1"]=>
+  bool(false)
+}
+
+Warning: odbc_fetch_into(): Cannot get data of column #3 (retcode 100) in %s on line %d
+array(3) {
+  [0]=>
+  string(1) "1"
+  [1]=>
+  string(5) "10.02"
+  [2]=>
+  bool(false)
+}
+
+Warning: odbc_result(): Cannot get data of column #3 (retcode 100) in %s on line %d
+bool(false)
+<table><tr><th>ID</th><th>real1</th><th>text1</th></tr>
+<tr><td>1</td><td>10.02</td><td></td></tr></table>
+Warning: odbc_result_all(): Cannot get data of column #3 (retcode 100) in %s on line %d