Bug 1577107 - Avoid following the prototype chain r=dveditz a=lizzard
authorYaron Tausky <ytausky@mozilla.com>
Mon, 07 Oct 2019 17:14:12 +0200
changeset 555528 34ec5064e2631b83ed041945cf525b41af6058d4
parent 555527 932c858be1c00881b81c258df8e61c6176eea8c3
child 555529 b2a2101f93867eaa161bbe09f7d3af7d448dae99
push id2165
push userffxbld-merge
push dateMon, 14 Oct 2019 16:30:58 +0000
treeherdermozilla-release@0eae18af659f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdveditz, lizzard
bugs1577107
milestone70.0
Bug 1577107 - Avoid following the prototype chain r=dveditz a=lizzard With this commit we no longer follow the value's prototype chain when creating index updates in IndexedDB. Differential Revision: https://phabricator.services.mozilla.com/D48151
dom/indexedDB/IDBObjectStore.cpp
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -900,16 +900,19 @@ already_AddRefed<IDBObjectStore> IDBObje
 
 // static
 void IDBObjectStore::AppendIndexUpdateInfo(
     int64_t aIndexID, const KeyPath& aKeyPath, bool aUnique, bool aMultiEntry,
     const nsCString& aLocale, JSContext* aCx, JS::Handle<JS::Value> aVal,
     nsTArray<IndexUpdateInfo>& aUpdateInfoArray, ErrorResult& aRv) {
   const bool localeAware = !aLocale.IsEmpty();
 
+  // This precondition holds when `aVal` is the result of a structured clone.
+  js::AutoAssertNoContentJS noContentJS(aCx);
+
   if (!aMultiEntry) {
     Key key;
     aRv = aKeyPath.ExtractKey(aCx, aVal, key);
 
     // If an index's keyPath doesn't match an object, we ignore that object.
     if (aRv.ErrorCodeIs(NS_ERROR_DOM_INDEXEDDB_DATA_ERR) || key.IsUnset()) {
       aRv.SuppressException();
       return;
@@ -937,33 +940,52 @@ void IDBObjectStore::AppendIndexUpdateIn
   }
 
   JS::Rooted<JS::Value> val(aCx);
   if (NS_FAILED(aKeyPath.ExtractKeyAsJSVal(aCx, aVal, val.address()))) {
     return;
   }
 
   bool isArray;
-  if (!JS_IsArrayObject(aCx, val, &isArray)) {
+  if (NS_WARN_IF(!JS_IsArrayObject(aCx, val, &isArray))) {
     IDB_REPORT_INTERNAL_ERR();
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return;
   }
   if (isArray) {
     JS::Rooted<JSObject*> array(aCx, &val.toObject());
     uint32_t arrayLength;
     if (NS_WARN_IF(!JS_GetArrayLength(aCx, array, &arrayLength))) {
       IDB_REPORT_INTERNAL_ERR();
       aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
       return;
     }
 
     for (uint32_t arrayIndex = 0; arrayIndex < arrayLength; arrayIndex++) {
-      JS::Rooted<JS::Value> arrayItem(aCx);
-      if (NS_WARN_IF(!JS_GetElement(aCx, array, arrayIndex, &arrayItem))) {
+      JS::RootedId indexId(aCx);
+      if (NS_WARN_IF(!JS_IndexToId(aCx, arrayIndex, &indexId))) {
+        IDB_REPORT_INTERNAL_ERR();
+        aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+        return;
+      }
+
+      bool hasOwnProperty;
+      if (NS_WARN_IF(
+              !JS_HasOwnPropertyById(aCx, array, indexId, &hasOwnProperty))) {
+        IDB_REPORT_INTERNAL_ERR();
+        aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+        return;
+      }
+
+      if (!hasOwnProperty) {
+        continue;
+      }
+
+      JS::RootedValue arrayItem(aCx);
+      if (NS_WARN_IF(!JS_GetPropertyById(aCx, array, indexId, &arrayItem))) {
         IDB_REPORT_INTERNAL_ERR();
         aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
         return;
       }
 
       Key value;
       auto result = value.SetFromJSVal(aCx, arrayItem, aRv);
       if (!result.Is(Ok, aRv) || value.IsUnset()) {