Bug 1188760 - Added a regex check to execute and executeCached of Sqlite.jsm. r=mak
authorKalpesh Krishna <kalpeshk2011@gmail.com>
Wed, 23 Sep 2015 09:01:00 +0200
changeset 297550 5aeeb7979d4fbcc7c7efd93d7068b8fdd180643d
parent 297549 5906d37343fa76675acba45ef38c686edfeb3815
child 297551 4d86ae08548baf2cd2cab3e4e58084dd912cfad3
push id5392
push userraliiev@mozilla.com
push dateMon, 14 Dec 2015 20:08:23 +0000
treeherdermozilla-beta@16ce8562a975 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmak
bugs1188760
milestone44.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1188760 - Added a regex check to execute and executeCached of Sqlite.jsm. r=mak
toolkit/modules/Sqlite.jsm
toolkit/modules/tests/xpcshell/test_sqlite.js
--- a/toolkit/modules/Sqlite.jsm
+++ b/toolkit/modules/Sqlite.jsm
@@ -33,16 +33,19 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyServiceGetter(this, "FinalizationWitnessService",
                                    "@mozilla.org/toolkit/finalizationwitness;1",
                                    "nsIFinalizationWitnessService");
 XPCOMUtils.defineLazyModuleGetter(this, "PromiseUtils",
                                   "resource://gre/modules/PromiseUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "console",
                                   "resource://gre/modules/devtools/shared/Console.jsm");
 
+// Regular expression used by isInvalidBoundLikeQuery
+var likeSqlRegex = /\bLIKE\b\s(?![@:?])/i;
+
 // Counts the number of created connections per database basename(). This is
 // used for logging to distinguish connection instances.
 var connectionCounters = new Map();
 
 // Tracks identifiers of wrapped connections, that are Storage connections
 // opened through mozStorage and then wrapped by Sqlite.jsm to use its syntactic
 // sugar API.  Since these connections have an unknown origin, we use this set
 // to differentiate their behavior.
@@ -55,16 +58,27 @@ var isClosed = false;
 
 var Debugging = {
   // Tests should fail if a connection auto closes.  The exception is
   // when finalization itself is tested, in which case this flag
   // should be set to false.
   failTestsOnAutoClose: true
 };
 
+/**
+ * Helper function to check whether LIKE is implemented using proper bindings.
+ *
+ * @param sql
+ *        (string) The SQL query to be verified.
+ * @return boolean value telling us whether query was correct or not
+*/
+function isInvalidBoundLikeQuery(sql) {
+  return likeSqlRegex.test(sql);
+}
+
 // Displays a script error message
 function logScriptError(message) {
   let consoleMessage = Cc["@mozilla.org/scripterror;1"].
                        createInstance(Ci.nsIScriptError);
   let stack = new Error();
   consoleMessage.init(message, stack.fileName, null, stack.lineNumber, 0,
                       Ci.nsIScriptError.errorFlag, "component javascript");
   Services.console.logMessage(consoleMessage);
@@ -1268,16 +1282,19 @@ OpenedConnection.prototype = Object.free
    * @param name
    *        (string) The name of the registered statement to execute.
    * @param params optional
    *        (Array or object) Parameters to bind.
    * @param onRow optional
    *        (function) Callback to receive each row from result.
    */
   executeCached: function (sql, params=null, onRow=null) {
+    if (isInvalidBoundLikeQuery(sql)) {
+      throw new Error("Please enter a LIKE clause with bindings");
+    }
     return this._connectionData.executeCached(sql, params, onRow);
   },
 
   /**
    * Execute a one-shot SQL statement.
    *
    * If you find yourself feeding the same SQL string in this function, you
    * should *not* use this function and instead use `executeCached`.
@@ -1287,16 +1304,19 @@ OpenedConnection.prototype = Object.free
    * @param sql
    *        (string) SQL to execute.
    * @param params optional
    *        (Array or Object) Parameters to bind to the statement.
    * @param onRow optional
    *        (function) Callback to receive result of a single row.
    */
   execute: function (sql, params=null, onRow=null) {
+    if (isInvalidBoundLikeQuery(sql)) {
+      throw new Error("Please enter a LIKE clause with bindings");
+    }
     return this._connectionData.execute(sql, params, onRow);
   },
 
   /**
    * Whether a transaction is currently in progress.
    */
   get transactionInProgress() {
     return this._connectionData.transactionInProgress;
--- a/toolkit/modules/tests/xpcshell/test_sqlite.js
+++ b/toolkit/modules/tests/xpcshell/test_sqlite.js
@@ -270,16 +270,25 @@ add_task(function* test_execute_invalid_
   yield deferred.promise;
 
   // Ensure we don't leak the statement instance.
   do_check_eq(c._connectionData._anonymousStatements.size, 0);
 
   yield c.close();
 });
 
+add_task(function* test_incorrect_like_bindings() {
+  let c = yield getDummyDatabase("incorrect_like_bindings");
+
+  let sql = "select * from dirs where path LIKE 'non%'";
+  Assert.throws(() => c.execute(sql), /Please enter a LIKE clause/);
+  Assert.throws(() => c.executeCached(sql), /Please enter a LIKE clause/);
+
+  yield c.close();
+});
 add_task(function* test_on_row_exception_ignored() {
   let c = yield getDummyDatabase("on_row_exception_ignored");
 
   let sql = "INSERT INTO dirs (path) VALUES (?)";
   for (let i = 0; i < 10; i++) {
     yield c.executeCached(sql, ["dir" + i]);
   }