1
/*
2
 * Copyright © 2021 Adrian Johnson
3
 *
4
 * Permission is hereby granted, free of charge, to any person
5
 * obtaining a copy of this software and associated documentation
6
 * files (the "Software"), to deal in the Software without
7
 * restriction, including without limitation the rights to use, copy,
8
 * modify, merge, publish, distribute, sublicense, and/or sell copies
9
 * of the Software, and to permit persons to whom the Software is
10
 * furnished to do so, subject to the following conditions:
11
 *
12
 * The above copyright notice and this permission notice shall be
13
 * included in all copies or substantial portions of the Software.
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
 * SOFTWARE.
23
 *
24
 * Author: Adrian Johnson <ajohnson@redneon.com>
25
 */
26

            
27

            
28
#include "cairo-test.h"
29

            
30
#include <cairo.h>
31

            
32
/* Uncomment to enable faulty test data in order to force a
33
 * failure. This allows the error logging path to be tested.
34
 */
35
/* #define FORCE_FAILURE 1 */
36

            
37
struct test_data {
38
    uint64_t a;
39
    uint64_t b;
40
    uint64_t result;
41
    cairo_bool_t overflow;
42
};
43

            
44
#if SIZEOF_SIZE_T == 4
45
static const struct test_data add_32bit_test_data[] = {
46
    { 0x00000000, 0x00000000, 0x00000000, 0 },
47
    { 0x00000001, 0x00000000, 0x00000001, 0 },
48
    { 0x00000000, 0x00000001, 0x00000001, 0 },
49
    { 0xffffffff, 0x00000001, 0x00000000, 1 },
50
    { 0x00000001, 0xffffffff, 0x00000000, 1 },
51
    { 0xfffffffe, 0x00000001, 0xffffffff, 0 },
52
    { 0x00000001, 0xfffffffe, 0xffffffff, 0 },
53
    { 0x12345678, 0x98765432, 0xaaaaaaaa, 0 },
54
    { 0x80000000, 0x80000000, 0x00000000, 1 },
55

            
56
#if FORCE_FAILURE
57
    { 0x00000001, 0x00000002, 0x00000004, 1 },
58
#endif
59
};
60

            
61
static const struct test_data mul_32bit_test_data[] = {
62
    { 0x00000000, 0x00000000, 0x00000000, 0 },
63
    { 0x0000ffff, 0x0000ffff, 0xfffe0001, 0 },
64
    { 0x00010000, 0x00010000, 0x00000000, 1 },
65
    { 0x00000002, 0x80000000, 0x00000000, 1 },
66
    { 0x80000000, 0x00000002, 0x00000000, 1 },
67
    { 0xffffffff, 0x00000001, 0xffffffff, 0 },
68
};
69
#endif
70

            
71
#if SIZEOF_SIZE_T == 8
72
static const struct test_data add_64bit_test_data[] = {
73
    { 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0 },
74
    { 0x0000000000000001, 0x0000000000000000, 0x0000000000000001, 0 },
75
    { 0x0000000000000000, 0x0000000000000001, 0x0000000000000001, 0 },
76
    { 0xffffffffffffffff, 0x0000000000000001, 0x0000000000000000, 1 },
77
    { 0x0000000000000001, 0xffffffffffffffff, 0x0000000000000000, 1 },
78
    { 0x0000000000000001, 0xfffffffffffffffe, 0xffffffffffffffff, 0 },
79
    { 0xfffffffffffffffe, 0x0000000000000001, 0xffffffffffffffff, 0 },
80
    { 0x123456789abcdef0, 0x987654320fedcbba, 0xaaaaaaaaaaaaaaaa, 0 },
81
    { 0x8000000000000000, 0x8000000000000000, 0x0000000000000000, 1 },
82

            
83
#if FORCE_FAILURE
84
    { 0x0000000000000001, 0x0000000000000002, 0x0000000000000004, 1 },
85
#endif
86
};
87

            
88
static const struct test_data mul_64bit_test_data[] = {
89
    { 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0 },
90
    { 0x00000000ffffffff, 0x00000000ffffffff, 0xfffffffe00000001, 0 },
91
    { 0x0000000100000000, 0x0000000100000000, 0x0000000000000000, 1 },
92
    { 0x0000000000000002, 0x8000000000000000, 0x0000000000000000, 1 },
93
    { 0x8000000000000000, 0x0000000000000002, 0x0000000000000000, 1 },
94
    { 0xffffffffffffffff, 0x0000000000000001, 0xffffffffffffffff, 0 },
95
};
96
#endif
97

            
98
static cairo_bool_t
99
30
check_if_result_fail (cairo_test_context_t *ctx,
100
                      size_t result,
101
                      cairo_bool_t overflow,
102
                      const struct test_data *data,
103
                      const char *func_name)
104
{
105
30
    int hex_digits = SIZEOF_SIZE_T * 2;
106
30
    if (overflow != data->overflow || (!data->overflow && result != data->result)) {
107
        cairo_test_log (ctx, "%s a = 0x%0*llx b = 0x%0*llx result = 0x%0*llx overflow = %d\n",
108
                        func_name,
109
                        hex_digits,
110
                        (unsigned long long)data->a,
111
                        hex_digits,
112
                        (unsigned long long)data->b,
113
                        hex_digits,
114
                        (unsigned long long)result,
115
                        overflow);
116
        if (data->overflow)
117
            cairo_test_log (ctx, "EXPECTED overflow = 1\n");
118
        else
119
            cairo_test_log (ctx, "EXPECTED result = 0x%0*llx overflow = 0\n",
120
                            hex_digits,
121
                            (unsigned long long)data->result);
122
        return TRUE;
123
    }
124
30
    return FALSE;
125
}
126

            
127
static cairo_test_status_t
128
1
preamble (cairo_test_context_t *ctx)
129
{
130
    int i;
131
    cairo_bool_t overflow;
132
    size_t result;
133

            
134
#if SIZEOF_SIZE_T == 4
135
    const struct test_data *add_data = add_32bit_test_data;
136
    int num_add_tests = ARRAY_LENGTH(add_32bit_test_data);
137
    const struct test_data *mul_data = mul_32bit_test_data;
138
    int num_mul_tests = ARRAY_LENGTH(mul_32bit_test_data);
139
#elif SIZEOF_SIZE_T == 8
140
1
    const struct test_data *add_data = add_64bit_test_data;
141
1
    int num_add_tests = ARRAY_LENGTH(add_64bit_test_data);
142
1
    const struct test_data *mul_data = mul_64bit_test_data;
143
1
    int num_mul_tests = ARRAY_LENGTH(mul_64bit_test_data);
144
#else
145
    cairo_test_log (ctx, "sizeof(size_t) = %lld is not supported by this test\n",
146
                    (unsigned long long)sizeof(size_t));
147
    return CAIRO_TEST_UNTESTED;
148
#endif
149

            
150
    /* First check the fallback versions of the overflow functions. */
151
10
    for (i = 0; i < num_add_tests; i++) {
152
9
        const struct test_data *data = &add_data[i];
153
9
        overflow = _cairo_fallback_add_size_t_overflow (data->a, data->b, &result);
154
9
        if (check_if_result_fail (ctx,
155
                                  result,
156
                                  overflow,
157
                                  data,
158
                                  "_cairo_fallback_add_size_t_overflow"))
159
        {
160
            return CAIRO_TEST_FAILURE;
161
        }
162
    }
163

            
164
7
    for (i = 0; i < num_mul_tests; i++) {
165
6
        const struct test_data *data = &mul_data[i];
166
6
        overflow = _cairo_fallback_mul_size_t_overflow (data->a, data->b, &result);
167
6
        if (check_if_result_fail (ctx,
168
                                  result,
169
                                  overflow,
170
                                  data,
171
                                  "_cairo_fallback_mul_size_t_overflow"))
172
        {
173
            return CAIRO_TEST_FAILURE;
174
        }
175
    }
176
    /* Next check the compiler builtins (if available, otherwise the
177
     * fallback versions are tested again). This is to ensure the fallback version
178
     * produces identical results to the compiler builtins.
179
     */
180
10
    for (i = 0; i < num_add_tests; i++) {
181
9
        const struct test_data *data = &add_data[i];
182
9
        overflow = _cairo_add_size_t_overflow (data->a, data->b, &result);
183
9
        if (check_if_result_fail (ctx,
184
                                  result,
185
                                  overflow,
186
                                  data,
187
                                  "_cairo_add_size_t_overflow"))
188
        {
189
            return CAIRO_TEST_FAILURE;
190
        }
191
    }
192

            
193
7
    for (i = 0; i < num_mul_tests; i++) {
194
6
        const struct test_data *data = &mul_data[i];
195
6
        overflow = _cairo_mul_size_t_overflow (data->a, data->b, &result);
196
6
        if (check_if_result_fail (ctx,
197
                                  result,
198
                                  overflow,
199
                                  data,
200
                                  "_cairo_mul_size_t_overflow"))
201
        {
202
            return CAIRO_TEST_FAILURE;
203
        }
204
    }
205

            
206
1
    return CAIRO_TEST_SUCCESS;
207
}
208

            
209
1
CAIRO_TEST (overflow,
210
	    "Test the _cairo_*_size_t_overflow functions.",
211
	    "memory", /* keywords */
212
	    NULL, /* requirements */
213
	    0, 0,
214
	    preamble, NULL)