Bug Summary

File:Destroy.c
Location:line 342, column 9
Description:Access to field 'in_phase2_destroy' results in a dereference of a null pointer (loaded from variable 'app')

Annotated Source Code

1/***********************************************************
2Copyright (c) 1993, Oracle and/or its affiliates. All rights reserved.
3
4Permission is hereby granted, free of charge, to any person obtaining a
5copy of this software and associated documentation files (the "Software"),
6to deal in the Software without restriction, including without limitation
7the rights to use, copy, modify, merge, publish, distribute, sublicense,
8and/or sell copies of the Software, and to permit persons to whom the
9Software is furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice (including the next
12paragraph) shall be included in all copies or substantial portions of the
13Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21DEALINGS IN THE SOFTWARE.
22
23Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
24
25 All Rights Reserved
26
27Permission to use, copy, modify, and distribute this software and its
28documentation for any purpose and without fee is hereby granted,
29provided that the above copyright notice appear in all copies and that
30both that copyright notice and this permission notice appear in
31supporting documentation, and that the name of Digital not be
32used in advertising or publicity pertaining to distribution of the
33software without specific, written prior permission.
34
35DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
36ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
37DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
38ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
39WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
40ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
41SOFTWARE.
42
43******************************************************************/
44
45/*
46
47Copyright 1987, 1988, 1994, 1998 The Open Group
48
49Permission to use, copy, modify, distribute, and sell this software and its
50documentation for any purpose is hereby granted without fee, provided that
51the above copyright notice appear in all copies and that both that
52copyright notice and this permission notice appear in supporting
53documentation.
54
55The above copyright notice and this permission notice shall be included in
56all copies or substantial portions of the Software.
57
58THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
61OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
62AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
63CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
64
65Except as contained in this notice, the name of The Open Group shall not be
66used in advertising or otherwise to promote the sale, use or other dealings
67in this Software without prior written authorization from The Open Group.
68
69*/
70
71#ifdef HAVE_CONFIG_H1
72#include <config.h>
73#endif
74#include "IntrinsicI.h"
75
76struct _DestroyRec {
77 int dispatch_level;
78 Widget widget;
79};
80
81static void Recursive(Widget widget, XtWidgetProc proc)
82{
83 register Cardinal i;
84 CompositePart *cwp;
85
86 /* Recurse down normal children */
87 if (XtIsComposite(widget)(((Object)(widget))->object.widget_class->core_class.class_inited
& 0x08)
) {
88 cwp = &(((CompositeWidget) widget)->composite);
89 for (i = 0; i < cwp->num_children; i++) {
90 Recursive(cwp->children[i], proc);
91 }
92 }
93
94 /* Recurse down popup children */
95 if (XtIsWidget(widget)(((Object)(widget))->object.widget_class->core_class.class_inited
& 0x04)
) {
96 for (i = 0; i < widget->core.num_popups; i++) {
97 Recursive(widget->core.popup_list[i], proc);
98 }
99 }
100
101 /* Finally, apply procedure to this widget */
102 (*proc) (widget);
103} /* Recursive */
104
105static void Phase1Destroy (Widget widget)
106{
107 Widget hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget)((((Object)(widget))->object.widget_class->core_class.class_inited
& 0x04) ? (widget)->core.screen->display : _XtIsHookObject
(widget) ? ((HookObject)(widget))->hooks.screen->display
: _XtWindowedAncestor(widget)->core.screen->display)
);
108
109 widget->core.being_destroyed = TRUE1;
110 if (XtHasCallbacks(hookobj, XtNdestroyHook((char*)&XtStrings[2099])) == XtCallbackHasSome) {
111 XtDestroyHookDataRec call_data;
112
113 call_data.type = XtHdestroy((char*)&XtStrings[2639]);
114 call_data.widget = widget;
115 XtCallCallbackList(hookobj,
116 ((HookObject)hookobj)->hooks.destroyhook_callbacks,
117 (XtPointer) &call_data);
118 }
119} /* Phase1Destroy */
120
121static void Phase2Callbacks(Widget widget)
122{
123 if (widget->core.destroy_callbacks != NULL((void*)0)) {
124 XtCallCallbackList(widget,
125 widget->core.destroy_callbacks, (XtPointer) NULL((void*)0));
126 }
127} /* Phase2Callbacks */
128
129static void Phase2Destroy(register Widget widget)
130{
131 register WidgetClass class;
132 register ConstraintWidgetClass cwClass;
133 ObjectClassExtension ext;
134
135 /* Call constraint destroy procedures */
136 if (XtParent(widget)((widget)->core.parent) != NULL((void*)0) && !XtIsShell(widget)(((Object)(widget))->object.widget_class->core_class.class_inited
& 0x20)
&& XtIsConstraint(XtParent(widget))(((Object)(((widget)->core.parent)))->object.widget_class
->core_class.class_inited & 0x10)
) {
137 LOCK_PROCESSif(_XtProcessLock)(*_XtProcessLock)();
138 cwClass = (ConstraintWidgetClass)XtParent(widget)((widget)->core.parent)->core.widget_class;
139 UNLOCK_PROCESSif(_XtProcessUnlock)(*_XtProcessUnlock)();
140 for (;;) {
141 XtWidgetProc destroy;
142
143 LOCK_PROCESSif(_XtProcessLock)(*_XtProcessLock)();
144 destroy = cwClass->constraint_class.destroy;
145 UNLOCK_PROCESSif(_XtProcessUnlock)(*_XtProcessUnlock)();
146 if (destroy)
147 (*destroy) (widget);
148 if (cwClass == (ConstraintWidgetClass)constraintWidgetClass) break;
149 LOCK_PROCESSif(_XtProcessLock)(*_XtProcessLock)();
150 cwClass = (ConstraintWidgetClass) cwClass->core_class.superclass;
151 UNLOCK_PROCESSif(_XtProcessUnlock)(*_XtProcessUnlock)();
152 }
153 }
154
155 /* Call widget destroy procedures */
156 LOCK_PROCESSif(_XtProcessLock)(*_XtProcessLock)();
157 for (class = widget->core.widget_class;
158 class != NULL((void*)0);
159 class = class->core_class.superclass) {
160 XtWidgetProc destroy;
161
162 destroy = class->core_class.destroy;
163 UNLOCK_PROCESSif(_XtProcessUnlock)(*_XtProcessUnlock)();
164 if (destroy)
165 (*destroy) (widget);
166 LOCK_PROCESSif(_XtProcessLock)(*_XtProcessLock)();
167 }
168
169 /* Call widget deallocate procedure */
170 ext = (ObjectClassExtension)
171 XtGetClassExtension(widget->core.widget_class,
172 XtOffsetOf(CoreClassPart, extension)__builtin_offsetof(CoreClassPart, extension),
173 NULLQUARK((XrmQuark) 0), XtObjectExtensionVersion1L,
174 sizeof(ObjectClassExtensionRec));
175 if (ext && ext->deallocate) {
176 XtDeallocateProc deallocate;
177 deallocate = ext->deallocate;
178 UNLOCK_PROCESSif(_XtProcessUnlock)(*_XtProcessUnlock)();
179 (*deallocate)(widget, NULL((void*)0));
180 } else {
181 UNLOCK_PROCESSif(_XtProcessUnlock)(*_XtProcessUnlock)();
182 XtFree((char *)widget);
183 }
184} /* Phase2Destroy */
185
186static Boolean IsDescendant(Widget widget, Widget root)
187{
188 while ((widget = XtParent(widget)((widget)->core.parent)) != root) {
189 if (widget == NULL((void*)0)) return False0;
190 }
191 return True1;
192}
193
194static void XtPhase2Destroy (Widget widget)
195{
196 Display *display = NULL((void*)0);
197 Window window;
198 Widget parent;
199 XtAppContext app = XtWidgetToApplicationContext(widget);
200 Widget outerInPhase2Destroy = app->in_phase2_destroy;
201 int starting_count = app->destroy_count;
202 Boolean isPopup = False0;
203
204 /* invalidate focus trace cache for this display */
205 _XtGetPerDisplay(XtDisplayOfObject(widget)((((Object)(widget))->object.widget_class->core_class.class_inited
& 0x04) ? (widget)->core.screen->display : _XtIsHookObject
(widget) ? ((HookObject)(widget))->hooks.screen->display
: _XtWindowedAncestor(widget)->core.screen->display)
)->pdi.traceDepth = 0;
206
207 parent = widget->core.parent;
208
209 if (parent && XtIsWidget(parent)(((Object)(parent))->object.widget_class->core_class.class_inited
& 0x04)
&& parent->core.num_popups) {
210 Cardinal i;
211 for (i = 0; i < parent->core.num_popups; i++) {
212 if (parent->core.popup_list[i] == widget) {
213 isPopup = True1;
214 break;
215 }
216 }
217 }
218
219 if (!isPopup && parent && XtIsComposite(parent)(((Object)(parent))->object.widget_class->core_class.class_inited
& 0x08)
) {
220 XtWidgetProc delete_child;
221
222 LOCK_PROCESSif(_XtProcessLock)(*_XtProcessLock)();
223 delete_child =
224 ((CompositeWidgetClass) parent->core.widget_class)->
225 composite_class.delete_child;
226 UNLOCK_PROCESSif(_XtProcessUnlock)(*_XtProcessUnlock)();
227 if (XtIsRectObj(widget)(((Object)(widget))->object.widget_class->core_class.class_inited
& 0x02)
) {
228 XtUnmanageChild(widget);
229 }
230 if (delete_child == NULL((void*)0)) {
231 String param;
232 Cardinal num_params = 1;
233
234 LOCK_PROCESSif(_XtProcessLock)(*_XtProcessLock)();
235 param = parent->core.widget_class->core_class.class_name;
236 UNLOCK_PROCESSif(_XtProcessUnlock)(*_XtProcessUnlock)();
237 XtAppWarningMsg(XtWidgetToApplicationContext(widget),
238 "invalidProcedure","deleteChild",XtCXtToolkitError,
239 "null delete_child procedure for class %s in XtDestroy",
240 &param, &num_params);
241 } else {
242 (*delete_child) (widget);
243 }
244 }
245
246 /* widget is freed in Phase2Destroy, so retrieve window now.
247 * Shells destroy their own windows, to prevent window leaks in
248 * popups; this test is practical only when XtIsShell() is cheap.
249 */
250 if (XtIsShell(widget)(((Object)(widget))->object.widget_class->core_class.class_inited
& 0x20)
|| !XtIsWidget(widget)(((Object)(widget))->object.widget_class->core_class.class_inited
& 0x04)
) {
251 window = 0;
252 }
253 else {
254 display = XtDisplay(widget)(((widget)->core.screen)->display);
255 window = widget->core.window;
256 }
257
258 Recursive(widget, Phase2Callbacks);
259 if (app->destroy_count > starting_count) {
260 int i = starting_count;
261 while (i < app->destroy_count) {
262
263 DestroyRec * dr = app->destroy_list + i;
264 if (IsDescendant(dr->widget, widget)) {
265 Widget descendant = dr->widget;
266 register int j;
267 app->destroy_count--;
268 for (j = app->destroy_count - i; --j >= 0; dr++)
269 *dr = *(dr + 1);
270 XtPhase2Destroy(descendant);
271 }
272 else i++;
273 }
274 }
275
276 app->in_phase2_destroy = widget;
277 Recursive(widget, Phase2Destroy);
278 app->in_phase2_destroy = outerInPhase2Destroy;
279
280 if (isPopup) {
281 Cardinal i;
282 for (i = 0; i < parent->core.num_popups; i++)
283 if (parent->core.popup_list[i] == widget) {
284 parent->core.num_popups--;
285 while (i < parent->core.num_popups) {
286 parent->core.popup_list[i] = parent->core.popup_list[i+1];
287 i++;
288 }
289 break;
290 }
291 }
292
293 /* %%% the following parent test hides a more serious problem,
294 but it avoids breaking those who depended on the old bug
295 until we have time to fix it properly. */
296
297 if (window && (parent == NULL((void*)0) || !parent->core.being_destroyed))
298 XDestroyWindow(display, window);
299} /* XtPhase2Destroy */
300
301
302void _XtDoPhase2Destroy(XtAppContext app, int dispatch_level)
303{
304 /* Phase 2 must occur in fifo order. List is not necessarily
305 * contiguous in dispatch_level.
306 */
307
308 int i = 0;
309 while (i < app->destroy_count) {
310
311 /* XtPhase2Destroy can result in calls to XtDestroyWidget,
312 * and these could cause app->destroy_list to be reallocated.
313 */
314
315 DestroyRec* dr = app->destroy_list + i;
316 if (dr->dispatch_level >= dispatch_level) {
317 Widget w = dr->widget;
318 register int j;
319 app->destroy_count--;
320 for (j = app->destroy_count - i; --j >=0; dr++)
321 *dr = *(dr + 1);
322 XtPhase2Destroy(w);
323 }
324 else i++;
325 }
326}
327
328
329void XtDestroyWidget (Widget widget)
330{
331 XtAppContext app;
332 DestroyRec *dr, *dr2;
333
334 app = XtWidgetToApplicationContext(widget);
335 LOCK_APP(app)if(app && app->lock)(*app->lock)(app);
336 if (widget->core.being_destroyed) {
1
Taking false branch
337 UNLOCK_APP(app)if(app && app->unlock)(*app->unlock)(app);
338 return;
339 }
340 Recursive(widget, Phase1Destroy);
341
342 if (app->in_phase2_destroy &&
2
Access to field 'in_phase2_destroy' results in a dereference of a null pointer (loaded from variable 'app')
343 IsDescendant(widget, app->in_phase2_destroy))
344 {
345 XtPhase2Destroy(widget);
346 UNLOCK_APP(app)if(app && app->unlock)(*app->unlock)(app);
347 return;
348 }
349
350 if (app->destroy_count == app->destroy_list_size) {
351 app->destroy_list_size += 10;
352 app->destroy_list = (DestroyRec*)
353 XtRealloc( (char*)app->destroy_list,
354 (unsigned)sizeof(DestroyRec)*app->destroy_list_size
355 );
356 }
357 dr = app->destroy_list + app->destroy_count++;
358 dr->dispatch_level = app->dispatch_level;
359 dr->widget = widget;
360
361 if (app->dispatch_level > 1) {
362 int i;
363 for (i = app->destroy_count - 1; i;) {
364 /* this handles only one case of nesting difficulties */
365 dr = app->destroy_list + (--i);
366 if (dr->dispatch_level < app->dispatch_level &&
367 IsDescendant(dr->widget, widget)) {
368 dr2 = app->destroy_list + (app->destroy_count-1);
369 dr2->dispatch_level = dr->dispatch_level;
370 break;
371 }
372 }
373 }
374
375 if (_XtSafeToDestroy(app)((app)->dispatch_level == 0)) {
376 app->dispatch_level = 1; /* avoid nested _XtDoPhase2Destroy */
377 _XtDoPhase2Destroy(app, 0);
378 app->dispatch_level = 0;
379 }
380 UNLOCK_APP(app)if(app && app->unlock)(*app->unlock)(app);
381
382} /* XtDestroyWidget */