Commit 3ad9b29
authored
Fix misaligned memory access in
* Fix misaligned memory access in `LossyDctDecoder_execute` HALF→FLOAT expansion
After DCT decoding, `LossyDctDecoder_execute()` expands FLOAT-type channels
from their intermediate HALF (16-bit) XDR representation back to FLOAT (32-bit)
XDR in place. The expansion was done by casting `_rows[y]` (a `uint8_t *`)
directly to `float *` and `uint16_t *`, then reading and writing through those
typed pointers.
Because row buffers are assigned by advancing a byte pointer with no alignment
padding (`outBufferEnd += chan->width * chan->bytes_per_element` in
`internal_dwa_compressor.h`), a FLOAT channel that follows a HALF channel of
odd width receives a `_rows[y]` pointer that is 2-byte aligned but not 4-byte
aligned. Dereferencing a `float *` cast from such a pointer is undefined
behavior under the C standard:
- On ARM, RISC-V, and MIPS (strict alignment) this crashes immediately.
- On x86 it is silently tolerated at the hardware level but remains UB:
auto-vectorizing compilers (SSE/AVX) may assume aligned access and generate
incorrect code.
- UBSan reports: `store to misaligned address ... for type 'float', which
requires 4 byte alignment` at `internal_dwa_decoder.h:749`.
Fix: replace the cast-and-dereference pattern with the `unaligned_load16` /
`memcpy` / `unaligned_store32` helpers already used throughout the rest of
OpenEXRCore (`internal_xdr.h`, `unpack.c`, `pack.c`, `internal_pxr24.c`).
These helpers use `memcpy` internally, which the C standard guarantees is safe
for unaligned addresses and which compilers compile to a single load/store
instruction on architectures that support it.
The byte-order handling is preserved correctly:
- `unaligned_load16` reads 2 bytes via `memcpy` and applies `one_to_native16`
(XDR → native), returning a native-endian HALF value.
- `half_to_float` converts native HALF → native float.
- `memcpy(&bits, &f, 4)` reinterprets the float's bit pattern as `uint32_t`
without numeric conversion (the correct type-pun idiom in C).
- `unaligned_store32` applies `one_from_native32` (native → XDR) and writes
4 bytes via `memcpy`, storing the result in XDR float format.
Made-with: Cursor
Signed-off-by: Cary Phillips <cary@ilm.com>
* add TODO comment
Signed-off-by: Cary Phillips <cary@ilm.com>
---------
Signed-off-by: Cary Phillips <cary@ilm.com>LossyDctDecoder_execute HALF→FLOAT expansion (#2324)1 parent fd6e400 commit 3ad9b29
1 file changed
Lines changed: 13 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
741 | 741 | | |
742 | 742 | | |
743 | 743 | | |
744 | | - | |
745 | | - | |
| 744 | + | |
746 | 745 | | |
747 | 746 | | |
748 | 747 | | |
749 | | - | |
750 | | - | |
| 748 | + | |
| 749 | + | |
| 750 | + | |
| 751 | + | |
| 752 | + | |
| 753 | + | |
| 754 | + | |
| 755 | + | |
| 756 | + | |
| 757 | + | |
| 758 | + | |
| 759 | + | |
751 | 760 | | |
752 | 761 | | |
753 | 762 | | |
| |||
0 commit comments