InitializeCriticalSection работает в одном проекте, но не работает в другом - PullRequest
1 голос
/ 06 мая 2020

Использование 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. Благодарю Желудь и Рэймонда Чена ... здравомыслие восстановлено в этом уголке вселенной.

1 Ответ

2 голосов
/ 07 мая 2020

Если ваша программа вылетает из-под WPO (оптимизация, предполагающая, что все, что вы компилируете, является всей программой), это означает, что либо предположение неверно, либо оптимизатор в конечном итоге использует какое-то неопределенное поведение, которого раньше не было (без примененная оптимизация), даже если предположение верно.

В общем, избегайте включения оптимизаций, если вы действительно не уверены, что соответствуете их требованиям.

Для дальнейшего анализа предоставьте MRE .

...