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 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | #include "nsd.h" |
39 | |
40 | typedef void *(AtProc)(Ns_Callback *proc, void *data); |
41 | |
42 | |
43 | |
44 | |
45 | |
46 | |
47 | static Ns_ShutdownProc ShutdownProc; |
48 | static int AtObjCmd(AtProc *atProc, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) |
49 | NS_GNUC_NONNULL(1) NS_GNUC_NONNULL(2); |
50 | |
51 | |
52 |
|
53 | |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | |
60 | |
61 | |
62 | |
63 | |
64 | |
65 | |
66 | |
67 | |
68 | |
69 | |
70 | |
71 | |
72 | Ns_TclCallback * |
73 | Ns_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); |
79 | NS_NONNULL_ASSERT(cbProc != NULL); |
80 | NS_NONNULL_ASSERT(scriptObjPtr != NULL); |
81 | |
82 | cbPtr = ns_malloc(sizeof(Ns_TclCallback) + |
83 | + (objc > 1 ? (size_t)(objc-1) * sizeof(char *) : 0u) ); |
| |
| |
84 | if (unlikely(cbPtr == NULL)) { |
| 7 | | Assuming 'cbPtr' is not equal to null | |
|
| |
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 > 0) { |
| |
95 | int i; |
96 | |
97 | for (i = 0; i < 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 | |
110 | |
111 | |
112 | |
113 | |
114 | |
115 | |
116 | |
117 | |
118 | |
119 | |
120 | |
121 | |
122 | void |
123 | Ns_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 | |
141 | |
142 | |
143 | |
144 | |
145 | |
146 | |
147 | |
148 | |
149 | |
150 | |
151 | |
152 | |
153 | |
154 | |
155 | int |
156 | Ns_TclEvalCallback(Tcl_Interp *interp, const Ns_TclCallback *cbPtr, |
157 | Tcl_DString *resultDString, ...) |
158 | { |
159 | Ns_DString ds; |
160 | bool deallocInterp = NS_FALSE; |
161 | int status = TCL_ERROR; |
162 | |
163 | NS_NONNULL_ASSERT(cbPtr != NULL); |
164 | |
165 | if (interp == NULL) { |
166 | interp = Ns_TclAllocateInterp(cbPtr->server); |
167 | deallocInterp = NS_TRUE; |
168 | } |
169 | if (interp != NULL) { |
170 | const char *arg; |
171 | int ii; |
172 | va_list ap; |
173 | |
174 | Ns_DStringInit(&ds); |
175 | Ns_DStringAppend(&ds, cbPtr->script); |
176 | va_start(ap, resultDString); |
177 | |
178 | for (arg = va_arg(ap, char *); arg != NULL; arg = va_arg(ap, char *)) { |
179 | Ns_DStringAppendElement(&ds, arg); |
180 | } |
181 | va_end(ap); |
182 | |
183 | for (ii = 0; ii < cbPtr->argc; ii++) { |
184 | Ns_DStringAppendElement(&ds, cbPtr->argv[ii]); |
185 | } |
186 | status = Tcl_EvalEx(interp, ds.string, ds.length, 0); |
187 | if (status != TCL_OK) { |
188 | Ns_DStringSetLength(&ds, 0); |
189 | Ns_DStringAppend(&ds, "\n while executing callback\n"); |
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); |
194 | } |
195 | } else if (resultDString != NULL) { |
196 | Ns_DStringAppend(resultDString, Tcl_GetStringResult(interp)); |
197 | } |
198 | Ns_DStringFree(&ds); |
199 | if (deallocInterp) { |
200 | Ns_TclDeAllocateInterp(interp); |
201 | } |
202 | } |
203 | |
204 | return status; |
205 | } |
206 | |
207 |
|
208 | |
209 | |
210 | |
211 | |
212 | |
213 | |
214 | |
215 | |
216 | |
217 | |
218 | |
219 | |
220 | |
221 | |
222 | |
223 | |
224 | void |
225 | Ns_TclCallbackProc(void *arg) |
226 | { |
227 | const Ns_TclCallback *cbPtr = arg; |
228 | |
229 | (void) Ns_TclEvalCallback(NULL, cbPtr, (Ns_DString *)NULL, (char *)0L); |
230 | } |
231 | |
232 |
|
233 | |
234 | |
235 | |
236 | |
237 | |
238 | |
239 | |
240 | |
241 | |
242 | |
243 | |
244 | |
245 | |
246 | |
247 | |
248 | |
249 | void |
250 | Ns_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 | |
266 | |
267 | |
268 | |
269 | |
270 | |
271 | |
272 | |
273 | |
274 | |
275 | |
276 | |
277 | |
278 | |
279 | static int |
280 | AtObjCmd(AtProc *atProc, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) |
281 | { |
282 | int result = TCL_OK; |
283 | |
284 | NS_NONNULL_ASSERT(interp != NULL); |
285 | |
286 | if (objc < 2) { |
| |
| |
287 | Tcl_WrongNumArgs(interp, 1, objv, "script ?args?"); |
288 | result = TCL_ERROR; |
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 | |
300 | int |
301 | NsTclAtPreStartupObjCmd(ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) |
302 | { |
303 | return AtObjCmd(Ns_RegisterAtPreStartup, interp, objc, objv); |
304 | } |
305 | |
306 | int |
307 | NsTclAtStartupObjCmd(ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) |
308 | { |
309 | return AtObjCmd(Ns_RegisterAtStartup, interp, objc, objv); |
310 | } |
311 | |
312 | int |
313 | NsTclAtSignalObjCmd(ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) |
314 | { |
315 | return AtObjCmd(Ns_RegisterAtSignal, interp, objc, objv); |
316 | } |
317 | |
318 | int |
319 | NsTclAtExitObjCmd(ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) |
320 | { |
321 | return AtObjCmd(Ns_RegisterAtExit, interp, objc, objv); |
| |
322 | } |
323 | |
324 |
|
325 | |
326 | |
327 | |
328 | |
329 | |
330 | |
331 | |
332 | |
333 | |
334 | |
335 | |
336 | |
337 | |
338 | |
339 | |
340 | |
341 | |
342 | int |
343 | NsTclAtShutdownObjCmd(ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) |
344 | { |
345 | int result = TCL_OK; |
346 | static bool initialized = NS_FALSE; |
347 | |
348 | if (!initialized) { |
349 | Ns_RegisterProcInfo((ns_funcptr_t)ShutdownProc, "ns:tclshutdown", |
350 | Ns_TclCallbackArgProc); |
351 | initialized = NS_TRUE; |
352 | } |
353 | if (objc < 2) { |
354 | Tcl_WrongNumArgs(interp, 1, objv, "script ?args?"); |
355 | result = TCL_ERROR; |
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 | |
365 | static void |
366 | ShutdownProc(const Ns_Time *toPtr, void *arg) |
367 | { |
368 | if (toPtr == NULL) { |
369 | Ns_TclCallbackProc(arg); |
370 | } |
371 | } |
372 | |
373 | |
374 | |
375 | |
376 | |
377 | |
378 | |
379 | |
380 | |