[RFC] glx: fix DRI2 memory leak
Shuang He
shuang.he at intel.com
Wed Apr 1 18:41:34 PDT 2009
Michel Dänzer wrote:
> On Mon, 2009-03-30 at 13:04 +0800, Shuang He wrote:
>
>> Shuang He wrote:
>>
>>> Jesse Barnes wrote:
>>>
>>>> On Fri, 27 Mar 2009 13:20:25 -0400
>>>> Kristian Høgsberg <krh at bitplanet.net> wrote:
>>>>
>>>>> The leak is (as you pointed out before) because we NULL the pDraw
>>>>> pointer before calling the backend destructor, which then can't unref
>>>>> the DRI2Drawable, which we then leak. You had the right fix in the
>>>>> originial post, we just need to not touch glxPriv after
>>>>> __glXUnrefDrawable if it got destroyed. I suggest this change to
>>>>> DrawableGone in irc:
>>>>>
>>>>> refcount = glxPriv->refcount;
>>>>> __glXUnrefDrawable(glxPriv);
>>>>> if (refcount > 1) {
>>>>> glxPriv->pDraw = NULL;
>>>>> glxPriv->drawId = 0;
>>>>> }
>>>>>
>>>>>
>>>> Yep, that seems to work too... Magnus or Vasily can you guys confirm?
>>>>
>>>>
>>> Memory leak problem seems resolved, but I still see X crash with:
>>> (gdb) bt
>>> #0 0xb7fd5424 in __kernel_vsyscall ()
>>> #1 0x03155660 in raise () from /lib/libc.so.6
>>> #2 0x03157028 in abort () from /lib/libc.so.6
>>> #3 0x031925bd in __libc_message () from /lib/libc.so.6
>>> #4 0x031987e4 in malloc_printerr () from /lib/libc.so.6
>>> #5 0x0319c441 in _int_realloc () from /lib/libc.so.6
>>> #6 0x0319d176 in realloc () from /lib/libc.so.6
>>> #7 0x08131002 in Xrealloc (ptr=0x6, amount=0) at utils.c:1133
>>> #8 0x0806d10b in dixAllocatePrivate (privates=0x91487c8, key=0xb7e90a3c)
>>> at privates.c:129
>>> #9 0x0806d1cc in dixSetPrivate (privates=0x91487c8, key=0xb7e90a3c, val=0x0)
>>> at privates.c:193
>>> #10 0xb7e8eca1 in DRI2DestroyDrawable (pDraw=0x91487b0) at dri2.c:218
>>> #11 0xb7eee668 in __glXDRIdrawableDestroy (drawable=0x9205ff0) at glxdri2.c:108
>>> #12 0xb7ee49bb in __glXUnrefDrawable (glxPriv=0x9205ff0) at glxutil.c:58
>>> #13 0xb7ee3183 in DrawableGone (glxPriv=0x9205ff0, xid=12583326)
>>> at glxext.c:131
>>> #14 0x0806efdc in FreeResource (id=12583326, skipDeleteFuncType=0)
>>> at resource.c:561
>>> #15 0xb7edffa6 in DoDestroyDrawable (cl=<value optimized out>,
>>> glxdrawable=12583326, type=1) at glxcmds.c:1225
>>> #16 0xb7ee340a in __glXDispatch (client=0x8d79db8) at glxext.c:523
>>> #17 0x080874cf in Dispatch () at dispatch.c:437
>>> ---Type <return> to continue, or q <return> to quit---
>>> #18 0x0806c69d in main (argc=2, argv=0xbf9d2754, envp=Cannot access memory at
>>> address 0xbde
>>>
>> Just debug a bit, check out this series of calls in DRI2DestroyDrawable when X
>> crashed:
>> in (*ds->DestroyBuffers)(pDraw, pPriv->buffers, pPriv->bufferCount);
>> Xfree: free(0x9eef330)
>> Xfree: free(0x9eeef20)
>> Xfree: free(0x9efdde0)
>> Xfree: free(0x9efce08)
>> Xfree: free(0x9eee8b0)
>> Xrealloc: ptr = 0x9efaf20
>> Xrealloc: amount = 384
>> Xfree: free(0x9efcd18)
>> Xfree: free(0x9ef8468)
>> Xrealloc: ptr = 0x9efa278
>> Xrealloc: amount = 384
>> Xfree: free(0x9efcd18)
>> Xfree: free(0x9ef9808)
>> Xfree: free(0x9eeef38)
>> Xfree: free(0x9efa648)
>> Xfree: free(0x9efd788)
>> in dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, NULL);
>> Xrealloc: ptr = 0x9efce08
>> Xrealloc: amount = 512
>>
>> So dixSetPrivate is trying to realloc memory at 0x9efce08, which is alreay
>> freed in DetroyBuffers. So maybe we should also do this: [...]
>>
>
> The real problem was pointed out by Pierre Willenbrock: If
> glxPriv->pDraw is a pixmap, DrawableGone() destroys it, then later
> DRI2DestroyDrawable dereferences it... The patch below seems to work
> here - at least it hasn't crashed in a couple of hours, not sure about
> the leak yet.
>
> Note that unless I'm missing something, it might still be possible for
> this to occur with windows if the underlying DrawableRec is freed before
> this code is reached.
>
> Also, I don't really understand the logic behind clearing glxPriv->pDraw
> and ->drawId here. In particular, I'm not sure DrawableGone will ever be
> called with glxPriv->refCount > 1. If it won't, this change makes the
> assignments unreachable. And if it will, we'll again leak because the
> cleanup code won't be able to get to the underlying DrawableRec?
>
>
> diff --git a/glx/glxext.c b/glx/glxext.c
> index c882372..e74d00e 100644
> --- a/glx/glxext.c
> +++ b/glx/glxext.c
> @@ -119,17 +119,25 @@ static int ContextGone(__GLXcontext* cx, XID id)
> static Bool DrawableGone(__GLXdrawable *glxPriv, XID xid)
> {
> ScreenPtr pScreen = glxPriv->pDraw->pScreen;
> + PixmapPtr pPixmap = NULL;
> + int refcount;
>
> switch (glxPriv->type) {
> case GLX_DRAWABLE_PIXMAP:
> case GLX_DRAWABLE_PBUFFER:
> - (*pScreen->DestroyPixmap)((PixmapPtr) glxPriv->pDraw);
> + pPixmap = (PixmapPtr) glxPriv->pDraw;
> break;
> }
>
> - glxPriv->pDraw = NULL;
> - glxPriv->drawId = 0;
> + refcount = glxPriv->refCount;
> __glXUnrefDrawable(glxPriv);
> + if (refcount > 1) {
> + glxPriv->pDraw = NULL;
> + glxPriv->drawId = 0;
> + }
> +
> + if (pPixmap)
> + (*pScreen->DestroyPixmap)(pPixmap);
>
> return True;
> }
>
>
>
This works for me. I don't see the memory leaks or X crashes.
Thanks
--Shuang
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.x.org/archives/xorg/attachments/20090402/6e2e1339/attachment.html>
More information about the xorg
mailing list