Skip to content
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

bpo-46906: Add PyFloat_Pack8() to the C API #31657

Merged
merged 2 commits into from
Mar 11, 2022
Merged

bpo-46906: Add PyFloat_Pack8() to the C API #31657

merged 2 commits into from
Mar 11, 2022

Conversation

vstinner
Copy link
Member

@vstinner vstinner commented Mar 3, 2022

Add new functions to pack and unpack C double (serialize and
deserialize):

  • PyFloat_Pack2()
  • PyFloat_Pack4()
  • PyFloat_Pack8()
  • PyFloat_Unpack2()
  • PyFloat_Unpack4()
  • PyFloat_Unpack8()

Document these functions and add unit tests.

Rename functions and move them from the internal C API to the public
C API:

  • _PyFloat_Pack2() => PyFloat_Pack2()
  • _PyFloat_Pack4() => PyFloat_Pack4()
  • _PyFloat_Pack8() => PyFloat_Pack8()
  • _PyFloat_Unpack2() => PyFloat_Unpack2()
  • _PyFloat_Unpack4() => PyFloat_Unpack4()
  • _PyFloat_Unpack8() => PyFloat_Unpack8()

Replace the "unsigned char*" type with "char*" which is more common
and easy to use.

https://bugs.python.org/issue46906

@vstinner
Copy link
Member Author

vstinner commented Mar 3, 2022

cc @methane @mdickinson

Doc/c-api/float.rst Outdated Show resolved Hide resolved
@@ -1057,10 +1056,10 @@ f_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
if (x == -1 && PyErr_Occurred())
return NULL;
#ifdef WORDS_BIGENDIAN
Copy link
Member

Choose a reason for hiding this comment

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

Can the le argument of PyFloat_{Un}Pack* be replaced with three-value endianness ( big, little, and native)? The native option would allow to move all #ifdef WORDS_BIGENDIAN fiddling inside the (up)pack functions.

Copy link
Member Author

Choose a reason for hiding this comment

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

If this parameter is changed, it will be way harder to provide this function in pythoncapi_compat to older Python versions: python/pythoncapi-compat#26 And it maybe become more complicated to write a single code base supporting old and new Python versions.

It's easy to implement the "native" behavior by checking if your system uses little endian or not with your preferred way.

  • marshal uses little endian
  • struct supports big and little endian
  • pickle uses big endian
  • ctypes supports big and little endian
  • msgpack uses big endian

So far, I didn't see a module using the "native endian". For a serialization function, it's not convenient.

Copy link
Member Author

Choose a reason for hiding this comment

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

I wrote #31832 to suggest using PY_BIG_ENDIAN macro to use the native endian.

Doc/c-api/float.rst Outdated Show resolved Hide resolved
@vstinner vstinner added the 🔨 test-with-buildbots Test PR w/ buildbots; report in status section label Mar 3, 2022
@bedevere-bot
Copy link

🤖 New build scheduled with the buildbot fleet by @vstinner for commit a02f8e9ec0c570411ce862dc2d42004cc833aeb9 🤖

If you want to schedule another build, you need to add the ":hammer: test-with-buildbots" label again.

@bedevere-bot bedevere-bot removed the 🔨 test-with-buildbots Test PR w/ buildbots; report in status section label Mar 3, 2022
@vstinner
Copy link
Member Author

vstinner commented Mar 3, 2022

I launch a job on buildbots to see how tests go on various architectures and platforms.

@vstinner
Copy link
Member Author

vstinner commented Mar 3, 2022

So far, tests pass on:

  • OS: Windows, macOS, FreeBSD, Linux (Debian, Fedora, Gentoo, RHEL8, SLES)
  • Arch: x86 (32 bit, x87?, little endian), x86-64 (64 bit, SSE?, little endian), ARM64 (little endian), PPC64 (big endian), s390x (big endian)

@vstinner
Copy link
Member Author

vstinner commented Mar 3, 2022

Hum, I'm not sure if the PR is related to the USAN failure.

AMD64 Arch Linux Usan PR failed:

test_ints (ctypes.test.test_bitfields.C_Test) ... ok
/buildbot/buildarea/pull_request.pablogsal-arch-x86_64.clang-ubsan/build/Modules/_ctypes/cfield.c:554:5: runtime error: shift exponent 18446744073709551614 is too large for 16-bit type 'short'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /buildbot/buildarea/pull_request.pablogsal-arch-x86_64.clang-ubsan/build/Modules/_ctypes/cfield.c:554:5 in 

It's a test on the h format code:

#define LOW_BIT(x)  ((x) & 0xFFFF)
#define NUM_BITS(x) ((x) >> 16)

#define GET_BITFIELD(v, size)                                           \
    if (NUM_BITS(size)) {                                               \
        v <<= (sizeof(v)*8 - LOW_BIT(size) - NUM_BITS(size));           \
        v >>= (sizeof(v)*8 - NUM_BITS(size));                           \

static PyObject *
h_get(void *ptr, Py_ssize_t size)
{
    short val;
    memcpy(&val, ptr, sizeof(val));
    GET_BITFIELD(val, size); // <==== HERE
    return PyLong_FromLong((long)val);
}

static struct fielddesc formattable[] = {
    ...
    { 'h', h_set, h_get, NULL, h_set_sw, h_get_sw},
    ...
};

@vstinner
Copy link
Member Author

vstinner commented Mar 3, 2022

AMD64 Arch Linux Usan PR failed

Oh, I fact 3 tests failed: test_ctypes, test_faulthandler, test_hashlib.

But it's unrelated to the PR, UBSan is also failing without this PR. I created: https://bugs.python.org/issue46913

Copy link
Member

@mdickinson mdickinson left a comment

Choose a reason for hiding this comment

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

I've left a few comments, mostly on the docs.

Doc/c-api/float.rst Outdated Show resolved Hide resolved
Doc/c-api/float.rst Outdated Show resolved Hide resolved
Doc/c-api/float.rst Outdated Show resolved Hide resolved
Doc/c-api/float.rst Outdated Show resolved Hide resolved
Doc/c-api/float.rst Outdated Show resolved Hide resolved
attempting to unpack a bytes string containing an IEEE INF or NaN will raise an
exception.

On non-IEEE platforms with more precision, or larger dynamic range, than IEEE
Copy link
Member

Choose a reason for hiding this comment

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

Presumably once we're assuming IEEE 754 for CPython, all this text can be dropped?

Copy link
Member Author

Choose a reason for hiding this comment

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

My plan is to first fix the Python 3.11 "regression" by exposing these functions as public C API functions. And then deprecate or remove support for non-IEEE 754 platforms.

Copy link
Member Author

Choose a reason for hiding this comment

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

Require IEEE 754 support is tracked by https://bugs.python.org/issue46917

Doc/c-api/float.rst Outdated Show resolved Hide resolved
Doc/c-api/float.rst Outdated Show resolved Hide resolved
Doc/c-api/float.rst Outdated Show resolved Hide resolved
Doc/c-api/float.rst Outdated Show resolved Hide resolved
Add new functions to pack and unpack C double (serialize and
deserialize):

* PyFloat_Pack2()
* PyFloat_Pack4()
* PyFloat_Pack8()
* PyFloat_Unpack2()
* PyFloat_Unpack4()
* PyFloat_Unpack8()

Document these functions and add unit tests.

Rename functions and move them from the internal C API to the public
C API:

* _PyFloat_Pack2() => PyFloat_Pack2()
* _PyFloat_Pack4() => PyFloat_Pack4()
* _PyFloat_Pack8() => PyFloat_Pack8()
* _PyFloat_Unpack2() => PyFloat_Unpack2()
* _PyFloat_Unpack4() => PyFloat_Unpack4()
* _PyFloat_Unpack8() => PyFloat_Unpack8()

Replace the "unsigned char*" type with "char*" which is more common
and easy to use.
@vstinner
Copy link
Member Author

@mdickinson: I addressed your comments. Since the documentation is quite long and complicated, I decided to remove it from Include/cpython/floatobject.h.

@vstinner vstinner merged commit 882d809 into python:main Mar 11, 2022
@vstinner vstinner deleted the float_pack branch March 11, 2022 23:10
@vstinner
Copy link
Member Author

Thanks everyone for your valuable reviews! I merged my PR.

There is likely room for enhancement on the doc, but it will be easier to read it once it will be rendered as HTML online at: https://docs.python.org/dev/c-api/float.html First, I only moved the existing doc from comments to the Python doc. This PR was a great opportunity to update the outdated doc and fix it!

Dropping support for non-IEEE 754 floating pointer formats is now tracked by https://bugs.python.org/issue46917

@vstinner
Copy link
Member Author

Functions added to pythoncapi_compat: python/pythoncapi-compat@6d2c96e

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants