Bug Summary

File:/shared/playproj/i2c/src/util/ddcutil_config_file.c
Warning:line 180, column 30
Array access (from variable 'config_tokens') results in a null pointer dereference

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ddcutil_config_file.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -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 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-11/lib/clang/11.0.0 -D HAVE_CONFIG_H -I . -I ../.. -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/libdrm -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-11/lib/clang/11.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir /shared/playproj/i2c/src/util -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -o ddcutil_config_file.plist -x c ddcutil_config_file.c
1/** \file ddcutil_config_file.c
2 * Processes an INI file used for ddcutil options
3 *
4 * This is not a generic utility file, but is included in
5 * the util directory to simplify its copying unmodified into
6 * the ddcui source tree.
7 */
8
9// Copyright (C) 2021 Sanford Rockowitz <rockowitz@minsoft.com>
10// SPDX-License-Identifier: GPL-2.0-or-later
11
12#include <assert.h>
13#include <errno(*__errno_location ()).h>
14#include <stdbool.h>
15#include <stddef.h>
16#include <stdio.h>
17#include <wordexp.h>
18
19#include "config_file.h"
20#include "string_util.h"
21#include "xdg_util.h"
22
23#include "ddcutil_config_file.h"
24
25
26/** Tokenize a string as per the command line
27 *
28 * \param string to tokenize
29 * \param tokens_loc where to return the address of a
30 * null-terminate list of tokens
31 * \return number of tokens
32 */
33int tokenize_init_line(char * string, char ***tokens_loc) {
34 bool_Bool debug = false0;
35 wordexp_t p;
36 int flags = WRDE_NOCMD;
37 if (debug)
38 flags |= WRDE_SHOWERR;
39 wordexp(string, &p, flags);
40 *tokens_loc = p.we_wordv;
41 if (debug) {
42 ntsa_show(p.we_wordv);
43 printf("(%s) Returning: %ld\n", __func__, p.we_wordc);
44 }
45 return p.we_wordc;
46}
47
48
49/** Processes a ddcutil configuration file, returning the options in both an untokenized and
50 * a tokenized form.
51 *
52 * \param ddcutil_application "ddcutil", "libddcutil", "ddcui"
53 * \param tokenized_options_loc where to return the address of the null terminated token list
54 * \param untokenized_option_loc where to return untokenized string of options obtained from
55 * the configuration file
56 * \param errmsgs collects error messages if non-NULL
57 * \param config_filename_loc where to return fully qualified name of configuration file
58 * \param verbose issue error messages if true
59 * \return 0, < 0 if errors
60 * It is not an error if the configuration file does not exist.
61 * In that case 0 is returned..
62 */
63int read_ddcutil_config_file(
64 const char * ddcutil_application,
65 char *** tokenized_options_loc,
66 char** untokenized_option_string_loc,
67 GPtrArray * errmsgs,
68 char ** config_fn_loc,
69 bool_Bool verbose)
70{
71 bool_Bool debug = false0;
72
73 int result = 0;
74 int token_ct = 0;
75 *tokenized_options_loc = NULL((void*)0);
2
Null pointer value stored to 'cmd_prefix_tokens'
76 *untokenized_option_string_loc = NULL((void*)0);
77 *config_fn_loc = NULL((void*)0);
78 char ** prefix_tokens = NULL((void*)0);
79
80 char * config_fn = find_xdg_config_file("ddcutil", "ddcutilrc");
81 *config_fn_loc = config_fn;
82 if (!config_fn) {
3
Assuming 'config_fn' is null
4
Taking true branch
83 if (debug
4.1
'debug' is false
)
5
Taking false branch
84 printf("(%s) Configuration file not found\n", __func__);
85 result = 0;
86 token_ct = 0;
87 goto bye;
6
Control jumps to line 137
88 }
89
90 GHashTable * config_hash = NULL((void*)0);
91 if (debug)
92 printf("(%s) Before load_configuration_file(), config_fn = %s\n",
93 __func__, config_fn);
94 int load_rc = load_configuration_file(config_fn, &config_hash, errmsgs, false0);
95 if (debug)
96 fprintf(stderrstderr, "load_configuration file() returned %d\n", load_rc);
97 if (load_rc < 0) {
98 if (load_rc == -ENOENT2) {
99 result = 0;
100 token_ct = 0;
101 }
102
103 else {
104 if (verbose)
105 fprintf(stderrstderr, "Error loading configuration file: %d\n", load_rc);
106 result = load_rc;
107 }
108 }
109 if (verbose && errmsgs && errmsgs->len > 0) {
110 fprintf(stderrstderr, "Error(s) processing configuration file %s\n", config_fn);
111 for (int ndx = 0; ndx < errmsgs->len; ndx++) {
112 fprintf(stderrstderr, " %s\n", (char*) g_ptr_array_index(errmsgs, ndx)((errmsgs)->pdata)[ndx]);
113 }
114 }
115
116 if (load_rc == 0 || load_rc == -EBADMSG74) {
117 if (debug) {
118 dump_ini_hash(config_hash);
119 }
120 char * global_options = get_config_value(config_hash, "global", "options");
121 char * ddcutil_options = get_config_value(config_hash, ddcutil_application, "options");
122
123 char * combined_options = g_strdup_printf("%s %s",
124 (global_options) ? global_options : "",
125 (ddcutil_options) ? ddcutil_options : "");
126 if (debug)
127 printf("(%s) combined_options= |%s|\n", __func__, combined_options);
128 *untokenized_option_string_loc = combined_options;
129
130 if (combined_options) {
131 token_ct = tokenize_init_line(combined_options, &prefix_tokens);
132 *tokenized_options_loc = prefix_tokens;
133 }
134 }
135
136bye:
137 if (debug
6.1
'debug' is false
) {
7
Taking false branch
138 printf("(%s) Returning untokenized options: |%s|, token_ct = %d, *config_fn_loc=%s\n",
139 __func__, *untokenized_option_string_loc, token_ct, *config_fn_loc);
140 printf("(%s) prefix_tokens:\n", __func__);
141 ntsa_show(prefix_tokens);
142 printf("(%s) Returning: %d\n", __func__, result);
143 }
144 return result;
145}
146
147
148/** Merges the tokenized command string passed to the program with tokens
149 * obtained from the configuration file.
150 *
151 * \param old_argc original argument count
152 * \param old_argv original argument list
153 * \param config_token_ct number of tokens to insert
154 * \param config_tokens list of tokens
155 * \param new_argv_loc where to return address of merged argument list
156 * \return length of merged argument list
157 */
158int merge_command_tokens(
159 int old_argc,
160 char ** old_argv,
161 int config_token_ct,
162 char ** config_tokens,
163 char *** new_argv_loc)
164{
165 bool_Bool debug = false0;
166
167 // default, assume no config file parms
168 *new_argv_loc = old_argv;
169 int new_argc = old_argc;
170
171 if (config_token_ct
15.1
'config_token_ct' is > 0
> 0) {
16
Taking true branch
172 int new_ct = config_token_ct + old_argc + 1;
173 if (debug
16.1
'debug' is false
)
17
Taking false branch
174 printf("(%s) config_token_ct = %d, argc=%d, new_ct=%d\n",
175 __func__, config_token_ct, old_argc, new_ct);
176 char ** combined = calloc(new_ct, sizeof(char *));
177 combined[0] = old_argv[0]; // command
178 int new_ndx = 1;
179 for (int prefix_ndx = 0; prefix_ndx
17.1
'prefix_ndx' is < 'config_token_ct'
< config_token_ct; prefix_ndx++, new_ndx++) {
18
Loop condition is true. Entering loop body
180 combined[new_ndx] = config_tokens[prefix_ndx];
19
Array access (from variable 'config_tokens') results in a null pointer dereference
181 }
182 for (int old_ndx = 1; old_ndx < old_argc; old_ndx++, new_ndx++) {
183 combined[new_ndx] = old_argv[old_ndx];
184 }
185 combined[new_ndx] = NULL((void*)0);
186 if (debug)
187 printf("(%s) Final new_ndx = %d\n", __func__, new_ndx);
188 *new_argv_loc = combined;
189 new_argc = new_ct - 1;
190 assert(new_argc == ntsa_length(combined))((void) sizeof ((new_argc == ntsa_length(combined)) ? 1 : 0),
__extension__ ({ if (new_argc == ntsa_length(combined)) ; else
__assert_fail ("new_argc == ntsa_length(combined)", "ddcutil_config_file.c"
, 190, __extension__ __PRETTY_FUNCTION__); }))
;
191 }
192
193 if (debug) {
194 printf("(%s) Returning %d, *new_argv_loc=%p\n", __func__, new_argc, *new_argv_loc);
195 printf("(%s) tokens:\n", __func__);
196 ntsa_show(*new_argv_loc);
197 }
198
199 return new_argc;
200}
201
202
203/** Reads and tokenizes the appropriate options entries in the config file,
204 * then combines the tokenized options from the ddcutil configuration file
205 * with the command line arguments, returning a new list of tokens.
206 *
207 * \param old_argc argc as passed on the command line
208 * \param old argv argv as passed on the command line
209 * \param new_argv_loc where to return the address of the combined token list
210 * as a Null_Terminated_String_Array
211 * \param detault_options_loc where to return string of options obtained from ini file
212 * \return number of tokens in the combined list, -1 if errors
213 * reading the configuration file. n. it is not an error if the
214 * configuration file does not exist. In that case 0 is returned.
215 */
216int read_parse_and_merge_config_file(
217 const char * ddcutil_application, // "ddcutil", "ddcui"
218 int old_argc,
219 char ** old_argv,
220 char *** new_argv_loc,
221 char** untokenized_cmd_prefix_loc,
222 char** configure_fn_loc,
223 GPtrArray * errmsgs)
224{
225 bool_Bool debug = false0;
226 char **cmd_prefix_tokens = NULL((void*)0);
227
228 *new_argv_loc = old_argv;
229 int new_argc = old_argc;
230
231 int read_config_rc =
232 read_ddcutil_config_file(
1
Calling 'read_ddcutil_config_file'
8
Returning from 'read_ddcutil_config_file'
233 ddcutil_application,
234 &cmd_prefix_tokens,
235 untokenized_cmd_prefix_loc,
236 errmsgs,
237 configure_fn_loc,
238 debug); // verbose
239 int prefix_token_ct = ntsa_length(cmd_prefix_tokens);
240 if (debug
8.1
'debug' is false
)
9
Taking false branch
241 printf("(%s) get_config_file() returned %d, configure_fn: %s\n",
242 __func__, read_config_rc, *configure_fn_loc);
243
244 if (prefix_token_ct < 0) {
10
Assuming 'prefix_token_ct' is >= 0
11
Taking false branch
245 new_argc = -1;
246 }
247 else if (prefix_token_ct > 0) {
12
Assuming 'prefix_token_ct' is > 0
13
Taking true branch
248 new_argc = merge_command_tokens(
15
Calling 'merge_command_tokens'
249 old_argc,
250 old_argv,
251 prefix_token_ct,
252 cmd_prefix_tokens,
14
Passing null pointer value via 4th parameter 'config_tokens'
253 new_argv_loc);
254 }
255 if (cmd_prefix_tokens)
256 ntsa_free(cmd_prefix_tokens, false0);
257
258 if (debug) {
259 printf("(%s) Returning %d, *new_argv_loc=%p\n", __func__, new_argc, *new_argv_loc);
260 printf("(%s) tokens:\n", __func__);
261 ntsa_show(*new_argv_loc);
262 }
263
264 return new_argc;
265}
266