Bug 1731039 - ArrayBufferOrView subclasses should null-check in unwrap() r=jonco
authorSteve Fink <sfink@mozilla.com>
Thu, 21 Oct 2021 17:55:30 +0000
changeset 596645 a24fb00bab8ea918e6751ddde6d7b71c12563d29
parent 596644 d6f67ce93bf23378b26d18f2ee2a5202ad7d866e
child 596646 5a5e1e27fb39d7ab9c1383615c9812e5e5c44513
push id151953
push usersfink@mozilla.com
push dateThu, 21 Oct 2021 17:57:55 +0000
treeherderautoland@a24fb00bab8e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco
bugs1731039
milestone95.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 1731039 - ArrayBufferOrView subclasses should null-check in unwrap() r=jonco Differential Revision: https://phabricator.services.mozilla.com/D129092
js/public/experimental/TypedData.h
js/src/jit-test/tests/typedarray/dom-view.js
js/src/vm/ArrayBufferObject.cpp
js/src/vm/TypedArrayObject.cpp
--- a/js/public/experimental/TypedData.h
+++ b/js/public/experimental/TypedData.h
@@ -374,16 +374,19 @@ class JS_PUBLIC_API ArrayBuffer : public
 class JS_PUBLIC_API ArrayBufferView : public ArrayBufferOrView {
  protected:
   explicit ArrayBufferView(JSObject* unwrapped)
       : ArrayBufferOrView(unwrapped) {}
 
  public:
   static inline ArrayBufferView fromObject(JSObject* unwrapped);
   static ArrayBufferView unwrap(JSObject* maybeWrapped) {
+    if (!maybeWrapped) {
+      return ArrayBufferView(nullptr);
+    }
     ArrayBufferView view = fromObject(maybeWrapped);
     if (view) {
       return view;
     }
     return fromObject(js::CheckedUnwrapStatic(maybeWrapped));
   }
 
   bool isDetached() const;
@@ -410,16 +413,19 @@ class JS_PUBLIC_API DataView : public Ar
   static DataView fromObject(JSObject* unwrapped) {
     if (unwrapped && GetClass(unwrapped) == ClassPtr) {
       return DataView(unwrapped);
     }
     return DataView(nullptr);
   }
 
   static DataView unwrap(JSObject* maybeWrapped) {
+    if (!maybeWrapped) {
+      return DataView(nullptr);
+    }
     DataView view = fromObject(maybeWrapped);
     if (view) {
       return view;
     }
     return fromObject(js::CheckedUnwrapStatic(maybeWrapped));
   }
 };
 
@@ -429,16 +435,19 @@ class JS_PUBLIC_API TypedArray_base : pu
   explicit TypedArray_base(JSObject* unwrapped) : ArrayBufferView(unwrapped) {}
 
   static const JSClass* const classes;
 
  public:
   static TypedArray_base fromObject(JSObject* unwrapped);
 
   static TypedArray_base unwrap(JSObject* maybeWrapped) {
+    if (!maybeWrapped) {
+      return TypedArray_base(nullptr);
+    }
     TypedArray_base view = fromObject(maybeWrapped);
     if (view) {
       return view;
     }
     return fromObject(js::CheckedUnwrapStatic(maybeWrapped));
   }
 };
 
@@ -473,18 +482,24 @@ class JS_PUBLIC_API TypedArray : public 
   static TypedArray fromObject(JSObject* unwrapped) {
     if (unwrapped && GetClass(unwrapped) == clasp()) {
       return TypedArray(unwrapped);
     }
     return TypedArray(nullptr);
   }
 
   static TypedArray unwrap(JSObject* maybeWrapped) {
+    if (!maybeWrapped) {
+      return TypedArray(nullptr);
+    }
     TypedArray view = fromObject(maybeWrapped);
-    return view ? view : fromObject(js::CheckedUnwrapStatic(maybeWrapped));
+    if (view) {
+      return view;
+    }
+    return fromObject(js::CheckedUnwrapStatic(maybeWrapped));
   }
 
   // Return a pointer to the start of the data referenced by a typed array. The
   // data is still owned by the typed array, and should not be modified on
   // another thread. Furthermore, the pointer can become invalid on GC (if the
   // data is small and fits inside the array's GC header), so callers must take
   // care not to hold on across anything that could GC.
   //
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/typedarray/dom-view.js
@@ -0,0 +1,13 @@
+// Bug 1731039 fuzzbug. Exercises one of the new ArrayBufferOrView classes.
+
+var error;
+try {
+  encodeAsUtf8InBuffer("", "");
+} catch (e) {
+  error = e;
+}
+
+assertEq(error.message.includes("must be a Uint8Array"), true);
+
+if (typeof reportCompare === "function")
+    reportCompare(true, true);
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -2030,11 +2030,14 @@ uint8_t* JS::ArrayBuffer::getLengthAndDa
     *isSharedMemory = true;
     return buffer->dataPointerEither().unwrap();
   }
   *isSharedMemory = false;
   return buffer->as<ArrayBufferObject>().dataPointer();
 };
 
 JS::ArrayBuffer JS::ArrayBuffer::unwrap(JSObject* maybeWrapped) {
+  if (!maybeWrapped) {
+    return JS::ArrayBuffer(nullptr);
+  }
   auto* ab = maybeWrapped->maybeUnwrapIf<ArrayBufferObjectMaybeShared>();
   return fromObject(ab);
 }
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -2768,16 +2768,19 @@ namespace JS {
 const JSClass* const TypedArray_base::classes = TypedArrayObject::classes;
 
 #define INSTANTIATE(ExternalType, NativeType, Name) \
   template class TypedArray<JS::Scalar::Name>;
 JS_FOR_EACH_TYPED_ARRAY(INSTANTIATE)
 #undef INSTANTIATE
 
 JS::ArrayBufferOrView JS::ArrayBufferOrView::unwrap(JSObject* maybeWrapped) {
+  if (!maybeWrapped) {
+    return JS::ArrayBufferOrView(nullptr);
+  }
   auto* ab = maybeWrapped->maybeUnwrapIf<ArrayBufferObjectMaybeShared>();
   if (ab) {
     return ArrayBufferOrView::fromObject(ab);
   }
 
   return ArrayBufferView::unwrap(maybeWrapped);
 }