scaling-crash-test.c revision 6ba797d6
1#include <assert.h>
2#include <stdlib.h>
3#include <stdio.h>
4#include <string.h>
5#include "pixman.h"
6
7/*
8 * We have a source image filled with solid color, set NORMAL or PAD repeat,
9 * and some transform which results in nearest neighbour scaling.
10 *
11 * The expected result is either that the destination image filled with this solid
12 * color or, if the transformation is such that we can't composite anything at
13 * all, that nothing has changed in the destination.
14 *
15 * The surrounding memory of the source image is a different solid color so that
16 * we are sure to get failures if we access it.
17 */
18static int
19run_test (int32_t		dst_width,
20	  int32_t		dst_height,
21	  int32_t		src_width,
22	  int32_t		src_height,
23	  int32_t		src_x,
24	  int32_t		src_y,
25	  int32_t		scale_x,
26	  int32_t		scale_y,
27	  pixman_filter_t	filter,
28	  pixman_repeat_t	repeat)
29{
30    pixman_image_t *   src_img;
31    pixman_image_t *   dst_img;
32    pixman_transform_t transform;
33    uint32_t *         srcbuf;
34    uint32_t *         dstbuf;
35    pixman_box32_t     box = { 0, 0, src_width, src_height };
36    pixman_color_t     color_cc = { 0xcccc, 0xcccc, 0xcccc, 0xcccc };
37    int result;
38    int i;
39
40    static const pixman_fixed_t kernel[] =
41    {
42#define D(f)	(pixman_double_to_fixed (f) + 0x0001)
43
44	pixman_int_to_fixed (5),
45	pixman_int_to_fixed (5),
46	D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0),
47	D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0),
48	D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0),
49	D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0),
50	D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0)
51    };
52
53    result = 0;
54
55    srcbuf = (uint32_t *)malloc ((src_width + 10) * (src_height + 10) * 4);
56    dstbuf = (uint32_t *)malloc (dst_width * dst_height * 4);
57
58    memset (srcbuf, 0x88, src_width * src_height * 4);
59    memset (dstbuf, 0x33, dst_width * dst_height * 4);
60
61    src_img = pixman_image_create_bits (
62        PIXMAN_a8r8g8b8, src_width, src_height,
63	srcbuf + (src_width + 10) * 5 + 5, (src_width + 10) * 4);
64
65    pixman_image_fill_boxes (PIXMAN_OP_SRC, src_img, &color_cc, 1, &box);
66
67    dst_img = pixman_image_create_bits (
68        PIXMAN_a8r8g8b8, dst_width, dst_height, dstbuf, dst_width * 4);
69
70    pixman_transform_init_scale (&transform, scale_x, scale_y);
71    pixman_image_set_transform (src_img, &transform);
72    pixman_image_set_repeat (src_img, repeat);
73    if (filter == PIXMAN_FILTER_CONVOLUTION)
74	pixman_image_set_filter (src_img, filter, kernel, 27);
75    else
76	pixman_image_set_filter (src_img, filter, NULL, 0);
77
78    pixman_image_composite (PIXMAN_OP_SRC, src_img, NULL, dst_img,
79                            src_x, src_y, 0, 0, 0, 0, dst_width, dst_height);
80
81    pixman_image_unref (src_img);
82    pixman_image_unref (dst_img);
83
84    for (i = 0; i < dst_width * dst_height; i++)
85    {
86	if (dstbuf[i] != 0xCCCCCCCC && dstbuf[i] != 0x33333333)
87	{
88	    result = 1;
89	    break;
90	}
91    }
92
93    free (srcbuf);
94    free (dstbuf);
95    return result;
96}
97
98typedef struct filter_info_t filter_info_t;
99struct filter_info_t
100{
101    pixman_filter_t value;
102    char name[28];
103};
104
105static const filter_info_t filters[] =
106{
107    { PIXMAN_FILTER_NEAREST, "NEAREST" },
108    { PIXMAN_FILTER_BILINEAR, "BILINEAR" },
109    { PIXMAN_FILTER_CONVOLUTION, "CONVOLUTION" },
110};
111
112typedef struct repeat_info_t repeat_info_t;
113struct repeat_info_t
114{
115    pixman_repeat_t value;
116    char name[28];
117};
118
119
120static const repeat_info_t repeats[] =
121{
122    { PIXMAN_REPEAT_PAD, "PAD" },
123    { PIXMAN_REPEAT_REFLECT, "REFLECT" },
124    { PIXMAN_REPEAT_NORMAL, "NORMAL" }
125};
126
127static int
128do_test (int32_t		dst_size,
129	 int32_t		src_size,
130	 int32_t		src_offs,
131	 int32_t		scale_factor)
132{
133#define N_ELEMENTS(a)	(sizeof (a) / sizeof ((a)[0]))
134    int i, j;
135
136    for (i = 0; i < N_ELEMENTS(filters); ++i)
137    {
138	for (j = 0; j < N_ELEMENTS (repeats); ++j)
139	{
140	    /* horizontal test */
141	    if (run_test (dst_size, 1,
142			  src_size, 1,
143			  src_offs, 0,
144			  scale_factor, 65536,
145			  filters[i].value,
146			  repeats[j].value) != 0)
147	    {
148		printf ("Vertical test failed with %s filter and repeat mode %s\n",
149			filters[i].name, repeats[j].name);
150
151		return 1;
152	    }
153
154	    /* vertical test */
155	    if (run_test (1, dst_size,
156			  1, src_size,
157			  0, src_offs,
158			  65536, scale_factor,
159			  filters[i].value,
160			  repeats[j].value) != 0)
161	    {
162		printf ("Vertical test failed with %s filter and repeat mode %s\n",
163			filters[i].name, repeats[j].name);
164
165		return 1;
166	    }
167	}
168    }
169
170    return 0;
171}
172
173int
174main (int argc, char *argv[])
175{
176    int i;
177
178    pixman_disable_out_of_bounds_workaround ();
179
180    /* can potentially crash */
181    assert (do_test (
182		48000, 32767, 1, 65536 * 128) == 0);
183
184    /* can potentially get into a deadloop */
185    assert (do_test (
186		16384, 65536, 32, 32768) == 0);
187
188    /* can potentially access memory outside source image buffer */
189    assert (do_test (
190		10, 10, 0, 1) == 0);
191    assert (do_test (
192		10, 10, 0, 0) == 0);
193
194    for (i = 0; i < 100; ++i)
195    {
196	pixman_fixed_t one_seventh =
197	    (((pixman_fixed_48_16_t)pixman_fixed_1) << 16) / (7 << 16);
198
199	assert (do_test (
200		    1, 7, 3, one_seventh + i - 50) == 0);
201    }
202
203    for (i = 0; i < 100; ++i)
204    {
205	pixman_fixed_t scale =
206	    (((pixman_fixed_48_16_t)pixman_fixed_1) << 16) / (32767 << 16);
207
208	assert (do_test (
209		    1, 32767, 16383, scale + i - 50) == 0);
210    }
211
212    /* can potentially provide invalid results (out of range matrix stuff) */
213    assert (do_test (
214	48000, 32767, 16384, 65536 * 128) == 0);
215
216    return 0;
217}
218