Bug Summary

File:lapiz/bacon-message-connection.c
Warning:line 282, column 6
The 1st argument to 'connect' is -1 but should be >= 0

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 bacon-message-connection.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 -fhalf-no-semantic-interposition -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/lapiz -fcoverage-compilation-dir=/rootdir/lapiz -resource-dir /usr/lib/llvm-19/lib/clang/19 -D HAVE_CONFIG_H -I . -I .. -I .. -I . -I ./smclient -I /usr/include/libxml2 -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 -I /usr/local/include/ctksourceview-4 -I /usr/local/include/libbean-2.0 -I /usr/include/gobject-introspection-1.0 -I /usr/include/gobject-introspection-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -D DATADIR="/usr/share" -D LAPIZ_DATADIR="/usr/share/lapiz" -D LIBDIR="/usr/lib" -D PIC -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-06-29-104434-32812-1 -x c bacon-message-connection.c
1/*
2 * Copyright (C) 2003 Bastien Nocera <hadess@hadess.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <fcntl.h>
23#include <stdio.h>
24#include <string.h>
25#include <unistd.h>
26#include <sys/types.h>
27#include <sys/socket.h>
28#include <sys/un.h>
29#include <errno(*__errno_location ()).h>
30
31#include "bacon-message-connection.h"
32
33#ifndef UNIX_PATH_MAX108
34#define UNIX_PATH_MAX108 108
35#endif
36
37struct BaconMessageConnection {
38 /* A server accepts connections */
39 gboolean is_server;
40
41 /* The socket path itself */
42 char *path;
43
44 /* File descriptor of the socket */
45 int fd;
46 /* Channel to watch */
47 GIOChannel *chan;
48 /* Event id returned by g_io_add_watch() */
49 int conn_id;
50
51 /* Connections accepted by this connection */
52 GSList *accepted_connections;
53
54 /* callback */
55 void (*func) (const char *message, gpointer user_data);
56 gpointer data;
57};
58
59static gboolean
60test_is_socket (const char *path)
61{
62 struct stat s;
63
64 if (stat (path, &s) == -1)
65 return FALSE(0);
66
67 if (S_ISSOCK (s.st_mode)((((s.st_mode)) & 0170000) == (0140000)))
68 return TRUE(!(0));
69
70 return FALSE(0);
71}
72
73static gboolean
74is_owned_by_user_and_socket (const char *path)
75{
76 struct stat s;
77
78 if (stat (path, &s) == -1)
79 return FALSE(0);
80
81 if (s.st_uid != geteuid ())
82 return FALSE(0);
83
84 if ((s.st_mode & S_IFSOCK0140000) != S_IFSOCK0140000)
85 return FALSE(0);
86
87 return TRUE(!(0));
88}
89
90static gboolean server_cb (GIOChannel *source,
91 GIOCondition condition, gpointer data);
92
93static gboolean
94setup_connection (BaconMessageConnection *conn)
95{
96 g_return_val_if_fail (conn->chan == NULL, FALSE)do { if ((conn->chan == ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "conn->chan == NULL"
); return ((0)); } } while (0)
;
97
98 conn->chan = g_io_channel_unix_new (conn->fd);
99 if (!conn->chan) {
100 return FALSE(0);
101 }
102 g_io_channel_set_line_term (conn->chan, "\n", 1);
103 conn->conn_id = g_io_add_watch (conn->chan, G_IO_IN, server_cb, conn);
104
105 return TRUE(!(0));
106}
107
108static void
109accept_new_connection (BaconMessageConnection *server_conn)
110{
111 BaconMessageConnection *conn;
112 int alen;
113
114 g_return_if_fail (server_conn->is_server)do { if ((server_conn->is_server)) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "server_conn->is_server"
); return; } } while (0)
;
115
116 conn = g_new0 (BaconMessageConnection, 1)((BaconMessageConnection *) g_malloc0_n ((1), sizeof (BaconMessageConnection
)))
;
117 conn->is_server = FALSE(0);
118 conn->func = server_conn->func;
119 conn->data = server_conn->data;
120
121 conn->fd = accept (server_conn->fd, NULL((void*)0), (guint *)&alen);
122
123 server_conn->accepted_connections =
124 g_slist_prepend (server_conn->accepted_connections, conn);
125
126 setup_connection (conn);
127}
128
129static gboolean
130server_cb (GIOChannel *source,
131 GIOCondition condition G_GNUC_UNUSED__attribute__ ((__unused__)),
132 gpointer data)
133{
134 BaconMessageConnection *conn = (BaconMessageConnection *)data;
135 char *message, *subs, buf;
136 int cd, rc, offset;
137 gboolean finished;
138
139 offset = 0;
140 if (conn->is_server && conn->fd == g_io_channel_unix_get_fd (source)) {
141 accept_new_connection (conn);
142 return TRUE(!(0));
143 }
144 message = g_malloc (1);
145 cd = conn->fd;
146 rc = read (cd, &buf, 1);
147 while (rc > 0 && buf != '\n')
148 {
149 message = g_realloc (message, rc + offset + 1);
150 message[offset] = buf;
151 offset = offset + rc;
152 rc = read (cd, &buf, 1);
153 }
154 if (rc <= 0) {
155 g_io_channel_shutdown (conn->chan, FALSE(0), NULL((void*)0));
156 g_io_channel_unref (conn->chan);
157 conn->chan = NULL((void*)0);
158 close (conn->fd);
159 conn->fd = -1;
160 g_free (message);
161 conn->conn_id = 0;
162
163 return FALSE(0);
164 }
165 message[offset] = '\0';
166
167 subs = message;
168 finished = FALSE(0);
169
170 while (finished == FALSE(0) && *subs != '\0')
171 {
172 if (conn->func != NULL((void*)0))
173 (*conn->func) (subs, conn->data);
174
175 subs += strlen (subs) + 1;
176 if (subs - message >= offset)
177 finished = TRUE(!(0));
178 }
179
180 g_free (message);
181
182 return TRUE(!(0));
183}
184
185static char *
186find_file_with_pattern (const char *dir, const char *pattern)
187{
188 GDir *filedir;
189 char *found_filename;
190 const char *filename;
191 GPatternSpec *pat;
192
193 filedir = g_dir_open (dir, 0, NULL((void*)0));
194 if (filedir == NULL((void*)0))
195 return NULL((void*)0);
196
197 pat = g_pattern_spec_new (pattern);
198 if (pat == NULL((void*)0))
199 {
200 g_dir_close (filedir);
201 return NULL((void*)0);
202 }
203
204 found_filename = NULL((void*)0);
205
206 while ((filename = g_dir_read_name (filedir)))
207 {
208 if (g_pattern_match_string (pat, filename))
209 {
210 char *tmp = g_build_filename (dir, filename, NULL((void*)0));
211 if (is_owned_by_user_and_socket (tmp))
212 found_filename = g_strdup (filename)g_strdup_inline (filename);
213 g_free (tmp);
214 }
215
216 if (found_filename != NULL((void*)0))
217 break;
218 }
219
220 g_pattern_spec_free (pat);
221 g_dir_close (filedir);
222
223 return found_filename;
224}
225
226static char *
227socket_filename (const char *prefix)
228{
229 char *pattern, *path, *filename;
230 const char *tmpdir;
231
232 pattern = g_strdup_printf ("%s.%s.*", prefix, g_get_user_name ());
233 tmpdir = g_get_tmp_dir ();
234 filename = find_file_with_pattern (tmpdir, pattern);
235 if (filename == NULL((void*)0))
236 {
237 char *newfile;
238
239 newfile = g_strdup_printf ("%s.%s.%u", prefix,
240 g_get_user_name (), g_random_int ());
241 path = g_build_filename (tmpdir, newfile, NULL((void*)0));
242 g_free (newfile);
243 } else {
244 path = g_build_filename (tmpdir, filename, NULL((void*)0));
245 g_free (filename);
246 }
247
248 g_free (pattern);
249 return path;
250}
251
252static gboolean
253try_server (BaconMessageConnection *conn)
254{
255 struct sockaddr_un uaddr;
256
257 uaddr.sun_family = AF_UNIX1;
258 strncpy (uaddr.sun_path, conn->path,
259 MIN (strlen(conn->path)+1, UNIX_PATH_MAX)(((strlen(conn->path)+1) < (108)) ? (strlen(conn->path
)+1) : (108))
);
260 conn->fd = socket (PF_UNIX1, SOCK_STREAMSOCK_STREAM, 0);
261 if (bind (conn->fd, (struct sockaddr *) &uaddr, sizeof (uaddr)) == -1)
262 {
263 conn->fd = -1;
264 return FALSE(0);
265 }
266 listen (conn->fd, 5);
267
268 if (!setup_connection (conn))
269 return FALSE(0);
270 return TRUE(!(0));
271}
272
273static gboolean
274try_client (BaconMessageConnection *conn)
275{
276 struct sockaddr_un uaddr;
277
278 uaddr.sun_family = AF_UNIX1;
279 strncpy (uaddr.sun_path, conn->path,
280 MIN(strlen(conn->path)+1, UNIX_PATH_MAX)(((strlen(conn->path)+1) < (108)) ? (strlen(conn->path
)+1) : (108))
);
6
Assuming the condition is false
7
'?' condition is false
281 conn->fd = socket (PF_UNIX1, SOCK_STREAMSOCK_STREAM, 0);
8
Assuming that 'socket' fails
9
Value assigned to field 'fd'
282 if (connect (conn->fd, (struct sockaddr *) &uaddr,
10
The 1st argument to 'connect' is -1 but should be >= 0
283 sizeof (uaddr)) == -1)
284 {
285 conn->fd = -1;
286 return FALSE(0);
287 }
288
289 return setup_connection (conn);
290}
291
292BaconMessageConnection *
293bacon_message_connection_new (const char *prefix)
294{
295 BaconMessageConnection *conn;
296
297 g_return_val_if_fail (prefix != NULL, NULL)do { if ((prefix != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "prefix != NULL")
; return (((void*)0)); } } while (0)
;
1
Assuming 'prefix' is not equal to null
2
Taking true branch
3
Loop condition is false. Exiting loop
298
299 conn = g_new0 (BaconMessageConnection, 1)((BaconMessageConnection *) g_malloc0_n ((1), sizeof (BaconMessageConnection
)))
;
300 conn->path = socket_filename (prefix);
301
302 if (test_is_socket (conn->path) == FALSE(0))
4
Taking false branch
303 {
304 if (!try_server (conn))
305 {
306 bacon_message_connection_free (conn);
307 return NULL((void*)0);
308 }
309
310 conn->is_server = TRUE(!(0));
311 return conn;
312 }
313
314 if (try_client (conn) == FALSE(0))
5
Calling 'try_client'
315 {
316 unlink (conn->path);
317 try_server (conn);
318 if (conn->fd == -1)
319 {
320 bacon_message_connection_free (conn);
321 return NULL((void*)0);
322 }
323
324 conn->is_server = TRUE(!(0));
325 return conn;
326 }
327
328 conn->is_server = FALSE(0);
329 return conn;
330}
331
332void
333bacon_message_connection_free (BaconMessageConnection *conn)
334{
335 GSList *child_conn;
336
337 g_return_if_fail (conn != NULL)do { if ((conn != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "conn != NULL"); return
; } } while (0)
;
338 /* Only servers can accept other connections */
339 g_return_if_fail (conn->is_server != FALSE ||do { if ((conn->is_server != (0) || conn->accepted_connections
== ((void*)0))) { } else { g_return_if_fail_warning (((gchar
*) 0), ((const char*) (__func__)), "conn->is_server != FALSE || conn->accepted_connections == NULL"
); return; } } while (0)
340 conn->accepted_connections == NULL)do { if ((conn->is_server != (0) || conn->accepted_connections
== ((void*)0))) { } else { g_return_if_fail_warning (((gchar
*) 0), ((const char*) (__func__)), "conn->is_server != FALSE || conn->accepted_connections == NULL"
); return; } } while (0)
;
341
342 child_conn = conn->accepted_connections;
343 while (child_conn != NULL((void*)0)) {
344 bacon_message_connection_free (child_conn->data);
345 child_conn = g_slist_next (child_conn)((child_conn) ? (((GSList *)(child_conn))->next) : ((void*
)0))
;
346 }
347 g_slist_free (conn->accepted_connections);
348
349 if (conn->conn_id) {
350 g_source_remove (conn->conn_id);
351 conn->conn_id = 0;
352 }
353 if (conn->chan) {
354 g_io_channel_shutdown (conn->chan, FALSE(0), NULL((void*)0));
355 g_io_channel_unref (conn->chan);
356 }
357
358 if (conn->is_server != FALSE(0)) {
359 unlink (conn->path);
360 }
361 if (conn->fd != -1) {
362 close (conn->fd);
363 }
364
365 g_free (conn->path);
366 g_free (conn);
367}
368
369void
370bacon_message_connection_set_callback (BaconMessageConnection *conn,
371 BaconMessageReceivedFunc func,
372 gpointer user_data)
373{
374 g_return_if_fail (conn != NULL)do { if ((conn != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "conn != NULL"); return
; } } while (0)
;
375
376 conn->func = func;
377 conn->data = user_data;
378}
379
380void
381bacon_message_connection_send (BaconMessageConnection *conn,
382 const char *message)
383{
384 g_return_if_fail (conn != NULL)do { if ((conn != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "conn != NULL"); return
; } } while (0)
;
385 g_return_if_fail (message != NULL)do { if ((message != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "message != NULL"
); return; } } while (0)
;
386
387 g_io_channel_write_chars (conn->chan, message, strlen (message),
388 NULL((void*)0), NULL((void*)0));
389 g_io_channel_write_chars (conn->chan, "\n", 1, NULL((void*)0), NULL((void*)0));
390 g_io_channel_flush (conn->chan, NULL((void*)0));
391}
392
393gboolean
394bacon_message_connection_get_is_server (BaconMessageConnection *conn)
395{
396 g_return_val_if_fail (conn != NULL, FALSE)do { if ((conn != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "conn != NULL"); return
((0)); } } while (0)
;
397
398 return conn->is_server;
399}
400