-
Notifications
You must be signed in to change notification settings - Fork 663
Fix reading EXR images on 32bit Windows with OpenEXR 3.3 #1952
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix reading EXR images on 32bit Windows with OpenEXR 3.3 #1952
Conversation
|
Thanks for finding this! Would you mind doing the CLA business noted in the message above? |
meshula
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me, but I'll defer to @kdt3rd for a second approval.
I reached out to my company's legal department but won't be able to sign off the CLA before monday. |
|
That's perfectly fine :) Thanks for looking into it. |
|
hrm, it should have been uintptr_t in the msvc block at lines 35-48, this is more likely my poor win32 programming substituting in for not having stdatomic.h properly implemented in msvc at the time I did it - there should be a 32 vs 64 bit switch depending on what size uintptr_t is - it is always pointing to a uint64 as you note (it's an offset into the file), but might be a 32-bit pointer (4-byte pointer) pointing to that array of 8-byte values, so what is there seems not quite right to me, although will work, but not as efficiently as it could on a 32-bit machine, the implementations of the atomic function for msvc should instead check #if sizeof(void *) == 4 or so and it should deal with uintptr_t... |
|
concretely, those two functions at line 35 should likely be #ifdef _WIN64 then use Interlocked64 or use Interlocked32 and take uintptr_t values... thanks for finding that |
I'll take a look at implementing it more efficent using the proposed |
|
I did take another look and tried the following: static inline int
atomic_compare_exchange_strong (
atomic_uintptr_t volatile* object, uintptr_t* expected, uintptr_t desired)
{
uintptr_t prev =
# ifdef _WIN64
(uintptr_t) InterlockedCompareExchange64 (object, desired, *expected);
# else
(uintptr_t) InterlockedCompareExchange ((uintptr_t volatile*) object, desired, *expected);
# endif
if (prev == *expected) return 1;
*expected = prev;
return 0;
}This seemlingly worked on 32 and 64 bits and allowed me to revert However, please note that this code now has a conversion of pointer to a 64-bit value The reason is the define for openexr/src/lib/OpenEXRCore/internal_structs.h Lines 57 to 59 in 8bc3fae
This would introduce a similar error as the one I wanted to fix. However, instead of falsely reading additional bytes, here the four additional bytes wouldn't be correclty overwritten in the scope of I also briefly tried changing the TL;DR I would rather keep the proposed solution to use 64 bit values for |
be27945 to
6d8e291
Compare
It took a few more days, but now it's signed. |
|
Oh, sorry, yes - for that definition of atomic_uintptr_t i bodged in to internal structs, switching to uint64 would likely be a good solution. However, the uintptr_t values in chunk.c you've changed to uint64_t are then the wrong thing for a 32 bit system where the atomic_uintptr_t type is appropriately defined (and is the natural representation so you don't want to do a double cas if you don't need to). Or if you use clang / gcc under windows. I continue to think I shouldn't have been lazy, and it should be properly represented in internal_structs an ifdef on sizeof(void*) and then with the ifdefs in the compare and exchange as well... Thanks again for tracking this down and getting the cla stuff done! |
|
Sounds like the PR is good to merge then? |
6d8e291 to
fd385e3
Compare
|
Is there anything I can do to help get this PR merged? |
…pe on 32 bit platforms Signed-off-by: Christopher Schwartz <christopherschwartz@xrite.com>
cary-ilm
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry this has dragged on so long. @kdt3rd is the authority, but I did notice that the assignment to nptr on line 642 still casts to uintptr_t, which now seems incorrect.
And the assignment to ctable on line 650 is unnecessary, since both sides are now the same type.
(Why won't GitHub allow you to leave a comment on a line with no edit??)
Thanks for having another look and pointing these two casts out! I didn't see them myself initially. I think the cast technically doesn't do any harm, as it won't do anything on a 64 bit system anyways.
The cast is not unnecessary after all. |
…oth, 32 and 64 bit platforms Signed-off-by: Christopher Schwartz <christopherschwartz@xrite.com>
9a31c1e to
6e8e640
Compare
cary-ilm
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apologies for letting this go stale, it's fine as is. Note that now nptr and ctable are both of the same type )uint64_t), but the cast is harmless.
…wareFoundation#1952) * Fix issue with atomic_compare_exchange_strong due to inappropriate type on 32 bit platforms Signed-off-by: Christopher Schwartz <christopherschwartz@xrite.com> * Change casted type to match the type of the assigned to variable on both, 32 and 64 bit platforms Signed-off-by: Christopher Schwartz <christopherschwartz@xrite.com> --------- Signed-off-by: Christopher Schwartz <christopherschwartz@xrite.com> Co-authored-by: Cary Phillips <cary@ilm.com>
…wareFoundation#1952) * Fix issue with atomic_compare_exchange_strong due to inappropriate type on 32 bit platforms Signed-off-by: Christopher Schwartz <christopherschwartz@xrite.com> * Change casted type to match the type of the assigned to variable on both, 32 and 64 bit platforms Signed-off-by: Christopher Schwartz <christopherschwartz@xrite.com> --------- Signed-off-by: Christopher Schwartz <christopherschwartz@xrite.com> Co-authored-by: Cary Phillips <cary@ilm.com>
…wareFoundation#1952) * Fix issue with atomic_compare_exchange_strong due to inappropriate type on 32 bit platforms Signed-off-by: Christopher Schwartz <christopherschwartz@xrite.com> * Change casted type to match the type of the assigned to variable on both, 32 and 64 bit platforms Signed-off-by: Christopher Schwartz <christopherschwartz@xrite.com> --------- Signed-off-by: Christopher Schwartz <christopherschwartz@xrite.com> Co-authored-by: Cary Phillips <cary@ilm.com>
* Fix issue with atomic_compare_exchange_strong due to inappropriate type on 32 bit platforms Signed-off-by: Christopher Schwartz <christopherschwartz@xrite.com> * Change casted type to match the type of the assigned to variable on both, 32 and 64 bit platforms Signed-off-by: Christopher Schwartz <christopherschwartz@xrite.com> --------- Signed-off-by: Christopher Schwartz <christopherschwartz@xrite.com> Co-authored-by: Cary Phillips <cary@ilm.com>
|
It turns out this doesn't even compile on MINGW32, see #2009, since there's a mismatch in the types of the arguments to @ChristopherSchwartzXRITE and @kdt3rd, could one of you take a look at a fresh solution? Thanks! |
I agree that this is annoying and the build needs to be fixed. I suppose the reason why the failed build went unnoticed on MSVC but is now causing an issue with MINGW32 is the special define of openexr/src/lib/OpenEXRCore/internal_structs.h Lines 41 to 62 in 75b70c6
Similarly, openexr/src/lib/OpenEXRCore/chunk.c Lines 29 to 51 in 75b70c6
I think that means that my original problem (see this PR's description) is also just a problem for MSVC due to the special handling. So I suppose this could be quick-fixed by making the type change introduced in this PR depend on a similar ---uint64_t eptr = 0, nptr = 0;
+++#ifdef EXR_HAS_STD_ATOMICS
+++ uintptr_t eptr = 0, nptr = 0;
+++#elif defined(_MSC_VER)
+++ uint64_t eptr = 0, nptr = 0;
+++#else
+++# error OS unimplemented support for atomics
+++#endif |
|
I opened PR #2009 with the changes proposed above. |
…wareFoundation#1952) * Fix issue with atomic_compare_exchange_strong due to inappropriate type on 32 bit platforms Signed-off-by: Christopher Schwartz <christopherschwartz@xrite.com> * Change casted type to match the type of the assigned to variable on both, 32 and 64 bit platforms Signed-off-by: Christopher Schwartz <christopherschwartz@xrite.com> --------- Signed-off-by: Christopher Schwartz <christopherschwartz@xrite.com> Co-authored-by: Cary Phillips <cary@ilm.com>
This PR fixes an issue with
atomic_compare_exchange_strongin chunk.c due to inappropriate type on 32 bit platforms.Context:
When switching from OpenEXR 3.2.4 to OpenEXR 3.3.2, I noticed that reading image content from file (via
ImfInputFile::readPixels(int, int)) failed most of the time (but not always) in 32 bit Windows.I found that OpenEXR 3.3 apparently changed the reading routine to use
extract_chunk_tablefrom OpenEXRCore's chunk.c.Here, two variables
eptrandnptrare declared to be of typeuintptr_tinopenexr/src/lib/OpenEXRCore/chunk.c
Line 568 in 8bc3fae
However, in
openexr/src/lib/OpenEXRCore/chunk.c
Lines 644 to 647 in 8bc3fae
, they are used in an
atomic_compare_exchange_strongcall asuint64_t*anduint64_trespectively.See
openexr/src/lib/OpenEXRCore/chunk.c
Lines 38 to 47 in 8bc3fae
While the latter isn't a problem per-se, the usage of
&eptrasuint64_t*letsatomic_compare_exchange_stronginterpret whatever is at the address ofeptras an 8 byte long number.However, the actual type
uintptr_tis only 4 bytes long.So, whatever is in the next four bytes will garble the value originally stored in
eptr.As a result in the comparison of
prev(which holds "0" if the exchange worked as expected) does not compare to the expected and declare value ofuintptr_t eptr = 0from line 568 but any number that is in the respective full 8 bytes of memory will fail and set the full 8 bytes to 0.openexr/src/lib/OpenEXRCore/chunk.c
Lines 44 to 46 in 8bc3fae
This not only misleads the calling code to assume that it failed to thread-safe exchange the pointers but also overwrites the
ctablepointer with the (now 8 bytes of zeros) addresss and eventually (falsely) report "out of memory".openexr/src/lib/OpenEXRCore/chunk.c
Lines 649 to 652 in 8bc3fae
My proposed minimal fix simply changes the type of
eptr(andnptr) to always be an unsigned 64 bit value, which should work for both, 32 and 64 bit platforms.