php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #44251 Question mark and an escaped singel quote lead to an exception
Submitted: 2008-02-26 11:11 UTC Modified: 2008-10-10 12:18 UTC
Votes:11
Avg. Score:4.8 ± 0.4
Reproduced:10 of 10 (100.0%)
Same Version:7 (70.0%)
Same OS:6 (60.0%)
From: om at viazenetti dot de Assigned: felipe
Status: Closed Package: PDO related
PHP Version: 5.2.5 OS: Linux
Private report: No CVE-ID:
 [2008-02-26 11:11 UTC] om at viazenetti dot de
Description:
------------
If a question mark and an escaped singel quote appear in a where statement as value, the PDO method prepare tries to bind a value to the question mark.

Because no values are passed, pdo throws an exception (Only tested with where statements):

PDOStatement::execute() [function.PDOStatement-execute]: SQLSTATE[HY093]: Invalid parameter number: no parameters were bound in

Reproduce code:
---------------
<?php

    $db  = new PDO('mysql:host=localhost;dbname=DATABASE', 'USER', 'PASSWORD');
    $sth = $db->prepare("SELECT * FROM `TABLE` WHERE (login = '?\'')");

    $sth->execute();

    var_dump($sth->fetch());

Expected result:
----------------
Array or false

Actual result:
--------------
Exception: PDOStatement::execute() [function.PDOStatement-execute]: SQLSTATE[HY093]: Invalid parameter number: no parameters were bound in

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2008-09-05 17:59 UTC] tsteiner at nerdclub dot net
This bug is a direct result of the fix for Bug #36798.

The patch for that bug removed code in the parser that would ignore an escaped quote when inside of quotes (ie: "foo\"bar" or 'foo\'bar').

This causes the parser to think it has found the end of quoted text, when it has not.  Because of this, ? characters after an escaped quote are treated as placeholders.  Additionally, I have found it causes the parser to parse beyond the end of the query and into unknown memory contents.

It looks like Bug #36798 needs to be reopened!
 [2008-09-09 14:38 UTC] om at viazenetti dot de
Nice, after almost seven months, this bug still exists and no one cares about it?
 [2008-10-01 17:26 UTC] tsteiner at nerdclub dot net
Here's a patch to PHP 5.2.6 that seems to both fix this bug and not affect the test case in Bug #36798:



--- php-5.2.6/ext/pdo/pdo_sql_parser.re	2007-12-31 01:17:40.000000000 -0600
+++ php-5.2.6.fixed/ext/pdo/pdo_sql_parser.re	2008-09-08 11:06:39.000000000 -0500
@@ -55,8 +55,8 @@
 	*/
 
 	/*!re2c
-		(["] ([^"])* ["])		{ RET(PDO_PARSER_TEXT); }
-		(['] ([^'])* ['])		{ RET(PDO_PARSER_TEXT); }
+		(["](([\\]ANYNOEOF)|ANYNOEOF\["\\])*["]) { RET(PDO_PARSER_TEXT); }
+		(['](([\\]ANYNOEOF)|ANYNOEOF\['\\])*[']) { RET(PDO_PARSER_TEXT); }
 		MULTICHAR{2,}							{ RET(PDO_PARSER_TEXT); }
		BINDCHR						{ RET(PDO_PARSER_BIND); }
 		QUESTION								{ RET(PDO_PARSER_BIND_POS); }
--- php-5.2.6/ext/pdo/pdo_sql_parser.c	2008-04-30 13:37:40.000000000 -0500
+++ php-5.2.6.fixed/ext/pdo/pdo_sql_parser.c	2008-09-08 11:06:43.000000000 -0500
@@ -1,4 +1,5 @@
-/* Generated by re2c 0.11.0 on Mon Nov 26 16:10:28 2007 */
+/* Generated by re2c 0.13.5 on Mon Sep  8 11:06:43 2008 */
+#line 1 "ext/pdo/pdo_sql_parser.re"
 /*
   +----------------------------------------------------------------------+
   | PHP Version 5                                                        |
@@ -17,7 +18,7 @@
   +----------------------------------------------------------------------+
 */
 
-/* $Id: pdo_sql_parser.c,v 1.35.2.6.2.15 2007/12/31 07:20:09 sebastian Exp $ */
+/* $Id: pdo_sql_parser.re,v 1.28.2.4.2.12 2007/12/31 07:17:40 sebastian Exp $ */
 
 #include "php.h"
 #include "php_pdo_driver.h"
@@ -46,15 +47,17 @@
 	char *cursor = s->cur;
 
 	s->tok = cursor;
+	#line 55 "ext/pdo/pdo_sql_parser.re"
 
 
 	
+#line 55 "ext/pdo/pdo_sql_parser.c"
 {
 	YYCTYPE yych;
 
-	if((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
+	if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
 	yych = *YYCURSOR;
-	switch(yych) {
+	switch (yych) {
 	case 0x00:	goto yy11;
 	case '"':	goto yy2;
 	case '\'':	goto yy4;
@@ -63,16 +66,19 @@
 	default:	goto yy8;
 	}
 yy2:
-	yych = *++YYCURSOR;
-	goto yy24;
+	yych = *(YYMARKER = ++YYCURSOR);
+	if (yych >= 0x01) goto yy26;
 yy3:
+#line 63 "ext/pdo/pdo_sql_parser.re"
 	{ SKIP_ONE(PDO_PARSER_TEXT); }
+#line 75 "ext/pdo/pdo_sql_parser.c"
 yy4:
-	yych = *++YYCURSOR;
+	yych = *(YYMARKER = ++YYCURSOR);
+	if (yych <= 0x00) goto yy3;
 	goto yy20;
 yy5:
 	yych = *++YYCURSOR;
-	switch(yych) {
+	switch (yych) {
 	case '0':
 	case '1':
 	case '2':
@@ -142,18 +148,20 @@
 	}
 yy6:
 	++YYCURSOR;
-	switch((yych = *YYCURSOR)) {
+	switch ((yych = *YYCURSOR)) {
 	case ':':
 	case '?':	goto yy13;
 	default:	goto yy7;
 	}
 yy7:
+#line 62 "ext/pdo/pdo_sql_parser.re"
 	{ RET(PDO_PARSER_BIND_POS); }
+#line 160 "ext/pdo/pdo_sql_parser.c"
 yy8:
 	++YYCURSOR;
-	if(YYLIMIT == YYCURSOR) YYFILL(1);
+	if (YYLIMIT <= YYCURSOR) YYFILL(1);
 	yych = *YYCURSOR;
-	switch(yych) {
+	switch (yych) {
 	case 0x00:
 	case '"':
 	case '\'':
@@ -162,26 +170,32 @@
 	default:	goto yy8;
 	}
 yy10:
+#line 64 "ext/pdo/pdo_sql_parser.re"
 	{ RET(PDO_PARSER_TEXT); }
+#line 176 "ext/pdo/pdo_sql_parser.c"
 yy11:
 	++YYCURSOR;
+#line 65 "ext/pdo/pdo_sql_parser.re"
 	{ RET(PDO_PARSER_EOI); }
+#line 181 "ext/pdo/pdo_sql_parser.c"
 yy13:
 	++YYCURSOR;
-	if(YYLIMIT == YYCURSOR) YYFILL(1);
+	if (YYLIMIT <= YYCURSOR) YYFILL(1);
 	yych = *YYCURSOR;
-	switch(yych) {
+	switch (yych) {
 	case ':':
 	case '?':	goto yy13;
 	default:	goto yy15;
 	}
 yy15:
+#line 60 "ext/pdo/pdo_sql_parser.re"
 	{ RET(PDO_PARSER_TEXT); }
+#line 194 "ext/pdo/pdo_sql_parser.c"
 yy16:
 	++YYCURSOR;
-	if(YYLIMIT == YYCURSOR) YYFILL(1);
+	if (YYLIMIT <= YYCURSOR) YYFILL(1);
 	yych = *YYCURSOR;
-	switch(yych) {
+	switch (yych) {
 	case '0':
 	case '1':
 	case '2':
@@ -248,32 +262,58 @@
 	default:	goto yy18;
 	}
 yy18:
+#line 61 "ext/pdo/pdo_sql_parser.re"
 	{ RET(PDO_PARSER_BIND); }
+#line 268 "ext/pdo/pdo_sql_parser.c"
 yy19:
 	++YYCURSOR;
-	if(YYLIMIT == YYCURSOR) YYFILL(1);
+	if (YYLIMIT <= YYCURSOR) YYFILL(1);
 	yych = *YYCURSOR;
 yy20:
-	switch(yych) {
-	case '\'':	goto yy21;
+	switch (yych) {
+	case 0x00:	goto yy21;
+	case '\'':	goto yy23;
+	case '\\':	goto yy22;
 	default:	goto yy19;
 	}
 yy21:
+	YYCURSOR = YYMARKER;
+	goto yy3;
+yy22:
 	++YYCURSOR;
-	{ RET(PDO_PARSER_TEXT); }
+	if (YYLIMIT <= YYCURSOR) YYFILL(1);
+	yych = *YYCURSOR;
+	if (yych <= 0x00) goto yy21;
+	goto yy19;
 yy23:
 	++YYCURSOR;
-	if(YYLIMIT == YYCURSOR) YYFILL(1);
+#line 59 "ext/pdo/pdo_sql_parser.re"
+	{ RET(PDO_PARSER_TEXT); }
+#line 293 "ext/pdo/pdo_sql_parser.c"
+yy25:
+	++YYCURSOR;
+	if (YYLIMIT <= YYCURSOR) YYFILL(1);
 	yych = *YYCURSOR;
-yy24:
-	switch(yych) {
-	case '"':	goto yy25;
-	default:	goto yy23;
+yy26:
+	switch (yych) {
+	case 0x00:	goto yy21;
+	case '"':	goto yy28;
+	case '\\':	goto yy27;
+	default:	goto yy25;
 	}
-yy25:
+yy27:
+	++YYCURSOR;
+	if (YYLIMIT <= YYCURSOR) YYFILL(1);
+	yych = *YYCURSOR;
+	if (yych <= 0x00) goto yy21;
+	goto yy25;
+yy28:
 	++YYCURSOR;
+#line 58 "ext/pdo/pdo_sql_parser.re"
 	{ RET(PDO_PARSER_TEXT); }
+#line 315 "ext/pdo/pdo_sql_parser.c"
 }
+#line 66 "ext/pdo/pdo_sql_parser.re"
 	
 }
 [2008-10-10 12:18 UTC] felipe@php.net
This bug has been fixed in CVS.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.

Thanks for the patch.

Fixed in 5.2, 5.3 and HEAD.
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Fri Apr 25 07:02:14 2014 UTC