mirror of
https://github.com/opencv/opencv.git
synced 2026-07-21 19:33:03 +04:00
Merge pull request #29345 from uwezkhan:onnx-tile-bounds
bound tile axis and repeats length in onnx parseTile #29345 OpenCV Extra: https://github.com/opencv/opencv_extra/pull/1385 parseTile sizes repeats_vec from the input-0 rank, then fills it from fields of the model that are never checked against that size. In the tile-1 path the axis taken from the third input indexes repeats_vec directly, and in the tile>1 path the loop writes one entry per element of the repeats tensor. A crafted ONNX with an out-of-range axis, or a repeats tensor longer than the input rank, writes past repeats_vec while loading the model through readNetFromONNX. The fix runs axis through normalize_axis, the same helper the squeeze and concat paths in this file already use, so a negative or oversized axis is rejected before the write, and it checks the repeats length equals the input rank before the loop. Keeping both bounds in the parser puts the check next to the write instead of trusting the model to be well formed. Before, a repeats tensor shorter than the rank was silently accepted; after, it is rejected, which matches the ONNX rule that repeats carries one entry per input dimension. - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [ ] There is a reference to the original bug report and related work - [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable - [ ] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
@@ -80,8 +80,10 @@ public:
|
||||
{
|
||||
tmp = tmp.reshape(0, dims);
|
||||
tmp = cv::repeat(tmp, 1, rep_i);
|
||||
dims *= out_shape[i];
|
||||
}
|
||||
// accumulate for every axis so a repeated non-leading axis tiles
|
||||
// per-axis blocks instead of repeating the whole flattened tensor
|
||||
dims *= out_shape[i];
|
||||
}
|
||||
tmp = tmp.reshape(0, out_shape);
|
||||
|
||||
|
||||
@@ -3132,13 +3132,14 @@ void ONNXImporter::parseTile(LayerParams& layerParams, const opencv_onnx::NodePr
|
||||
// input2 in tile-1: axis, 1d tensor of shape [1]
|
||||
Mat input2_blob = getBlob(node_proto, 2);
|
||||
CV_CheckEQ(input2_blob.total(), 1ull, "ONNX/Tile: axis must be a 0D tensor or 1D tensor of shape [1].");
|
||||
int axis = input2_blob.at<int>(0);
|
||||
int axis = normalize_axis(input2_blob.at<int>(0), input0_dims);
|
||||
repeats_vec[axis] = tiles;
|
||||
}
|
||||
else
|
||||
{
|
||||
// input1 in tile>1: repeats
|
||||
CV_CheckEQ(input1_blob.dims, 2, "ONNX/Tile: repeats must be a 1D tensor."); // 1D tensor is represented as a 2D Mat
|
||||
CV_CheckEQ((int)input1_blob.total(), input0_dims, "ONNX/Tile: repeats length must match the input rank.");
|
||||
for (int i = 0; i < input1_blob.total(); i++)
|
||||
repeats_vec[i] = input1_blob.at<int>(i);
|
||||
}
|
||||
|
||||
@@ -3039,6 +3039,9 @@ TEST_P(Test_ONNX_nets, YOLOv5n)
|
||||
TEST_P(Test_ONNX_layers, Tile)
|
||||
{
|
||||
testONNXModels("tile", pb);
|
||||
// tile-1 (opset 1) form with a negative axis; the parser must normalize it
|
||||
// against the input rank instead of indexing the repeats buffer directly.
|
||||
testONNXModels("tile_neg_axis");
|
||||
}
|
||||
|
||||
TEST_P(Test_ONNX_layers, Gelu)
|
||||
|
||||
Reference in New Issue
Block a user