Microsoft.ACE.OLEDB.12.0 bug in multithread scenario

3

I use in my x64 application the Microsoft Access Database Engine 2010 (part of Microsoft Office 2016) for working with mdb files. But, current version of Microsoft Access Database Engine 2010 (OLEDB provider Microsoft.ACE.OLEDB.12.0) have a bug. This engine crashes in multithread work. If I create two OLE DB (or ADO DB) connections with this provider in different threads, then one of them will crashed in Mso40UIwin32client.dll with exception 0xC0000005: Access violation writing location 0x0000000000000000.

Exception stack:

  • Exception thrown at 0x00007FFB32361F28 in ACEOLEDBTest.exe: Microsoft C++ exception: std::runtime_error at memory location 0x0000006B771FEAF0.
  • Exception thrown at 0x00007FFB32361F28 in ACEOLEDBTest.exe: Microsoft C++ exception: [rethrow] at memory location 0x0000000000000000.
  • Exception thrown at 0x00007FFB32361F28 in ACEOLEDBTest.exe: Microsoft C++ exception: std::runtime_error at memory location 0x0000006B771FEAF0.
  • Exception thrown at 0x00007FFB32361F28 in ACEOLEDBTest.exe: Microsoft C++ exception: std::runtime_error at memory location 0x0000006B771FEFB8.
  • Exception thrown at 0x00007FFAF9ED1271 (Mso40UIwin32client.dll) in ACEOLEDBTest.exe: 0xC0000005: Access violation writing location 0x0000000000000000.

C++ code sample with this error:

#include "stdafx.h"
#include <atlcom.h>
#include <atldbcli.h>
#include <conio.h>

typedef UINT(__stdcall* fnThread)(PVOID);

HANDLE hExitEvent = NULL;

UINT __stdcall DbThread1(IN PVOID context)
{
    HRESULT hRes = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
    _ASSERTE(SUCCEEDED(hRes));

    CDataSource DataSource;         // Data source connection object

    while (::WaitForSingleObject(hExitEvent, 0) != WAIT_OBJECT_0)
    {
        // Open DB connection
        ATLTRACE2(atlTraceGeneral, 0, L"DbThread1: Create connection...\n");
        hRes = DataSource.OpenFromInitializationString(L"Provider=Microsoft.ACE.OLEDB.12.0; Data Source=\"C:\\Temp\\Index_empty1.mdb\"; Persist Security Info=False;");
        _ASSERTE(SUCCEEDED(hRes));

        // Close DB connection
        DataSource.Close();
        ATLTRACE2(atlTraceGeneral, 0, L"DbThread1: Close connection...\n");
        Sleep(20);
    }

    ::CoUninitialize();
    _endthreadex(0);
    return 0;
}

UINT __stdcall DbThread2(IN PVOID context)
{
    HRESULT hRes = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
    _ASSERTE(SUCCEEDED(hRes));

    CDataSource DataSource;         // Data source connection object

    while (::WaitForSingleObject(hExitEvent, 0) != WAIT_OBJECT_0)
    {
        // Open DB connection
        ATLTRACE2(atlTraceGeneral, 0, L"DbThread2: Create connection...\n");
        hRes = DataSource.OpenFromInitializationString(L"Provider=Microsoft.ACE.OLEDB.12.0; Data Source=\"C:\\Temp\\Index_empty2.mdb\"; Persist Security Info=False;");
        _ASSERTE(SUCCEEDED(hRes));

        // Close DB connection
        DataSource.Close();
        ATLTRACE2(atlTraceGeneral, 0, L"DbThread2: Close connection...\n");
        Sleep(20);
    }

    ::CoUninitialize();
    _endthreadex(0);
    return 0;
}

int main()
{
    ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
    hExitEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);

    const fnThread aPtrs[] = { DbThread1, DbThread2 };
    HANDLE hDbThread[_countof(aPtrs)] = { NULL };
    for (int nIndex = 0; nIndex < _countof(aPtrs); nIndex++) {
        if ((hDbThread[nIndex] = (HANDLE)::_beginthreadex(nullptr, 0, aPtrs[nIndex], nullptr, 0, nullptr)) == NULL)
        {
            return 1;
        }
    }


    CComVariant varData;
    printf("Press any key to exit...");

    // Loop until any key struck
    while (!_kbhit())
    {
        for (DWORD i = 0; i < 100; i++)
        {
            // Test for bug of the OLEDB provider for MS ACCESS 2010.
            varData.Clear();
        }
        Sleep(0);
    }

    // Request threads to exit
    SetEvent(hExitEvent);

    // Wait for threads to exit
    WaitForMultipleObjects(_countof(hDbThread), hDbThread, TRUE, INFINITE);
    for (auto& h : hDbThread) {
        CloseHandle(h);
    }

    CloseHandle(hExitEvent);
    ::CoUninitialize();

    return 0;
}

You should build this sample for x64 platform with Visual C++ 2013/2015. Similar bug I found at MS forum. Can anybody help me?

multithreading
ms-access
visual-c++
ms-office
oledb
asked on Stack Overflow May 25, 2016 by 23W • edited May 25, 2016 by 23W

1 Answer

3

We too have encountered this issue in a multi-threaded VB.Net (Framework v4.5.2) service application. After much testing, the only way we found to resolve this was to either use a single thread or turn off connection pooling (using OLE DB Services=-2). In the end we have gone with the latter as we needed the system to be able to process requests in parallel.

FYI, the version of Office 2016 I have installed does not include this driver (hence why our program passed any kind of basic testing) but it was included with the version of Office 2016 that our customer installed. So far I have checked "Microsoft Office Professional Plus 2016" (from both MSDN and MS Partner Network) and "Microsoft Office 365 ProPlus" and none of them appear to come with the Microsoft.ACE.OLEDB.12.0 OLEDB provider. Also, as far as I can see, the only version of the Microsoft Access Database Engine 2010 Redistributable available to download is SP2 (released 22/07/2013) so it is hard to get this tested in a development environment!

answered on Stack Overflow Jun 17, 2016 by Gareth Thom

User contributions licensed under CC BY-SA 3.0