mirror of
https://github.com/facebook/sapling.git
synced 2024-10-12 09:48:05 +03:00
6c452184cb
Summary: Previously some of this code had undefined behavior because it was performing signed shifts that could overflow into the sign bit, as the result could not be represented in a signed `int`. This caused failures when built with UBSAN. This updates the code to consistently use the built-in `_byteswap_*` functions when compiling with Microsoft Visual Studio and the `__builtin_bswap*` when compiling with gcc or clang. Reviewed By: quark-zju Differential Revision: D7008197 fbshipit-source-id: adbe22032f05a35468195922ee00ccc3ff5efff9
101 lines
2.0 KiB
C
101 lines
2.0 KiB
C
#ifndef _HG_BITMANIPULATION_H_
|
|
#define _HG_BITMANIPULATION_H_
|
|
|
|
#include <string.h>
|
|
|
|
#include "compat.h"
|
|
|
|
#if defined(_MSC_VER)
|
|
/* Windows only supports little-endian platforms */
|
|
static inline uint64_t hg_be_u64(uint64_t x)
|
|
{
|
|
return _byteswap_uint64(x);
|
|
}
|
|
static inline uint32_t hg_be_u32(uint32_t x)
|
|
{
|
|
return _byteswap_ulong(x);
|
|
}
|
|
static inline uint16_t hg_be_u16(uint16_t x)
|
|
{
|
|
return _byteswap_ushort(x);
|
|
}
|
|
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
|
static inline uint64_t hg_be_u64(uint64_t x)
|
|
{
|
|
return __builtin_bswap64(x);
|
|
}
|
|
static inline uint32_t hg_be_u32(uint32_t x)
|
|
{
|
|
return __builtin_bswap32(x);
|
|
}
|
|
static inline uint16_t hg_be_u16(uint16_t x)
|
|
{
|
|
return __builtin_bswap16(x);
|
|
}
|
|
#else
|
|
/* For completeness... */
|
|
static inline uint64_t hg_be_u64(uint64_t x)
|
|
{
|
|
return x;
|
|
}
|
|
static inline uint32_t hg_be_u32(uint32_t x)
|
|
{
|
|
return x;
|
|
}
|
|
static inline uint16_t hg_be_u16(uint16_t x)
|
|
{
|
|
return x;
|
|
}
|
|
#endif
|
|
|
|
static inline uint32_t getbe32(const char *c)
|
|
{
|
|
uint32_t value;
|
|
memcpy(&value, c, sizeof(value));
|
|
return hg_be_u32(value);
|
|
}
|
|
|
|
static inline uint16_t getbeuint16(const char *c)
|
|
{
|
|
uint16_t value;
|
|
memcpy(&value, c, sizeof(value));
|
|
return hg_be_u16(value);
|
|
}
|
|
|
|
static inline int16_t getbeint16(const char *c)
|
|
{
|
|
/*
|
|
* Note: this code technically has undefined behavior for negative
|
|
* values, although it's written in a way that the compiler and UBSAN
|
|
* hopefully shouldn't complain about it.
|
|
*
|
|
* This relies on the platform using 2s-compliment representations for
|
|
* signed integers. This isn't guaranteed by the C standard, but is
|
|
* true in practice for all modern platforms.
|
|
*/
|
|
union {
|
|
uint16_t unsignedvalue;
|
|
int16_t signedvalue;
|
|
} u;
|
|
u.unsignedvalue = getbeuint16(c);
|
|
return u.signedvalue;
|
|
}
|
|
|
|
static inline void putbe32(uint32_t x, char *c)
|
|
{
|
|
uint32_t v = hg_be_u32(x);
|
|
memcpy(c, &v, sizeof(v));
|
|
}
|
|
|
|
static inline double getbefloat64(const char *c)
|
|
{
|
|
uint64_t n;
|
|
double d;
|
|
memcpy(&n, c, sizeof(n));
|
|
n = hg_be_u64(n);
|
|
memcpy(&d, &n, sizeof(n));
|
|
return d;
|
|
}
|
|
|
|
#endif
|