Automatic update from web-platform-tests [WebNN] Validate slice strides are within input tensor dimensions Add validation in ValidateSliceAndInferOutput to ensure that the stride for each dimension, when added to the starting index, does not exceed the input tensor's dimension size. This prevents out-of-bounds memory access when a stride is too large relative to the starting position. Bug: 505136164 Change-Id: Ib1575a942084d974cf358f0b2baa1d8e42a8295a Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7801676 Reviewed-by: Reilly Grant <reillyg@chromium.org> Reviewed-by: Hu, Ningxin <ningxin.hu@intel.com> Commit-Queue: Wang, Wei4 <wei4.wang@intel.com> Cr-Commit-Position: refs/heads/main@{#1624222} -- wpt-commits: c55f172dd7d26d4328f9aea5cc8a851a03eb74b4 wpt-pr: 59611
121 lines
3.6 KiB
JavaScript
121 lines
3.6 KiB
JavaScript
// META: title=validation tests for WebNN API slice operation
|
|
// META: global=window
|
|
// META: variant=?cpu
|
|
// META: variant=?gpu
|
|
// META: variant=?npu
|
|
// META: script=../resources/utils_validation.js
|
|
|
|
'use strict';
|
|
|
|
multi_builder_test(async (t, builder, otherBuilder) => {
|
|
const inputFromOtherBuilder =
|
|
otherBuilder.input('input', {dataType: 'float32', shape: [2, 2]});
|
|
|
|
const starts = [1, 1];
|
|
const sizes = [1, 1];
|
|
assert_throws_js(
|
|
TypeError, () => builder.slice(inputFromOtherBuilder, starts, sizes));
|
|
}, '[slice] throw if input is from another builder');
|
|
|
|
const tests = [
|
|
{
|
|
name: '[slice] Test with starts=[0, 1, 2] and sizes=[1, 2, 3].',
|
|
input: {dataType: 'float32', shape: [3, 4, 5]},
|
|
starts: [0, 1, 2],
|
|
sizes: [1, 2, 3],
|
|
output: {dataType: 'float32', shape: [1, 2, 3]}
|
|
},
|
|
{
|
|
name: '[slice] Test slicing a scalar with empty starts and sizes.',
|
|
input: {dataType: 'float32', shape: []},
|
|
starts: [],
|
|
sizes: [],
|
|
output: {dataType: 'float32', shape: []}
|
|
},
|
|
{
|
|
name: '[slice] Throw if input is a scalar and starts/sizes are not empty.',
|
|
input: {dataType: 'float32', shape: []},
|
|
starts: [0],
|
|
sizes: [1]
|
|
},
|
|
{
|
|
name:
|
|
'[slice] Throw if the length of sizes is not equal to the rank of the input tensor.',
|
|
input: {dataType: 'float32', shape: [3, 4, 5]},
|
|
starts: [1, 2, 3],
|
|
sizes: [1, 1]
|
|
},
|
|
{
|
|
name:
|
|
'[slice] Throw if the length of starts is not equal to the rank of the input tensor.',
|
|
input: {dataType: 'float32', shape: [3, 4, 5]},
|
|
starts: [1, 2, 1, 3],
|
|
sizes: [1, 1, 1]
|
|
},
|
|
{
|
|
name:
|
|
'[slice] Throw if the starting index is equal to or greater than input size in the same dimension.',
|
|
input: {dataType: 'float32', shape: [3, 4, 5]},
|
|
starts: [0, 4, 4],
|
|
sizes: [1, 1, 1]
|
|
},
|
|
{
|
|
name: '[slice] Throw if the number of elements to slice is equal to 0.',
|
|
input: {dataType: 'float32', shape: [3, 4, 5]},
|
|
starts: [1, 2, 3],
|
|
sizes: [1, 0, 1]
|
|
},
|
|
{
|
|
name:
|
|
'[slice] Throw if the ending index to slice is greater than input size in the same dimension.',
|
|
input: {dataType: 'float32', shape: [3, 4, 5]},
|
|
starts: [0, 1, 2],
|
|
sizes: [3, 4, 1]
|
|
},
|
|
{
|
|
name:
|
|
'[slice] Throw if the length of strides is not equal to the rank of the input tensor.',
|
|
input: {dataType: 'float32', shape: [3, 4, 5]},
|
|
starts: [1, 2, 3],
|
|
sizes: [1, 1, 1],
|
|
strides: [1, 1, 1, 1]
|
|
},
|
|
{
|
|
name: '[slice] Throw if the strides are less than 1.',
|
|
input: {dataType: 'float32', shape: [3, 4, 5]},
|
|
starts: [1, 2, 3],
|
|
sizes: [1, 1, 1],
|
|
strides: [0, 0, 0]
|
|
},
|
|
{
|
|
name: '[slice] Throw if the stride is greater than the size to slice in the same dimension.',
|
|
input: {dataType: 'float32', shape: [3, 4, 5]},
|
|
starts: [1, 2, 3],
|
|
sizes: [1, 1, 1],
|
|
strides: [1, 2, 1]
|
|
}
|
|
];
|
|
|
|
tests.forEach(
|
|
test => promise_test(async t => {
|
|
const builder = new MLGraphBuilder(context);
|
|
const input = builder.input('input', test.input);
|
|
const options = {};
|
|
if (test.strides) {
|
|
options.strides = test.strides;
|
|
}
|
|
|
|
if (test.output) {
|
|
const output = builder.slice(input, test.starts, test.sizes);
|
|
assert_equals(output.dataType, test.output.dataType);
|
|
assert_array_equals(output.shape, test.output.shape);
|
|
} else {
|
|
const label = 'slice_xxx';
|
|
options.label = label;
|
|
const regrexp = new RegExp('\\[' + label + '\\]');
|
|
assert_throws_with_label(
|
|
() => builder.slice(input, test.starts, test.sizes, options),
|
|
regrexp);
|
|
}
|
|
}, test.name));
|