64-битный поставщик ACE OLEDB вызывает нарушение доступа в SysFreeString
Мое приложение использует файлы MS Access MDB из-за устаревших причин. Он подключается к базе данных с помощью ADO со следующей строкой подключения:
Provider = Microsoft.Jet.OLEDB.4.0; Persist Security Info = False; Источник данных =Dummy.mdb
Недавно я начал переносить приложение на 64-битную версию. Из-за того, что поставщик Jet OLEDB недоступен в 64-разрядных системах, я использовал поставщика ACE OLEDB со следующей строкой подключения:
Provider = Microsoft.ACE.OLEDB.12.0; Persist Security Info = False; Источник данных =Dummy.mdb
Приложение также использует MS XML DOM для работы с файлами XML. Иногда происходит сбой 64-битной версии с исключением нарушения прав доступа в SysFreeString, который вызывается из одного из методов-оболочек MS XML. 32-битная версия не имеет этих проблем. Я перевел проблему в приложение тестера.
#define _WIN32_WINNT 0x0501
#include <stdio.h>
#include <windows.h>
#include <process.h>
#include <conio.h>
#include <ObjBase.h>
#import <msxml6.dll>
#import <msado15.dll> rename("EOF", "EndOfFile")
using namespace ADODB;
bool s_bRepeat = true;
unsigned __stdcall XmlThreadFunc(void*)
{
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
MSXML2::IXMLDOMDocumentPtr l_pXMLDom;
l_pXMLDom.CreateInstance(__uuidof(DOMDocument), NULL, CLSCTX_INPROC_SERVER);
l_pXMLDom->async = VARIANT_FALSE;
MSXML2::IXMLDOMElementPtr l_pRoot = l_pXMLDom->createElement("root");
l_pXMLDom->appendChild(l_pRoot);
unsigned int l_nCnt = 0;
while (s_bRepeat)
{
if (0 == l_nCnt++ % 1000)
{
printf(".");
}
l_pRoot->setAttribute("test", "Test1");
Sleep(0);
}
CoUninitialize();
_endthreadex(0);
return 0;
}
unsigned __stdcall DbThreadFunc(void*)
{
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
_ConnectionPtr l_pConnection;
l_pConnection.CreateInstance(__uuidof(Connection));
#ifdef _WIN64
LPCSTR l_cszConnectStr = "Provider=Microsoft.ACE.OLEDB.12.0;Persist Security Info=False;Data Source=Dummy.mdb";
#else
LPCSTR l_cszConnectStr = "Provider=Microsoft.Jet.OLEDB.4.0;Persist Security Info=False;Data Source=Dummy.mdb";
#endif
while (s_bRepeat)
{
l_pConnection->Open(l_cszConnectStr, "", "", adConnectUnspecified);
Sleep(1000);
printf("(");
l_pConnection->Close();
printf(")");
}
CoUninitialize();
_endthreadex(0);
return 0;
}
int main()
{
HANDLE l_hXmlThread = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0, &XmlThreadFunc, NULL, 0, NULL));
HANDLE l_hDbThread = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0, &DbThreadFunc, NULL, 0, NULL));
_getch();
s_bRepeat = false;
HANDLE l_Handles[2] = { l_hXmlThread, l_hDbThread };
WaitForMultipleObjects(2, l_Handles, TRUE, INFINITE);
CloseHandle(l_hXmlThread);
CloseHandle(l_hDbThread);
return 0;
}
Стек аварийного вызова выглядит следующим образом:
OLEAUT32!SysFreeString
TestCrash64Lean!_bstr_t::Data_t::_Free
TestCrash64Lean!_bstr_t::Data_t::~Data_t
TestCrash64Lean!_bstr_t::Data_t::`scalar deleting destructor'
TestCrash64Lean!_bstr_t::Data_t::Release
TestCrash64Lean!_bstr_t::_Free
TestCrash64Lean!_bstr_t::~_bstr_t
TestCrash64Lean!MSXML2::IXMLDOMElement::setAttribute
TestCrash64Lean!XmlThreadFunc
MSVCR80D!_callthreadstartex
MSVCR80D!_threadstartex
kernel32!BaseThreadInitThunk
ntdll!RtlUserThreadStart
При сбое поток БД всегда находится в следующем состоянии:
MSVCR90!memset
mso!Ordinal4118
mso!Ordinal7994
mso!MsoUninitOffice
ACECORE
ACECORE
ACEOLEDB!DllGetClassObject
ACEOLEDB!DllGetClassObject
ACEOLEDB!DllGetClassObject
ACEOLEDB!DllGetClassObject
oledb32!CAcm::FinalRelease
oledb32!ATL::CComPolyObject<CDCM>::~CComPolyObject<CDCM>
oledb32!ATL::CComPolyObject<CDCM>::Release
oledb32!CDCMCreator::DestroyResource
comsvcs!CHolder::SafeDispenserDriver::DestroyResource
comsvcs!CHolder::ProcessDestroyList
comsvcs!CHolder::FreeResource
oledb32!CDCMCreator::ReleaseResource
oledb32!CDPO::ReturnDCMToPool
oledb32!CDPO::FinalRelease
oledb32!ATL::CComPolyObject<CDPO>::`scalar deleting destructor'
oledb32!ATL::CComPolyObject<CDPO>::Release
msado15!CConnection::_Close
msado15!CConnection::Close
TestCrash64Lean!ADODB::Connection15::Close
TestCrash64Lean!DbThreadFunc
MSVCR80D!_callthreadstartex
MSVCR80D!_threadstartex
kernel32!BaseThreadInitThunk
ntdll!RtlUserThreadStart
Я обнаружил, что в качестве обходного пути, если я оставлю одно открытое соединение с каким-либо пустым файлом базы данных, я могу открывать и закрывать соединения с реальными файлами базы данных, и приложение не падает. В любом случае, я бы лучше понял настоящую причину аварии. Буду признателен за любые предложения.
Моя конфигурация следующая:
Microsoft Visual Studio 2005 версии 8.0.50727.4039 (QFE.050727-4000)
Windows Server 2008 R2 Standard 64 бит
Процессор: Intel(R) Xeon(R) E5645 @ 2,40 ГГц
Память: 16,0 ГБ
1 ответ
Похоже, что это проблема поставщика ACE OLEDB из Microsoft Access Database Engine 2010 Redistributable. Переход на провайдера из Microsoft Access 2013 Runtime решил проблему.