Skip to content

Commit 427bb68

Browse files
SoapGentoomroeschke
authored andcommitted
Fix pandas-dev#54391: Use memcpy() for unaligned loads (pandas-dev#54407)
1 parent f6cb0fe commit 427bb68

File tree

1 file changed

+26
-34
lines changed

1 file changed

+26
-34
lines changed

pandas/_libs/byteswap.pyx

+26-34
Original file line numberDiff line numberDiff line change
@@ -10,53 +10,57 @@ from libc.stdint cimport (
1010
uint32_t,
1111
uint64_t,
1212
)
13+
from libc.string cimport memcpy
1314

1415

1516
def read_float_with_byteswap(bytes data, Py_ssize_t offset, bint byteswap):
16-
assert offset + 4 < len(data)
17-
cdef:
18-
const char *data_ptr = data
19-
float res = (<float*>(data_ptr + offset))[0]
17+
cdef uint32_t value
18+
assert offset + sizeof(value) < len(data)
19+
cdef const void *ptr = <unsigned char*>(data) + offset
20+
memcpy(&value, ptr, sizeof(value))
2021
if byteswap:
21-
res = _byteswap_float(res)
22+
value = _byteswap4(value)
23+
24+
cdef float res
25+
memcpy(&res, &value, sizeof(res))
2226
return res
2327

2428

2529
def read_double_with_byteswap(bytes data, Py_ssize_t offset, bint byteswap):
26-
assert offset + 8 < len(data)
27-
cdef:
28-
const char *data_ptr = data
29-
double res = (<double*>(data_ptr + offset))[0]
30+
cdef uint64_t value
31+
assert offset + sizeof(value) < len(data)
32+
cdef const void *ptr = <unsigned char*>(data) + offset
33+
memcpy(&value, ptr, sizeof(value))
3034
if byteswap:
31-
res = _byteswap_double(res)
35+
value = _byteswap8(value)
36+
37+
cdef double res
38+
memcpy(&res, &value, sizeof(res))
3239
return res
3340

3441

3542
def read_uint16_with_byteswap(bytes data, Py_ssize_t offset, bint byteswap):
36-
assert offset + 2 < len(data)
37-
cdef:
38-
const char *data_ptr = data
39-
uint16_t res = (<uint16_t *>(data_ptr + offset))[0]
43+
cdef uint16_t res
44+
assert offset + sizeof(res) < len(data)
45+
memcpy(&res, <const unsigned char*>(data) + offset, sizeof(res))
4046
if byteswap:
4147
res = _byteswap2(res)
4248
return res
4349

4450

4551
def read_uint32_with_byteswap(bytes data, Py_ssize_t offset, bint byteswap):
46-
assert offset + 4 < len(data)
47-
cdef:
48-
const char *data_ptr = data
49-
uint32_t res = (<uint32_t *>(data_ptr + offset))[0]
52+
cdef uint32_t res
53+
assert offset + sizeof(res) < len(data)
54+
memcpy(&res, <const unsigned char*>(data) + offset, sizeof(res))
5055
if byteswap:
5156
res = _byteswap4(res)
5257
return res
5358

5459

5560
def read_uint64_with_byteswap(bytes data, Py_ssize_t offset, bint byteswap):
56-
assert offset + 8 < len(data)
57-
cdef:
58-
const char *data_ptr = data
59-
uint64_t res = (<uint64_t *>(data_ptr + offset))[0]
61+
cdef uint64_t res
62+
assert offset + sizeof(res) < len(data)
63+
memcpy(&res, <const unsigned char*>(data) + offset, sizeof(res))
6064
if byteswap:
6165
res = _byteswap8(res)
6266
return res
@@ -79,15 +83,3 @@ cdef extern from *:
7983
uint16_t _byteswap2(uint16_t)
8084
uint32_t _byteswap4(uint32_t)
8185
uint64_t _byteswap8(uint64_t)
82-
83-
84-
cdef float _byteswap_float(float num):
85-
cdef uint32_t *intptr = <uint32_t *>&num
86-
intptr[0] = _byteswap4(intptr[0])
87-
return num
88-
89-
90-
cdef double _byteswap_double(double num):
91-
cdef uint64_t *intptr = <uint64_t *>&num
92-
intptr[0] = _byteswap8(intptr[0])
93-
return num

0 commit comments

Comments
 (0)