Использование Visual Studio 2019 Professional на Windows 10 x64. У меня есть несколько проектов C ++ DLL, некоторые из которых многопоточные. Я использую CRITICAL_SECTION
объекты для обеспечения безопасности потоков.
В DLL1:
CRITICAL_SECTION critDLL1;
InitializeCriticalSection(&critDLL1);
В DLL2:
CRITICAL_SECTION critDLL2;
InitializeCriticalSection(&critDLL2);
Когда я использую critDLL1 с EnterCriticalSection
или LeaveCriticalSection
все нормально как в режиме _DEBUG
, так и NDEBUG
. Но когда я использую crisDLL2, я получаю нарушение прав доступа в ntdll.dll в NDEBUG
(хотя и не в _DEBUG
).
После появления окон сообщений в режиме NDEBUG
я в конечном итоге возможность отследить проблему вплоть до первого использования EnterCriticalSection
.
Что может быть причиной сбоя CRITICAL_SECTION
в одном проекте, но работы в других? Страница MSDN не помогла.
ОБНОВЛЕНИЕ 1
После сравнения настроек проекта DLL1 (работает) и DLL2 (не работает), я У меня случайно заработала DLL2. Я подтвердил это, вернувшись к более ранней версии (которая дает сбой), а затем внесет изменения в проект (без cra sh!).
Это настройка:
Project Properties > C/C++ > Optimization > Whole Program Optimization
Установите значение Yes (/GL)
, и моя программа выйдет из строя. Измените это на No
, и он отлично работает. Что делает переключатель /GL
и почему он может вызывать эту ошибку sh?
UPDATE 2
Отличный ответ от @Acorn и комментарий от @RaymondChen , дал подсказки, чтобы отследить, а затем решить проблему. Были две проблемы (обе ошибки программиста).
ПРОБЛЕМА 1
Предполагается, что Whole Program Optimzation
(wPO) - компилятор MSV C компилирует «всю программу». Это неверное предположение для моего проекта DLL, который внутренне использует стороннюю библиотеку и, в свою очередь, использует внешнее приложение, написанное на Delphi. По умолчанию для этого параметра установлено значение Yes (/GL)
, но должно быть No
. Это похоже на ошибку в Visual Studio, но в любом случае программист должен знать об этом. Я не знаю всех деталей того, что должен делать WPO
, но, по крайней мере, для DLL, предназначенных для использования другими приложениями, значение по умолчанию следует изменить.
ПРОБЛЕМА 2
Серьезная ошибка программиста. Это был вызов сторонней библиотеки, которая вернула 128-байтовый код ASCII, что и было ошибкой:
// Before
// m_config::acSerial defined as "char acSerial[21]"
(void) m_pLib->GetPara(XPARA_PRODUCT_INFO, &m_config.acSerial[0]);
EnterCriticalSection(&crit); // Crash!
// After
#define SERIAL_LEN 20
// m_config::acSerial defined as "char acSerial[SERIAL_LEN+1]"
//...
char acSerial[128];
(void) m_pLib->GetPara(XPARA_PRODUCT_INFO, &acSerial[0]);
strncpy(m_config.acSerial, acSerial, max(SERIAL_LEN, strlen(acSerial)));
EnterCriticalSection(&crit); // Works!
Ошибка, теперь очевидная, заключается в том, что сторонняя библиотека не скопировала серийный номер. устройства в char*
, который я предоставил ... он скопировал 128 байт в мой char*
, перебирая все, что находится в памяти после acSerial
. Раньше этого не замечали, потому что m_pLib->GetPara(XPARA_PRODUCT_INFO, ...)
был одним из первых вызовов сторонней библиотеки, а остальные непрерывные данные в этот момент были в основном NULL.
Проблема никогда не заключалась в CRITICAL_SECTION
. Благодарю Желудь и Рэймонда Чена ... здравомыслие восстановлено в этом уголке вселенной.