-
Notifications
You must be signed in to change notification settings - Fork 7.9k
sqlite PDO::quote silently corrupts strings with null bytes #13952
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Lovely, the implementation even has a comment above it stating it is broken: php-src/ext/pdo_sqlite/sqlite_driver.c Lines 222 to 235 in 08b2ab2
|
Any idea what
Maybe PHP max string length? Idk |
It's protection against integer overflow causing a buffer overflow. |
I think the best solution is to just implement this thing ourselves, looking at the sqlite code it doesn't seem difficult at all. |
proposed fix: #13953 |
I meant concat using |
I agree with @mvorisek |
I actually tried doing concat-optimizations, and was very surprised to learn that SQLite's concat operator does not support nulls:
@nielsdos have you actually tested your approach with null bytes? it seems to me like your approach tries using the |
@divinity76 Yes, my approach works (test program below). Interesting results though! Even the printf one doesn't properly work as it shows 6 instead of 7... $stmt = $db->prepare("SELECT 'foo' || x'00' || 'bar'");
$stmt->execute();
var_dump($stmt->fetchAll()); outputs:
Perhaps the sqlite3 command line client also has issues with NUL byte processing. This is the test program I'm using: <?php
declare(strict_types=1);
$db = new \PDO('sqlite::memory:', null, null, array(
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
\PDO::ATTR_EMULATE_PREPARES => false,
));
$db->exec('CREATE TABLE test (name TEXT)');
$db->exec("INSERT INTO test (name) VALUES (" . $db->quote("foo'bar") . ")");
$db->exec("INSERT INTO test (name) VALUES (" . $db->quote("\x00foo\x00\x00\x00bar\x00") . ")");
$stmt = $db->prepare('SELECT * FROM test');
$stmt->execute();
var_dump($stmt->fetchAll()); This shows:
which is expected (note the length 11 for foobar). |
…l bytes The built-in way to quote string using sqlite3's custom printf does not support NULL bytes in a string. Reimplement it ourselves. This also gets rid of the integer-based length limit.
Implements x'hex' encoding in pdo::quote for handling strings with null bytes, providing a reliable workaround for issue phpGH-13952. An alternative fix is discussed in PR php#13956 PR php#13956 does something interesting, it avoids the overhead of copying to/from sqlite3_snprintf, probably speeding up PDO::quote, but right now I just want to keep things simple.
Implements x'hex' encoding in pdo::quote for handling strings with null bytes, providing a reliable workaround for issue phpGH-13952. An alternative fix is discussed in PR php#13956 PR php#13956 does something interesting, it avoids the overhead of copying to/from sqlite3_snprintf, probably speeding up PDO::quote, but right now I just want to keep things simple. Co-authored-by: Niels Dossche <nielsdos@php.net>
Implements x'hex' encoding in pdo::quote for handling strings with null bytes, providing a reliable workaround for issue phpGH-13952. An alternative fix is discussed in PR php#13956 PR php#13956 does something interesting, it avoids the overhead of copying to/from sqlite3_snprintf, probably speeding up PDO::quote, but right now I just want to keep things simple. Co-authored-by: Niels Dossche <nielsdos@php.net>
I have reported it to sqlite along with the reproduction code. |
resolves issue phpGH-13952, this is basically a smart_str() version of PR php#13956 per php#13962 (comment) this is 1 of the 4 proposed alternatives to the problem, and the pros of this solution is that it produces smaller queries than the alternatives, and retains the sqlite datatype 'string' (instead of changing it to blob), and should make PDO::quote faster as we now avoid the overhead of copying data to/from sqlite3_snprintf. The cons of this solution, that I can think of right now, is that the implementation is non-trivial, involves a bunch of php-allocator-reallocs() (PR php#13956 does not invovle reallocs, as it pre-computes the length. also worth noting that php allocator's reallocs() are faster than libc realloc, often avoiding talking to the OS), and SQLite's LENGTH(('foo'||x'00'||'bar')) returns 3 instead of 7, and binary strings gets the datatype 'string' instead of 'blob' (that can be considered both a pro and a con) Co-authored-by: Niels Dossche <nielsdos@php.net>
fix a corruption issue where PDO::quote for SQLite would silently truncate strings with null bytes in them, by throwing. resolve phpGH-13952 close phpGH-13972
Description
The following code:
Resulted in this output:
But I expected this output instead:
-or-
(but preferably the former)
PHP Version
PHP 8.3.4
Operating System
Ubuntu 24.04-beta
The text was updated successfully, but these errors were encountered: