Skip to content

Commit 1e17c93

Browse files
kernighJens-G
authored andcommitted
rewrite the endian conversion to fix a big-endian host
Client: py Change htolell(dub) to htolell(transfer.t) in compact.h, because the conversion takes a long long, not a double. This matters on a big-endian host, where the conversion must swap bytes. The big-endian letohll(n) failed because ntohl(n) is just n, doesn't swap n. Rewrite ntohll(n) and letohll(n) to use the same code with both big-endian and little-endian hosts. Expect the compiler to optimize away one of ntohll(n) or letohll(n) when it doesn't swap n.
1 parent 5b096a0 commit 1e17c93

File tree

2 files changed

+32
-60
lines changed

2 files changed

+32
-60
lines changed

lib/py/src/ext/compact.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ class CompactProtocol : public ProtocolBase<CompactProtocol> {
4949
double f;
5050
int64_t t;
5151
} transfer;
52-
transfer.f = htolell(dub);
52+
transfer.f = dub;
53+
transfer.t = htolell(transfer.t);
5354
writeBuffer(reinterpret_cast<char*>(&transfer.t), sizeof(int64_t));
5455
}
5556

lib/py/src/ext/endian.h

Lines changed: 30 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -27,70 +27,41 @@
2727
#else
2828
#include <winsock2.h>
2929
#pragma comment(lib, "ws2_32.lib")
30-
#define BIG_ENDIAN (4321)
31-
#define LITTLE_ENDIAN (1234)
32-
#define BYTE_ORDER LITTLE_ENDIAN
3330
#define inline __inline
3431
#endif
3532

36-
/* Fix endianness issues on Solaris */
37-
#if defined(__SVR4) && defined(__sun)
38-
#if defined(__i386) && !defined(__i386__)
39-
#define __i386__
40-
#endif
33+
static inline unsigned long long ntohll(unsigned long long n) {
34+
union {
35+
unsigned long long f;
36+
unsigned char t[8];
37+
} u;
38+
u.f = n;
39+
return static_cast<unsigned long long>(u.t[0]) << 56
40+
| static_cast<unsigned long long>(u.t[1]) << 48
41+
| static_cast<unsigned long long>(u.t[2]) << 40
42+
| static_cast<unsigned long long>(u.t[3]) << 32
43+
| static_cast<unsigned long long>(u.t[4]) << 24
44+
| static_cast<unsigned long long>(u.t[5]) << 16
45+
| static_cast<unsigned long long>(u.t[6]) << 8 | static_cast<unsigned long long>(u.t[7]);
46+
}
4147

42-
#ifndef BIG_ENDIAN
43-
#define BIG_ENDIAN (4321)
44-
#endif
45-
#ifndef LITTLE_ENDIAN
46-
#define LITTLE_ENDIAN (1234)
47-
#endif
48+
#define htonll(n) ntohll(n)
4849

49-
/* I386 is LE, even on Solaris */
50-
#if !defined(BYTE_ORDER) && defined(__i386__)
51-
#define BYTE_ORDER LITTLE_ENDIAN
52-
#endif
53-
#endif
50+
static inline unsigned long long letohll(unsigned long long n) {
51+
union {
52+
unsigned long long f;
53+
unsigned char t[8];
54+
} u;
55+
u.f = n;
56+
return static_cast<unsigned long long>(u.t[0]) | static_cast<unsigned long long>(u.t[1]) << 8
57+
| static_cast<unsigned long long>(u.t[2]) << 16
58+
| static_cast<unsigned long long>(u.t[3]) << 24
59+
| static_cast<unsigned long long>(u.t[4]) << 32
60+
| static_cast<unsigned long long>(u.t[5]) << 40
61+
| static_cast<unsigned long long>(u.t[6]) << 48
62+
| static_cast<unsigned long long>(u.t[7]) << 56;
63+
}
5464

55-
#ifndef __BYTE_ORDER
56-
#if defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN)
57-
#define __BYTE_ORDER BYTE_ORDER
58-
#define __LITTLE_ENDIAN LITTLE_ENDIAN
59-
#define __BIG_ENDIAN BIG_ENDIAN
60-
#else
61-
#error "Cannot determine endianness"
62-
#endif
63-
#endif
64-
65-
// Same comment as the enum. Sorry.
66-
#if __BYTE_ORDER == __BIG_ENDIAN
67-
#define ntohll(n) (n)
68-
#define htonll(n) (n)
69-
#if defined(__GNUC__) && defined(__GLIBC__)
70-
#include <byteswap.h>
71-
#define letohll(n) bswap_64(n)
72-
#define htolell(n) bswap_64(n)
73-
#else /* GNUC & GLIBC */
74-
#define letohll(n) ((((unsigned long long)ntohl(n)) << 32) + ntohl(n >> 32))
75-
#define htolell(n) ((((unsigned long long)htonl(n)) << 32) + htonl(n >> 32))
76-
#endif
77-
#elif __BYTE_ORDER == __LITTLE_ENDIAN
78-
#if defined(__GNUC__) && defined(__GLIBC__)
79-
#include <byteswap.h>
80-
#define ntohll(n) bswap_64(n)
81-
#define htonll(n) bswap_64(n)
82-
#elif defined(_MSC_VER)
83-
#include <stdlib.h>
84-
#define ntohll(n) _byteswap_uint64(n)
85-
#define htonll(n) _byteswap_uint64(n)
86-
#else /* GNUC & GLIBC */
87-
#define ntohll(n) ((((unsigned long long)ntohl(n)) << 32) + ntohl(n >> 32))
88-
#define htonll(n) ((((unsigned long long)htonl(n)) << 32) + htonl(n >> 32))
89-
#endif /* GNUC & GLIBC */
90-
#define letohll(n) (n)
91-
#define htolell(n) (n)
92-
#else /* __BYTE_ORDER */
93-
#error "Can't define htonll or ntohll!"
94-
#endif
65+
#define htolell(n) letohll(n)
9566

9667
#endif // THRIFT_PY_ENDIAN_H

0 commit comments

Comments
 (0)