Opened 13 years ago

Closed 9 years ago

#3605 closed Bugs (fixed)

Boost.Asio: Static Initialization causes Deadlock during WSAStartup and other problems

Reported by: ulrich.kroemer@… Owned by: chris_kohlhoff
Milestone: Boost 1.41.0 Component: asio
Version: Boost 1.53.0 Severity: Problem
Keywords: deadlock asio WSAStartup Cc:

Description

I am experiencing spurios deadlocks during static initialization of the do_init global instance (win_sock_init.hpp).

The scenario is this: I am using a static library version of Boost.Asio, which means that once my .dll gets loaded, the do_init global instance is initialized and a call to WSAStartup is made.

At the same time a different thread of the application is already in a call to WSAStartup and already holds the critical section inside the WSAStartup function. Now inside that critical section a call to load the old winsock.dll is made and so the other thread tries to gain the loader lock, which my thread currently is the owner of. Therefore the application deadlocks.

I know that this might actually be a problem of WSAStartup all together, however due to the static initialization there is no workaround to the problem, as the time when the call to WSAStartup is made can't be configured.

Change History (8)

comment:1 by chris_kohlhoff, 13 years ago

Resolution: wontfix
Status: newclosed

I don't plan to make any changes to this area at this time. A possible workaround would be to specialise the winsock_init template:

#include <asio/detail/winsock_init.hpp>

namespace asio
{
  namespace detail
  {
    template <> class winsock_init<2, 0>
    {
    };
  }
}

and then manage the winsock initialisation yourself.

comment:2 by jlcastillo@…, 12 years ago

Resolution: wontfix
Status: closedreopened
Summary: Boost.Asio: Deadlock during WSAStartupBoost.Asio: Static Initialization causes Deadlock during WSAStartup and other problems
Version: Boost 1.40.0Boost 1.45.0

The static initialization might cause other problems appart from locking. If you divide your project into DLLs, and at least one of them uses Boost Asio, the initialization of static objects and data inside DllMain(), before main() is called. As you can read from Microsoft documentation:

"Calling functions that require DLLs other than Kernel32.dll may result in problems that are difficult to diagnose. For example, calling User, Shell, and COM functions can cause access violation errors, because some functions load other system components. Conversely, calling functions such as these during termination can cause access violation errors because the corresponding component may already have been unloaded or uninitialized. If your DLL is linked with the C run-time library (CRT), the entry point provided by the CRT calls the constructors and destructors for global and static C++ objects. Therefore, these restrictions for DllMain also apply to constructors and destructors and any code that is called from them."

Full article: http://msdn.microsoft.com/en-us/library/ms682583(VS.85).aspx

In our case, we experienced odd behaviour in a program that could run without problems from the command line or as a service. In Windows XP it worked in all cases, while in Windows Vista it only worked from the command line, but not as a service. Unfortunately we were not able to reproduce it with a small fragment of code.

The solution was to comment out the following line in winsock_init.hpp:

//static const winsock_init<>& winsock_init_instance = winsock_init<>(false);

and include the following in our own source code:

#include <boost/asio/detail/winsock_init.hpp>
using namespace boost::asio::detail;
winsock_init<> * winsock_init_instance = NULL;

void BoostAsioInit()
{
	if(winsock_init_instance == NULL)
		winsock_init_instance = new winsock_init<>(false);
}

void BoostAsioFinish()
{
	delete winsock_init_instance;
	winsock_init_instance = NULL;
}

comment:3 by chris_kohlhoff, 12 years ago

Resolution: wontfix
Status: reopenedclosed

Thanks for the additional info. However, please see comment 1.

in reply to:  3 comment:4 by anonymous, 10 years ago

Resolution: wontfix
Status: closedreopened
Version: Boost 1.45.0Boost 1.53.0

Replying to chris_kohlhoff:

Thanks for the additional info. However, please see comment 1.

Your comment 1 is wrong.

As long as the line

static const winsock_init<>& winsock_init_instance = winsock_init<>(false);

in winsock_init.hpp exists, there is no way to manage the winsock initialization.

Please make the winsock initialization managable by the user of asio. The static initialization within DllMain is wrong.

comment:5 by Fedor Trushkin <ted-xp@…>, 9 years ago

I happened to encounter this particular issue today. I was surprised that it has been registered several years ago already.

Here are my reasons why this should be considered as a critical issue:

  • as noticed kindly by jlcastillo current library code simply contradicts MSDN documentation;
  • the deadlock under discussion being rarely reproducable has all chances to leak to production;
  • the workaround you proposed is error-prone. Having just a single CPP file with directly included asio libraries will make the whole application buggy;
  • WinSock initialization will be performed before any consious user actions. Actually, you don't have even to create any of asio-related classes. Just include winsock_init.hpp to any of your cpp files;
  • winsock initialization will be called multiple times: once for every cpp file including winsock_init.hpp. It's not an error, but looks untidy.

I would suggest the following:

  • remove static winsock_init_instance from headers;
  • leave its instances as private member of io_service;
  • require that asio library initialization should be performed before using its classes.

comment:6 by anonymous, 9 years ago

Chris, could you at least consider a pre-processor define to disable the static init?

#ifndef BOOST_ASIO_NO_WINSOCKINIT
static const winsock_init<>& winsock_init_instance = winsock_init<>(false);
#endif

comment:7 by chris_kohlhoff, 9 years ago

(In [84877]) Add mechanism for disabling automatic Winsock initialisation. Refs #3605

comment:8 by chris_kohlhoff, 9 years ago

Resolution: fixed
Status: reopenedclosed

(In [84895]) Merge from trunk. Fixes #3605.


r84880 | chris_kohlhoff | 2013-06-22 23:02:21 +1000 (Sat, 22 Jun 2013) | 1 line

Revision history.


r84879 | chris_kohlhoff | 2013-06-22 22:58:50 +1000 (Sat, 22 Jun 2013) | 1 line

Regenerate documentation.


r84878 | chris_kohlhoff | 2013-06-22 22:57:51 +1000 (Sat, 22 Jun 2013) | 1 line

Add missing documentation for use_future_t::allocator_type.


r84877 | chris_kohlhoff | 2013-06-22 22:47:44 +1000 (Sat, 22 Jun 2013) | 1 line

Add mechanism for disabling automatic Winsock initialisation. Refs #3605


r84876 | chris_kohlhoff | 2013-06-22 22:45:33 +1000 (Sat, 22 Jun 2013) | 1 line

Fix memory leak in ssl::rfc2818_verification class.


r84875 | chris_kohlhoff | 2013-06-22 22:44:53 +1000 (Sat, 22 Jun 2013) | 1 line

Add support for both boost.coroutine v1 and v2.

Note: See TracTickets for help on using tickets.