1 /*
2  * Copyright © 2013 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 #include <gtest/gtest.h>
24 #include <signal.h>
25 #include <setjmp.h>
26 
27 #include "glxclient.h"
28 #include "glx_error.h"
29 
30 extern bool GetGLXScreenConfigs_called;
31 extern struct glx_screen *psc;
32 
33 struct attribute_test_vector {
34    const char *string;
35    int value;
36 };
37 
38 #define E(x) { # x, x }
39 
40 
41 
42 static bool got_sigsegv;
43 static jmp_buf jmp;
44 
45 static void
sigsegv_handler(int sig)46 sigsegv_handler(int sig)
47 {
48    (void) sig;
49    got_sigsegv = true;
50    longjmp(jmp, 1);
51 }
52 
53 static bool query_renderer_string_called = false;
54 static bool query_renderer_integer_called = false;
55 
56 static int
fake_query_renderer_integer(struct glx_screen * psc,int attribute,unsigned int * value)57 fake_query_renderer_integer(struct glx_screen *psc, int attribute,
58                             unsigned int *value)
59 {
60    (void) psc;
61    (void) attribute;
62    (void) value;
63 
64    query_renderer_integer_called = true;
65 
66    return -1;
67 }
68 
69 static int
fake_query_renderer_string(struct glx_screen * psc,int attribute,const char ** value)70 fake_query_renderer_string(struct glx_screen *psc, int attribute,
71                            const char **value)
72 {
73    (void) psc;
74    (void) attribute;
75    (void) value;
76 
77    query_renderer_string_called = true;
78 
79    return -1;
80 }
81 
82 struct glx_screen_vtable fake_vtable = {
83    NULL,
84    NULL,
85    fake_query_renderer_integer,
86    fake_query_renderer_string
87 };
88 
89 class query_renderer_string_test : public ::testing::Test {
90 public:
91    virtual void SetUp();
92    virtual void TearDown();
93 
94    struct glx_screen scr;
95    struct sigaction sa;
96    struct sigaction old_sa;
97    Display dpy;
98 };
99 
100 class query_renderer_integer_test : public query_renderer_string_test {
101 };
102 
SetUp()103 void query_renderer_string_test::SetUp()
104 {
105    memset(&scr, 0, sizeof(scr));
106    scr.vtable = &fake_vtable;
107    psc = &scr;
108 
109    got_sigsegv = false;
110 
111    sa.sa_handler = sigsegv_handler;
112    sigemptyset(&sa.sa_mask);
113    sa.sa_flags = 0;
114    sigaction(SIGSEGV, &sa, &old_sa);
115 }
116 
TearDown()117 void query_renderer_string_test::TearDown()
118 {
119    sigaction(SIGSEGV, &old_sa, NULL);
120 }
121 
122 /**
123  * glXQueryRendererStringMESA will return \c NULL if the query_render_string
124  * vtable entry is \c NULL.  It will also not segfault.
125  */
TEST_F(query_renderer_string_test,null_query_render_string)126 TEST_F(query_renderer_string_test, null_query_render_string)
127 {
128    struct glx_screen_vtable vtable = {
129       NULL,
130       NULL,
131       NULL,
132       NULL
133    };
134 
135    scr.vtable = &vtable;
136 
137    if (setjmp(jmp) == 0) {
138       const char *str =
139          glXQueryRendererStringMESA(&dpy, 0, 0, GLX_RENDERER_VENDOR_ID_MESA);
140       EXPECT_EQ((char *)0, str);
141    } else {
142       EXPECT_FALSE(got_sigsegv);
143    }
144 }
145 
146 /**
147  * glXQueryRendererStringMESA will not call the screen query_render_string
148  * function with an invalid GLX enum value, and it will return NULL.
149  */
TEST_F(query_renderer_string_test,invalid_attribute)150 TEST_F(query_renderer_string_test, invalid_attribute)
151 {
152    static const attribute_test_vector invalid_attributes[] = {
153       /* These values are just plain invalid for use with this extension.
154        */
155       E(0),
156       E(GLX_VENDOR),
157       E(GLX_VERSION),
158       E(GLX_EXTENSIONS),
159       E(GLX_RENDERER_VENDOR_ID_MESA + 0x10000),
160       E(GLX_RENDERER_DEVICE_ID_MESA + 0x10000),
161 
162       /* These enums are part of the extension, but they are not allowed for
163        * the string query.
164        */
165       E(GLX_RENDERER_VERSION_MESA),
166       E(GLX_RENDERER_ACCELERATED_MESA),
167       E(GLX_RENDERER_VIDEO_MEMORY_MESA),
168       E(GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA),
169       E(GLX_RENDERER_PREFERRED_PROFILE_MESA),
170       E(GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA),
171       E(GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA),
172       E(GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA),
173       E(GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA),
174    };
175 
176    for (unsigned i = 0; i < ARRAY_SIZE(invalid_attributes); i++) {
177       query_renderer_integer_called = false;
178       query_renderer_string_called = false;
179 
180       const char *str =
181          glXQueryRendererStringMESA(&dpy, 0, 0, invalid_attributes[i].value);
182       EXPECT_EQ((char *)0, str) << invalid_attributes[i].string;
183       EXPECT_FALSE(query_renderer_integer_called)
184          << invalid_attributes[i].string;
185       EXPECT_FALSE(query_renderer_string_called)
186          << invalid_attributes[i].string;
187    }
188 }
189 
190 /**
191  * glXQueryRendererStringMESA will not call GetGLXScreenConfigs if the display
192  * pointer is \c NULL.  It will also not segfault.
193  */
TEST_F(query_renderer_string_test,null_display_pointer)194 TEST_F(query_renderer_string_test, null_display_pointer)
195 {
196    if (setjmp(jmp) == 0) {
197       GetGLXScreenConfigs_called = false;
198 
199       const char *str =
200          glXQueryRendererStringMESA(NULL, 0, 0, GLX_RENDERER_VENDOR_ID_MESA);
201       EXPECT_EQ((char *)0, str);
202       EXPECT_FALSE(GetGLXScreenConfigs_called);
203    } else {
204       EXPECT_FALSE(got_sigsegv);
205    }
206 }
207 
208 /**
209  * glXQueryRendererStringMESA will return error if GetGLXScreenConfigs returns
210  * NULL.  It will also not segfault.
211  */
TEST_F(query_renderer_string_test,null_screen_pointer)212 TEST_F(query_renderer_string_test, null_screen_pointer)
213 {
214    psc = NULL;
215 
216    if (setjmp(jmp) == 0) {
217       GetGLXScreenConfigs_called = false;
218 
219       const char *str =
220          glXQueryRendererStringMESA(&dpy, 0, 0, GLX_RENDERER_VENDOR_ID_MESA);
221       EXPECT_EQ((char *)0, str);
222       EXPECT_TRUE(GetGLXScreenConfigs_called);
223    } else {
224       EXPECT_FALSE(got_sigsegv);
225    }
226 }
227 
228 /**
229  * glXQueryRendererStringMESA will not call the screen query_render_string
230  * function if the renderer is invalid, and it will return NULL.
231  */
TEST_F(query_renderer_string_test,invalid_renderer_index)232 TEST_F(query_renderer_string_test, invalid_renderer_index)
233 {
234    static const int invalid_renderer_indices[] = {
235       -1,
236       1,
237       999,
238    };
239 
240    if (setjmp(jmp) == 0) {
241       for (unsigned i = 0; i < ARRAY_SIZE(invalid_renderer_indices); i++) {
242          const char *str =
243             glXQueryRendererStringMESA(&dpy, 0,
244                                        invalid_renderer_indices[i],
245                                        GLX_RENDERER_VENDOR_ID_MESA);
246          EXPECT_EQ((char *)0, str) << invalid_renderer_indices[i];
247          EXPECT_FALSE(query_renderer_integer_called)
248             << invalid_renderer_indices[i];
249          EXPECT_FALSE(query_renderer_string_called)
250             << invalid_renderer_indices[i];
251       }
252    } else {
253       EXPECT_FALSE(got_sigsegv);
254    }
255 }
256 
257 /**
258  * glXQueryCurrentRendererStringMESA will return error if there is no context
259  * current.  It will also not segfault.
260  */
TEST_F(query_renderer_string_test,no_current_context)261 TEST_F(query_renderer_string_test, no_current_context)
262 {
263    if (setjmp(jmp) == 0) {
264       const char *str =
265          glXQueryCurrentRendererStringMESA(GLX_RENDERER_VENDOR_ID_MESA);
266       EXPECT_EQ((char *)0, str);
267    } else {
268       EXPECT_FALSE(got_sigsegv);
269    }
270 }
271 
272 /**
273  * glXQueryCurrentRendererIntegerMESA will return \c NULL if the
274  * query_render_string vtable entry is \c NULL.  It will also not segfault.
275  */
TEST_F(query_renderer_integer_test,null_query_render_string)276 TEST_F(query_renderer_integer_test, null_query_render_string)
277 {
278    struct glx_screen_vtable vtable = {
279       NULL,
280       NULL,
281       NULL,
282       NULL
283    };
284 
285    scr.vtable = &vtable;
286 
287    if (setjmp(jmp) == 0) {
288       unsigned value = 0xDEADBEEF;
289       Bool success = glXQueryRendererIntegerMESA(&dpy, 0, 0,
290                                                  GLX_RENDERER_VENDOR_ID_MESA,
291                                                  &value);
292       EXPECT_FALSE(success);
293       EXPECT_EQ(0xDEADBEEF, value);
294    } else {
295       EXPECT_FALSE(got_sigsegv);
296    }
297 }
298 
299 /**
300  * glXQueryCurrentRendererIntegerMESA will not call the screen
301  * query_render_string function with an invalid GLX enum value, and it will
302  * return NULL.
303  */
TEST_F(query_renderer_integer_test,invalid_attribute)304 TEST_F(query_renderer_integer_test, invalid_attribute)
305 {
306    static const attribute_test_vector invalid_attributes[] = {
307       /* These values are just plain invalid for use with this extension.
308        */
309       E(0),
310       E(GLX_VENDOR),
311       E(GLX_VERSION),
312       E(GLX_EXTENSIONS),
313       E(GLX_RENDERER_VENDOR_ID_MESA + 0x10000),
314       E(GLX_RENDERER_DEVICE_ID_MESA + 0x10000),
315       E(GLX_RENDERER_VERSION_MESA + 0x10000),
316       E(GLX_RENDERER_ACCELERATED_MESA + 0x10000),
317       E(GLX_RENDERER_VIDEO_MEMORY_MESA + 0x10000),
318       E(GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA + 0x10000),
319       E(GLX_RENDERER_PREFERRED_PROFILE_MESA + 0x10000),
320       E(GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA + 0x10000),
321       E(GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA + 0x10000),
322       E(GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA + 0x10000),
323       E(GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA + 0x10000),
324    };
325 
326    for (unsigned i = 0; i < ARRAY_SIZE(invalid_attributes); i++) {
327       query_renderer_integer_called = false;
328       query_renderer_string_called = false;
329 
330       unsigned value = 0xDEADBEEF;
331       Bool success =
332          glXQueryRendererIntegerMESA(&dpy, 0, 0,
333                                      invalid_attributes[i].value,
334                                      &value);
335       EXPECT_FALSE(success) << invalid_attributes[i].string;
336       EXPECT_EQ(0xDEADBEEF, value) << invalid_attributes[i].string;
337       EXPECT_FALSE(query_renderer_integer_called)
338          << invalid_attributes[i].string;
339       EXPECT_FALSE(query_renderer_string_called)
340          << invalid_attributes[i].string;
341    }
342 }
343 
344 /**
345  * glXQueryCurrentRendererIntegerMESA will not call GetGLXScreenConfigs if the
346  * display pointer is \c NULL.  It will also not segfault.
347  */
TEST_F(query_renderer_integer_test,null_display_pointer)348 TEST_F(query_renderer_integer_test, null_display_pointer)
349 {
350    if (setjmp(jmp) == 0) {
351       GetGLXScreenConfigs_called = false;
352 
353       unsigned value = 0xDEADBEEF;
354       Bool success =
355          glXQueryRendererIntegerMESA(NULL, 0, 0, GLX_RENDERER_VENDOR_ID_MESA,
356                                      &value);
357       EXPECT_FALSE(success);
358       EXPECT_EQ(0xDEADBEEF, value);
359       EXPECT_FALSE(GetGLXScreenConfigs_called);
360    } else {
361       EXPECT_FALSE(got_sigsegv);
362    }
363 }
364 
365 /**
366  * glXQueryCurrentRendererIntegerMESA will return error if GetGLXScreenConfigs
367  * returns NULL.  It will also not segfault.
368  */
TEST_F(query_renderer_integer_test,null_screen_pointer)369 TEST_F(query_renderer_integer_test, null_screen_pointer)
370 {
371    psc = NULL;
372 
373    if (setjmp(jmp) == 0) {
374       GetGLXScreenConfigs_called = false;
375 
376       unsigned value = 0xDEADBEEF;
377       Bool success =
378          glXQueryRendererIntegerMESA(&dpy, 0, 0, GLX_RENDERER_VENDOR_ID_MESA,
379             &value);
380       EXPECT_FALSE(success);
381       EXPECT_EQ(0xDEADBEEF, value);
382       EXPECT_TRUE(GetGLXScreenConfigs_called);
383    } else {
384       EXPECT_FALSE(got_sigsegv);
385    }
386 }
387 
388 /**
389  * glXQueryRendererIntegerMESA will not call the screen query_render_integer
390  * function if the renderer is invalid, and it will return NULL.
391  */
TEST_F(query_renderer_integer_test,invalid_renderer_index)392 TEST_F(query_renderer_integer_test, invalid_renderer_index)
393 {
394    static const int invalid_renderer_indices[] = {
395       -1,
396       1,
397       999,
398    };
399 
400    if (setjmp(jmp) == 0) {
401       for (unsigned i = 0; i < ARRAY_SIZE(invalid_renderer_indices); i++) {
402          unsigned value = 0xDEADBEEF;
403          Bool success =
404             glXQueryRendererIntegerMESA(&dpy, 0,
405                                         invalid_renderer_indices[i],
406                                         GLX_RENDERER_VENDOR_ID_MESA,
407                                         &value);
408          EXPECT_FALSE(success) << invalid_renderer_indices[i];
409          EXPECT_EQ(0xDEADBEEF, value) << invalid_renderer_indices[i];
410          EXPECT_FALSE(query_renderer_integer_called)
411             << invalid_renderer_indices[i];
412          EXPECT_FALSE(query_renderer_string_called)
413             << invalid_renderer_indices[i];
414       }
415    } else {
416       EXPECT_FALSE(got_sigsegv);
417    }
418 }
419 
420 /**
421  * glXQueryCurrentRendererIntegerMESA will return error if there is no context
422  * current.  It will also not segfault.
423  */
TEST_F(query_renderer_integer_test,no_current_context)424 TEST_F(query_renderer_integer_test, no_current_context)
425 {
426    if (setjmp(jmp) == 0) {
427       unsigned value = 0xDEADBEEF;
428       Bool success =
429          glXQueryCurrentRendererIntegerMESA(GLX_RENDERER_VENDOR_ID_MESA,
430                                             &value);
431       EXPECT_FALSE(success);
432       EXPECT_EQ(0xDEADBEEF, value);
433    } else {
434       EXPECT_FALSE(got_sigsegv);
435    }
436 }
437