Bug 68498

Summary: test-loopback crashes on wine
Product: dbus Reporter: Ralf Habacker <ralf.habacker>
Component: coreAssignee: Havoc Pennington <hp>
Status: RESOLVED DUPLICATE QA Contact:
Severity: normal    
Priority: medium    
Version: unspecified   
Hardware: Other   
OS: All   
Whiteboard:
i915 platform: i915 features:
Attachments: Crash fix

Description Ralf Habacker 2013-08-24 09:57:35 UTC
When running test-loopback on wine with a cross compiled dbus/dbus-glib 

opensuse 12.2
wine 1.6.0 and 1.7.0
dbus 1.7.6 (git master)
dbus-glib 0.100 

it crashes in _dbus_mem_pool_dealloc with a zero pool pointer.

It looks that

/* Protected by _DBUS_LOCK (list) */
static DBusMemPool *list_pool;

in dbus-list.c seems not to be initialized. This will be the case when in alloc_link() 

  if (!_DBUS_LOCK (list))
    return FALSE;

fails.

static DBusList*
alloc_link (void *data)
{
  DBusList *link;

  if (!_DBUS_LOCK (list))
    return FALSE;

  if (list_pool == NULL)
    {      
      list_pool = _dbus_mem_pool_new (sizeof (DBusList), TRUE);

      if (list_pool == NULL)
        {
          _DBUS_UNLOCK (list);
          return NULL;
        }

      link = _dbus_mem_pool_alloc (list_pool);



#0  _dbus_mem_pool_dealloc (pool=0x0, element=0x14d314) at dbus-mempool.c:398
#1  0x66074584 in free_link (link=0x14d314) at dbus-list.c:97
#2  0x6604f2bf in dbus_connection_dispatch (connection=0x14eca0) at dbus-connection.c:4805
#3  0x67281b6d in message_queue_dispatch (source=source@entry=0x14ee50, callback=0x0, user_data=0x0) at dbus-gmain.c:90
#4  0x685f1b1b in g_main_dispatch (context=0x14d6c0, context@entry=0x13b020) at gmain.c:3054
#5  g_main_context_dispatch (context=context@entry=0x14d6c0) at gmain.c:3630
#6  0x685f1e4a in g_main_context_iterate (context=context@entry=0x14d6c0, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at gmain.c:3701
#7  0x685f208a in g_main_context_iteration (context=0x14d6c0, may_block=1) at gmain.c:3762
#8  0x0040204d in test_message (f=0x14e308, addr=0x4754b2 <_Jv_RegisterClasses+4674738>) at /home/ralf/src/dbus/test/loopback.c:200
#9  0x686136a8 in test_case_run (tc=0x13d018) at gtestutils.c:1714
#10 g_test_run_suite_internal (suite=suite@entry=0x13c030, path=<optimized out>, path@entry=0x68677d5d <__PRETTY_FUNCTION__.3097+265> "") at gtestutils.c:1767
#11 0x6861384c in g_test_run_suite_internal (suite=suite@entry=0x13c010, path=<optimized out>, path@entry=0x68677d5d <__PRETTY_FUNCTION__.3097+265> "") at gtestutils.c:1778
#12 0x68613b79 in g_test_run_suite (suite=0x13c010) at gtestutils.c:1823
#13 0x68613bc0 in g_test_run () at gtestutils.c:1324
#14 0x004027c1 in main (argc=1, argv=0x14b770) at /home/ralf/src/dbus/test/loopback.c:276
(gdb)
Comment 1 Simon McVittie 2013-08-27 13:06:32 UTC
(In reply to comment #0)
> It looks that
> 
> /* Protected by _DBUS_LOCK (list) */
> static DBusMemPool *list_pool;
> 
> in dbus-list.c seems not to be initialized. This will be the case when in
> alloc_link() 
> 
>   if (!_DBUS_LOCK (list))
>     return FALSE;
> 
> fails.

That really shouldn't happen. _DBUS_LOCK (list) expands to _dbus_lock(_DBUS_LOCK_list) which can only fail if dbus_threads_init_default() fails, which can only fail if dbus_threads_init(NULL) fails, and that should only fail on OOM...

> #1  0x66074584 in free_link (link=0x14d314) at dbus-list.c:97

How would it allocate a non-NULL link without successfully initializing the memory pool?

Trying to get my cross-compiling environment up and running again,
Comment 2 Ralf Habacker 2013-08-27 13:16:51 UTC
(In reply to comment #1)
> (In reply to comment #0)
> > It looks that
> > 
> > /* Protected by _DBUS_LOCK (list) */
> > static DBusMemPool *list_pool;
> > 
> > in dbus-list.c seems not to be initialized. This will be the case when in
> > alloc_link() 
> > 
> >   if (!_DBUS_LOCK (list))
> >     return FALSE;
> > 
> > fails.
> 

There is another case in free_link(), when a list_pool do not contain no links (see !!!)

static void
free_link (DBusList *link)
{  
  if (!_DBUS_LOCK (list))
    _dbus_assert_not_reached ("we should have initialized global locks "
        "before we allocated a linked-list link");

  if (_dbus_mem_pool_dealloc (list_pool, link))
    {
      _dbus_mem_pool_free (list_pool);
!!!      list_pool = NULL;
    }
  
  _DBUS_UNLOCK (list);
}

calling free_link() again will result into this crash at

  if (_dbus_mem_pool_dealloc (list_pool, link))

Although this might be a dbus-glib issue there should be an assert ?
Comment 3 Simon McVittie 2013-08-27 14:00:31 UTC
(In reply to comment #2)
> calling free_link() again will result into this crash at
> 
>   if (_dbus_mem_pool_dealloc (list_pool, link))

Ah, so it might be a double-free...

> Although this might be a dbus-glib issue there should be an assert ?

Did you compile your libdbus with asserts enabled?
Comment 4 Ralf Habacker 2013-08-27 14:05:30 UTC
(In reply to comment #3)
> (In reply to comment #2)
> > calling free_link() again will result into this crash at
> > 
> >   if (_dbus_mem_pool_dealloc (list_pool, link))
> 
> Ah, so it might be a double-free...
> 
> > Although this might be a dbus-glib issue there should be an assert ?
> 
> Did you compile your libdbus with asserts enabled?

yes 
       Building w/o assertions:  OFF             
        Building w/o checks:      OFF
Comment 5 Simon McVittie 2013-08-27 14:30:59 UTC
On Debian unstable with Wine 1.4.1, dbus master, dbus-glib master, GLib 2.36:

/connect/tcp: .OK
/connect/nonce-tcp: 
** (test-loopback.exe:35): ERROR **: expected success but got error: org.freedesktop.DBus.Error.Failed: Failed to bind socket "127.0.0.1:44204": Address already in use

... which isn't ideal, but seems like a good start.
Comment 6 Simon McVittie 2013-08-27 14:31:25 UTC
and on a re-run:

/connect/tcp: .OK
/connect/nonce-tcp: .OK
/message/tcp: ..fixme:iphlpapi:GetExtendedTcpTable ulAf = 2, TableClass = 5 not supportted
....Using your real home directory for testing, set DBUS_TEST_HOMEDIR to avoid
...........OK
/message/nonce-tcp: ..fixme:iphlpapi:GetExtendedTcpTable ulAf = 2, TableClass = 5 not supportted
...............OK
/message/bad-guid: ..fixme:iphlpapi:GetExtendedTcpTable ulAf = 2, TableClass = 5 not supportted
..............OK

Perhaps something regressed in newer Wine?
Comment 7 Ralf Habacker 2013-08-27 15:51:35 UTC
(In reply to comment #6)
> and on a re-run:

> Perhaps something regressed in newer Wine?

downgraded to wine 1.4.1 and got
/connect/tcp: .OK
/connect/nonce-tcp: .OK
/message/tcp: ..fixme:iphlpapi:GetExtendedTcpTable ulAf = 2, TableClass = 5 not supportted
unexpected error returned from GetExtendedTcpTable: Request not supported.

....Using your real home directory for testing, set DBUS_TEST_HOMEDIR to avoid

then crashed on the adress initial mentioned with pool=0

_dbus_mem_pool_dealloc (pool=0x0, element=0x14c3bc) at dbus-mempool.c:398
Comment 8 Simon McVittie 2013-08-27 15:55:35 UTC
(In reply to comment #7)
> downgraded to wine 1.4.1 and got [...]

I see from your backtrace that it was also the /message/tcp test (or possibly /message/nonce-tcp) that failed with newer Wine, and /connect/tcp succeeded? Sorry, I didn't spot that before.
Comment 9 Ralf Habacker 2013-08-27 16:33:40 UTC
Created attachment 84730 [details] [review]
Crash fix

With the appended patch I got the following output: 

DBUS_SESSION_BUS_ADDRESS=autolaunch: wine bin/test-loopback.exe 
/connect/tcp: .OK
/connect/nonce-tcp: .OK
/message/tcp: ..fixme:iphlpapi:GetExtendedTcpTable ulAf = 2, TableClass = 5 not supportted
unexpected error returned from GetExtendedTcpTable: Request not supported.

....Using your real home directory for testing, set DBUS_TEST_HOMEDIR to avoid
...........OK
/message/nonce-tcp: ..fixme:iphlpapi:GetExtendedTcpTable ulAf = 2, TableClass = 5 not supportted
unexpected error returned from GetExtendedTcpTable: Request not supported.

...............OK
/message/bad-guid: ..fixme:iphlpapi:GetExtendedTcpTable ulAf = 2, TableClass = 5 not supportted
unexpected error returned from GetExtendedTcpTable: Request not supported.

..............OK
Comment 10 Simon McVittie 2013-08-29 10:18:20 UTC
Comment on attachment 84730 [details] [review]
Crash fix

Review of attachment 84730 [details] [review]:
-----------------------------------------------------------------

This is "wallpapering over the cracks": if we have allocated a non-NULL link and not yet freed it, then the list_pool ought to be non-NULL too - so we're either freeing something twice, or freeing something that wasn't even allocated from that pool. Either is a bug.
Comment 11 Simon McVittie 2013-09-02 16:52:42 UTC
Works for me (under Debian's wine). I'm going to assume this was really the same thing as Bug #68496: linking the same test to libdbus-1.la and to libdbus-internal.la can't work.

*** This bug has been marked as a duplicate of bug 68852 ***
Comment 12 Simon McVittie 2013-09-02 16:54:05 UTC
(In reply to comment #1)
> That really shouldn't happen. _DBUS_LOCK (list) expands to
> _dbus_lock(_DBUS_LOCK_list) which can only fail if
> dbus_threads_init_default() fails, which can only fail if
> dbus_threads_init(NULL) fails, and that should only fail on OOM...

Locking problems are consistent with having linked more than one copy of libdbus (which would have two copies of the lock - badness ensues).

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.