Skip to content

bpo-40302: Add _Py_bswap32() function to pyport.h #19552

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

Merged
merged 3 commits into from
Apr 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions Include/internal/pycore_byteswap.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/* Bytes swap functions, reverse order of bytes:

- _Py_bswap16(uint16_t)
- _Py_bswap32(uint32_t)
- _Py_bswap64(uint64_t)
*/

#ifndef Py_INTERNAL_BSWAP_H
#define Py_INTERNAL_BSWAP_H
#ifdef __cplusplus
extern "C" {
#endif

#ifndef Py_BUILD_CORE
# error "this header requires Py_BUILD_CORE define"
#endif

#if defined(__clang__) || \
(defined(__GNUC__) && \
((__GNUC__ >= 5) || (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)))
/* __builtin_bswap16() is available since GCC 4.8,
__builtin_bswap32() is available since GCC 4.3,
__builtin_bswap64() is available since GCC 4.3. */
# define _PY_HAVE_BUILTIN_BSWAP
#endif

#ifdef _MSC_VER
/* Get _byteswap_ushort(), _byteswap_ulong(), _byteswap_uint64() */
# include <intrin.h>
#endif

static inline uint16_t
_Py_bswap16(uint16_t word)
{
#ifdef _PY_HAVE_BUILTIN_BSWAP
return __builtin_bswap16(word);
#elif defined(_MSC_VER)
Py_BUILD_ASSERT(sizeof(word) == sizeof(unsigned short));
return _byteswap_ushort(word);
#else
// Portable implementation which doesn't rely on circular bit shift
return ( ((word & UINT16_C(0x00FF)) << 8)
| ((word & UINT16_C(0xFF00)) >> 8));
#endif
}

static inline uint32_t
_Py_bswap32(uint32_t word)
{
#ifdef _PY_HAVE_BUILTIN_BSWAP
return __builtin_bswap32(word);
#elif defined(_MSC_VER)
Py_BUILD_ASSERT(sizeof(word) == sizeof(unsigned long));
return _byteswap_ulong(word);
#else
// Portable implementation which doesn't rely on circular bit shift
return ( ((word & UINT32_C(0x000000FF)) << 24)
| ((word & UINT32_C(0x0000FF00)) << 8)
| ((word & UINT32_C(0x00FF0000)) >> 8)
| ((word & UINT32_C(0xFF000000)) >> 24));
#endif
}

static inline uint64_t
_Py_bswap64(uint64_t word)
{
#ifdef _PY_HAVE_BUILTIN_BSWAP
return __builtin_bswap64(word);
#elif defined(_MSC_VER)
return _byteswap_uint64(word);
#else
// Portable implementation which doesn't rely on circular bit shift
return ( ((word & UINT64_C(0x00000000000000FF)) << 56)
| ((word & UINT64_C(0x000000000000FF00)) << 40)
| ((word & UINT64_C(0x0000000000FF0000)) << 24)
| ((word & UINT64_C(0x00000000FF000000)) << 8)
| ((word & UINT64_C(0x000000FF00000000)) >> 8)
| ((word & UINT64_C(0x0000FF0000000000)) >> 24)
| ((word & UINT64_C(0x00FF000000000000)) >> 40)
| ((word & UINT64_C(0xFF00000000000000)) >> 56));
#endif
}


#ifdef __cplusplus
}
#endif
#endif /* !Py_INTERNAL_BSWAP_H */

8 changes: 4 additions & 4 deletions Include/pyport.h
Original file line number Diff line number Diff line change
Expand Up @@ -768,11 +768,11 @@ extern char * _getpty(int *, int, mode_t, int);
*/

#ifdef WORDS_BIGENDIAN
#define PY_BIG_ENDIAN 1
#define PY_LITTLE_ENDIAN 0
# define PY_BIG_ENDIAN 1
# define PY_LITTLE_ENDIAN 0
#else
#define PY_BIG_ENDIAN 0
#define PY_LITTLE_ENDIAN 1
# define PY_BIG_ENDIAN 0
# define PY_LITTLE_ENDIAN 1
#endif

#ifdef Py_BUILD_CORE
Expand Down
8 changes: 8 additions & 0 deletions Lib/test/test_capi.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
# Skip this test if the _testcapi module isn't available.
_testcapi = support.import_module('_testcapi')

import _testinternalcapi

# Were we compiled --with-pydebug or with #define Py_DEBUG?
Py_DEBUG = hasattr(sys, 'gettotalrefcount')

Expand Down Expand Up @@ -658,6 +660,12 @@ class Test_testcapi(unittest.TestCase):
if name.startswith('test_') and not name.endswith('_code'))


class Test_testinternalcapi(unittest.TestCase):
locals().update((name, getattr(_testinternalcapi, name))
for name in dir(_testinternalcapi)
if name.startswith('test_'))


class PyMemDebugTests(unittest.TestCase):
PYTHONMALLOC = 'debug'
# '0x04c06e0' or '04C06E0'
Expand Down
1 change: 1 addition & 0 deletions Makefile.pre.in
Original file line number Diff line number Diff line change
Expand Up @@ -1083,6 +1083,7 @@ PYTHON_HEADERS= \
$(srcdir)/Include/internal/pycore_abstract.h \
$(srcdir)/Include/internal/pycore_accu.h \
$(srcdir)/Include/internal/pycore_atomic.h \
$(srcdir)/Include/internal/pycore_byteswap.h \
$(srcdir)/Include/internal/pycore_bytes_methods.h \
$(srcdir)/Include/internal/pycore_call.h \
$(srcdir)/Include/internal/pycore_ceval.h \
Expand Down
4 changes: 2 additions & 2 deletions Modules/Setup
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,8 @@ _symtable symtablemodule.c
# The _sha module implements the SHA checksum algorithms.
# (NIST's Secure Hash Algorithms.)
#_sha1 sha1module.c
#_sha256 sha256module.c
#_sha512 sha512module.c
#_sha256 sha256module.c -DPy_BUILD_CORE_BUILTIN
#_sha512 sha512module.c -DPy_BUILD_CORE_BUILTIN
#_sha3 _sha3/sha3module.c

# _blake module
Expand Down
101 changes: 48 additions & 53 deletions Modules/_ctypes/cfield.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "Python.h"
#include "pycore_byteswap.h" // _Py_bswap32()

#include <ffi.h>
#ifdef MS_WIN32
Expand Down Expand Up @@ -448,46 +449,32 @@ get_ulonglong(PyObject *v, unsigned long long *p)
( ( (type)x & ~(BIT_MASK(type, size) << LOW_BIT(size)) ) | ( ((type)v & BIT_MASK(type, size)) << LOW_BIT(size) ) ) \
: (type)v)

/* byte swapping macros */
#define SWAP_2(v) \
( ( (v >> 8) & 0x00FF) | \
( (v << 8) & 0xFF00) )

#define SWAP_4(v) \
( ( (v & 0x000000FF) << 24 ) | \
( (v & 0x0000FF00) << 8 ) | \
( (v & 0x00FF0000) >> 8 ) | \
( ((v >> 24) & 0xFF)) )

#ifdef _MSC_VER
#define SWAP_8(v) \
( ( (v & 0x00000000000000FFL) << 56 ) | \
( (v & 0x000000000000FF00L) << 40 ) | \
( (v & 0x0000000000FF0000L) << 24 ) | \
( (v & 0x00000000FF000000L) << 8 ) | \
( (v & 0x000000FF00000000L) >> 8 ) | \
( (v & 0x0000FF0000000000L) >> 24 ) | \
( (v & 0x00FF000000000000L) >> 40 ) | \
( ((v >> 56) & 0xFF)) )
#if SIZEOF_SHORT == 2
# define SWAP_SHORT _Py_bswap16
#else
#define SWAP_8(v) \
( ( (v & 0x00000000000000FFLL) << 56 ) | \
( (v & 0x000000000000FF00LL) << 40 ) | \
( (v & 0x0000000000FF0000LL) << 24 ) | \
( (v & 0x00000000FF000000LL) << 8 ) | \
( (v & 0x000000FF00000000LL) >> 8 ) | \
( (v & 0x0000FF0000000000LL) >> 24 ) | \
( (v & 0x00FF000000000000LL) >> 40 ) | \
( ((v >> 56) & 0xFF)) )
# error "unsupported short size"
#endif

#define SWAP_INT SWAP_4
#if SIZEOF_INT == 4
# define SWAP_INT _Py_bswap32
#else
# error "unsupported int size"
#endif

#if SIZEOF_LONG == 4
# define SWAP_LONG SWAP_4
# define SWAP_LONG _Py_bswap32
#elif SIZEOF_LONG == 8
# define SWAP_LONG SWAP_8
# define SWAP_LONG _Py_bswap64
#else
# error "unsupported long size"
#endif

#if SIZEOF_LONG_LONG == 8
# define SWAP_LONG_LONG _Py_bswap64
#else
# error "unsupported long long size"
#endif

/*****************************************************************
* The setter methods return an object which must be kept alive, to keep the
* data valid which has been stored in the memory block. The ctypes object
Expand Down Expand Up @@ -569,12 +556,13 @@ h_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
{
long val;
short field;
if (get_long(value, &val) < 0)
if (get_long(value, &val) < 0) {
return NULL;
}
memcpy(&field, ptr, sizeof(field));
field = SWAP_2(field);
field = SWAP_SHORT(field);
field = SET(short, field, val, size);
field = SWAP_2(field);
field = SWAP_SHORT(field);
memcpy(ptr, &field, sizeof(field));
_RET(value);
}
Expand All @@ -593,7 +581,7 @@ h_get_sw(void *ptr, Py_ssize_t size)
{
short val;
memcpy(&val, ptr, sizeof(val));
val = SWAP_2(val);
val = SWAP_SHORT(val);
GET_BITFIELD(val, size);
return PyLong_FromLong(val);
}
Expand All @@ -616,12 +604,13 @@ H_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
{
unsigned long val;
unsigned short field;
if (get_ulong(value, &val) < 0)
if (get_ulong(value, &val) < 0) {
return NULL;
}
memcpy(&field, ptr, sizeof(field));
field = SWAP_2(field);
field = SWAP_SHORT(field);
field = SET(unsigned short, field, val, size);
field = SWAP_2(field);
field = SWAP_SHORT(field);
memcpy(ptr, &field, sizeof(field));
_RET(value);
}
Expand All @@ -641,7 +630,7 @@ H_get_sw(void *ptr, Py_ssize_t size)
{
unsigned short val;
memcpy(&val, ptr, sizeof(val));
val = SWAP_2(val);
val = SWAP_SHORT(val);
GET_BITFIELD(val, size);
return PyLong_FromLong(val);
}
Expand All @@ -664,8 +653,9 @@ i_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
{
long val;
int field;
if (get_long(value, &val) < 0)
if (get_long(value, &val) < 0) {
return NULL;
}
memcpy(&field, ptr, sizeof(field));
field = SWAP_INT(field);
field = SET(int, field, val, size);
Expand Down Expand Up @@ -757,8 +747,9 @@ I_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
{
unsigned long val;
unsigned int field;
if (get_ulong(value, &val) < 0)
if (get_ulong(value, &val) < 0) {
return NULL;
}
memcpy(&field, ptr, sizeof(field));
field = SWAP_INT(field);
field = SET(unsigned int, field, (unsigned int)val, size);
Expand Down Expand Up @@ -805,8 +796,9 @@ l_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
{
long val;
long field;
if (get_long(value, &val) < 0)
if (get_long(value, &val) < 0) {
return NULL;
}
memcpy(&field, ptr, sizeof(field));
field = SWAP_LONG(field);
field = SET(long, field, val, size);
Expand Down Expand Up @@ -853,8 +845,9 @@ L_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
{
unsigned long val;
unsigned long field;
if (get_ulong(value, &val) < 0)
if (get_ulong(value, &val) < 0) {
return NULL;
}
memcpy(&field, ptr, sizeof(field));
field = SWAP_LONG(field);
field = SET(unsigned long, field, val, size);
Expand Down Expand Up @@ -901,12 +894,13 @@ q_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
{
long long val;
long long field;
if (get_longlong(value, &val) < 0)
if (get_longlong(value, &val) < 0) {
return NULL;
}
memcpy(&field, ptr, sizeof(field));
field = SWAP_8(field);
field = SWAP_LONG_LONG(field);
field = SET(long long, field, val, size);
field = SWAP_8(field);
field = SWAP_LONG_LONG(field);
memcpy(ptr, &field, sizeof(field));
_RET(value);
}
Expand All @@ -925,7 +919,7 @@ q_get_sw(void *ptr, Py_ssize_t size)
{
long long val;
memcpy(&val, ptr, sizeof(val));
val = SWAP_8(val);
val = SWAP_LONG_LONG(val);
GET_BITFIELD(val, size);
return PyLong_FromLongLong(val);
}
Expand All @@ -948,12 +942,13 @@ Q_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
{
unsigned long long val;
unsigned long long field;
if (get_ulonglong(value, &val) < 0)
if (get_ulonglong(value, &val) < 0) {
return NULL;
}
memcpy(&field, ptr, sizeof(field));
field = SWAP_8(field);
field = SWAP_LONG_LONG(field);
field = SET(unsigned long long, field, val, size);
field = SWAP_8(field);
field = SWAP_LONG_LONG(field);
memcpy(ptr, &field, sizeof(field));
_RET(value);
}
Expand All @@ -972,7 +967,7 @@ Q_get_sw(void *ptr, Py_ssize_t size)
{
unsigned long long val;
memcpy(&val, ptr, sizeof(val));
val = SWAP_8(val);
val = SWAP_LONG_LONG(val);
GET_BITFIELD(val, size);
return PyLong_FromUnsignedLongLong(val);
}
Expand Down
Loading