Bug Summary

File:d/tclcallbacks.c
Warning:line 98, column 32
Access out-of-bound array element (buffer overflow)

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 tclcallbacks.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 tclcallbacks.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 * tclcallbacks.c --
33 *
34 * Support for executing Tcl code in response to a callback event.
35 *
36 */
37
38#include "nsd.h"
39
40typedef void *(AtProc)(Ns_Callback *proc, void *data);
41
42
43/*
44 * Local functions defined in this file
45 */
46
47static Ns_ShutdownProc ShutdownProc;
48static int AtObjCmd(AtProc *atProc, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv)
49 NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))) NS_GNUC_NONNULL(2)__attribute__((__nonnull__(2)));
50
51
52
53/*
54 *----------------------------------------------------------------------
55 *
56 * Ns_TclNewCallback --
57 *
58 * Create a new script callback. The callback uses a single memory chunk,
59 * which can be freed as well by a single ns_free() operation. In order
60 * to get alignment right, we use a minimal array in the ns_callback
61 * guarantees proper alignment of the argument vector after the
62 * Ns_TclCallback structure.
63 *
64 * Results:
65 * Pointer to Ns_TclCallback.
66 *
67 * Side effects:
68 * Copies are made of script and arguments
69 *
70 *----------------------------------------------------------------------
71 */
72Ns_TclCallback *
73Ns_TclNewCallback(Tcl_Interp *interp, ns_funcptr_t cbProc, Tcl_Obj *scriptObjPtr,
74 int objc, Tcl_Obj *const* objv)
75{
76 Ns_TclCallback *cbPtr;
77
78 NS_NONNULL_ASSERT(interp != NULL)((void) (0));
79 NS_NONNULL_ASSERT(cbProc != NULL)((void) (0));
80 NS_NONNULL_ASSERT(scriptObjPtr != NULL)((void) (0));
81
82 cbPtr = ns_malloc(sizeof(Ns_TclCallback) +
83 + (objc > 1 ? (size_t)(objc-1) * sizeof(char *) : 0u) );
5
Assuming 'objc' is > 1
6
'?' condition is true
84 if (unlikely(cbPtr == NULL)(__builtin_expect((cbPtr == ((void*)0)), 0))) {
7
Assuming 'cbPtr' is not equal to null
8
Taking false branch
85 Ns_Fatal("tclcallback: out of memory while creating callback");
86 } else {
87
88 cbPtr->cbProc = cbProc;
89 cbPtr->server = Ns_TclInterpServer(interp);
90 cbPtr->script = ns_strdup(Tcl_GetString(scriptObjPtr));
91 cbPtr->argc = objc;
92 cbPtr->argv = (char **)&cbPtr->args;
93
94 if (objc
8.1
'objc' is > 0
> 0) {
9
Taking true branch
95 int i;
96
97 for (i = 0; i
9.1
'i' is < 'objc'
10.1
'i' is < 'objc'
< objc; i++) {
10
Loop condition is true. Entering loop body
11
Loop condition is true. Entering loop body
98 cbPtr->argv[i] = ns_strdup(Tcl_GetString(objv[i]));
12
Access out-of-bound array element (buffer overflow)
99 }
100 }
101 }
102 return cbPtr;
103}
104
105
106/*
107 *----------------------------------------------------------------------
108 *
109 * Ns_TclFreeCallback --
110 *
111 * Free a callback created with Ns_TclNewCallback.
112 *
113 * Results:
114 * None.
115 *
116 * Side effects:
117 * None.
118 *
119 *----------------------------------------------------------------------
120 */
121
122void
123Ns_TclFreeCallback(void *arg)
124{
125 int ii;
126 Ns_TclCallback *cbPtr = arg;
127
128 for (ii = 0; ii < cbPtr->argc; ii++) {
129 ns_free(cbPtr->argv[ii]);
130 }
131
132 ns_free((void *)cbPtr->script);
133 ns_free(cbPtr);
134}
135
136
137/*
138 *----------------------------------------------------------------------
139 *
140 * Ns_TclEvalCallback --
141 *
142 * Evaluate a Tcl callback in the given interp.
143 *
144 * Results:
145 * Tcl return code. Result of successful script execution will
146 * be appended to dstring if given.
147 *
148 * Side effects:
149 * An interp may be allocated if none given and none already
150 * cached for current thread.
151 *
152 *----------------------------------------------------------------------
153 */
154
155int
156Ns_TclEvalCallback(Tcl_Interp *interp, const Ns_TclCallback *cbPtr,
157 Tcl_DString *resultDString, ...)
158{
159 Ns_DStringTcl_DString ds;
160 bool_Bool deallocInterp = NS_FALSE0;
161 int status = TCL_ERROR1;
162
163 NS_NONNULL_ASSERT(cbPtr != NULL)((void) (0));
164
165 if (interp == NULL((void*)0)) {
166 interp = Ns_TclAllocateInterp(cbPtr->server);
167 deallocInterp = NS_TRUE1;
168 }
169 if (interp != NULL((void*)0)) {
170 const char *arg;
171 int ii;
172 va_list ap;
173
174 Ns_DStringInitTcl_DStringInit(&ds);
175 Ns_DStringAppend(&ds, cbPtr->script)Tcl_DStringAppend((&ds), (cbPtr->script), -1);
176 va_start(ap, resultDString)__builtin_va_start(ap, resultDString);
177
178 for (arg = va_arg(ap, char *)__builtin_va_arg(ap, char *); arg != NULL((void*)0); arg = va_arg(ap, char *)__builtin_va_arg(ap, char *)) {
179 Ns_DStringAppendElementTcl_DStringAppendElement(&ds, arg);
180 }
181 va_end(ap)__builtin_va_end(ap);
182
183 for (ii = 0; ii < cbPtr->argc; ii++) {
184 Ns_DStringAppendElementTcl_DStringAppendElement(&ds, cbPtr->argv[ii]);
185 }
186 status = Tcl_EvalEx(interp, ds.string, ds.length, 0);
187 if (status != TCL_OK0) {
188 Ns_DStringSetLengthTcl_DStringSetLength(&ds, 0);
189 Ns_DStringAppend(&ds, "\n while executing callback\n")Tcl_DStringAppend((&ds), ("\n while executing callback\n"
), -1)
;
190 Ns_GetProcInfo(&ds, (ns_funcptr_t)cbPtr->cbProc, cbPtr);
191 Tcl_AddObjErrorInfo(interp, ds.string, ds.length);
192 if (deallocInterp) {
193 (void) Ns_TclLogErrorInfo(interp, NULL((void*)0));
194 }
195 } else if (resultDString != NULL((void*)0)) {
196 Ns_DStringAppend(resultDString, Tcl_GetStringResult(interp))Tcl_DStringAppend((resultDString), (Tcl_GetStringResult(interp
)), -1)
;
197 }
198 Ns_DStringFreeTcl_DStringFree(&ds);
199 if (deallocInterp) {
200 Ns_TclDeAllocateInterp(interp);
201 }
202 }
203
204 return status;
205}
206
207
208/*
209 *----------------------------------------------------------------------
210 *
211 * Ns_TclCallbackProc --
212 *
213 * Callback routine which evaluates the registered Tcl script.
214 *
215 * Results:
216 * None.
217 *
218 * Side effects:
219 * Depends on Tcl script.
220 *
221 *----------------------------------------------------------------------
222 */
223
224void
225Ns_TclCallbackProc(void *arg)
226{
227 const Ns_TclCallback *cbPtr = arg;
228
229 (void) Ns_TclEvalCallback(NULL((void*)0), cbPtr, (Ns_DStringTcl_DString *)NULL((void*)0), (char *)0L);
230}
231
232
233/*
234 *----------------------------------------------------------------------
235 *
236 * Ns_TclCallbackArgProc --
237 *
238 * Proc info routine to copy Tcl callback script.
239 *
240 * Results:
241 * None.
242 *
243 * Side effects:
244 * Will copy script to given dstring.
245 *
246 *----------------------------------------------------------------------
247 */
248
249void
250Ns_TclCallbackArgProc(Tcl_DString *dsPtr, const void *arg)
251{
252 int ii;
253 const Ns_TclCallback *cbPtr = arg;
254
255 Tcl_DStringAppendElement(dsPtr, cbPtr->script);
256 for (ii = 0; ii < cbPtr->argc; ii++) {
257 Tcl_DStringAppendElement(dsPtr, cbPtr->argv[ii]);
258 }
259}
260
261
262/*
263 *----------------------------------------------------------------------
264 *
265 * AtObjCmd --
266 *
267 * Implements "ns_atprestartup", "ns_atstartup", "ns_atsignal",
268 * and "ns_atexit".
269 *
270 * Results:
271 * Tcl result.
272 *
273 * Side effects:
274 * Script will be run some time in the future when the event occurs.
275 *
276 *----------------------------------------------------------------------
277 */
278
279static int
280AtObjCmd(AtProc *atProc, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv)
281{
282 int result = TCL_OK0;
283
284 NS_NONNULL_ASSERT(interp != NULL)((void) (0));
285
286 if (objc < 2) {
2
Assuming 'objc' is >= 2
3
Taking false branch
287 Tcl_WrongNumArgs(interp, 1, objv, "script ?args?");
288 result = TCL_ERROR1;
289
290 } else {
291 Ns_TclCallback *cbPtr = Ns_TclNewCallback(interp,
4
Calling 'Ns_TclNewCallback'
292 (ns_funcptr_t)Ns_TclCallbackProc, objv[1],
293 objc - 2, objv + 2);
294 (void) (*atProc)(Ns_TclCallbackProc, cbPtr);
295 }
296
297 return result;
298}
299
300int
301NsTclAtPreStartupObjCmd(ClientData UNUSED(clientData)UNUSED_clientData __attribute__((__unused__)), Tcl_Interp *interp, int objc, Tcl_Obj *const* objv)
302{
303 return AtObjCmd(Ns_RegisterAtPreStartup, interp, objc, objv);
304}
305
306int
307NsTclAtStartupObjCmd(ClientData UNUSED(clientData)UNUSED_clientData __attribute__((__unused__)), Tcl_Interp *interp, int objc, Tcl_Obj *const* objv)
308{
309 return AtObjCmd(Ns_RegisterAtStartup, interp, objc, objv);
310}
311
312int
313NsTclAtSignalObjCmd(ClientData UNUSED(clientData)UNUSED_clientData __attribute__((__unused__)), Tcl_Interp *interp, int objc, Tcl_Obj *const* objv)
314{
315 return AtObjCmd(Ns_RegisterAtSignal, interp, objc, objv);
316}
317
318int
319NsTclAtExitObjCmd(ClientData UNUSED(clientData)UNUSED_clientData __attribute__((__unused__)), Tcl_Interp *interp, int objc, Tcl_Obj *const* objv)
320{
321 return AtObjCmd(Ns_RegisterAtExit, interp, objc, objv);
1
Calling 'AtObjCmd'
322}
323
324
325/*
326 *----------------------------------------------------------------------
327 *
328 * NsTclAtShutdownObjCmd --
329 *
330 * Implements "ns_atshutdown". The callback timeout parameter is
331 * ignored.
332 *
333 * Results:
334 * Tcl result.
335 *
336 * Side effects:
337 * None.
338 *
339 *----------------------------------------------------------------------
340 */
341
342int
343NsTclAtShutdownObjCmd(ClientData UNUSED(clientData)UNUSED_clientData __attribute__((__unused__)), Tcl_Interp *interp, int objc, Tcl_Obj *const* objv)
344{
345 int result = TCL_OK0;
346 static bool_Bool initialized = NS_FALSE0;
347
348 if (!initialized) {
349 Ns_RegisterProcInfo((ns_funcptr_t)ShutdownProc, "ns:tclshutdown",
350 Ns_TclCallbackArgProc);
351 initialized = NS_TRUE1;
352 }
353 if (objc < 2) {
354 Tcl_WrongNumArgs(interp, 1, objv, "script ?args?");
355 result = TCL_ERROR1;
356
357 } else {
358 Ns_TclCallback *cbPtr = Ns_TclNewCallback(interp, (ns_funcptr_t)ShutdownProc,
359 objv[1], objc - 2, objv + 2);
360 (void) Ns_RegisterAtShutdown(ShutdownProc, cbPtr);
361 }
362 return result;
363}
364
365static void
366ShutdownProc(const Ns_Time *toPtr, void *arg)
367{
368 if (toPtr == NULL((void*)0)) {
369 Ns_TclCallbackProc(arg);
370 }
371}
372
373/*
374 * Local Variables:
375 * mode: c
376 * c-basic-offset: 4
377 * fill-column: 78
378 * indent-tabs-mode: nil
379 * End:
380 */