Bug Summary

File:d/tclenv.c
Warning:line 365, column 12
Potential leak of memory pointed to by 's'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name tclenv.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 -fhalf-no-semantic-interposition -mframe-pointer=none -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=/home/isvv/naviserver/nsd -resource-dir /usr/local/lib/clang/15.0.0 -D _FORTIFY_SOURCE=2 -D NDEBUG -D SYSTEM_MALLOC -I ../include -I /usr/include/tcl8.6 -D HAVE_CONFIG_H -internal-isystem /usr/local/lib/clang/15.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/11/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -std=c99 -fdebug-compilation-dir=/home/isvv/naviserver/nsd -ferror-limit 19 -stack-protector 2 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker alpha -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-07-23-130959-11103-1 -x c tclenv.c
1/*
2 * The contents of this file are subject to the Mozilla Public License
3 * Version 1.1 (the "License"); you may not use this file except in
4 * compliance with the License. You may obtain a copy of the License at
5 * http://mozilla.org/.
6 *
7 * Software distributed under the License is distributed on an "AS IS"
8 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9 * the License for the specific language governing rights and limitations
10 * under the License.
11 *
12 * The Original Code is AOLserver Code and related documentation
13 * distributed by AOL.
14 *
15 * The Initial Developer of the Original Code is America Online,
16 * Inc. Portions created by AOL are Copyright (C) 1999 America Online,
17 * Inc. All Rights Reserved.
18 *
19 * Alternatively, the contents of this file may be used under the terms
20 * of the GNU General Public License (the "GPL"), in which case the
21 * provisions of GPL are applicable instead of those above. If you wish
22 * to allow use of your version of this file only under the terms of the
23 * GPL and not to allow others to use your version of this file under the
24 * License, indicate your decision by deleting the provisions above and
25 * replace them with the notice and other provisions required by the GPL.
26 * If you do not delete the provisions above, a recipient may use your
27 * version of this file under either the License or the GPL.
28 */
29
30
31/*
32 * tclenv.c --
33 *
34 * Implements "ns_env".
35 */
36
37#include "nsd.h"
38
39#ifdef HAVE__NSGETENVIRON
40# include <crt_externs.h>
41#elif !defined(_WIN32)
42extern char **environ;
43#endif
44
45/*
46 * Local functions defined in this file.
47 */
48
49static int PutEnv(Tcl_Interp *interp, const char *name, const char *value);
50
51/*
52 * Loca variables defined in this file.
53 */
54
55static Ns_Mutex lock = NULL((void*)0);
56
57
58/*
59 *----------------------------------------------------------------------
60 *
61 * NsInitTclEnv --
62 *
63 * Global initialization for tasks.
64 *
65 * Results:
66 * None.
67 *
68 * Side effects:
69 * None.
70 *
71 *----------------------------------------------------------------------
72 */
73
74void
75NsInitTclEnv(void)
76{
77 static bool_Bool initialized = NS_FALSE0;
78
79 if (!initialized) {
80 Ns_MutexInit(&lock);
81 Ns_MutexSetName(&lock, "ns:env");
82 initialized = NS_TRUE1;
83 }
84}
85
86/*
87 *----------------------------------------------------------------------
88 *
89 * Ns_GetEnviron --
90 *
91 * Return the environment vector.
92 *
93 * Results:
94 * Pointer to environment.
95 *
96 * Side effects:
97 * None.
98 *
99 *----------------------------------------------------------------------
100 */
101
102char **
103Ns_GetEnviron(void)
104{
105 char **envp;
106
107#ifdef HAVE__NSGETENVIRON
108 envp = *_NSGetEnviron();
109#else
110 envp = environ;
111#endif
112 return envp;
113}
114
115
116/*
117 *----------------------------------------------------------------------
118 *
119 * Ns_CopyEnviron --
120 *
121 * Copy the environment to the given dstring along with
122 * an argv vector.
123 *
124 * Results:
125 * Pointer to dsPtr->string.
126 *
127 * Side effects:
128 * None.
129 *
130 *----------------------------------------------------------------------
131 */
132
133char **
134Ns_CopyEnviron(Ns_DStringTcl_DString *dsPtr)
135{
136 char *const*envp;
137 int i;
138
139 NS_NONNULL_ASSERT(dsPtr != NULL)((void) (0));
140
141 Ns_MutexLock(&lock);
142 envp = Ns_GetEnviron();
143 for (i = 0; envp[i] != NULL((void*)0); ++i) {
144 Ns_DStringAppendArg(dsPtr, envp[i]);
145 }
146 Ns_MutexUnlock(&lock);
147
148 return Ns_DStringAppendArgv(dsPtr);
149}
150
151
152/*
153 *----------------------------------------------------------------------
154 *
155 * NsTclEnvObjCmd --
156 *
157 * Implements "ns_env". No attempt is made to avoid the
158 * race condition between finding a variable and using it as it is
159 * assumed the environment would only be modified, if ever, at
160 * startup.
161 *
162 * Results:
163 * Tcl result.
164 *
165 * Side effects:
166 * Environment variables may be updated.
167 *
168 *----------------------------------------------------------------------
169 */
170
171int
172NsTclEnvObjCmd(ClientData UNUSED(clientData)UNUSED_clientData __attribute__((__unused__)), Tcl_Interp *interp, int objc, Tcl_Obj *const* objv)
173{
174 int result, opt;
175 static const char *const opts[] = {
176 "exists", "names", "get", "set", "unset", NULL((void*)0)
177 };
178 enum {
179 IExistsIdx, INamesIdx, IGetIdx, ISetIdx, IUnsetIdx
180 };
181
182 if (objc < 2) {
1
Assuming 'objc' is >= 2
2
Taking false branch
183 Tcl_WrongNumArgs(interp, 1, objv, "command ?args ...?");
184 result = TCL_ERROR1;
185
186 } else if (Tcl_GetIndexFromObj(interp, objv[1], opts, "command", 0,Tcl_GetIndexFromObjStruct(interp, objv[1], opts, sizeof(char *
), "command", 0, &opt)
3
Assuming the condition is false
4
Taking false branch
187 &opt)Tcl_GetIndexFromObjStruct(interp, objv[1], opts, sizeof(char *
), "command", 0, &opt)
!= TCL_OK0
) {
188 result = TCL_ERROR1;
189
190 } else {
191 const char *name, *value;
192 char *const *envp;
193 Tcl_Obj *resultObj;
194 int i;
195
196 result = TCL_OK0;
197 Ns_MutexLock(&lock);
198
199 switch (opt) {
5
Control jumps to 'case ISetIdx:' at line 225
200 case IExistsIdx:
201 if (objc != 3) {
202 Tcl_WrongNumArgs(interp, 2, objv, "name");
203 result = TCL_ERROR1;
204 } else {
205 Tcl_SetObjResult(interp, Tcl_NewBooleanObj((getenv(Tcl_GetString(objv[2])) != NULL) ? 1 : 0)Tcl_NewIntObj(((getenv(Tcl_GetString(objv[2])) != ((void*)0))
? 1 : 0)!=0)
);
206 }
207 break;
208
209 case INamesIdx:
210 envp = Ns_GetEnviron();
211 resultObj = Tcl_GetObjResult(interp);
212 for (i = 0; envp[i] != NULL((void*)0); ++i) {
213 Tcl_Obj *obj;
214
215 name = envp[i];
216 value = strchr(name, INTCHAR('=')((int)((unsigned char)(('=')))));
217 obj = Tcl_NewStringObj(name, (value != NULL((void*)0)) ? (int)(value - name) : -1);
218 if (Tcl_ListObjAppendElement(interp, resultObj, obj) != TCL_OK0) {
219 result = TCL_ERROR1;
220 break;
221 }
222 }
223 break;
224
225 case ISetIdx:
226 if (objc != 4) {
6
Assuming 'objc' is equal to 4
7
Taking false branch
227 Tcl_WrongNumArgs(interp, 2, objv, "name value");
228 result = TCL_ERROR1;
229
230 } else if (PutEnv(interp, Tcl_GetString(objv[2]), Tcl_GetString(objv[3])) != TCL_OK0) {
8
Calling 'PutEnv'
231 result = TCL_ERROR1;
232 }
233 break;
234
235 case IGetIdx:
236 case IUnsetIdx:
237 if (objc != 3 && objc != 4) {
238 Tcl_WrongNumArgs(interp, 2, objv, "?-nocomplain? name");
239 result = TCL_ERROR1;
240
241 } else if (objc == 4) {
242 const char *arg = Tcl_GetString(objv[2]);
243
244 if (!STREQ(arg, "-nocomplain")(((*(arg)) == (*("-nocomplain"))) && (strcmp((arg),("-nocomplain"
)) == 0))
) {
245 Tcl_WrongNumArgs(interp, 2, objv, "?-nocomplain? name");
246 result = TCL_ERROR1;
247 }
248 }
249
250 if (result == TCL_OK0) {
251 name = Tcl_GetString(objv[2]);
252 value = getenv(name);
253 if (value == NULL((void*)0) && objc != 4) {
254 Ns_TclPrintfResult(interp, "no such environment variable: %s", name);
255 result = TCL_ERROR1;
256
257 } else if ((opt == IUnsetIdx) && (PutEnv(interp, name, NULL((void*)0)) != TCL_OK0)) {
258 result = TCL_ERROR1;
259
260 } else {
261 Tcl_SetObjResult(interp, Tcl_NewStringObj(value, -1));
262 }
263 }
264 break;
265
266 default:
267 /* unexpected value */
268 assert(opt && 0)((void) (0));
269 break;
270 }
271
272 Ns_MutexUnlock(&lock);
273 }
274 return result;
275}
276
277
278/*
279 *----------------------------------------------------------------------
280 *
281 * PutEnv --
282 *
283 * NsTclEnvObjCmd helper routine to update an environment variable.
284 *
285 * Results:
286 * TCL_OK or TCL_ERROR.
287 *
288 * Side effects:
289 * Environment variable is set.
290 *
291 *----------------------------------------------------------------------
292 */
293
294static int
295PutEnv(Tcl_Interp *interp, const char *name, const char *value)
296{
297 char *s;
298 size_t len, nameLength, valueLength;
299 int result = TCL_OK0;
300
301#ifdef HAVE_UNSETENV1
302 if (value == NULL((void*)0)) {
9
Assuming 'value' is not equal to NULL
10
Taking false branch
303 unsetenv(name);
304 return result;
305 }
306#endif
307
308 /*
309 * In case we have no unsetenv(), we have to deal with the value==NULL
310 * case here. If the value is not NULL, valueLength contains the
311 * terminating NUL character.
312 */
313 len = nameLength = strlen(name);
314 if (value
10.1
'value' is not equal to NULL
!= NULL((void*)0)) {
11
Taking true branch
315 valueLength = strlen(value) + 1;
316 len += valueLength + 1u;
317 } else {
318 len += 1u;
319 valueLength = 0u;
320 }
321
322 /*
323 * Use malloc() directly (and not ns_malloc())
324 * as putenv() expects.
325 */
326 s = malloc(len + 1u);
12
Memory is allocated
327 if (s == NULL((void*)0)) {
13
Assuming 's' is not equal to NULL
14
Taking false branch
328 Ns_TclPrintfResult(interp, "could not allocate memory for new env entry");
329 result = TCL_ERROR1;
330 } else {
331
332 /*
333 * This complication for value == NULL below is needed on
334 * some platforms (Solaris) which do not have unsetenv()
335 * and are picky if we try to pass a value to putenv not
336 * conforming to the "name=value" format.
337 *
338 * This trick will of course work only for platforms which
339 * conform to Single Unix Spec and actually uses the storage
340 * passed to putenv() to hold the environ entry.
341 * However, there are some libc implementations (notably
342 * recent BSDs) that do not obey SUS but copy the presented
343 * string. This method fails on such platforms.
344 */
345 memcpy(s, name, nameLength);
346 *(s + nameLength) = '=';
347
348 if (valueLength
14.1
'valueLength' is not equal to 0
!= 0u) {
15
Taking true branch
349 /*
350 * Copy the value including the terminatig NUL character.
351 */
352 memcpy(s + nameLength + 1, value, valueLength);
353 } else {
354 *(s + nameLength + 1u) = '\0';
355 }
356
357 if (putenv(s) != 0) {
16
Assuming the condition is false
17
Taking false branch
358 Ns_TclPrintfResult(interp, "could not put environment entry \"%s\": %s",
359 s, Tcl_PosixError(interp));
360 free(s);
361 result = TCL_ERROR1;
362 }
363 }
364
365 return result;
18
Potential leak of memory pointed to by 's'
366}
367
368/*
369 * Local Variables:
370 * mode: c
371 * c-basic-offset: 4
372 * fill-column: 78
373 * indent-tabs-mode: nil
374 * End:
375 */