Commit efe7f7a1 authored by Jason Madden's avatar Jason Madden

Explicitly use unsigned hex literals when [un]packing timestamps.

This should fix #86

Run a compiler with wrapv turned off to verify this.
parent 9b8ca93f
...@@ -10,6 +10,8 @@ matrix: ...@@ -10,6 +10,8 @@ matrix:
python: 3.5 python: 3.5
- os: linux - os: linux
python: 3.6 python: 3.6
# Test for https://github.com/zopefoundation/persistent/issues/86
env: CFLAGS="-fno-wrapv"
- os: linux - os: linux
python: pypy python: pypy
- os: linux - os: linux
......
...@@ -4,7 +4,10 @@ ...@@ -4,7 +4,10 @@
4.4.2 (unreleased) 4.4.2 (unreleased)
------------------ ------------------
- Nothing changed yet. - Explicitly use unsigned constants for packing and unpacking C
timestamps, fixing an arithmetic issue for GCC when optimizations
are enabled and ``-fwrapv`` is *not* enabled. See `issue 86
<https://github.com/zopefoundation/persistent/issues/86>`_.
4.4.1 (2018-08-23) 4.4.1 (2018-08-23)
......
...@@ -35,7 +35,7 @@ static char TimeStampModule_doc[] = ...@@ -35,7 +35,7 @@ static char TimeStampModule_doc[] =
To get (close to) the original seconds back, use To get (close to) the original seconds back, use
`TS_UNPACK_UINT32_FROM_BYTES` and *multiply* by this number. `TS_UNPACK_UINT32_FROM_BYTES` and *multiply* by this number.
*/ */
#define TS_SECOND_BYTES_BIAS ((double)60) / ((double)(0x10000)) / ((double)(0x10000)) #define TS_SECOND_BYTES_BIAS ((double)((double)60) / ((double)(0x10000)) / ((double)(0x10000)))
#define TS_BASE_YEAR 1900 #define TS_BASE_YEAR 1900
#define TS_MINUTES_PER_DAY 1440 #define TS_MINUTES_PER_DAY 1440
/* We pretend there are always 31 days in a month; this has us using /* We pretend there are always 31 days in a month; this has us using
...@@ -45,6 +45,15 @@ static char TimeStampModule_doc[] = ...@@ -45,6 +45,15 @@ static char TimeStampModule_doc[] =
#define TS_MINUTES_PER_MONTH (TS_DAYS_PER_MONTH * TS_MINUTES_PER_DAY) #define TS_MINUTES_PER_MONTH (TS_DAYS_PER_MONTH * TS_MINUTES_PER_DAY)
#define TS_MINUTES_PER_YEAR (TS_MINUTES_PER_MONTH * TS_MONTHS_PER_YEAR) #define TS_MINUTES_PER_YEAR (TS_MINUTES_PER_MONTH * TS_MONTHS_PER_YEAR)
/* The U suffixes matter on these constants to be sure
the compiler generates the appropriate instructions when
optimizations are enabled. On x86_64 GCC, if -fno-wrapv is given
and -O is used, the compiler might choose to treat these as 32 bit
signed quantities otherwise, producing incorrect results on
some corner cases. See
https://github.com/zopefoundation/persistent/issues/86
*/
/** /**
* Given an unsigned int *v*, pack it into the four * Given an unsigned int *v*, pack it into the four
* unsigned char bytes beginning at *bytes*. If *v* is larger * unsigned char bytes beginning at *bytes*. If *v* is larger
...@@ -56,10 +65,10 @@ static char TimeStampModule_doc[] = ...@@ -56,10 +65,10 @@ static char TimeStampModule_doc[] =
* *
*/ */
#define TS_PACK_UINT32_INTO_BYTES(v, bytes) do { \ #define TS_PACK_UINT32_INTO_BYTES(v, bytes) do { \
*(bytes) = v / 0x1000000; \ *(bytes) = v / 0x1000000U; \
*(bytes + 1) = (v % 0x1000000) / 0x10000; \ *(bytes + 1) = (v % 0x1000000U) / 0x10000U; \
*(bytes + 2) = (v % 0x10000) / 0x100; \ *(bytes + 2) = (v % 0x10000U) / 0x100U; \
*(bytes + 3) = v % 0x100; \ *(bytes + 3) = v % 0x100U; \
} while (0) } while (0)
/** /**
...@@ -71,7 +80,7 @@ static char TimeStampModule_doc[] = ...@@ -71,7 +80,7 @@ static char TimeStampModule_doc[] =
* may not exactly match the original value. If the original value * may not exactly match the original value. If the original value
* was greater than 2^31 it will definitely not match. * was greater than 2^31 it will definitely not match.
*/ */
#define TS_UNPACK_UINT32_FROM_BYTES(bytes) (*(bytes) * 0x1000000 + *(bytes + 1) * 0x10000 + *(bytes + 2) * 0x100 + *(bytes + 3)) #define TS_UNPACK_UINT32_FROM_BYTES(bytes) (*(bytes) * 0x1000000U + *(bytes + 1) * 0x10000U + *(bytes + 2) * 0x100U + *(bytes + 3))
typedef struct typedef struct
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment