]> granicus.if.org Git - php/commitdiff
Fix #68760: Fix freeing null segfault. Added test for behaviour.
authorDanack <Danack@basereality.com>
Tue, 6 Jan 2015 22:09:13 +0000 (22:09 +0000)
committerStanislav Malyshev <stas@php.net>
Sun, 22 Mar 2015 23:44:06 +0000 (16:44 -0700)
NEWS
ext/sqlite3/sqlite3.c
ext/sqlite3/tests/bug68760.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 78da94f3c1b68bcb0c1ecbec0ab2eadefbbefd80..2b4479c5502b7b316baf15cc08725d2ffd7d701f 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -36,6 +36,10 @@ PHP                                                                        NEWS
    . Fixed bug #69227 (Use after free in zval_scan caused by
      spl_object_storage_get_gc). (adam dot scarr at 99designs dot com)
 
+- SQLITE:
+   . Fixed bug #68760 (SQLITE segfaults if custom collator throws an exception).
+     (Dan Ackroyd)
+
 19 Mar 2015, PHP 5.6.7
 
 - Core:
index ca3e155e2a0ada356153b215f73b0e286bca577f..bec51cc9f84a4934f3469080c380482a927fcb93 100644 (file)
@@ -906,16 +906,21 @@ static int php_sqlite3_callback_compare(void *coll, int a_len, const void *a, in
        efree(zargs[1]);
        efree(zargs);
 
-       //retval ought to contain a ZVAL_LONG by now
-       // (the result of a comparison, i.e. most likely -1, 0, or 1)
-       //I suppose we could accept any scalar return type, though.
-       if (Z_TYPE_P(retval) != IS_LONG){
+       if (!retval) {
+               //Exception was thrown by callback, default to 0 for compare
+               ret = 0;
+       } else if (Z_TYPE_P(retval) != IS_LONG) {
+               //retval ought to contain a ZVAL_LONG by now
+       // (the result of a comparison, i.e. most likely -1, 0, or 1)
+       //I suppose we could accept any scalar return type, though.
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "An error occurred while invoking the compare callback (invalid return type).  Collation behaviour is undefined.");
-       }else{
+       } else {
                ret = Z_LVAL_P(retval);
        }
 
-       zval_ptr_dtor(&retval);
+       if (retval) {
+               zval_ptr_dtor(&retval);
+       }
 
        return ret;
 }
diff --git a/ext/sqlite3/tests/bug68760.phpt b/ext/sqlite3/tests/bug68760.phpt
new file mode 100644 (file)
index 0000000..5eb7d84
--- /dev/null
@@ -0,0 +1,32 @@
+--TEST--
+Bug #68760 (Callback throws exception behaviour. Segfault in 5.6)
+--FILE--
+<?php
+function oopsFunction($a, $b) {
+       echo "callback";
+       throw new \Exception("oops");
+}
+
+$db = new SQLite3(":memory:");
+$db->exec("CREATE TABLE test (col1 string)");
+$db->exec("INSERT INTO test VALUES ('a1')");
+$db->exec("INSERT INTO test VALUES ('a10')");
+$db->exec("INSERT INTO test VALUES ('a2')");
+
+try {
+    $db->createCollation('NATURAL_CMP', 'oopsFunction');
+    $naturalSort = $db->query("SELECT col1 FROM test ORDER BY col1 COLLATE NATURAL_CMP");
+    while ($row = $naturalSort->fetchArray()) {
+        echo $row['col1'], "\n";
+    }
+    $db->close();
+}
+catch(\Exception $e) {
+    echo "Exception: ".$e->getMessage();
+}
+?>
+--EXPECTF--
+callback
+Warning: SQLite3::query(): An error occurred while invoking the compare callback in %a/bug68760.php on line %i
+Exception: oops
+