`mruby-pack` should not rely on `MRB_ENDIAN_BIG` macro; fix #4190

The `MRB_ENDIAN_BIG` macro is originally used for `NaN` boxing.
We cannot assume it is defined on every big endian platform (#4190
is the case). So instead of relying on untrusted `MRB_ENDIAN_BIG`, we
use `BYTE_ORDER` macro with a fallback function to check endian in
runtime.
parent 7e35c659
...@@ -60,19 +60,28 @@ enum { ...@@ -60,19 +60,28 @@ enum {
#define PACK_BASE64_IGNORE 0xff #define PACK_BASE64_IGNORE 0xff
#define PACK_BASE64_PADDING 0xfe #define PACK_BASE64_PADDING 0xfe
static int littleendian = 0;
const static unsigned char base64chars[] = const static unsigned char base64chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static unsigned char base64_dec_tab[128]; static unsigned char base64_dec_tab[128];
#ifdef BYTE_ORDER
static int # if BYTE_ORDER == BIG_ENDIAN
# define littleendian 0
# define check_little_endian() (void)0
# elif BYTE_ORDER == LITTLE_ENDIAN
# define littleendian 1
# define check_little_endian() (void)0
# else
/* can't distinguish endian in compile time */
static int littleendian = 0;
static void
check_little_endian(void) check_little_endian(void)
{ {
unsigned int n = 1; unsigned int n = 1;
return (*(unsigned char *)&n == 1); littleendian = (*(unsigned char *)&n == 1);
} }
# endif
#endif
static unsigned int static unsigned int
hex2int(unsigned char ch) hex2int(unsigned char ch)
...@@ -313,21 +322,23 @@ pack_double(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned i ...@@ -313,21 +322,23 @@ pack_double(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned i
d = mrb_float(o); d = mrb_float(o);
if (flags & PACK_FLAG_LITTLEENDIAN) { if (flags & PACK_FLAG_LITTLEENDIAN) {
#ifdef MRB_ENDIAN_BIG if (littleendian) {
for (i = 0; i < 8; ++i) { memcpy(RSTRING_PTR(str) + sidx, buffer, 8);
RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1]; }
else {
for (i = 0; i < 8; ++i) {
RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1];
}
} }
#else
memcpy(RSTRING_PTR(str) + sidx, buffer, 8);
#endif
} else { } else {
#ifdef MRB_ENDIAN_BIG if (littleendian) {
memcpy(RSTRING_PTR(str) + sidx, buffer, 8); for (i = 0; i < 8; ++i) {
#else RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1];
for (i = 0; i < 8; ++i) { }
RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1]; }
else {
memcpy(RSTRING_PTR(str) + sidx, buffer, 8);
} }
#endif
} }
return 8; return 8;
...@@ -341,21 +352,23 @@ unpack_double(mrb_state *mrb, const unsigned char * src, int srclen, mrb_value a ...@@ -341,21 +352,23 @@ unpack_double(mrb_state *mrb, const unsigned char * src, int srclen, mrb_value a
uint8_t *buffer = (uint8_t *)&d; uint8_t *buffer = (uint8_t *)&d;
if (flags & PACK_FLAG_LITTLEENDIAN) { if (flags & PACK_FLAG_LITTLEENDIAN) {
#ifdef MRB_ENDIAN_BIG if (littleendian) {
for (i = 0; i < 8; ++i) { memcpy(buffer, src, 8);
buffer[8 - i - 1] = src[i]; }
else {
for (i = 0; i < 8; ++i) {
buffer[8 - i - 1] = src[i];
}
} }
#else
memcpy(buffer, src, 8);
#endif
} else { } else {
#ifdef MRB_ENDIAN_BIG if (littleendian) {
memcpy(buffer, src, 8); for (i = 0; i < 8; ++i) {
#else buffer[8 - i - 1] = src[i];
for (i = 0; i < 8; ++i) { }
buffer[8 - i - 1] = src[i]; }
else {
memcpy(buffer, src, 8);
} }
#endif
} }
mrb_ary_push(mrb, ary, mrb_float_value(mrb, d)); mrb_ary_push(mrb, ary, mrb_float_value(mrb, d));
...@@ -372,21 +385,23 @@ pack_float(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned in ...@@ -372,21 +385,23 @@ pack_float(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned in
f = (float)mrb_float(o); f = (float)mrb_float(o);
if (flags & PACK_FLAG_LITTLEENDIAN) { if (flags & PACK_FLAG_LITTLEENDIAN) {
#ifdef MRB_ENDIAN_BIG if (littleendian) {
for (i = 0; i < 4; ++i) { memcpy(RSTRING_PTR(str) + sidx, buffer, 4);
RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1]; }
else {
for (i = 0; i < 4; ++i) {
RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1];
}
} }
#else
memcpy(RSTRING_PTR(str) + sidx, buffer, 4);
#endif
} else { } else {
#ifdef MRB_ENDIAN_BIG if (littleendian) {
memcpy(RSTRING_PTR(str) + sidx, buffer, 4); for (i = 0; i < 4; ++i) {
#else RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1];
for (i = 0; i < 4; ++i) { }
RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1]; }
else {
memcpy(RSTRING_PTR(str) + sidx, buffer, 4);
} }
#endif
} }
return 4; return 4;
...@@ -400,21 +415,23 @@ unpack_float(mrb_state *mrb, const unsigned char * src, int srclen, mrb_value ar ...@@ -400,21 +415,23 @@ unpack_float(mrb_state *mrb, const unsigned char * src, int srclen, mrb_value ar
uint8_t *buffer = (uint8_t *)&f; uint8_t *buffer = (uint8_t *)&f;
if (flags & PACK_FLAG_LITTLEENDIAN) { if (flags & PACK_FLAG_LITTLEENDIAN) {
#ifdef MRB_ENDIAN_BIG if (littleendian) {
for (i = 0; i < 4; ++i) { memcpy(buffer, src, 4);
buffer[4 - i - 1] = src[i]; }
else {
for (i = 0; i < 4; ++i) {
buffer[4 - i - 1] = src[i];
}
} }
#else
memcpy(buffer, src, 4);
#endif
} else { } else {
#ifdef MRB_ENDIAN_BIG if (littleendian) {
memcpy(buffer, src, 4); for (i = 0; i < 4; ++i) {
#else buffer[4 - i - 1] = src[i];
for (i = 0; i < 4; ++i) { }
buffer[4 - i - 1] = src[i]; }
else {
memcpy(buffer, src, 4);
} }
#endif
} }
mrb_ary_push(mrb, ary, mrb_float_value(mrb, f)); mrb_ary_push(mrb, ary, mrb_float_value(mrb, f));
...@@ -1297,7 +1314,7 @@ mrb_pack_unpack1(mrb_state *mrb, mrb_value str) ...@@ -1297,7 +1314,7 @@ mrb_pack_unpack1(mrb_state *mrb, mrb_value str)
void void
mrb_mruby_pack_gem_init(mrb_state *mrb) mrb_mruby_pack_gem_init(mrb_state *mrb)
{ {
littleendian = check_little_endian(); check_little_endian();
make_base64_dec_tab(); make_base64_dec_tab();
mrb_define_method(mrb, mrb->array_class, "pack", mrb_pack_pack, MRB_ARGS_REQ(1)); mrb_define_method(mrb, mrb->array_class, "pack", mrb_pack_pack, MRB_ARGS_REQ(1));
......
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