Skip to content

cudaarithm: do not reinterpret misaligned rows in bitwise ops - #4215

Open
SichenLiang wants to merge 1 commit into
opencv:4.xfrom
SichenLiang:fix-4211-bitwise-misaligned
Open

cudaarithm: do not reinterpret misaligned rows in bitwise ops#4215
SichenLiang wants to merge 1 commit into
opencv:4.xfrom
SichenLiang:fix-4211-bitwise-misaligned

Conversation

@SichenLiang

Copy link
Copy Markdown

cv::cuda::bitwise_and, bitwise_or, bitwise_xor and bitwise_not without a
mask choose a 32-bit or a 16-bit word path from the row width in bytes alone,
without looking at the data pointers or at the steps. Two kinds of ordinary
matrix break that.

A ROI whose x offset is not a multiple of the word size misaligns every row;
that is the reported case. And a matrix from cv::cuda::createContinuous() has
step = cols * elemSize(), which need not be a multiple of the word size
either, so rows after the first can be misaligned even at x offset 0:
createContinuous(8, 17, CV_8UC1) gives step 17 and crashes today with no ROI
involved. Both end in a misaligned address CUDA error that is sticky: it also
breaks every later CUDA call in the process, so one fault can turn a whole test
run red.

Take a word path only when the row width and the data pointer and step of every
operand are aligned to that word size, and fall back to the 16-bit path, or to
the byte path when even that does not hold. This is the check
cudev::TransformDispatcher makes on data and step before it vectorises
(modules/cudev/include/opencv2/cudev/grid/detail/transform.hpp). Its own
fallback does not help here, because that fallback still dereferences the type
the caller reinterpreted the row as, which is why the fault surfaces inside
TransformDispatcher<false> rather than at the call site. Inputs whose pointers
and steps are already aligned keep the path they had.

Bitwise_Array_Misaligned covers the four operations on CV_8UC1, CV_8UC3 and
CV_16UC1, with the misalignment coming either from a one-element ROI x offset or
from a createContinuous() step, applied to src1, to src2, to the
destination, or to all three, so that a check which misses one operand is not
enough. 192 instances, all 192 of which fail without the change.

One thing worth knowing before reading a CI result. opencv_test_cudaarithm
shares a single cv::theRNG() stream across the whole process (CUDA_TEST_P
does not call cvtest::testSetUp(), so --test_seed does not move it), and a
few CUDA_Arithm tests compare a GPU result against a CPU one on random data
that can land on a tie. Adding any test that draws from that stream shifts where
those tests sample it. On an unmodified library, with no change to
bitwise_mat.cu and no test added to it, a throwaway test that consumes 47
bytes of random data is enough to turn the suite red on
CUDA_Arithm/ThresholdOtsu.Accuracy/8; 4 of the first 100 draw offsets I tried
do it, and CUDA_Arithm/PolarToCart.Accuracy is sensitive in the same way. The
suite is green here with this patch and its tests, but if you see either of
those fail on this PR, it is that pre-existing sensitivity and not this change.
I am happy to hand over the reproducer.

Fixes #4211

Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

  • I agree to contribute to the project under Apache 2 License.
  • 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
  • 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
    Patch to opencv_extra has the same branch name.
  • The feature is well documented and sample code can be built with the project CMake

bitwise_and/or/xor/not without a mask process the rows as 32-bit or
16-bit words whenever the row width in bytes allows it, without
looking at the data pointers or at the steps. Two ordinary matrices
break that. A ROI whose x offset is not a multiple of the word size
misaligns every row; that is the reported case. And a matrix from
cv::cuda::createContinuous() has step = cols * elemSize(), which
need not be a multiple of the word size either, so rows after the
first can be misaligned even at x offset 0. Both end in a
"misaligned address" CUDA error that is sticky: it also breaks every
later CUDA call in the process.

Take a word path only when the row width and the data pointer and
step of every operand are aligned to that word size, and fall back
to the 16-bit path, or to the byte path when even that does not
hold. This is the check cudev::TransformDispatcher makes on data and
step before it vectorises, in
modules/cudev/include/opencv2/cudev/grid/detail/transform.hpp; its own
fallback does not help here, because that fallback still dereferences
the type the caller reinterpreted the row as.
Inputs whose pointers and steps are already aligned keep the path
they had.

Add Bitwise_Array_Misaligned: the four operations on CV_8UC1,
CV_8UC3 and CV_16UC1, at a row width in bytes that is a multiple of 4
and, for the 8-bit types, at one that is a multiple of 2 only, with the
misalignment coming either from a one element ROI x offset or from a
createContinuous() step, and applied to src1, to src2, to the
destination or to all three, so that a check that misses one operand
is not enough. 192 instances, all 192 of which fail without the
change above.

Fixes opencv#4211
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant