Bug 485107 - Do not throw in NewResolve
authorShawn Wilsher <sdwilsh@shawnwilsher.com>
Thu, 11 Jun 2009 13:18:58 -0700
changeset 29096 c30ed3e7e0ceb18560dabe54501f8c3c2ddabab6
parent 29095 90ac3a21ea497a0275f0c57ef3b07ecb601e1922
child 29097 d891a7418d9514991182f2a9df9e360ebd0848db
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs485107
milestone1.9.2a1pre
Bug 485107 - Do not throw in NewResolve This changeset makes sure that we allow for properties to be defined on the prototype chain for the JS language helpers in storage. r=bent
storage/src/mozStorageStatementParams.cpp
storage/src/mozStorageStatementRow.cpp
storage/test/unit/test_js_helpers_prototype_chain_safe.js
--- a/storage/src/mozStorageStatementParams.cpp
+++ b/storage/src/mozStorageStatementParams.cpp
@@ -191,31 +191,34 @@ StatementParams::NewResolve(nsIXPConnect
   // because we want to allow the prototype chain to be checked for the
   // property.
 
   PRUint32 idx;
 
   if (JSVAL_IS_INT(aId)) {
     idx = JSVAL_TO_INT(aId);
 
-    // Ensure that our index is within range.
+    // Ensure that our index is within range.  We do not care about the
+    // prototype chain being checked here.
     if (idx >= mParamCount)
       return NS_ERROR_INVALID_ARG;
   }
   else if (JSVAL_IS_STRING(aId)) {
     JSString *str = JSVAL_TO_STRING(aId);
     jschar *nameChars = ::JS_GetStringChars(str);
     size_t nameLength = ::JS_GetStringLength(str);
 
     // Check to see if there's a parameter with this name, and if not, let
     // the rest of the prototype chain be checked.
     NS_ConvertUTF16toUTF8 name(nameChars, nameLength);
     nsresult rv = mStatement->GetParameterIndex(name, &idx);
-    if (NS_FAILED(rv))
+    if (NS_FAILED(rv)) {
+      *_objp = NULL;
       return NS_OK;
+    }
 
     *_retval = ::JS_DefineUCProperty(aCtx, aScopeObj, nameChars, nameLength,
                                      JSVAL_VOID, nsnull, nsnull, 0);
     NS_ENSURE_TRUE(*_retval, NS_OK);
   }
   else {
     // We do not handle other types.
     return NS_OK;
--- a/storage/src/mozStorageStatementRow.cpp
+++ b/storage/src/mozStorageStatementRow.cpp
@@ -151,31 +151,38 @@ StatementRow::NewResolve(nsIXPConnectWra
                          JSContext *aCtx,
                          JSObject *aScopeObj,
                          jsval aId,
                          PRUint32 aFlags,
                          JSObject **_objp,
                          PRBool *_retval)
 {
   NS_ENSURE_TRUE(mStatement, NS_ERROR_NOT_INITIALIZED);
+  // We do not throw at any point after this because we want to allow the
+  // prototype chain to be checked for the property.
 
   if (JSVAL_IS_STRING(aId)) {
     JSString *str = JSVAL_TO_STRING(aId);
     nsDependentCString name(::JS_GetStringBytes(str));
 
     PRUint32 idx;
     nsresult rv = mStatement->GetColumnIndex(name, &idx);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (NS_FAILED(rv)) {
+      // It's highly likely that the name doesn't exist, so let the JS engine
+      // check the prototype chain and throw if that doesn't have the property
+      // either.
+      *_objp = NULL;
+      return NS_OK;
+    }
 
     *_retval = ::JS_DefineUCProperty(aCtx, aScopeObj, ::JS_GetStringChars(str),
                                      ::JS_GetStringLength(str),
                                      JSVAL_VOID,
                                      nsnull, nsnull, 0);
     *_objp = aScopeObj;
-    return *_retval ? NS_OK : NS_ERROR_FAILURE;
+    return NS_OK;
   }
 
-  *_retval = PR_TRUE;
   return NS_OK;
 }
 
 } // namespace storage
 } // namescape mozilla
new file mode 100644
--- /dev/null
+++ b/storage/test/unit/test_js_helpers_prototype_chain_safe.js
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=2 sts=2 et
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Storage Test Code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Shawn Wilsher <me@shawnwilsher.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * This file tests that the JS language helpers check their prototype chain for
+ * most properties.
+ */
+
+////////////////////////////////////////////////////////////////////////////////
+//// Test Functions
+
+function test_params_prototype()
+{
+  let stmt = getOpenedDatabase().createStatement(
+    "SELECT * FROM sqlite_master"
+  );
+
+  // Set a property on the prototype and make sure it exist (will not be a
+  // bindable parameter, however).
+  stmt.params.__proto__.test = 2;
+  do_check_eq(stmt.params.test, 2);
+  stmt.finalize();
+}
+
+function test_row_prototype()
+{
+  // First, create a table so that we actually have data in sqlite_master.
+  getOpenedDatabase().createTable("test_table", "id INTEGER PRIMARY KEY");
+
+  let stmt = getOpenedDatabase().createStatement(
+    "SELECT * FROM sqlite_master"
+  );
+
+  do_check_true(stmt.executeStep());
+
+  // Set a property on the prototype and make sure it exists (will not be in the
+  // results, however).
+  stmt.row.__proto__.test = 2;
+  do_check_eq(stmt.row.test, 2);
+  stmt.finalize();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//// Test Runner
+
+let tests = [
+  test_params_prototype,
+  test_row_prototype,
+];
+function run_test()
+{
+  cleanup();
+
+  // Run the tests.
+  tests.forEach(function(test) test());
+}