Skip to content

Commit eb3dc58

Browse files
committed
Fix issue #24
Bump version Update copyrights
1 parent 5f5e11f commit eb3dc58

9 files changed

Lines changed: 173 additions & 26 deletions

File tree

cmp.c

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
The MIT License (MIT)
33
4-
Copyright (c) 2015 Charles Gunyon
4+
Copyright (c) 2017 Charles Gunyon
55
66
Permission is hereby granted, free of charge, to any person obtaining a copy
77
of this software and associated documentation files (the "Software"), to deal
@@ -28,7 +28,7 @@ THE SOFTWARE.
2828

2929
#include "cmp.h"
3030

31-
static const uint32_t version = 15;
31+
static const uint32_t version = 16;
3232
static const uint32_t mp_version = 5;
3333

3434
enum {
@@ -177,9 +177,7 @@ static uint64_t be64(uint64_t x) {
177177
return x;
178178
}
179179

180-
static float befloat(float x) {
181-
char *b = (char *)&x;
182-
180+
static void decode_befloat(char *b) {
183181
if (!is_bigendian()) {
184182
char swap = 0;
185183

@@ -191,13 +189,9 @@ static float befloat(float x) {
191189
b[1] = b[2];
192190
b[2] = swap;
193191
}
194-
195-
return x;
196192
}
197193

198-
static double bedouble(double x) {
199-
char *b = (char *)&x;
200-
194+
static void decode_bedouble(char *b) {
201195
if (!is_bigendian()) {
202196
char swap = 0;
203197

@@ -217,8 +211,6 @@ static double bedouble(double x) {
217211
b[3] = b[4];
218212
b[4] = swap;
219213
}
220-
221-
return x;
222214
}
223215

224216
static bool read_byte(cmp_ctx_t *ctx, uint8_t *x) {
@@ -405,7 +397,20 @@ bool cmp_write_float(cmp_ctx_t *ctx, float f) {
405397
if (!write_type_marker(ctx, FLOAT_MARKER))
406398
return false;
407399

408-
f = befloat(f);
400+
/*
401+
* We may need to swap the float's bytes, but we can't just swap them inside
402+
* the float because the swapped bytes may not constitute a valid float.
403+
* Therefore, we have to create a buffer and swap the bytes there.
404+
*/
405+
if (!is_bigendian()) {
406+
char swapped[sizeof(float)];
407+
char *fbuf = (char *)&f;
408+
409+
for (size_t i = 0; i < sizeof(float); i++)
410+
swapped[i] = fbuf[sizeof(float) - i - 1];
411+
412+
return ctx->write(ctx, swapped, sizeof(float));
413+
}
409414

410415
return ctx->write(ctx, &f, sizeof(float));
411416
}
@@ -414,7 +419,16 @@ bool cmp_write_double(cmp_ctx_t *ctx, double d) {
414419
if (!write_type_marker(ctx, DOUBLE_MARKER))
415420
return false;
416421

417-
d = bedouble(d);
422+
/* Same deal for doubles */
423+
if (!is_bigendian()) {
424+
char swapped[sizeof(double)];
425+
char *dbuf = (char *)&d;
426+
427+
for (size_t i = 0; i < sizeof(double); i++)
428+
swapped[i] = dbuf[sizeof(double) - i - 1];
429+
430+
return ctx->write(ctx, swapped, sizeof(double));
431+
}
418432

419433
return ctx->write(ctx, &d, sizeof(double));
420434
}
@@ -2137,20 +2151,26 @@ bool cmp_read_object(cmp_ctx_t *ctx, cmp_object_t *obj) {
21372151
obj->as.ext.type = ext_type;
21382152
}
21392153
else if (type_marker == FLOAT_MARKER) {
2154+
char bytes[sizeof(float)];
2155+
21402156
obj->type = CMP_TYPE_FLOAT;
2141-
if (!ctx->read(ctx, &obj->as.flt, sizeof(float))) {
2157+
if (!ctx->read(ctx, bytes, sizeof(float))) {
21422158
ctx->error = DATA_READING_ERROR;
21432159
return false;
21442160
}
2145-
obj->as.flt = befloat(obj->as.flt);
2161+
decode_befloat(bytes);
2162+
obj->as.flt = *(float *)(void *)bytes;
21462163
}
21472164
else if (type_marker == DOUBLE_MARKER) {
2165+
char bytes[sizeof(double)];
2166+
21482167
obj->type = CMP_TYPE_DOUBLE;
2149-
if (!ctx->read(ctx, &obj->as.dbl, sizeof(double))) {
2168+
if (!ctx->read(ctx, bytes, sizeof(double))) {
21502169
ctx->error = DATA_READING_ERROR;
21512170
return false;
21522171
}
2153-
obj->as.dbl = bedouble(obj->as.dbl);
2172+
decode_bedouble(bytes);
2173+
obj->as.dbl = *(double *)(void *)bytes;
21542174
}
21552175
else if (type_marker == U8_MARKER) {
21562176
obj->type = CMP_TYPE_UINT8;

cmp.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
The MIT License (MIT)
33
4-
Copyright (c) 2015 Charles Gunyon
4+
Copyright (c) 2017 Charles Gunyon
55
66
Permission is hereby granted, free of charge, to any person obtaining a copy
77
of this software and associated documentation files (the "Software"), to deal

examples/example1.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
The MIT License (MIT)
33
4-
Copyright (c) 2015 Charles Gunyon
4+
Copyright (c) 2017 Charles Gunyon
55
66
Permission is hereby granted, free of charge, to any person obtaining a copy
77
of this software and associated documentation files (the "Software"), to deal

examples/example2.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
The MIT License (MIT)
33
4-
Copyright (c) 2015 Charles Gunyon
4+
Copyright (c) 2017 Charles Gunyon
55
66
Permission is hereby granted, free of charge, to any person obtaining a copy
77
of this software and associated documentation files (the "Software"), to deal

test/buf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
The MIT License (MIT)
33
4-
Copyright (c) 2015 Charles Gunyon
4+
Copyright (c) 2017 Charles Gunyon
55
66
Permission is hereby granted, free of charge, to any person obtaining a copy
77
of this software and associated documentation files (the "Software"), to deal

test/buf.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
The MIT License (MIT)
33
4-
Copyright (c) 2015 Charles Gunyon
4+
Copyright (c) 2017 Charles Gunyon
55
66
Permission is hereby granted, free of charge, to any person obtaining a copy
77
of this software and associated documentation files (the "Software"), to deal

test/test.c

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
The MIT License (MIT)
33
4-
Copyright (c) 2015 Charles Gunyon
4+
Copyright (c) 2017 Charles Gunyon
55
66
Permission is hereby granted, free of charge, to any person obtaining a copy
77
of this software and associated documentation files (the "Software"), to deal
@@ -2769,6 +2769,132 @@ bool run_ext_tests(void) {
27692769
return true;
27702770
}
27712771

2772+
/* Thanks to andreyvps for this test */
2773+
bool run_float_flip_tests(void) {
2774+
buf_t buf;
2775+
cmp_ctx_t cmp;
2776+
float in;
2777+
float out;
2778+
char init[4];
2779+
char outnit[4];
2780+
2781+
setup_cmp_and_buf(&cmp, &buf);
2782+
// Writing and reading a float's bytes using cmp mangles one of the bytes
2783+
// for certain floats. This is one of them.
2784+
2785+
// Specify the binary representation of a problematic float
2786+
init[0] = -1;
2787+
init[1] = -121;
2788+
init[2] = -95;
2789+
init[3] = -66;
2790+
2791+
// construct the float from the memory, should be -0.315490693
2792+
memcpy(&in, init, sizeof(in));
2793+
2794+
error_clear();
2795+
2796+
if (!cmp_write_float(&cmp, in)) {
2797+
error_printf("run_float_flip_test:%d ", __LINE__);
2798+
error_printf("cmp_write_float(&cmp, %f) failed: %s\n",
2799+
in, cmp_strerror(&cmp)
2800+
);
2801+
return false;
2802+
}
2803+
2804+
// cmp writes the float header, then the bytes of the float in reversed order
2805+
// (endianness)
2806+
2807+
if (buf.data[1] != init[3]) {
2808+
error_printf("run_float_flip_test:%d ", __LINE__);
2809+
error_printf("[1] 0x%02x != 0x%02x\n", buf.data[1], init[3]);
2810+
return false;
2811+
}
2812+
2813+
if (buf.data[2] != init[2]) {
2814+
error_printf("run_float_flip_test:%d ", __LINE__);
2815+
error_printf("[2] 0x%02x != 0x%02x\n", buf.data[2], init[2]);
2816+
return false;
2817+
}
2818+
2819+
// asserts for 3rd output byte below
2820+
2821+
if (buf.data[4] != init[0]) {
2822+
error_printf("run_float_flip_test:%d ", __LINE__);
2823+
error_printf("[4] 0x%02x != 0x%02x\n", buf.data[4], init[0]);
2824+
return false;
2825+
}
2826+
2827+
// serialization flips the 2nd byte in this case
2828+
2829+
#if 0
2830+
if (buf.data[3] == init[1]) {
2831+
error_printf("run_float_flip_test:%d ", __LINE__);
2832+
error_printf("[3] 0x%02x == 0x%02x\n", buf.data[3], init[1]);
2833+
return false;
2834+
}
2835+
2836+
if (((signed char )buf.data[3]) != -57) {
2837+
error_printf("run_float_flip_test:%d ", __LINE__);
2838+
error_printf("[3] 0x%02x != -57\n", buf.data[3]);
2839+
return false;
2840+
}
2841+
#endif
2842+
2843+
M_BufferSeek(&buf, 0);
2844+
2845+
// read in the float using cmp.
2846+
if (!cmp_read_float(&cmp, &out)) {
2847+
error_printf("run_float_flip_test:%d ", __LINE__);
2848+
error_printf("cmp_read_float(&cmp, &out) failed: %s\n",
2849+
cmp_strerror(&cmp)
2850+
);
2851+
return false;
2852+
}
2853+
2854+
memcpy(outnit, &out, sizeof(out));
2855+
2856+
// The reader reads in exactly what was in the buffer
2857+
if (buf.data[1] != outnit[3]) {
2858+
error_printf("run_float_flip_test:%d ", __LINE__);
2859+
error_printf("[1] 0x%02x != 0x%02x\n", buf.data[1], outnit[3]);
2860+
return false;
2861+
}
2862+
2863+
if (buf.data[2] != outnit[2]) {
2864+
error_printf("run_float_flip_test:%d ", __LINE__);
2865+
error_printf("[2] 0x%02x != 0x%02x\n", buf.data[2], outnit[2]);
2866+
return false;
2867+
}
2868+
2869+
if (buf.data[3] != outnit[1]) {
2870+
error_printf("run_float_flip_test:%d ", __LINE__);
2871+
error_printf("[3] 0x%02x != 0x%02x\n", buf.data[3], outnit[1]);
2872+
return false;
2873+
}
2874+
2875+
if (buf.data[4] != outnit[0]) {
2876+
error_printf("run_float_flip_test:%d ", __LINE__);
2877+
error_printf("[4] 0x%02x != 0x%02x\n", buf.data[4], outnit[0]);
2878+
return false;
2879+
}
2880+
2881+
// The reader only seems ok. The issue happens when you fiddle with the float's bits
2882+
// in the first place. By the time you write, it's a "valid" float (though has the wrong
2883+
// contents), so when you read it, you're reading a seemingly ok float. When you fix
2884+
// the writer to write out the correct bytes, the reader then makes the same mistake.
2885+
if (in != out) {
2886+
error_printf("run_float_flip_test:%d ", __LINE__);
2887+
error_printf("%f != %f\n", in, out);
2888+
return false;
2889+
}
2890+
2891+
// The fix is to write the flipped bytes to a buffer and then write that buffer out.
2892+
// On the read end, you read into a buffer, then write the flipped bytes into a float.
2893+
// This way, the float is never populated with invalid bytes.
2894+
2895+
return true;
2896+
}
2897+
27722898
bool run_obj_tests(void) {
27732899
buf_t buf;
27742900
cmp_ctx_t cmp;
@@ -3370,6 +3496,7 @@ int main(void) {
33703496
run_tests(map);
33713497
run_tests(ext);
33723498
run_tests(obj);
3499+
run_tests(float_flip);
33733500

33743501
puts("\nAll tests pass!\n");
33753502

test/utils.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
The MIT License (MIT)
33
4-
Copyright (c) 2015 Charles Gunyon
4+
Copyright (c) 2017 Charles Gunyon
55
66
Permission is hereby granted, free of charge, to any person obtaining a copy
77
of this software and associated documentation files (the "Software"), to deal

test/utils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
The MIT License (MIT)
33
4-
Copyright (c) 2015 Charles Gunyon
4+
Copyright (c) 2017 Charles Gunyon
55
66
Permission is hereby granted, free of charge, to any person obtaining a copy
77
of this software and associated documentation files (the "Software"), to deal

0 commit comments

Comments
 (0)