|
1 | 1 | /* |
2 | 2 | The MIT License (MIT) |
3 | 3 |
|
4 | | -Copyright (c) 2015 Charles Gunyon |
| 4 | +Copyright (c) 2017 Charles Gunyon |
5 | 5 |
|
6 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | 7 | of this software and associated documentation files (the "Software"), to deal |
@@ -2769,6 +2769,132 @@ bool run_ext_tests(void) { |
2769 | 2769 | return true; |
2770 | 2770 | } |
2771 | 2771 |
|
| 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 | + |
2772 | 2898 | bool run_obj_tests(void) { |
2773 | 2899 | buf_t buf; |
2774 | 2900 | cmp_ctx_t cmp; |
@@ -3370,6 +3496,7 @@ int main(void) { |
3370 | 3496 | run_tests(map); |
3371 | 3497 | run_tests(ext); |
3372 | 3498 | run_tests(obj); |
| 3499 | + run_tests(float_flip); |
3373 | 3500 |
|
3374 | 3501 | puts("\nAll tests pass!\n"); |
3375 | 3502 |
|
|
0 commit comments