VERSION:
R6.6
CLIENT MACHINE and OPERATING SYSTEM:
Any, discovered on Solaris 8 using Purify 5.3 to debug Xnest
DISPLAY TYPE:
N/A
WINDOW MANAGER:
N/A
COMPILER:
N/A
AREA:
Xserver/dix/window.c
SYNOPSIS:
Calling WalkTree while deleting a window tree (from CrushTree) references
memory (a window pointer) which has already been freed because the tree
references are not maintained in a valid state while CrushTree is
executing.
DESCRIPTION:
The problem is in CrushTree() in dix/window.c. While the window tree below
the parent window which is passed in is being destroyed, CrushTree() calls
FreeWindowResources(), which eventually calls
xnestCountInstalledColormapWindows(). This code then calls TraverseTree()
with the root window of the screen. Unfortunately, CrushTree() does not
clean up the window hierarchy as it works, assuming that it doesn't have
to because the top level window will be destroyed, along with all the
children. Normally this is fine, but with Xnest, the code must keep track
of installed colormaps as windows are created and destroyed, so it
traverses the window tree (which still has pointers to freed windows in
it). Here is the stack trace of where Purify encountered the bug:
Breakpoint 1, 0x7c17c in purify_stop_here ()^M
(gdb) where^M
#0 0x7c17c in purify_stop_here ()^M
#1 0x1ca6ac in xnestCountInstalledColormapWindows (pWin=0x5f2bb8, ^M
ptr=0xffbeedd0) at Color.c:141^M
#2 0x85c0c in TraverseTree (pWin=0x522530, ^M
func=0x1ca5f8 <xnestCountInstalledColormapWindows>, data=0xffbeedd0)^M
at window.c:187^M
#3 0x85d84 in WalkTree (pScreen=0x51cda0, ^M
func=0x1ca5f8 <xnestCountInstalledColormapWindows>, data=0xffbeedd0)^M
at window.c:218^M
#4 0x1cadec in xnestSetInstalledColormapWindows (pScreen=0x51cda0)^M
at Color.c:202^M
#5 0x1c5c20 in xnestDestroyWindow (pWin=0x5bed28) at Window.c:158^M
#6 0x4550f4 in DbeDestroyWindow (pWin=0x5bed28) at dbe.c:1772^M
#7 0x895f0 in FreeWindowResources (pWin=0x5bed28) at window.c:805^M
#8 0x89940 in CrushTree (pWin=0x5f1240) at window.c:848^M
#9 0x89a5c in DeleteWindow (value=0x5f1240, wid=16777303) at window.c:883^M
#10 0x83fc0 in FreeResource (id=16777303, skipDeleteFuncType=0)^M
at resource.c:481^M
#11 0xbfe68 in ProcDestroyWindow (client=0x5e7510) at dispatch.c:440^M
#12 0xbf5f4 in Dispatch () at dispatch.c:304^M
#13 0x80960 in main (argc=4, argv=0xffbef73c) at main.c:364^M
This bug hasn't caused any crashes for me yet, but it's a timebomb
waiting to go off. Any DDX layer which calls TraverseTree in this
way might randomly crash should the freed memory be reused.
REPEAT BY:
I believe that creating a window tree, and installing colormaps onto the
windows, then deleting the top level tree should cause the problem.
I analyzed the bug with the following fictitious tree, to see how best
to fix it:
A
/ \
B C
/|\
D E F
What seems to happen if A is being deleted is that the code starts
with the first child of A (B), then traverses down to B's child (D),
frees its resources then frees the window pointer. It next goes to
the next sibling of D, which is E and does the same thing. Unfortunately
at this point, while freeing the resources of E xnestDestroyWindow is
called, which calls xnestSetInstalledColormapWindows, which calls
WalkTree looking for windows with certain colormaps, and it so happens
that window D (which has been freed) is still referenced by its parent
B at this time, so its pointer is dereferenced. If that freed memory has
been reused then a crash is likely.
SAMPLE FIX:
The fix is to fix up the parents firstChild and lastChild pointers
(if necessary) before freeing the window pointer in CrushTree. This
leaves the window tree in a valid state during the process of destroying
the tree, so that WalkTree (or PrintWindowTree) has a valid tree to
traverse.
sccs diffs -C window.c
------- window.c -------
*** /tmp/sccs.G1aq4z Thu Mar 13 16:44:21 2003
--- window.c Thu Mar 13 16:44:19 2003
***************
*** 1,4 ****
--- 1,5 ----
/* $Xorg: window.c,v 1.4 2001/02/09 02:04:41 xorgcvs Exp $ */
+
/*
Copyright 1987, 1998 The Open Group
***************
*** 844,849 ****
--- 845,857 ----
(*UnrealizeWindow)(pChild);
}
FreeWindowResources(pChild);
+
+ /* Remove child from the window tree */
+ if (pParent->firstChild == pChild)
+ pParent->firstChild = pChild->nextSib;
+ if (pParent->lastChild == pChild)
+ pParent->lastChild = pChild->prevSib;
+ if (pChild->nextSib)
+ pChild->nextSib->prevSib = pChild->prevSib;
+ if (pChild->prevSib)
+ pChild->prevSib->nextSib = pChild->nextSib;
+
xfree(pChild);
if ( (pChild = pSib) )
break;
_______________________________________________
Devel mailing list
[EMAIL PROTECTED]
http://XFree86.Org/mailman/listinfo/devel