On Fri, Mar 1, 2019 at 5:24 PM Johannes Schlüter <johan...@schlueters.de> wrote:
> On Fr, 2019-03-01 at 12:25 +0100, Nikita Popov wrote: > > > For extension authors, the guideline is: > > Will zend_parse_paramters and related detect if an exception is thrown > and fail? > Yes, of course :) That's one of the most important cases. I believe things like database (or other network) extensions have to be > really carefully checked, not that we store corrupted data (empty > string) in the database (or otherwise send via network) while returning > an error to the user. > > > Simple 5 minute example based on your branch: > > <?php > > class throws { > function __toString() { > throw new Exception("Sorry"); > } > } > > $db = new sqlite3(':memory:'); > $db->exec('CREATE TABLE t(id int, v varchar(255))'); > > $stmt = $db->prepare('INSERT INTO t VALUES(:i, :v)'); > $stmt->bindValue('i', 1234); > $stmt->bindValue('v', new throws); > > try { > $stmt->execute(); > } catch (Exception $e) { > echo "Exception thrown ...\n"; > } > > $stmt->execute(); > > $query = $db->query("SELECT * FROM t"); > while ($row = $query->fetchArray(SQLITE3_ASSOC)) { > print_r($row); > } > ?> > > This prints > > Exception thrown ... > Array > ( > [id] => 1234 > [v] => > ) > > So during the first execution it notices that the conversion went wrong > and aborts the operation, but it keeps th emtpy string as bound value. > On second execute it re-uses the values and doesn't notice the error. > Thanks for the example. I agree that keeping the empty value is not the correct behavior and have fixed this in https://github.com/php/php-src/pull/3887/commits/ac14ab02912b267dd370396937a971ff0b4daec8. I will also review the other database binding code, because I think I made the same mistake there. So there's one more point to add to the extension guidelines: * When working on non-temporary zvals, avoid leaving behind the converted string in case of exception. Prefer zend_string *str = zval_get_string(val); if (EG(exception)) { return; } // Do something with str zend_string_release(str); over convert_to_string(val); if (EG(exception)) { return; } // Do something with Z_STR_P(val) Of course, this should be preferred for other reasons as well. While working on this patch I've already fixed many illegal uses of convert_to_string, which were modifying shared values in-place. > I fear we have many such cases which are subtle ad hard to find without > deep review of any string conversion. And in future we will introduce > bugs due to this in places where new conversions are added ... I'm happy to find and fix these bugs, rather than leave the language buggy by design ;) Regards, Nikita On Fri, Mar 1, 2019 at 5:24 PM Johannes Schlüter <johan...@schlueters.de> wrote: > On Fr, 2019-03-01 at 12:25 +0100, Nikita Popov wrote: > > > For extension authors, the guideline is: > > Will zend_parse_paramters and related detect if an exception is thrown > and fail? > > I believe things like database (or other network) extensions have to be > really carefully checked, not that we store corrupted data (empty > string) in the database (or otherwise send via network) while returning > an error to the user. > > > Simple 5 minute example based on your branch: > > <?php > > class throws { > function __toString() { > throw new Exception("Sorry"); > } > } > > $db = new sqlite3(':memory:'); > $db->exec('CREATE TABLE t(id int, v varchar(255))'); > > $stmt = $db->prepare('INSERT INTO t VALUES(:i, :v)'); > $stmt->bindValue('i', 1234); > $stmt->bindValue('v', new throws); > > try { > $stmt->execute(); > } catch (Exception $e) { > echo "Exception thrown ...\n"; > } > > $stmt->execute(); > > $query = $db->query("SELECT * FROM t"); > while ($row = $query->fetchArray(SQLITE3_ASSOC)) { > print_r($row); > } > ?> > > This prints > > Exception thrown ... > Array > ( > [id] => 1234 > [v] => > ) > > So during the first execution it notices that the conversion went wrong > and aborts the operation, but it keeps th emtpy string as bound value. > On second execute it re-uses the values and doesn't notice the error. > > I fear we have many such cases which are subtle ad hard to find without > deep review of any string conversion. And in future we will introduce > bugs due to this in places where new conversions are added ... > > johannes >