Skip to content

imgcodecs: fix PNG read on BE platforms (s390x)#26915

Merged
asmorkalov merged 3 commits intoopencv:4.xfrom
mshabunin:fix-png-be
Feb 13, 2025
Merged

imgcodecs: fix PNG read on BE platforms (s390x)#26915
asmorkalov merged 3 commits intoopencv:4.xfrom
mshabunin:fix-png-be

Conversation

@mshabunin
Copy link
Copy Markdown
Contributor

@mshabunin mshabunin commented Feb 12, 2025

Resolves #26913
Related(?): #25715 #26832

memcpy(chunk.p.data(), size_id, 8);
if (readFromStreamOrBuffer(&chunk.p[8], chunk.p.size() - 8))
return id;
return isBigEndian() ? id : *((uint32_t*)(&size_id[4]));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since we just made id correct in both cases, why change the return here? wouldn't just return id; now be ok for both?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it needs further investigation - tests on other platforms fail with other PNG files.

const size_t size = static_cast<size_t>(png_get_uint_32(size_id)) + 12;

const uint32_t id = *(uint32_t*)(&size_id[4]);
uint32_t id = *((uint32_t*)(&size_id[4]));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually the proper way is to use:

const uint32_t id = png_get_uint_32(size_d + 4);

@mshabunin
Copy link
Copy Markdown
Contributor Author

If I understand correctly the problem has been introduced here: #25715 with introduction of constants id_IHDR, id_acTL, etc. which are defined in platform-dependent way, while in the actual file they are always in BE. So perhaps alternatively we can change definition of these constants.

@vrabaud
Copy link
Copy Markdown
Contributor

vrabaud commented Feb 13, 2025

@mshabunin , you are right. Let's use png_get_uint_32 because it has a constant endianness. We just need to have the chunk constants have the same endianness as what this function does, BE cf https://github.com/pnggroup/libpng/blob/b525503b78392335a43558c6a053e0209140762d/pngrutil.c#L63

@mshabunin
Copy link
Copy Markdown
Contributor Author

mshabunin commented Feb 13, 2025

I tried and apparently png_get_uint_32 does not work for this case, because we actually do not need to swap bytes - we need to just copy them as 4 bytes. Actually something like strncmp would fit better in this case:

const uint8_t * id_IHDR = "IHDR";
...
if (0  == strncmp(size_id + 4, id_IHDR, 4))
...

Maybe we could even switch to std::string to use operator==`...

UPD: oh, I think I made a mistake with byte swap and png routine can work

@mshabunin
Copy link
Copy Markdown
Contributor Author

OK, the last variant should work 😮‍💨

@vrabaud
Copy link
Copy Markdown
Contributor

vrabaud commented Feb 13, 2025

Perfect, LGTM ! @asmorkalov , ready to go.

@asmorkalov
Copy link
Copy Markdown
Contributor

@vrabaud please put formal approve.

@vrabaud
Copy link
Copy Markdown
Contributor

vrabaud commented Feb 13, 2025

@asmorkalov , how do I do that? (we LGTM internally :) )

@asmorkalov asmorkalov assigned asmorkalov and vrabaud and unassigned asmorkalov Feb 13, 2025
@asmorkalov asmorkalov merged commit 45aa502 into opencv:4.x Feb 13, 2025
28 of 29 checks passed
@mshabunin mshabunin deleted the fix-png-be branch February 13, 2025 15:46
@AdamWill
Copy link
Copy Markdown

thanks a lot, I will test this and see if I can confirm the fix.

@AdamWill
Copy link
Copy Markdown

Fix looks good in testing here! Thanks.

@AdamWill
Copy link
Copy Markdown

Oh, er, but...worryingly...it makes the test fail on x86_64, here.

@mshabunin
Copy link
Copy Markdown
Contributor Author

@AdamWill which test fails? Our CI had passed. Did you use the latest variant of the patch?

@AdamWill
Copy link
Copy Markdown

ah, yikes, probably my bad - I manually rebased the patch to 4.11.0 and missed the second chunk, only had the changes to the const definitions. I'll fix it and retest.

@AdamWill
Copy link
Copy Markdown

OK yeah, so I instead backported every change to the PNG code since 4.11.0, including this PR, and the test script passes on both x86_64 and s390x. Yay. Thanks.

@asmorkalov asmorkalov mentioned this pull request Feb 19, 2025
NanQin555 pushed a commit to NanQin555/opencv that referenced this pull request Feb 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OpenCV 4.11.0 broken on s390x (big endian) - cv::imread returns empty matrix for valid file

5 participants