Bug Summary

File:oss-switch.c
Warning:line 264, column 12
Access to field 'data' results in a dereference of a null pointer (loaded from field 'options')

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 oss-switch.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/backends/oss -fcoverage-compilation-dir=/rootdir/backends/oss -resource-dir /usr/lib/llvm-19/lib/clang/19 -D HAVE_CONFIG_H -I . -I ../.. -I ../.. -D G_LOG_DOMAIN="libcafemixer-oss" -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -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-02-07-125700-12031-1 -x c oss-switch.c
1/*
2 * Copyright (C) 2014 Michal Ratajsky <michal.ratajsky@gmail.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the licence, or (at your option) any later version.
8 *
9 * This library 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 GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <errno(*__errno_location ()).h>
19#include <glib.h>
20#include <glib-object.h>
21#include <libcafemixer/cafemixer.h>
22#include <libcafemixer/cafemixer-private.h>
23
24#include "oss-common.h"
25#include "oss-stream.h"
26#include "oss-switch.h"
27#include "oss-switch-option.h"
28
29struct _OssSwitchPrivate
30{
31 gint fd;
32 GList *options;
33};
34
35static void oss_switch_dispose (GObject *object);
36static void oss_switch_finalize (GObject *object);
37
38G_DEFINE_TYPE_WITH_PRIVATE (OssSwitch, oss_switch, CAFE_MIXER_TYPE_STREAM_SWITCH)static void oss_switch_init (OssSwitch *self); static void oss_switch_class_init
(OssSwitchClass *klass); static GType oss_switch_get_type_once
(void); static gpointer oss_switch_parent_class = ((void*)0)
; static gint OssSwitch_private_offset; static void oss_switch_class_intern_init
(gpointer klass) { oss_switch_parent_class = g_type_class_peek_parent
(klass); if (OssSwitch_private_offset != 0) g_type_class_adjust_private_offset
(klass, &OssSwitch_private_offset); oss_switch_class_init
((OssSwitchClass*) klass); } __attribute__ ((__unused__)) static
inline gpointer oss_switch_get_instance_private (OssSwitch *
self) { return (((gpointer) ((guint8*) (self) + (glong) (OssSwitch_private_offset
)))); } GType oss_switch_get_type (void) { static GType static_g_define_type_id
= 0; if ((__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) * (&static_g_define_type_id) : ((void*)
0)); (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter_pointer (
&static_g_define_type_id)); })) ) { GType g_define_type_id
= oss_switch_get_type_once (); (__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id
) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer
((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id
)); })) ; } return static_g_define_type_id; } __attribute__ (
(__noinline__)) static GType oss_switch_get_type_once (void) {
GType g_define_type_id = g_type_register_static_simple ((cafe_mixer_stream_switch_get_type
()), g_intern_static_string ("OssSwitch"), sizeof (OssSwitchClass
), (GClassInitFunc)(void (*)(void)) oss_switch_class_intern_init
, sizeof (OssSwitch), (GInstanceInitFunc)(void (*)(void)) oss_switch_init
, (GTypeFlags) 0); { {{ OssSwitch_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (OssSwitchPrivate)); };} } return g_define_type_id
; }
39
40static gboolean oss_switch_set_active_option (CafeMixerSwitch *mms,
41 CafeMixerSwitchOption *mmso);
42
43static const GList * oss_switch_list_options (CafeMixerSwitch *mms);
44
45static OssSwitchOption *choose_default_option (OssSwitch *swtch);
46
47static void
48oss_switch_class_init (OssSwitchClass *klass)
49{
50 GObjectClass *object_class;
51 CafeMixerSwitchClass *switch_class;
52
53 object_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), (((GType) ((20) << (2))))))))
;
54 object_class->dispose = oss_switch_dispose;
55 object_class->finalize = oss_switch_finalize;
56
57 switch_class = CAFE_MIXER_SWITCH_CLASS (klass)((((CafeMixerSwitchClass*) (void *) g_type_check_class_cast (
(GTypeClass*) ((klass)), ((cafe_mixer_switch_get_type ())))))
)
;
58 switch_class->set_active_option = oss_switch_set_active_option;
59 switch_class->list_options = oss_switch_list_options;
60}
61
62static void
63oss_switch_init (OssSwitch *swtch)
64{
65 swtch->priv = oss_switch_get_instance_private (swtch);
66}
67
68static void
69oss_switch_dispose (GObject *object)
70{
71 OssSwitch *swtch;
72
73 swtch = OSS_SWITCH (object)((((OssSwitch*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((oss_switch_get_type ()))))))
;
74
75 if (swtch->priv->options != NULL((void*)0)) {
76 g_list_free_full (swtch->priv->options, g_object_unref);
77 swtch->priv->options = NULL((void*)0);
78 }
79
80 G_OBJECT_CLASS (oss_switch_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((oss_switch_parent_class)), (((GType) ((20) << (2))
))))))
->dispose (object);
81}
82
83static void
84oss_switch_finalize (GObject *object)
85{
86 OssSwitch *swtch;
87
88 swtch = OSS_SWITCH (object)((((OssSwitch*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((oss_switch_get_type ()))))))
;
89
90 if (swtch->priv->fd != -1)
91 close (swtch->priv->fd);
92
93 G_OBJECT_CLASS (oss_switch_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((oss_switch_parent_class)), (((GType) ((20) << (2))
))))))
->finalize (object);
94}
95
96OssSwitch *
97oss_switch_new (OssStream *stream,
98 const gchar *name,
99 const gchar *label,
100 gint fd,
101 GList *options)
102{
103 OssSwitch *swtch;
104 gint newfd;
105
106 g_return_val_if_fail (OSS_IS_STREAM (stream), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((stream)); GType __t = ((oss_stream_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("libcafemixer-oss", ((const
char*) (__func__)), "OSS_IS_STREAM (stream)"); return (((void
*)0)); } } while (0)
;
107 g_return_val_if_fail (name != NULL, NULL)do { if ((name != ((void*)0))) { } else { g_return_if_fail_warning
("libcafemixer-oss", ((const char*) (__func__)), "name != NULL"
); return (((void*)0)); } } while (0)
;
108 g_return_val_if_fail (label != NULL, NULL)do { if ((label != ((void*)0))) { } else { g_return_if_fail_warning
("libcafemixer-oss", ((const char*) (__func__)), "label != NULL"
); return (((void*)0)); } } while (0)
;
109 g_return_val_if_fail (options != NULL, NULL)do { if ((options != ((void*)0))) { } else { g_return_if_fail_warning
("libcafemixer-oss", ((const char*) (__func__)), "options != NULL"
); return (((void*)0)); } } while (0)
;
110
111 newfd = dup (fd);
112 if (newfd == -1) {
113 g_warning ("Failed to duplicate file descriptor: %s",
114 g_strerror (errno(*__errno_location ())));
115 return NULL((void*)0);
116 }
117
118 swtch = g_object_new (OSS_TYPE_SWITCH(oss_switch_get_type ()),
119 "name", name,
120 "label", label,
121 "role", CAFE_MIXER_STREAM_SWITCH_ROLE_PORT,
122 "stream", stream,
123 NULL((void*)0));
124
125 /* Takes ownership of options */
126 swtch->priv->fd = newfd;
127 swtch->priv->options = options;
128
129 return swtch;
130}
131
132void
133oss_switch_load (OssSwitch *swtch)
134{
135 OssSwitchOption *option;
136 gint recsrc;
137 gint ret;
138
139 g_return_if_fail (OSS_IS_SWITCH (swtch))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((swtch)); GType __t = ((oss_switch_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("libcafemixer-oss", ((const
char*) (__func__)), "OSS_IS_SWITCH (swtch)"); return; } } while
(0)
;
1
Assuming '__inst' is non-null
2
Taking false branch
3
Assuming field 'g_class' is null
4
Assuming the condition is true
5
Taking true branch
6
Loop condition is false. Exiting loop
140
141 if (G_UNLIKELY (swtch->priv->fd == -1)(swtch->priv->fd == -1))
7
Assuming the condition is false
8
Taking false branch
142 return;
143
144 /* Recsrc contains a bitmask of currently enabled recording sources */
145 ret = ioctl (swtch->priv->fd, MIXER_READ (SOUND_MIXER_RECSRC)(((2U) << (((0 +8)+8)+14)) | ((('M')) << (0 +8)) |
(((0xff)) << 0) | ((((sizeof(int)))) << ((0 +8)+
8)))
, &recsrc);
146 if (ret == -1)
9
Assuming the condition is false
10
Taking false branch
147 return;
148
149 if (recsrc != 0) {
11
Assuming 'recsrc' is equal to 0
12
Taking false branch
150 GList *list = swtch->priv->options;
151
152 /* Find out which option is currently selected */
153 while (list != NULL((void*)0)) {
154 gint devnum;
155
156 option = OSS_SWITCH_OPTION (list->data)((((OssSwitchOption*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((list->data)), ((oss_switch_option_get_type ()))))))
;
157 devnum = oss_switch_option_get_devnum (option);
158
159 if (recsrc & (1 << devnum)) {
160 /* It is possible that some hardware might allow and have more recording
161 * sources active at the same time, but we only support one active
162 * source at a time */
163 _cafe_mixer_switch_set_active_option (CAFE_MIXER_SWITCH (swtch)((((CafeMixerSwitch*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((swtch)), ((cafe_mixer_switch_get_type ()))))))
,
164 CAFE_MIXER_SWITCH_OPTION (option)((((CafeMixerSwitchOption*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((option)), ((cafe_mixer_switch_option_get_type
()))))))
);
165 return;
166 }
167 list = list->next;
168 }
169
170 g_debug ("Switch %s has an unknown device as the active option",
171 cafe_mixer_switch_get_name (CAFE_MIXER_SWITCH (swtch)((((CafeMixerSwitch*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((swtch)), ((cafe_mixer_switch_get_type ()))))))
));
172
173 /* OSS shouldn't let a non-record device be selected, let's step in and select
174 * something reasonable instead... */
175 } else {
176 g_debug ("Switch %s has no active device",
177 cafe_mixer_switch_get_name (CAFE_MIXER_SWITCH (swtch)((((CafeMixerSwitch*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((swtch)), ((cafe_mixer_switch_get_type ()))))))
));
178
179 /* According to the OSS Programmer's Guide, if the recsrc value is 0, the
180 * microphone will be selected implicitly.
181 * Let's not assume that's true everywhere and select something explicitly... */
182 }
183
184 option = choose_default_option (swtch);
13
Calling 'choose_default_option'
185
186 g_debug ("Selecting default device %s as active for switch %s",
187 cafe_mixer_switch_option_get_name (CAFE_MIXER_SWITCH_OPTION (option)((((CafeMixerSwitchOption*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((option)), ((cafe_mixer_switch_option_get_type
()))))))
),
188 cafe_mixer_switch_get_name (CAFE_MIXER_SWITCH (swtch)((((CafeMixerSwitch*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((swtch)), ((cafe_mixer_switch_get_type ()))))))
));
189
190 if (cafe_mixer_switch_set_active_option (CAFE_MIXER_SWITCH (swtch)((((CafeMixerSwitch*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((swtch)), ((cafe_mixer_switch_get_type ()))))))
,
191 CAFE_MIXER_SWITCH_OPTION (option)((((CafeMixerSwitchOption*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((option)), ((cafe_mixer_switch_option_get_type
()))))))
) == FALSE(0)) {
192 g_debug ("Failed to set the default device, assuming it is selected anyway");
193
194 _cafe_mixer_switch_set_active_option (CAFE_MIXER_SWITCH (swtch)((((CafeMixerSwitch*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((swtch)), ((cafe_mixer_switch_get_type ()))))))
,
195 CAFE_MIXER_SWITCH_OPTION (option)((((CafeMixerSwitchOption*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((option)), ((cafe_mixer_switch_option_get_type
()))))))
);
196 }
197}
198
199void
200oss_switch_close (OssSwitch *swtch)
201{
202 g_return_if_fail (OSS_IS_SWITCH (swtch))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((swtch)); GType __t = ((oss_switch_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("libcafemixer-oss", ((const
char*) (__func__)), "OSS_IS_SWITCH (swtch)"); return; } } while
(0)
;
203
204 if (swtch->priv->fd == -1)
205 return;
206
207 close (swtch->priv->fd);
208 swtch->priv->fd = -1;
209}
210
211static gboolean
212oss_switch_set_active_option (CafeMixerSwitch *mms, CafeMixerSwitchOption *mmso)
213{
214 OssSwitch *swtch;
215 gint ret;
216 gint recsrc;
217
218 g_return_val_if_fail (OSS_IS_SWITCH (mms), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((mms)); GType __t = ((oss_switch_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("libcafemixer-oss", ((const
char*) (__func__)), "OSS_IS_SWITCH (mms)"); return ((0)); } }
while (0)
;
219 g_return_val_if_fail (OSS_IS_SWITCH_OPTION (mmso), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((mmso)); GType __t = ((oss_switch_option_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("libcafemixer-oss", ((const
char*) (__func__)), "OSS_IS_SWITCH_OPTION (mmso)"); return (
(0)); } } while (0)
;
220
221 swtch = OSS_SWITCH (mms)((((OssSwitch*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((mms)), ((oss_switch_get_type ()))))))
;
222
223 if (G_UNLIKELY (swtch->priv->fd == -1)(swtch->priv->fd == -1))
224 return FALSE(0);
225
226 recsrc = 1 << oss_switch_option_get_devnum (OSS_SWITCH_OPTION (mmso)((((OssSwitchOption*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((mmso)), ((oss_switch_option_get_type ()))))))
);
227
228 ret = ioctl (swtch->priv->fd, MIXER_WRITE (SOUND_MIXER_RECSRC)(((2U|1U) << (((0 +8)+8)+14)) | ((('M')) << (0 +8
)) | (((0xff)) << 0) | ((((sizeof(int)))) << ((0 +
8)+8)))
, &recsrc);
229 if (ret == -1)
230 return FALSE(0);
231
232 return TRUE(!(0));
233}
234
235static const GList *
236oss_switch_list_options (CafeMixerSwitch *mms)
237{
238 g_return_val_if_fail (OSS_IS_SWITCH (mms), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((mms)); GType __t = ((oss_switch_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("libcafemixer-oss", ((const
char*) (__func__)), "OSS_IS_SWITCH (mms)"); return (((void*)
0)); } } while (0)
;
239
240 return OSS_SWITCH (mms)((((OssSwitch*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((mms)), ((oss_switch_get_type ()))))))
->priv->options;
241}
242
243#define OSS_SWITCH_PREFERRED_DEFAULT_DEVNUM7 7 /* Microphone */
244
245static OssSwitchOption *
246choose_default_option (OssSwitch *swtch)
247{
248 GList *list = swtch->priv->options;
249
250 /* Search for the preferred device */
251 while (list != NULL((void*)0)) {
14
Assuming 'list' is equal to NULL
15
Loop condition is false. Execution continues on line 264
252 OssSwitchOption *option;
253 gint devnum;
254
255 option = OSS_SWITCH_OPTION (list->data)((((OssSwitchOption*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((list->data)), ((oss_switch_option_get_type ()))))))
;
256 devnum = oss_switch_option_get_devnum (option);
257
258 if (devnum == OSS_SWITCH_PREFERRED_DEFAULT_DEVNUM7)
259 return option;
260
261 list = list->next;
262 }
263 /* If the preferred device is not present, use the first available one */
264 return OSS_SWITCH_OPTION (swtch->priv->options->data)((((OssSwitchOption*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((swtch->priv->options->data)), ((oss_switch_option_get_type
()))))))
;
16
Access to field 'data' results in a dereference of a null pointer (loaded from field 'options')
265}