Bug Summary

File:tools/cafe-session-check-accelerated-gl-helper.c
Warning:line 504, column 30
This statement is never executed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name cafe-session-check-accelerated-gl-helper.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/rootdir/tools -fcoverage-compilation-dir=/rootdir/tools -resource-dir /usr/lib/llvm-19/lib/clang/19 -D HAVE_CONFIG_H -I . -I .. -D PKGDATADIR="/usr/share/cafe-session-manager" -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -D LOCALE_DIR="/usr/share/locale" -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2025-01-23-165114-18293-1 -x c cafe-session-check-accelerated-gl-helper.c
1/*
2 * Copyright (C) 2010 Novell, Inc.
3 * Copyright (C) 2006-2009 Red Hat, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * Author:
20 * Vincent Untz <vuntz@gnome.org>
21 *
22 * Most of the code comes from desktop-effects [1], released under GPLv2+.
23 * desktop-effects was written by:
24 * Soren Sandmann <sandmann@redhat.com>
25 *
26 * [1] http://git.fedorahosted.org/git/?p=desktop-effects.git;a=blob_plain;f=desktop-effects.c;hb=HEAD
27 */
28
29/*
30 * Here's the rationale behind this helper, quoting Owen, in his mail to the
31 * release team:
32 * (http://mail.gnome.org/archives/release-team/2010-June/msg00079.html)
33 *
34 * """
35 * There are some limits to what we can do here automatically without
36 * knowing anything about the driver situation on the system. The basic
37 * problem is that there are all sorts of suck:
38 *
39 * * No GL at all. This typically only happens if a system is
40 * misconfigured.
41 *
42 * * Only software GL. This one is easy to detect. We have code in
43 * the Fedora desktop-effects tool, etc.
44 *
45 * * GL that isn't featureful enough. (Tiny texture size limits, no
46 * texture-from-pixmap, etc.) Possible to detect with more work, but
47 * largely a fringe case.
48 *
49 * * Buggy GL. This isn't possible to detect. Except for the case where
50 * all GL programs crash. For that reason, we probably don't want
51 * gnome-session to directly try and do any GL detection; better to
52 * use a helper binary.
53 *
54 * * Horribly slow hardware GL. We could theoretically develop some sort
55 * of benchmark, but it's a tricky area. And how slow is too slow?
56 * """
57 *
58 * Some other tools are doing similar checks:
59 * - desktop-effects (Fedora Config Tool) [1]
60 * - drak3d (Mandriva Config Tool) [2]
61 * - compiz-manager (Compiz wrapper) [3]
62 *
63 * [1] http://git.fedorahosted.org/git/?p=desktop-effects.git;a=blob_plain;f=desktop-effects.c;hb=HEAD
64 * [2] http://svn.mandriva.com/cgi-bin/viewvc.cgi/soft/drak3d/trunk/lib/Xconfig/glx.pm?view=markup
65 * [3] http://git.compiz.org/fusion/misc/compiz-manager/tree/compiz-manager
66 */
67
68/* for strcasestr */
69#define _GNU_SOURCE
70
71#include <ctype.h>
72#include <locale.h>
73#include <stdio.h>
74#include <stdlib.h>
75#include <string.h>
76#include <glib.h>
77
78#include <regex.h>
79
80#ifdef __FreeBSD__
81#include <kenv.h>
82#endif
83
84#include <X11/Xlib.h>
85#include <X11/Xatom.h>
86#include <X11/extensions/Xcomposite.h>
87#include <GL/gl.h>
88#include <GL/glx.h>
89
90#include "cafe-session-check-accelerated-common.h"
91
92#define SIZE_UNSET0 0
93#define SIZE_ERROR-1 -1
94static int max_texture_size = SIZE_UNSET0;
95static int max_renderbuffer_size = SIZE_UNSET0;
96static gboolean has_llvmpipe = FALSE(0);
97
98static inline void
99_print_error (const char *str)
100{
101 fprintf (stderrstderr, "cafe-session-is-accelerated: %s\n", str);
102}
103
104#define CMDLINE_UNSET-1 -1
105#define CMDLINE_NON_FALLBACK_FORCED0 0
106#define CMDLINE_FALLBACK_FORCED1 1
107
108#if defined(__linux__1)
109static int
110_parse_kcmdline (void)
111{
112 int ret = CMDLINE_UNSET-1;
113 GRegex *regex;
114 GMatchInfo *match;
115 char *contents;
116 char *word;
117 const char *arg;
118
119 if (!g_file_get_contents ("/proc/cmdline", &contents, NULL((void*)0), NULL((void*)0)))
120 return ret;
121
122 regex = g_regex_new ("cafe.fallback=(\\S+)", 0, G_REGEX_MATCH_NOTEMPTY, NULL((void*)0));
123 if (!g_regex_match (regex, contents, G_REGEX_MATCH_NOTEMPTY, &match))
124 goto out;
125
126 word = g_match_info_fetch (match, 0);
127 g_debug ("Found command-line match '%s'", word);
128 arg = word + strlen ("cafe.fallback=");
129 if (*arg != '0' && *arg != '1')
130 fprintf (stderrstderr, "cafe-session-check-accelerated: Invalid value '%s' for cafe.fallback passed in kernel command line.\n", arg);
131 else
132 ret = atoi (arg);
133 g_free (word);
134
135out:
136 g_match_info_free (match);
137 g_regex_unref (regex);
138 g_free (contents);
139
140 g_debug ("Command-line parsed to %d", ret);
141
142 return ret;
143}
144#elif defined(__FreeBSD__)
145static int
146_parse_kcmdline (void)
147{
148 int ret = CMDLINE_UNSET-1;
149 char value[KENV_MVALLEN];
150
151 /* a compile time check to avoid unexpected stack overflow */
152 _Static_assert(KENV_MVALLEN < 1024 * 1024, "KENV_MVALLEN is too large");
153
154 if (kenv (KENV_GET, "cafe.fallback", value, KENV_MVALLEN) == -1)
155 return ret;
156
157 if (*value != '0' && *value != '1')
158 fprintf (stderrstderr, "cafe-session-is-accelerated: Invalid value '%s' for cafe.fallback passed in kernel environment.\n", value);
159 else
160 ret = atoi (value);
161
162 g_debug ("Kernel environment parsed to %d", ret);
163
164 return ret;
165}
166#else
167static int
168_parse_kcmdline (void)
169{
170 return CMDLINE_UNSET-1;
171}
172#endif
173
174static gboolean
175_has_composite (Display *display)
176{
177 int dummy1, dummy2;
178
179 return XCompositeQueryExtension (display, &dummy1, &dummy2);
180}
181
182static gboolean
183_is_comment (const char *line)
184{
185 while (*line && isspace(*line)((*__ctype_b_loc ())[(int) ((*line))] & (unsigned short int
) _ISspace)
)
186 line++;
187
188 if (*line == '#' || *line == '\0')
189 return TRUE(!(0));
190 return FALSE(0);
191}
192
193static gboolean
194_is_gl_renderer_blacklisted (const char *renderer)
195{
196 FILE *blacklist;
197 char *line = NULL((void*)0);
198 size_t line_len = 0;
199 gboolean ret = TRUE(!(0));
200
201 blacklist = fopen(PKGDATADIR"/usr/share/cafe-session-manager" "/hardware-compatibility", "r");
202 if (blacklist == NULL((void*)0))
203 goto out;
204
205 while (getline (&line, &line_len, blacklist) != -1) {
206 int whitelist = 0;
207 const char *re_str;
208 regex_t re;
209 int status;
210
211 if (line == NULL((void*)0))
212 break;
213
214 /* Drop trailing \n */
215 line[strlen(line) - 1] = '\0';
216
217 if (_is_comment (line)) {
218 free (line);
219 line = NULL((void*)0);
220 continue;
221 }
222
223 if (line[0] == '+')
224 whitelist = 1;
225 else if (line[0] == '-')
226 whitelist = 0;
227 else {
228 _print_error ("Invalid syntax in this line for hardware compatibility:");
229 _print_error (line);
230 free (line);
231 line = NULL((void*)0);
232 continue;
233 }
234
235 re_str = line + 1;
236
237 if (regcomp (&re, re_str, REG_EXTENDED1|REG_ICASE(1 << 1)|REG_NOSUB(1 << 3)) != 0) {
238 _print_error ("Cannot use this regular expression for hardware compatibility:");
239 _print_error (re_str);
240 } else {
241 status = regexec (&re, renderer, 0, NULL((void*)0), 0);
242 regfree(&re);
243
244 if (status == 0) {
245 if (whitelist)
246 ret = FALSE(0);
247 goto out;
248 }
249 }
250
251 free (line);
252 line = NULL((void*)0);
253 }
254
255 ret = FALSE(0);
256
257out:
258 if (line != NULL((void*)0))
259 free (line);
260
261 if (blacklist != NULL((void*)0))
262 fclose (blacklist);
263
264 return ret;
265}
266
267static char *
268_get_hardware_gl (Display *display)
269{
270 int screen;
271 Window root;
272 XVisualInfo *visual = NULL((void*)0);
273 GLXContext context = NULL((void*)0);
274 XSetWindowAttributes cwa = { 0 };
275 Window window = None0L;
276 char *renderer = NULL((void*)0);
277
278 int attrlist[] = {
279 GLX_RGBA4,
280 GLX_RED_SIZE8, 1,
281 GLX_GREEN_SIZE9, 1,
282 GLX_BLUE_SIZE10, 1,
283 GLX_DOUBLEBUFFER5,
284 None0L
285 };
286
287 screen = DefaultScreen (display)(((_XPrivDisplay)(display))->default_screen);
288 root = RootWindow (display, screen)((&((_XPrivDisplay)(display))->screens[screen])->root
)
;
289
290 visual = glXChooseVisual (display, screen, attrlist);
291 if (!visual)
292 goto out;
293
294 context = glXCreateContext (display, visual, NULL((void*)0), True1);
295 if (!context)
296 goto out;
297
298 cwa.colormap = XCreateColormap (display, root,
299 visual->visual, AllocNone0);
300 cwa.background_pixel = 0;
301 cwa.border_pixel = 0;
302 window = XCreateWindow (display, root,
303 0, 0, 1, 1, 0,
304 visual->depth, InputOutput1, visual->visual,
305 CWColormap(1L<<13) | CWBackPixel(1L<<1) | CWBorderPixel(1L<<3),
306 &cwa);
307
308 if (!glXMakeCurrent (display, window, context))
309 goto out;
310
311 renderer = g_strdup ((const char *) glGetString (GL_RENDERER))g_strdup_inline ((const char *) glGetString (0x1F01));
312 if (_is_gl_renderer_blacklisted (renderer)) {
313 g_clear_pointer (&renderer, g_free)do { _Static_assert (sizeof *(&renderer) == sizeof (gpointer
), "Expression evaluates to false"); __typeof__ ((&renderer
)) _pp = (&renderer); __typeof__ (*(&renderer)) _ptr =
*_pp; *_pp = ((void*)0); if (_ptr) (g_free) (_ptr); } while (
0)
;
314 goto out;
315 }
316 if (renderer && strcasestr (renderer, "llvmpipe"))
317 has_llvmpipe = TRUE(!(0));
318
319 /* we need to get the max texture and renderbuffer sizes while we have
320 * a context, but we'll check their values later */
321
322 glGetIntegerv (GL_MAX_TEXTURE_SIZE0x0D33, &max_texture_size);
323 if (glGetError() != GL_NO_ERROR0)
324 max_texture_size = SIZE_ERROR-1;
325
326 glGetIntegerv (GL_MAX_RENDERBUFFER_SIZE_EXT0x84E8, &max_renderbuffer_size);
327 if (glGetError() != GL_NO_ERROR0)
328 max_renderbuffer_size = SIZE_ERROR-1;
329
330out:
331 glXMakeCurrent (display, None0L, None0L);
332 if (context)
333 glXDestroyContext (display, context);
334 if (window)
335 XDestroyWindow (display, window);
336 if (cwa.colormap)
337 XFreeColormap (display, cwa.colormap);
338
339 return renderer;
340}
341
342static gboolean
343_has_extension (const char *extension_list,
344 const char *extension)
345{
346 char **extensions;
347 guint i;
348 gboolean ret;
349
350 g_return_val_if_fail (extension != NULL, TRUE)do { if ((extension != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "extension != NULL"
); return ((!(0))); } } while (0)
;
351
352 /* Extension_list is one big string, containing extensions
353 * separated by spaces. */
354 if (extension_list == NULL((void*)0))
355 return FALSE(0);
356
357 ret = FALSE(0);
358
359 extensions = g_strsplit (extension_list, " ", -1);
360 if (extensions == NULL((void*)0))
361 return FALSE(0);
362
363 for (i = 0; extensions[i] != NULL((void*)0); i++) {
364 if (g_str_equal (extensions[i], extension)(strcmp ((const char *) (extensions[i]), (const char *) (extension
)) == 0)
) {
365 ret = TRUE(!(0));
366 break;
367 }
368 }
369
370 g_strfreev (extensions);
371
372 return ret;
373}
374
375static gboolean
376_has_texture_from_pixmap (Display *display)
377{
378 int screen;
379 const char *server_extensions;
380 const char *client_extensions;
381 gboolean ret = FALSE(0);
382
383 screen = DefaultScreen (display)(((_XPrivDisplay)(display))->default_screen);
384
385 server_extensions = glXQueryServerString (display, screen,
386 GLX_EXTENSIONS3);
387 if (!_has_extension (server_extensions,
388 "GLX_EXT_texture_from_pixmap"))
389 goto out;
390
391 client_extensions = glXGetClientString (display, GLX_EXTENSIONS3);
392 if (!_has_extension (client_extensions,
393 "GLX_EXT_texture_from_pixmap"))
394 goto out;
395
396 ret = TRUE(!(0));
397
398out:
399 return ret;
400}
401
402static void
403_set_max_screen_size_property (Display *display, int screen, int size)
404{
405 Atom max_screen_size_atom;
406
407 max_screen_size_atom = XInternAtom (display, "_GNOME_MAX_SCREEN_SIZE",
408 False0);
409
410 /* Will be read by gnome-settings-daemon and
411 * gnome-control-center to avoid display configurations where 3D
412 * is not available (and would break gnome-shell) */
413 XChangeProperty (display, RootWindow(display, screen)((&((_XPrivDisplay)(display))->screens[screen])->root
)
,
414 max_screen_size_atom,
415 XA_CARDINAL((Atom) 6), 32, PropModeReplace0,
416 (unsigned char *)&size, 1);
417
418 XSync(display, False0);
419}
420
421static gboolean
422_is_max_texture_size_big_enough (Display *display)
423{
424 int screen, size;
425
426 screen = DefaultScreen (display)(((_XPrivDisplay)(display))->default_screen);
427 size = MIN(max_renderbuffer_size, max_texture_size)(((max_renderbuffer_size) < (max_texture_size)) ? (max_renderbuffer_size
) : (max_texture_size))
;
428 if (size < DisplayWidth (display, screen)((&((_XPrivDisplay)(display))->screens[screen])->width
)
||
429 size < DisplayHeight (display, screen)((&((_XPrivDisplay)(display))->screens[screen])->height
)
)
430 return FALSE(0);
431
432 _set_max_screen_size_property (display, screen, size);
433
434 return TRUE(!(0));
435}
436
437static gboolean print_renderer = FALSE(0);
438
439static const GOptionEntry entries[] = {
440 { "print-renderer", 'p', 0, G_OPTION_ARG_NONE, &print_renderer, "Print GL renderer name", NULL((void*)0) },
441 { NULL((void*)0) },
442};
443
444int
445main (int argc, char **argv)
446{
447 int kcmdline_parsed;
448 Display *display = NULL((void*)0);
449 int ret = HELPER_NO_ACCEL1;
450 GOptionContext *context;
451 GError *error = NULL((void*)0);
452 char *renderer = NULL((void*)0);
453
454 setlocale (LC_ALL6, "");
455
456 context = g_option_context_new (NULL((void*)0));
457 g_option_context_add_main_entries (context, entries, NULL((void*)0));
458
459 if (!g_option_context_parse (context, &argc, &argv, &error)) {
460 g_error ("Can't parse command line: %s\n", error->message);
461 g_error_free (error);
462 goto out;
463 }
464
465 kcmdline_parsed = _parse_kcmdline ();
466 if (kcmdline_parsed > CMDLINE_UNSET-1) {
467 if (kcmdline_parsed == CMDLINE_NON_FALLBACK_FORCED0) {
468 _print_error ("Non-fallback mode forced by kernel command line.");
469 ret = HELPER_ACCEL0;
470 goto out;
471 } else if (kcmdline_parsed == CMDLINE_FALLBACK_FORCED1) {
472 _print_error ("Fallback mode forced by kernel command line.");
473 goto out;
474 }
475 }
476
477 display = XOpenDisplay (NULL((void*)0));
478 if (!display) {
479 _print_error ("No X display.");
480 goto out;
481 }
482
483 if (!_has_composite (display)) {
484 _print_error ("No composite extension.");
485 goto out;
486 }
487
488 renderer = _get_hardware_gl (display);
489 if (!renderer) {
490 _print_error ("No hardware 3D support.");
491 goto out;
492 }
493
494 if (!_has_texture_from_pixmap (display)) {
495 _print_error ("No GLX_EXT_texture_from_pixmap support.");
496 goto out;
497 }
498
499 if (!_is_max_texture_size_big_enough (display)) {
500 _print_error ("GL_MAX_{TEXTURE,RENDERBUFFER}_SIZE is too small.");
501 goto out;
502 }
503
504 ret = has_llvmpipe ? HELPER_SOFTWARE_RENDERING2 : HELPER_ACCEL0;
This statement is never executed
505
506 if (print_renderer)
507 g_print ("%s", renderer);
508
509out:
510 if (display)
511 XCloseDisplay (display);
512 g_free (renderer);
513
514 return ret;
515}