Skip to content

Commit 82637e8

Browse files
cmb69Julien Pauli
authored and
Julien Pauli
committed
Fix #69975: PHP segfaults when accessing nvarchar(max) defined columns
The SQL Server Native Client 11.0 and maybe other ODBC drivers report NVARCHAR(MAX) columns as SQL_WVARCHAR with size 0. This causes too small a buffer to be emalloc'd, likely causing a segfault in the following. As we don't know the real size of the column data, we treat such colums as SQL_WLONGVARCHAR. The related bug #67437 suggests that some drivers report a size of ~4GB. It is not certain that this is really the case (there might be some integer overflow involved, and anyway, there has been no feedback), so we do not cater for this now. However, it would not be hard to treat all sizes above a certain threshold in a similar way, i.e. as SQL_WLONGVARCHAR. (cherry picked from commit 16db4d1) (cherry picked from commit 344ff5d)
1 parent 51b584b commit 82637e8

File tree

2 files changed

+39
-0
lines changed

2 files changed

+39
-0
lines changed

ext/odbc/php_odbc.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,13 @@ int odbc_bindcols(odbc_result *result TSRMLS_DC)
10071007
rc = SQLColAttributes(result->stmt, (SQLUSMALLINT)(i+1), SQL_COLUMN_DISPLAY_SIZE,
10081008
NULL, 0, NULL, &displaysize);
10091009
}
1010+
1011+
/* Workaround for drivers that report NVARCHAR(MAX) columns as SQL_WVARCHAR with size 0 (bug #69975) */
1012+
if (result->values[i].coltype == SQL_WVARCHAR && displaysize == 0) {
1013+
result->values[i].coltype = SQL_WLONGVARCHAR;
1014+
result->values[i].value = NULL;
1015+
break;
1016+
}
10101017
#endif
10111018
/* Workaround for Oracle ODBC Driver bug (#50162) when fetching TIMESTAMP column */
10121019
if (result->values[i].coltype == SQL_TIMESTAMP) {

ext/odbc/tests/bug69975.phpt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--TEST--
2+
Bug #69975 (PHP segfaults when accessing nvarchar(max) defined columns)
3+
--SKIPIF--
4+
<?php include 'skipif.inc'; ?>
5+
--FILE--
6+
<?php
7+
include 'config.inc';
8+
9+
$conn = odbc_connect($dsn, $user, $pass);
10+
@odbc_exec($conn, 'CREATE DATABASE odbcTEST');
11+
odbc_exec($conn, 'CREATE TABLE FOO (ID INT, VARCHAR_COL NVARCHAR(MAX))');
12+
odbc_exec($conn, "INSERT INTO FOO VALUES (1, 'foo')");
13+
14+
$result = odbc_exec($conn, "SELECT VARCHAR_COL FROM FOO");
15+
var_dump(odbc_fetch_array($result));
16+
17+
echo "ready";
18+
?>
19+
--EXPECT--
20+
array(1) {
21+
["VARCHAR_COL"]=>
22+
string(3) "foo"
23+
}
24+
ready
25+
--CLEAN--
26+
<?php
27+
include 'config.inc';
28+
29+
$conn = odbc_connect($dsn, $user, $pass);
30+
odbc_exec($conn, 'DROP TABLE FOO');
31+
odbc_exec($conn, 'DROP DATABASE odbcTEST');
32+
?>

0 commit comments

Comments
 (0)