Bug Summary

File:cafe-screenshot/src/screenshot-save.c
Warning:line 223, column 15
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 screenshot-save.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 -fcoverage-compilation-dir=/rootdir/cafe-screenshot/src -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I ../.. -I . -I . -D CAFELOCALEDIR="/usr/share/locale" -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D _REENTRANT -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -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 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -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 -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/cafe-screenshot/src -ferror-limit 19 -fgnuc-version=4.2.1 -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.core.SizeofPtr -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/2024-01-21-120408-94913-1 -x c screenshot-save.c
1/* screenshot-save.c - image saving functions for CAFE Screenshot
2 *
3 * Copyright (C) 2001-2006 Jonathan Blandford <jrb@alum.mit.edu>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (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 GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 */
19
20#include <config.h>
21#include <stdlib.h>
22#include <unistd.h>
23#include <errno(*__errno_location ()).h>
24#include <signal.h>
25#include <string.h>
26#include <glib/gi18n.h>
27
28#include "screenshot-save.h"
29
30static char *parent_dir = NULL((void*)0);
31static char *tmp_filename = NULL((void*)0);
32
33static SaveFunction save_callback = NULL((void*)0);
34static gpointer save_user_data = NULL((void*)0);
35
36/* Strategy for saving:
37 *
38 * We keep another process around to handle saving the image. This is
39 * done for two reasons. One, the saving takes a non-zero amount of
40 * time (about a quarter of a second on my box.) This will make it
41 * more interactive. The second reason is to make the child
42 * responsible for cleaning up the temp dir. If the parent process is
43 * killed or segfaults, the child process can clean up the temp dir.
44 */
45static void
46clean_up_temporary_dir (gboolean gui_on_error)
47{
48 char *message;
49 gboolean error_occurred = FALSE(0);
50 if (g_file_test (tmp_filename, G_FILE_TEST_EXISTS))
51 error_occurred = unlink (tmp_filename);
52 if (g_file_test (parent_dir, G_FILE_TEST_EXISTS))
53 error_occurred = rmdir (parent_dir) || error_occurred;
54
55 if (error_occurred)
56 {
57 message = g_strdup_printf (_("Unable to clear the temporary folder:\n%s")gettext ("Unable to clear the temporary folder:\n%s"),
58 tmp_filename);
59 if (gui_on_error)
60 {
61 CtkWidget *dialog;
62
63 dialog = ctk_message_dialog_new (NULL((void*)0), 0,
64 CTK_MESSAGE_ERROR,
65 CTK_BUTTONS_OK,
66 "%s", message);
67 ctk_dialog_run (CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_dialog_get_type ()))))))
);
68 ctk_widget_destroy (dialog);
69 }
70 else
71 {
72 g_warning ("%s", message);
73 }
74 g_free (message);
75 }
76 g_free (tmp_filename);
77 g_free (parent_dir);
78}
79
80static void
81child_done_notification (GPid pid,
82 gint status,
83 gpointer data)
84{
85 /* This should never be called. */
86
87 /* We expect the child to die after the parent. If the child dies
88 * than it either segfaulted, or was randomly killed. In either
89 * case, we can't reasonably continue. */
90 CtkWidget *dialog;
91
92 dialog = ctk_message_dialog_new (NULL((void*)0), 0,
93 CTK_MESSAGE_ERROR,
94 CTK_BUTTONS_OK,
95 _("The child save process unexpectedly exited. We are unable to write the screenshot to disk.")gettext ("The child save process unexpectedly exited. We are unable to write the screenshot to disk."
)
);
96 ctk_dialog_run (CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_dialog_get_type ()))))))
);
97 ctk_widget_destroy (dialog);
98
99 clean_up_temporary_dir (TRUE(!(0)));
100
101 exit (1);
102}
103
104static gboolean
105read_pipe_from_child (GIOChannel *source,
106 GIOCondition condition,
107 gpointer data)
108{
109 if (condition & G_IO_IN)
110 {
111 gchar *message = NULL((void*)0);
112 gchar *error_message = NULL((void*)0);
113 CtkWidget *dialog;
114 GIOStatus status;
115
116 status = g_io_channel_read_line (source, &error_message, NULL((void*)0), NULL((void*)0), NULL((void*)0));
117
118 if (status == G_IO_STATUS_NORMAL)
119 {
120 message = g_strdup_printf ("Unable to save the screenshot to disk:\n\n%s", error_message);
121 dialog = ctk_message_dialog_new (NULL((void*)0), 0,
122 CTK_MESSAGE_ERROR,
123 CTK_BUTTONS_OK,
124 "%s", message);
125 ctk_dialog_run (CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_dialog_get_type ()))))))
);
126 ctk_widget_destroy (dialog);
127 exit (1);
128 }
129 }
130
131 (*save_callback) (save_user_data);
132
133 return FALSE(0);
134}
135
136static char *
137make_temp_directory (void)
138{
139 gint result, i;
140 gchar *dir_name;
141
142 i = 0;
143 do
144 {
145 gchar *tmp_dir = g_strdup_printf ("cafe-screenshot.%u.%d",
146 (unsigned int) getpid (),
147 i++);
148
149 dir_name = g_build_filename (g_get_tmp_dir (),
150 tmp_dir,
151 NULL((void*)0));
152 g_free (tmp_dir);
153
154 result = g_mkdir_with_parents (dir_name, 0777);
155 if (result < 0)
156 {
157 g_free (dir_name);
158
159 if (errno(*__errno_location ()) != EEXIST17)
160 return NULL((void*)0);
161 else
162 continue;
163 }
164 else
165 return dir_name;
166 }
167 while (TRUE(!(0)));
168}
169
170static void
171signal_handler (int sig)
172{
173 clean_up_temporary_dir (FALSE(0));
174
175 signal (sig, SIG_DFL((__sighandler_t) 0));
176 kill (getpid (), sig);
177}
178
179void
180screenshot_save_start (GdkPixbuf *pixbuf,
181 SaveFunction callback,
182 gpointer user_data)
183{
184 GPid pid;
185 int parent_exit_notification[2];
186 int pipe_from_child[2];
187
188 if (pipe (parent_exit_notification) == -1)
189 perror("pipe error");
190
191 if (pipe (pipe_from_child) == -1)
192 perror("pipe error");
193
194 parent_dir = make_temp_directory ();
195 if (parent_dir == NULL((void*)0))
196 return;
197
198 tmp_filename = g_build_filename (parent_dir,
199 _("Screenshot.png")gettext ("Screenshot.png"),
200 NULL((void*)0));
201 save_callback = callback;
202 save_user_data = user_data;
203
204 pid = fork ();
205 if (pid == 0)
206 {
207 GError *error = NULL((void*)0);
208 char c;
209
210 signal (SIGINT2, signal_handler);
211 signal (SIGTERM15, signal_handler);
212
213 close (parent_exit_notification [1]);
214 close (pipe_from_child [0]);
215
216 if (! gdk_pixbuf_save (pixbuf, tmp_filename,
217 "png", &error,
218 "tEXt::Software", "cafe-screenshot",
219 NULL((void*)0)))
220 {
221 if (error && error->message)
222 if (write (pipe_from_child[1], error->message, strlen (error->message)) == -1)
223 perror("write error");
This statement is never executed
224 else
225#define ERROR_MESSAGEgettext ("Unknown error saving screenshot to disk") _("Unknown error saving screenshot to disk")gettext ("Unknown error saving screenshot to disk")
226 if (write (pipe_from_child[1], ERROR_MESSAGEgettext ("Unknown error saving screenshot to disk"), strlen (ERROR_MESSAGEgettext ("Unknown error saving screenshot to disk"))) == -1)
227 perror("write error");
228 }
229 /* By closing the pipe, we let the main process know that we're
230 * done saving it. */
231 close (pipe_from_child[1]);
232
233 if (read (parent_exit_notification[0], &c, 1) == -1)
234 perror("read error");
235
236 clean_up_temporary_dir (FALSE(0));
237 _exit (0);
238 }
239 else if (pid > 0)
240 {
241 GIOChannel *channel;
242
243 close (parent_exit_notification[0]);
244 close (pipe_from_child[1]);
245
246 channel = g_io_channel_unix_new (pipe_from_child[0]);
247 g_io_add_watch (channel,
248 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
249 read_pipe_from_child,
250 NULL((void*)0));
251 g_io_channel_unref (channel);
252 g_child_watch_add (pid, child_done_notification, NULL((void*)0));
253 }
254 else
255 /* George awesomely wrote code originally to handle the
256 * could-not-fork case synchronously. I'm not copying it, as I'm
257 * guessing that the system is pretty hosed if that's the case.
258 * However, he gets major kudos for trying. (-:
259 */
260 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "screenshot-save.c"
, 260, ((const char*) (__func__)), ((void*)0)); } while (0)
;
261}
262
263const char *
264screenshot_save_get_filename (void)
265{
266 return tmp_filename;
267}