From 0434697462c8d8d2f006cb938876277ea60f795e Mon Sep 17 00:00:00 2001 From: Ningxin Hu Date: Thu, 4 Apr 2024 18:03:36 -0700 Subject: [PATCH] WebNN: Check whether detached for each ArrayBufferView For input and output `NamedArrayBufferViews` passing to `MLContext.compute()`, it needs to check whether each `ArrayBufferView` is detached or not, because transferring an `ArrayBuffer` would impact all `ArrayBufferView`s that share the same `ArrayBuffer`. Bug: 332002364 Change-Id: I81c5d287ba8f54fd3b699e431ba12c7cf138557f Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5409549 Reviewed-by: Reilly Grant Reviewed-by: Austin Sullivan Commit-Queue: ningxin hu Cr-Commit-Position: refs/heads/main@{#1282875} --- ...iews-sharing-same-arraybuffer.https.any.js | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 webnn/validation_tests/compute-multiple-arraybufferviews-sharing-same-arraybuffer.https.any.js diff --git a/webnn/validation_tests/compute-multiple-arraybufferviews-sharing-same-arraybuffer.https.any.js b/webnn/validation_tests/compute-multiple-arraybufferviews-sharing-same-arraybuffer.https.any.js new file mode 100644 index 00000000000000..42b123a97e5732 --- /dev/null +++ b/webnn/validation_tests/compute-multiple-arraybufferviews-sharing-same-arraybuffer.https.any.js @@ -0,0 +1,50 @@ +// META: title=ensure WebNN MLContext.compute() rejecting detached buffers +// META: global=window,dedicatedworker +// META: script=../resources/utils_validation.js + +// These tests are used to reproduce the Chromium issue: +// https://issues.chromium.org/issues/332002364 +promise_test(async t => { + const a = builder.input('a', {dataType: 'float32', dimensions: [2]}); + const b = builder.input('b', {dataType: 'float32', dimensions: [2]}); + const c = builder.add(a, b); + const graph = await builder.build({c}); + const arraybuffer = new ArrayBuffer(100); + const aBuffer = new Float32Array(arraybuffer, 0, 2); + const bBuffer = new Float32Array(arraybuffer, 8, 2); + const cBuffer = new Float32Array(2); + const promise = context.compute(graph, {'a': aBuffer, 'b': bBuffer}, {'c': cBuffer}); + promise_rejects_js(t, TypeError, promise); + }, 'Throw if two input ArrayBufferViews sharing the same ArrayBuffer'); + +promise_test(async t => { + const a = builder.input('a', {dataType: 'float32', dimensions: [2]}); + const [b, c] = builder.split(a, 2); + const graph = await builder.build({b, c}); + const aBuffer = new Float32Array(2); + const arraybuffer = new ArrayBuffer(100); + const bBuffer = new Float32Array(arraybuffer, 0, 1); + const cBuffer = new Float32Array(arraybuffer, 4, 1); + const promise = context.compute(graph, {'a': aBuffer}, {'b': bBuffer, 'c': cBuffer}); + promise_rejects_js(t, TypeError, promise); +}, 'Throw if two output ArrayBufferViews sharing the same ArrayBuffer'); + +promise_test(async t => { + const a = builder.input('a', {dataType: 'float32', dimensions: [2]}); + const b = builder.relu(a); + const graph = await builder.build({b}); + const arraybuffer = new ArrayBuffer(100); + const aBuffer = new Float32Array(arraybuffer, 0, 2); + const bBuffer = new Float32Array(arraybuffer, 8, 2); + const promise = context.compute(graph, {'a': aBuffer}, {'b': bBuffer}); + promise_rejects_js(t, TypeError, promise); +}, 'Throw if input and output ArrayBufferViews sharing the same ArrayBuffer'); + +promise_test(async t => { + const a = builder.input('a', {dataType: 'float32', dimensions: [2]}); + const b = builder.relu(a); + const graph = await builder.build({b}); + const buffer = new Float32Array(2); + const promise = context.compute(graph, {'a': buffer}, {'b': buffer}); + promise_rejects_js(t, TypeError, promise); +}, 'Throw if input and output are the same ArrayBufferView');