1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-29 15:23:05 +04:00

Merge pull request #29378 from uwezkhan:qr-alpha-map-bound

bound alphanumeric values in qr decodeAlpha before map lookup #29378

decodeAlpha in the no-quirc QR backend reads alphanumeric symbols from the post-ECC bitstream and indexes a fixed 45-entry map[] with the raw values. The 11-bit pair from next(11) goes up to 2047, so tuple/45 lands on 45 once the pair passes 2024, and the 6-bit trailing char from next(6) goes up to 63, so map[value] runs out to map[63]. A QR whose data codewords carry an alphanumeric segment with one of those out-of-range values reads past the static array, and the stray byte lands in the string returned by detectAndDecode. WITH_QUIRC defaults off, so this is the decoder a stock build runs.

Before, the only guard was on the encode side, which never emits those values, so the decoder trusted the stream and indexed map[] directly. New version checks value range and return empty string for malformed qr codes.

### Pull Request Readiness Checklist

- [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:
uwezkhan
2026-06-28 16:48:20 +05:30
committed by GitHub
parent dd541965e9
commit 15b5d28325
2 changed files with 74 additions and 14 deletions
+48
View File
@@ -571,6 +571,54 @@ TEST(Objdetect_QRCode_decode, decode_regression_version_25)
EXPECT_EQ(expect_msg, decoded_msg);
}
TEST(Objdetect_QRCode_decode, decode_alphanumeric_out_of_range)
{
// Version 1 QR with a valid Reed-Solomon block whose alphanumeric segment
// carries an 11-bit pair value of 2047. decodeAlpha computes 2047 / 45 == 45
// and used to read map[45], one past the 45-entry table, leaking an adjacent
// byte into the decoded string. The decoder must reject it and return an
// empty string instead.
static const char* modules[21] = {
"000000011011010000000",
"011111010011010111110",
"010001011011010100010",
"010001010011010100010",
"010001011011010100010",
"011111010011010111110",
"000000010101010000000",
"111111111011011111111",
"000001000011001010101",
"111111101001011011000",
"000111010001011011000",
"001001100111011011000",
"000001011011011011000",
"111111110101011011000",
"000000010111011011001",
"011111011101011011001",
"010001010001011011011",
"010001010001011011011",
"010001010001011011011",
"011111010001011011010",
"000000010001011011011"
};
Mat qr(21, 21, CV_8UC1);
for (int i = 0; i < 21; i++)
for (int j = 0; j < 21; j++)
qr.at<uchar>(i, j) = modules[i][j] == '1' ? 255 : 0;
Mat src;
cv::resize(qr, src, qr.size() * 10, 0, 0, INTER_NEAREST);
cv::copyMakeBorder(src, src, 40, 40, 40, 40, BORDER_CONSTANT, Scalar(255));
QRCodeDetector qrcode;
std::vector<Point> corners;
ASSERT_TRUE(qrcode.detect(src, corners));
Mat straight_barcode;
std::string decoded_info;
EXPECT_NO_THROW(decoded_info = qrcode.decode(src, corners, straight_barcode));
EXPECT_TRUE(decoded_info.empty());
}
TEST_P(Objdetect_QRCode_detectAndDecodeMulti, decode_9_qrcodes_version7)
{
const std::string name_current_image = "9_qrcodes_version7.jpg";