From 4d4924e5105dbdfdcc3ff821671fba0dfeb11b11 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 4 Sep 2019 21:04:07 +0200 Subject: Fix a crash in IndexedDB. --- dom/indexedDB/IDBCursor.cpp | 8 ++++---- dom/indexedDB/IDBFactory.cpp | 4 ++-- dom/indexedDB/IDBKeyRange.cpp | 2 +- dom/indexedDB/IDBObjectStore.cpp | 15 ++++++++------- dom/indexedDB/Key.cpp | 38 +++++++++++++++++++++++++++----------- dom/indexedDB/Key.h | 15 +++++++++++---- dom/indexedDB/KeyPath.cpp | 22 +++++++++++++++------- dom/indexedDB/KeyPath.h | 12 +++++++++--- js/src/jsapi.cpp | 22 ++++++++++++++++++++++ js/src/jsapi.h | 3 +++ 10 files changed, 102 insertions(+), 39 deletions(-) diff --git a/dom/indexedDB/IDBCursor.cpp b/dom/indexedDB/IDBCursor.cpp index af88742f0..be0295dc7 100644 --- a/dom/indexedDB/IDBCursor.cpp +++ b/dom/indexedDB/IDBCursor.cpp @@ -430,7 +430,7 @@ IDBCursor::Continue(JSContext* aCx, } Key key; - aRv = key.SetFromJSVal(aCx, aKey); + aRv = key.SetFromJSVal(aCx, aKey, /* aCallGetters */ true); if (aRv.Failed()) { return; } @@ -536,7 +536,7 @@ IDBCursor::ContinuePrimaryKey(JSContext* aCx, } Key key; - aRv = key.SetFromJSVal(aCx, aKey); + aRv = key.SetFromJSVal(aCx, aKey, /* aCallGetters */ true); if (aRv.Failed()) { return; } @@ -558,7 +558,7 @@ IDBCursor::ContinuePrimaryKey(JSContext* aCx, } Key primaryKey; - aRv = primaryKey.SetFromJSVal(aCx, aPrimaryKey); + aRv = primaryKey.SetFromJSVal(aCx, aPrimaryKey, /* aCallGetters */ true); if (aRv.Failed()) { return; } @@ -718,7 +718,7 @@ IDBCursor::Update(JSContext* aCx, JS::Handle aValue, const KeyPath& keyPath = objectStore->GetKeyPath(); Key key; - aRv = keyPath.ExtractKey(aCx, aValue, key); + aRv = keyPath.ExtractKey(aCx, aValue, key, /* aCallGetters */ false); if (aRv.Failed()) { return nullptr; } diff --git a/dom/indexedDB/IDBFactory.cpp b/dom/indexedDB/IDBFactory.cpp index c1ef6353d..66471fe24 100644 --- a/dom/indexedDB/IDBFactory.cpp +++ b/dom/indexedDB/IDBFactory.cpp @@ -482,13 +482,13 @@ IDBFactory::Cmp(JSContext* aCx, JS::Handle aFirst, JS::Handle aSecond, ErrorResult& aRv) { Key first, second; - nsresult rv = first.SetFromJSVal(aCx, aFirst); + nsresult rv = first.SetFromJSVal(aCx, aFirst, /* aCallGetters */ true); if (NS_FAILED(rv)) { aRv.Throw(rv); return 0; } - rv = second.SetFromJSVal(aCx, aSecond); + rv = second.SetFromJSVal(aCx, aSecond, /* aCallGetters */ true); if (NS_FAILED(rv)) { aRv.Throw(rv); return 0; diff --git a/dom/indexedDB/IDBKeyRange.cpp b/dom/indexedDB/IDBKeyRange.cpp index e61c80617..168fb4a5a 100644 --- a/dom/indexedDB/IDBKeyRange.cpp +++ b/dom/indexedDB/IDBKeyRange.cpp @@ -24,7 +24,7 @@ GetKeyFromJSVal(JSContext* aCx, JS::Handle aVal, Key& aKey) { - nsresult rv = aKey.SetFromJSVal(aCx, aVal); + nsresult rv = aKey.SetFromJSVal(aCx, aVal, /* aCallGetters */ true); if (NS_FAILED(rv)) { MOZ_ASSERT(NS_ERROR_GET_MODULE(rv) == NS_ERROR_MODULE_DOM_INDEXEDDB); return rv; diff --git a/dom/indexedDB/IDBObjectStore.cpp b/dom/indexedDB/IDBObjectStore.cpp index 756792741..f86c619a7 100644 --- a/dom/indexedDB/IDBObjectStore.cpp +++ b/dom/indexedDB/IDBObjectStore.cpp @@ -1084,7 +1084,7 @@ IDBObjectStore::AppendIndexUpdateInfo( if (!aMultiEntry) { Key key; - rv = aKeyPath.ExtractKey(aCx, aVal, key); + rv = aKeyPath.ExtractKey(aCx, aVal, key, /* aCallGetters */ false); // If an index's keyPath doesn't match an object, we ignore that object. if (rv == NS_ERROR_DOM_INDEXEDDB_DATA_ERR || key.IsUnset()) { @@ -1128,13 +1128,13 @@ IDBObjectStore::AppendIndexUpdateInfo( for (uint32_t arrayIndex = 0; arrayIndex < arrayLength; arrayIndex++) { JS::Rooted arrayItem(aCx); - if (NS_WARN_IF(!JS_GetElement(aCx, array, arrayIndex, &arrayItem))) { + if (NS_WARN_IF(!JS_GetOwnElement(aCx, array, arrayIndex, &arrayItem))) { IDB_REPORT_INTERNAL_ERR(); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } Key value; - if (NS_FAILED(value.SetFromJSVal(aCx, arrayItem)) || + if (NS_FAILED(value.SetFromJSVal(aCx, arrayItem, /* aCallGetters */ false)) || value.IsUnset()) { // Not a value we can do anything with, ignore it. continue; @@ -1153,7 +1153,7 @@ IDBObjectStore::AppendIndexUpdateInfo( } else { Key value; - if (NS_FAILED(value.SetFromJSVal(aCx, val)) || + if (NS_FAILED(value.SetFromJSVal(aCx, val, /* aCallGetters */ false)) || value.IsUnset()) { // Not a value we can do anything with, ignore it. return NS_OK; @@ -1324,12 +1324,12 @@ IDBObjectStore::GetAddInfo(JSContext* aCx, if (!HasValidKeyPath()) { // Out-of-line keys must be passed in. - rv = aKey.SetFromJSVal(aCx, aKeyVal); + rv = aKey.SetFromJSVal(aCx, aKeyVal, /* aCallGetters */ true); if (NS_FAILED(rv)) { return rv; } } else if (!isAutoIncrement) { - rv = GetKeyPath().ExtractKey(aCx, aValue, aKey); + rv = GetKeyPath().ExtractKey(aCx, aValue, aKey, /* aCallGetters */ false); if (NS_FAILED(rv)) { return rv; } @@ -1368,7 +1368,8 @@ IDBObjectStore::GetAddInfo(JSContext* aCx, aValue, aKey, &GetAddInfoCallback, - &data); + &data, + /* aCallGetters */ false); } else { rv = GetAddInfoCallback(aCx, &data); } diff --git a/dom/indexedDB/Key.cpp b/dom/indexedDB/Key.cpp index 0f693b2c6..575734af2 100644 --- a/dom/indexedDB/Key.cpp +++ b/dom/indexedDB/Key.cpp @@ -201,8 +201,11 @@ Key::ToLocaleBasedKey(Key& aTarget, const nsCString& aLocale) const } nsresult -Key::EncodeJSValInternal(JSContext* aCx, JS::Handle aVal, - uint8_t aTypeOffset, uint16_t aRecursionDepth) +Key::EncodeJSValInternal(JSContext* aCx, + JS::Handle aVal, + uint8_t aTypeOffset, + uint16_t aRecursionDepth, + bool aCallGetters) { static_assert(eMaxType * kMaxArrayCollapse < 256, "Unable to encode jsvals."); @@ -257,13 +260,18 @@ Key::EncodeJSValInternal(JSContext* aCx, JS::Handle aVal, for (uint32_t index = 0; index < length; index++) { JS::Rooted val(aCx); - if (!JS_GetElement(aCx, obj, index, &val)) { + bool ok = aCallGetters ? JS_GetElement(aCx, obj, index, &val) + : JS_GetOwnElement(aCx, obj, index, &val); + if (!ok) { IDB_REPORT_INTERNAL_ERR(); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } - nsresult rv = EncodeJSValInternal(aCx, val, aTypeOffset, - aRecursionDepth + 1); + nsresult rv = EncodeJSValInternal(aCx, + val, + aTypeOffset, + aRecursionDepth + 1, + aCallGetters); if (NS_FAILED(rv)) { return rv; } @@ -406,9 +414,10 @@ Key::DecodeJSValInternal(const unsigned char*& aPos, const unsigned char* aEnd, nsresult Key::EncodeJSVal(JSContext* aCx, JS::Handle aVal, - uint8_t aTypeOffset) + uint8_t aTypeOffset, + bool aCallGetters) { - return EncodeJSValInternal(aCx, aVal, aTypeOffset, 0); + return EncodeJSValInternal(aCx, aVal, aTypeOffset, 0, aCallGetters); } void @@ -741,7 +750,8 @@ Key::SetFromValueArray(mozIStorageValueArray* aValues, nsresult Key::SetFromJSVal(JSContext* aCx, - JS::Handle aVal) + JS::Handle aVal, + bool aCallGetters) { mBuffer.Truncate(); @@ -750,7 +760,7 @@ Key::SetFromJSVal(JSContext* aCx, return NS_OK; } - nsresult rv = EncodeJSVal(aCx, aVal, 0); + nsresult rv = EncodeJSVal(aCx, aVal, 0, aCallGetters); if (NS_FAILED(rv)) { Unset(); return rv; @@ -793,9 +803,15 @@ Key::ToJSVal(JSContext* aCx, } nsresult -Key::AppendItem(JSContext* aCx, bool aFirstOfArray, JS::Handle aVal) +Key::AppendItem(JSContext* aCx, + bool aFirstOfArray, + JS::Handle aVal, + bool aCallGetters) { - nsresult rv = EncodeJSVal(aCx, aVal, aFirstOfArray ? eMaxType : 0); + nsresult rv = EncodeJSVal(aCx, + aVal, + aFirstOfArray ? eMaxType : 0, + aCallGetters); if (NS_FAILED(rv)) { Unset(); return rv; diff --git a/dom/indexedDB/Key.h b/dom/indexedDB/Key.h index 9d70ce6ad..a4fb65b48 100644 --- a/dom/indexedDB/Key.h +++ b/dom/indexedDB/Key.h @@ -203,7 +203,7 @@ public: } nsresult - SetFromJSVal(JSContext* aCx, JS::Handle aVal); + SetFromJSVal(JSContext* aCx, JS::Handle aVal, bool aCallGetters); nsresult ToJSVal(JSContext* aCx, JS::MutableHandle aVal) const; @@ -212,7 +212,10 @@ public: ToJSVal(JSContext* aCx, JS::Heap& aVal) const; nsresult - AppendItem(JSContext* aCx, bool aFirstOfArray, JS::Handle aVal); + AppendItem(JSContext* aCx, + bool aFirstOfArray, + JS::Handle aVal, + bool aCallGetters); nsresult ToLocaleBasedKey(Key& aTarget, const nsCString& aLocale) const; @@ -283,7 +286,10 @@ private: // Encoding functions. These append the encoded value to the end of mBuffer nsresult - EncodeJSVal(JSContext* aCx, JS::Handle aVal, uint8_t aTypeOffset); + EncodeJSVal(JSContext* aCx, + JS::Handle aVal, + uint8_t aTypeOffset, + bool aCallGetters); void EncodeString(const nsAString& aString, uint8_t aTypeOffset); @@ -331,7 +337,8 @@ private: EncodeJSValInternal(JSContext* aCx, JS::Handle aVal, uint8_t aTypeOffset, - uint16_t aRecursionDepth); + uint16_t aRecursionDepth, + bool aCallGetters); static nsresult DecodeJSValInternal(const unsigned char*& aPos, diff --git a/dom/indexedDB/KeyPath.cpp b/dom/indexedDB/KeyPath.cpp index 30edd8cd7..0221c9450 100644 --- a/dom/indexedDB/KeyPath.cpp +++ b/dom/indexedDB/KeyPath.cpp @@ -372,11 +372,13 @@ KeyPath::AppendStringWithValidation(const nsAString& aString) } nsresult -KeyPath::ExtractKey(JSContext* aCx, const JS::Value& aValue, Key& aKey) const +KeyPath::ExtractKey(JSContext* aCx, + const JS::Value& aValue, + Key& aKey, + bool aCallGetters) const { uint32_t len = mStrings.Length(); JS::Rooted value(aCx); - aKey.Unset(); for (uint32_t i = 0; i < len; ++i) { @@ -388,7 +390,10 @@ KeyPath::ExtractKey(JSContext* aCx, const JS::Value& aValue, Key& aKey) const return rv; } - if (NS_FAILED(aKey.AppendItem(aCx, IsArray() && i == 0, value))) { + if (NS_FAILED(aKey.AppendItem(aCx, + IsArray() && i == 0, + value, + aCallGetters))) { NS_ASSERTION(aKey.IsUnset(), "Encoding error should unset"); return NS_ERROR_DOM_INDEXEDDB_DATA_ERR; } @@ -437,9 +442,12 @@ KeyPath::ExtractKeyAsJSVal(JSContext* aCx, const JS::Value& aValue, } nsresult -KeyPath::ExtractOrCreateKey(JSContext* aCx, const JS::Value& aValue, - Key& aKey, ExtractOrCreateKeyCallback aCallback, - void* aClosure) const +KeyPath::ExtractOrCreateKey(JSContext* aCx, + const JS::Value& aValue, + Key& aKey, + ExtractOrCreateKeyCallback aCallback, + void* aClosure, + bool aCallGetters) const { NS_ASSERTION(IsString(), "This doesn't make sense!"); @@ -455,7 +463,7 @@ KeyPath::ExtractOrCreateKey(JSContext* aCx, const JS::Value& aValue, return rv; } - if (NS_FAILED(aKey.AppendItem(aCx, false, value))) { + if (NS_FAILED(aKey.AppendItem(aCx, false, value, aCallGetters))) { NS_ASSERTION(aKey.IsUnset(), "Should be unset"); return value.isUndefined() ? NS_OK : NS_ERROR_DOM_INDEXEDDB_DATA_ERR; } diff --git a/dom/indexedDB/KeyPath.h b/dom/indexedDB/KeyPath.h index c133cdc4a..e6e5f57d4 100644 --- a/dom/indexedDB/KeyPath.h +++ b/dom/indexedDB/KeyPath.h @@ -72,7 +72,10 @@ public: Parse(const Nullable& aValue, KeyPath* aKeyPath); nsresult - ExtractKey(JSContext* aCx, const JS::Value& aValue, Key& aKey) const; + ExtractKey(JSContext* aCx, + const JS::Value& aValue, + Key& aKey, + bool aCallGetters) const; nsresult ExtractKeyAsJSVal(JSContext* aCx, const JS::Value& aValue, @@ -82,9 +85,12 @@ public: (*ExtractOrCreateKeyCallback)(JSContext* aCx, void* aClosure); nsresult - ExtractOrCreateKey(JSContext* aCx, const JS::Value& aValue, Key& aKey, + ExtractOrCreateKey(JSContext* aCx, + const JS::Value& aValue, + Key& aKey, ExtractOrCreateKeyCallback aCallback, - void* aClosure) const; + void* aClosure, + bool aCallGetters) const; inline bool IsValid() const { return mType != NONEXISTENT; diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 84a315587..cad0840e0 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -2010,6 +2010,28 @@ JS_GetOwnUCPropertyDescriptor(JSContext* cx, HandleObject obj, const char16_t* n return JS_GetOwnPropertyDescriptorById(cx, obj, id, desc); } +JS_PUBLIC_API(bool) +JS_GetOwnElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp) +{ + RootedId id(cx); + if (!IndexToId(cx, index, &id)) { + return false; + } + + Rooted desc(cx); + if (!JS_GetOwnPropertyDescriptorById(cx, obj, id, &desc)) { + return false; + } + + if (desc.object() && desc.isDataDescriptor()) { + vp.set(desc.value()); + } else { + vp.setUndefined(); + } + + return true; +} + JS_PUBLIC_API(bool) JS_GetPropertyDescriptorById(JSContext* cx, HandleObject obj, HandleId id, MutableHandle desc) diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 67b3d4267..dc00c650d 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -2922,6 +2922,9 @@ extern JS_PUBLIC_API(bool) JS_GetOwnUCPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, JS::MutableHandle desc); +extern JS_PUBLIC_API(bool) +JS_GetOwnElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp); + /** * Like JS_GetOwnPropertyDescriptorById, but also searches the prototype chain * if no own property is found directly on obj. The object on which the -- cgit v1.2.3