- Fixed bug #44251 (Question mark and an escaped singel quote lead to an exception)

- Fixed bug #41125 (PDO mysql + quote() + prepare() can result in seg fault)
  Patch by: tsteiner at nerdclub dot net
This commit is contained in:
Felipe Pena 2008-10-10 12:08:07 +00:00
parent e541c64464
commit cdeea98d37
3 changed files with 234 additions and 110 deletions

View file

@ -1,4 +1,4 @@
/* Generated by re2c 0.11.0 on Mon Nov 26 16:10:00 2007 */ /* Generated by re2c 0.13.5 on Fri Oct 10 09:03:17 2008 */
#line 1 "ext/pdo/pdo_sql_parser.re" #line 1 "ext/pdo/pdo_sql_parser.re"
/* /*
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
@ -47,7 +47,7 @@ static int scan(Scanner *s)
char *cursor = s->cur; char *cursor = s->cur;
s->tok = cursor; s->tok = cursor;
#line 54 "ext/pdo/pdo_sql_parser.re" #line 55 "ext/pdo/pdo_sql_parser.re"
@ -55,9 +55,9 @@ static int scan(Scanner *s)
{ {
YYCTYPE yych; YYCTYPE yych;
if((YYLIMIT - YYCURSOR) < 3) YYFILL(3); if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
yych = *YYCURSOR; yych = *YYCURSOR;
switch(yych) { switch (yych) {
case 0x00: goto yy11; case 0x00: goto yy11;
case '"': goto yy2; case '"': goto yy2;
case '\'': goto yy4; case '\'': goto yy4;
@ -66,34 +66,19 @@ static int scan(Scanner *s)
default: goto yy8; default: goto yy8;
} }
yy2: yy2:
yych = *++YYCURSOR; yych = *(YYMARKER = ++YYCURSOR);
switch(yych) { if (yych >= 0x01) goto yy26;
case '"': goto yy26;
case '\'':
case ':':
case '?': goto yy28;
default: goto yy30;
}
yy3: yy3:
#line 62 "ext/pdo/pdo_sql_parser.re" #line 63 "ext/pdo/pdo_sql_parser.re"
{ SKIP_ONE(PDO_PARSER_TEXT); } { SKIP_ONE(PDO_PARSER_TEXT); }
#line 81 "ext/pdo/pdo_sql_parser.c" #line 75 "ext/pdo/pdo_sql_parser.c"
yy4: yy4:
yych = *++YYCURSOR; yych = *(YYMARKER = ++YYCURSOR);
switch(yych) { if (yych <= 0x00) goto yy3;
case '"': goto yy20;
case ':':
case '?': goto yy19;
case '\'': goto yy21;
default: goto yy23;
}
yy5: yy5:
yych = *++YYCURSOR; yych = *++YYCURSOR;
switch(yych) { switch (yych) {
case '"':
case '\'':
case ':':
case '?': goto yy13;
case '0': case '0':
case '1': case '1':
case '2': case '2':
@ -157,26 +142,26 @@ yy5:
case 'x': case 'x':
case 'y': case 'y':
case 'z': goto yy16; case 'z': goto yy16;
case ':':
case '?': goto yy13;
default: goto yy3; default: goto yy3;
} }
yy6: yy6:
++YYCURSOR; ++YYCURSOR;
switch((yych = *YYCURSOR)) { switch ((yych = *YYCURSOR)) {
case '"':
case '\'':
case ':': case ':':
case '?': goto yy13; case '?': goto yy13;
default: goto yy7; default: goto yy7;
} }
yy7: yy7:
#line 61 "ext/pdo/pdo_sql_parser.re" #line 62 "ext/pdo/pdo_sql_parser.re"
{ RET(PDO_PARSER_BIND_POS); } { RET(PDO_PARSER_BIND_POS); }
#line 175 "ext/pdo/pdo_sql_parser.c" #line 160 "ext/pdo/pdo_sql_parser.c"
yy8: yy8:
++YYCURSOR; ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1); if (YYLIMIT <= YYCURSOR) YYFILL(1);
yych = *YYCURSOR; yych = *YYCURSOR;
switch(yych) { switch (yych) {
case 0x00: case 0x00:
case '"': case '"':
case '\'': case '\'':
@ -185,34 +170,32 @@ yy8:
default: goto yy8; default: goto yy8;
} }
yy10: yy10:
#line 63 "ext/pdo/pdo_sql_parser.re" #line 64 "ext/pdo/pdo_sql_parser.re"
{ RET(PDO_PARSER_TEXT); } { RET(PDO_PARSER_TEXT); }
#line 191 "ext/pdo/pdo_sql_parser.c" #line 176 "ext/pdo/pdo_sql_parser.c"
yy11: yy11:
++YYCURSOR; ++YYCURSOR;
#line 64 "ext/pdo/pdo_sql_parser.re" #line 65 "ext/pdo/pdo_sql_parser.re"
{ RET(PDO_PARSER_EOI); } { RET(PDO_PARSER_EOI); }
#line 196 "ext/pdo/pdo_sql_parser.c" #line 181 "ext/pdo/pdo_sql_parser.c"
yy13: yy13:
++YYCURSOR; ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1); if (YYLIMIT <= YYCURSOR) YYFILL(1);
yych = *YYCURSOR; yych = *YYCURSOR;
switch(yych) { switch (yych) {
case '"':
case '\'':
case ':': case ':':
case '?': goto yy13; case '?': goto yy13;
default: goto yy15; default: goto yy15;
} }
yy15: yy15:
#line 59 "ext/pdo/pdo_sql_parser.re" #line 60 "ext/pdo/pdo_sql_parser.re"
{ RET(PDO_PARSER_TEXT); } { RET(PDO_PARSER_TEXT); }
#line 211 "ext/pdo/pdo_sql_parser.c" #line 194 "ext/pdo/pdo_sql_parser.c"
yy16: yy16:
++YYCURSOR; ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1); if (YYLIMIT <= YYCURSOR) YYFILL(1);
yych = *YYCURSOR; yych = *YYCURSOR;
switch(yych) { switch (yych) {
case '0': case '0':
case '1': case '1':
case '2': case '2':
@ -279,80 +262,58 @@ yy16:
default: goto yy18; default: goto yy18;
} }
yy18: yy18:
#line 60 "ext/pdo/pdo_sql_parser.re" #line 61 "ext/pdo/pdo_sql_parser.re"
{ RET(PDO_PARSER_BIND); } { RET(PDO_PARSER_BIND); }
#line 285 "ext/pdo/pdo_sql_parser.c" #line 268 "ext/pdo/pdo_sql_parser.c"
yy19: yy19:
if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); ++YYCURSOR;
if (YYLIMIT <= YYCURSOR) YYFILL(1);
yych = *YYCURSOR; yych = *YYCURSOR;
switch(yych) { yy20:
case '"': switch (yych) {
case ':': case 0x00: goto yy21;
case '?': goto yy19; case '\'': goto yy23;
case '\'': goto yy21; case '\\': goto yy22;
default: goto yy23; default: goto yy19;
} }
yy21: yy21:
++YYCURSOR; YYCURSOR = YYMARKER;
switch((yych = *YYCURSOR)) { goto yy3;
case '"':
case '\'':
case ':':
case '?': goto yy13;
default: goto yy22;
}
yy22: yy22:
#line 58 "ext/pdo/pdo_sql_parser.re" ++YYCURSOR;
{ RET(PDO_PARSER_TEXT); } if (YYLIMIT <= YYCURSOR) YYFILL(1);
#line 308 "ext/pdo/pdo_sql_parser.c" yych = *YYCURSOR;
if (yych <= 0x00) goto yy21;
goto yy19;
yy23: yy23:
++YYCURSOR; ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1); #line 59 "ext/pdo/pdo_sql_parser.re"
yych = *YYCURSOR; { RET(PDO_PARSER_TEXT); }
switch(yych) { #line 293 "ext/pdo/pdo_sql_parser.c"
case '\'': goto yy25;
default: goto yy23;
}
yy25: yy25:
yych = *++YYCURSOR;
goto yy22;
yy26:
++YYCURSOR; ++YYCURSOR;
switch((yych = *YYCURSOR)) { if (YYLIMIT <= YYCURSOR) YYFILL(1);
case '"': yych = *YYCURSOR;
case '\'': yy26:
case ':': switch (yych) {
case '?': goto yy13; case 0x00: goto yy21;
default: goto yy27; case '"': goto yy28;
case '\\': goto yy27;
default: goto yy25;
} }
yy27: yy27:
#line 57 "ext/pdo/pdo_sql_parser.re" ++YYCURSOR;
{ RET(PDO_PARSER_TEXT); } if (YYLIMIT <= YYCURSOR) YYFILL(1);
#line 332 "ext/pdo/pdo_sql_parser.c" yych = *YYCURSOR;
if (yych <= 0x00) goto yy21;
goto yy25;
yy28: yy28:
if((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
yych = *YYCURSOR;
switch(yych) {
case '"': goto yy26;
case '\'':
case ':':
case '?': goto yy28;
default: goto yy30;
}
yy30:
++YYCURSOR; ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1); #line 58 "ext/pdo/pdo_sql_parser.re"
yych = *YYCURSOR; { RET(PDO_PARSER_TEXT); }
switch(yych) { #line 315 "ext/pdo/pdo_sql_parser.c"
case '"': goto yy32;
default: goto yy30;
}
yy32:
++YYCURSOR;
yych = *YYCURSOR;
goto yy27;
} }
#line 65 "ext/pdo/pdo_sql_parser.re" #line 66 "ext/pdo/pdo_sql_parser.re"
} }
@ -496,7 +457,7 @@ safe:
size_t len; size_t len;
char *buf = NULL; char *buf = NULL;
len = php_stream_copy_to_mem(stm, &buf, PHP_STREAM_COPY_ALL, 0); len = php_stream_copy_to_mem(stm, (void *)&buf, PHP_STREAM_COPY_ALL, 0);
if (!stmt->dbh->methods->quoter(stmt->dbh, buf, len, &plc->quoted, &plc->qlen, if (!stmt->dbh->methods->quoter(stmt->dbh, buf, len, &plc->quoted, &plc->qlen,
param->param_type TSRMLS_CC)) { param->param_type TSRMLS_CC)) {
/* bork */ /* bork */

View file

@ -49,14 +49,15 @@ static int scan(Scanner *s)
BINDCHR = [:][a-zA-Z0-9_]+; BINDCHR = [:][a-zA-Z0-9_]+;
QUESTION = [?]; QUESTION = [?];
SPECIALS = [:?"']; SPECIALS = [:?"'];
EOF = [\000]; MULTICHAR = [:?];
EOF = [\000];
ANYNOEOF = [\001-\377]; ANYNOEOF = [\001-\377];
*/ */
/*!re2c /*!re2c
(["] ([^"])* ["]) { RET(PDO_PARSER_TEXT); } (["](([\\]ANYNOEOF)|ANYNOEOF\["\\])*["]) { RET(PDO_PARSER_TEXT); }
(['] ([^'])* [']) { RET(PDO_PARSER_TEXT); } (['](([\\]ANYNOEOF)|ANYNOEOF\['\\])*[']) { RET(PDO_PARSER_TEXT); }
SPECIALS{2,} { RET(PDO_PARSER_TEXT); } MULTICHAR{2,} { RET(PDO_PARSER_TEXT); }
BINDCHR { RET(PDO_PARSER_BIND); } BINDCHR { RET(PDO_PARSER_BIND); }
QUESTION { RET(PDO_PARSER_BIND_POS); } QUESTION { RET(PDO_PARSER_BIND_POS); }
SPECIALS { SKIP_ONE(PDO_PARSER_TEXT); } SPECIALS { SKIP_ONE(PDO_PARSER_TEXT); }

View file

@ -0,0 +1,162 @@
--TEST--
Bug #41125 (PDO mysql + quote() + prepare() can result in seg fault)
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
$search = "o'";
$sql = "SELECT 1 FROM DUAL WHERE 'o''riley' LIKE " . $db->quote('%' . $search . '%');
$stmt = $db->prepare($sql);
$stmt->execute();
print implode(' - ', (($r = @$stmt->fetch(PDO::FETCH_NUM)) ? $r : array())) ."\n";
print implode(' - ', $stmt->errorinfo()) ."\n";
print "-------------------------------------------------------\n";
$queries = array(
"SELECT 1 FROM DUAL WHERE 1 = '?\'\''",
"SELECT 'a\\'0' FROM DUAL WHERE 1 = ?",
"SELECT 'a', 'b\'' FROM DUAL WHERE '''' LIKE '\\'' AND ?",
"SELECT 'foo?bar', '', '''' FROM DUAL WHERE ?"
);
foreach ($queries as $k => $query) {
$stmt = $db->prepare($query);
$stmt->execute(array(1));
printf("[%d] Query: [[%s]]\n", $k + 1, $query);
print implode(' - ', (($r = @$stmt->fetch(PDO::FETCH_NUM)) ? $r : array())) ."\n";
print implode(' - ', $stmt->errorinfo()) ."\n";
print "--------\n";
}
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
$sql = "SELECT upper(:id) FROM DUAL WHERE '1'";
$stmt = $db->prepare($sql);
$id = 'o\'\0';
$stmt->bindParam(':id', $id);
$stmt->execute();
printf("Query: [[%s]]\n", $sql);
print implode(' - ', (($r = @$stmt->fetch(PDO::FETCH_NUM)) ? $r : array())) ."\n";
print implode(' - ', $stmt->errorinfo()) ."\n";
print "-------------------------------------------------------\n";
$queries = array(
"SELECT 1, 'foo' FROM DUAL WHERE 1 = :id AND '\\0' IS NULL AND 2 <> :id",
"SELECT 1 FROM DUAL WHERE 1 = :id AND '' AND 2 <> :id",
"SELECT 1 FROM DUAL WHERE 1 = :id AND '\'\'' = '''' AND 2 <> :id",
"SELECT 1 FROM DUAL WHERE 1 = :id AND '\'' = '''' AND 2 <> :id",
"SELECT 'a', 'b\'' FROM DUAL WHERE '''' LIKE '\\'' AND 1",
"SELECT 'a''', '\'b\'' FROM DUAL WHERE '''' LIKE '\\'' AND 1",
"SELECT UPPER(:id) FROM DUAL WHERE '1'",
"SELECT 1 FROM DUAL WHERE '\''",
"SELECT 1 FROM DUAL WHERE :id AND '\\0' OR :id",
"SELECT 1 FROM DUAL WHERE 'a\\f\\n\\0' AND 1 >= :id",
"SELECT 1 FROM DUAL WHERE '\'' = ''''",
"SELECT '\\n' '1 FROM DUAL WHERE '''' and :id'",
"SELECT 1 'FROM DUAL WHERE :id AND '''' = '''' OR 1 = 1 AND ':id",
);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
$id = 1;
foreach ($queries as $k => $query) {
$stmt = $db->prepare($query);
$stmt->bindParam(':id', $id);
$stmt->execute();
printf("[%d] Query: [[%s]]\n", $k + 1, $query);
print implode(' - ', (($r = @$stmt->fetch(PDO::FETCH_NUM)) ? $r : array())) ."\n";
print implode(' - ', $stmt->errorinfo()) ."\n";
print "--------\n";
}
?>
--EXPECT--
1
00000
-------------------------------------------------------
[1] Query: [[SELECT 1 FROM DUAL WHERE 1 = '?\'\'']]
00000
--------
[2] Query: [[SELECT 'a\'0' FROM DUAL WHERE 1 = ?]]
a'0
00000
--------
[3] Query: [[SELECT 'a', 'b\'' FROM DUAL WHERE '''' LIKE '\'' AND ?]]
a - b'
00000
--------
[4] Query: [[SELECT 'foo?bar', '', '''' FROM DUAL WHERE ?]]
foo?bar - - '
00000
--------
Query: [[SELECT upper(:id) FROM DUAL WHERE '1']]
O'\0
00000
-------------------------------------------------------
[1] Query: [[SELECT 1, 'foo' FROM DUAL WHERE 1 = :id AND '\0' IS NULL AND 2 <> :id]]
00000
--------
[2] Query: [[SELECT 1 FROM DUAL WHERE 1 = :id AND '' AND 2 <> :id]]
00000
--------
[3] Query: [[SELECT 1 FROM DUAL WHERE 1 = :id AND '\'\'' = '''' AND 2 <> :id]]
00000
--------
[4] Query: [[SELECT 1 FROM DUAL WHERE 1 = :id AND '\'' = '''' AND 2 <> :id]]
1
00000
--------
[5] Query: [[SELECT 'a', 'b\'' FROM DUAL WHERE '''' LIKE '\'' AND 1]]
a - b'
00000
--------
[6] Query: [[SELECT 'a''', '\'b\'' FROM DUAL WHERE '''' LIKE '\'' AND 1]]
a' - 'b'
00000
--------
[7] Query: [[SELECT UPPER(:id) FROM DUAL WHERE '1']]
1
00000
--------
[8] Query: [[SELECT 1 FROM DUAL WHERE '\'']]
00000
--------
[9] Query: [[SELECT 1 FROM DUAL WHERE :id AND '\0' OR :id]]
1
00000
--------
[10] Query: [[SELECT 1 FROM DUAL WHERE 'a\f\n\0' AND 1 >= :id]]
00000
--------
[11] Query: [[SELECT 1 FROM DUAL WHERE '\'' = '''']]
1
00000
--------
[12] Query: [[SELECT '\n' '1 FROM DUAL WHERE '''' and :id']]
1 FROM DUAL WHERE '' and :id
00000
--------
[13] Query: [[SELECT 1 'FROM DUAL WHERE :id AND '''' = '''' OR 1 = 1 AND ':id]]
1
00000
--------