2017-01-23 1 views
1

Я пытаюсь научиться использовать классы Crypto++. Моя цель - генерировать открытые и закрытые ключи для шифрования RSA, а затем выполнять базовое шифрование и расшифровку открытого текста.Утечка памяти в Crypto ++ RSAES class

Так что я везу их примеру from here - "RSA Encryption Scheme (OAEP и SHA) с помощью фильтров", слегка модифицирован для читаемости:

Эта часть работает нормально:

CryptoPP::AutoSeededRandomPool rng; 

    //Generate Parameters 
    CryptoPP::InvertibleRSAFunction params; 
    params.GenerateRandomWithKeySize(rng, 3072); 

    //Create Keys 
    CryptoPP::RSA::PrivateKey privateKey(params); 
    CryptoPP::RSA::PublicKey publicKey(params); 

    std::string plain="Hello world!", cipher, recovered; 

    //Encryption 
    CryptoPP::RSAES_OAEP_SHA_Encryptor e(publicKey); 

Но тогда, когда я называю этот блок:

CryptoPP::StringSink* pSS = new CryptoPP::StringSink(cipher); 
    CryptoPP::PK_EncryptorFilter* pEF = new CryptoPP::PK_EncryptorFilter(rng, e, pSS); 

    CryptoPP::StringSource ss1(plain, true, pEF); 

Это вызывает утечку памяти. Я получаю следующее в окне Visual Studio вывода:

Detected memory leaks! 
Dumping objects -> 
{24781} normal block at 0x029BCFF8, 28 bytes long. 
Data: <class CryptoPP::> 63 6C 61 73 73 20 43 72 79 70 74 6F 50 50 3A 3A 
{24780} normal block at 0x029BCFB0, 8 bytes long. 
Data: <  > F8 CF 9B 02 00 00 00 00 
Object dump complete. 

ОК, так что я сделал самую очевидную вещь и добавил эти:

delete pEF; 
    delete pSS; 

но это вызвало необработанное исключение, поэтому я предположил, что один из деструкторы в классах Crypto ++ позаботились об удалении некоторых из этих объектов.

Итак, вопрос в том, откуда эта утечка?

Я попытался заходя в StringSink, PK_EncryptorFilter и StringSource с Visual Studio отладчик, чтобы посмотреть, что происходит, но код довольно запутанным, чтобы понять это сразу.

Любая идея, как исправить эти утечки памяти?

+1

Наверняка вы можете урезать свою утечку до [mcve] –

+0

@jww: я сам смог ответить на свой второй вопрос. См. Редактирование в моем OP. – c00000fd

+0

@jww: Эй! Я только что опубликовал решение этой второй проблемы, и вы удалили ее. WTF? – c00000fd

ответ

0

Это вызывает утечку памяти. Я получаю следующее в окне вывода Visual Studio :

Detected memory leaks! 
Dumping objects -> 
{24781} normal block at 0x029BCFF8, 28 bytes long. 
Data: <class CryptoPP::> 63 6C 61 73 73 20 43 72 79 70 74 6F 50 50 3A 3A 
{24780} normal block at 0x029BCFB0, 8 bytes long. 
Data: <  > F8 CF 9B 02 00 00 00 00 
Object dump complete. 

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

Я считаю, что то, что вы видите, - это старая ошибка Microsoft от typeinfo.name() memory leaks. Это было вокруг с VC 5.0 или VC 6.0 дней.


CryptoPP::StringSink* pSS = new CryptoPP::StringSink(cipher); 
CryptoPP::PK_EncryptorFilter* pEF = new CryptoPP::PK_EncryptorFilter(rng, e, pSS); 

CryptoPP::StringSource ss1(plain, true, pEF); 

Вот что трубопровод часто выглядит следующим образом:

CryptoPP::StringSource ss(plain, true, 
    new CryptoPP::PK_EncryptorFilter(rng, e, 
     new CryptoPP::StringSink(cipher))); 

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


ОК, так что я сделал самую очевидную вещь и добавил эти:

delete pEF; 
delete pSS; 

но это вызвало необработанное исключение

Да, это было не так. Из Readme.txt:

* Важные замечания по использованию *

  1. Если конструктор A принимает указатель на объект B (за исключением примитивных типов, таких как Int и голец), то А принадлежит B и удалит B при уничтожении А. Если конструктор для A берет ссылку на объект B, то вызывающий абонент сохраняет право собственности на B и не должен уничтожить его до тех пор, пока ему не понадобится.

  2. Crypto ++ является потокобезопасным на уровне класса. Это означает, что вы можете безопасно использовать Crypto ++ в многопоточном приложении, но вы должны обеспечить синхронизацию , когда несколько потоков обращаются к общему объекту Crypto ++.

pEF и pSS были указатели, и они принадлежали кому-то другому. Они были удалены дважды, что вызвало исключение.


Утечка памяти в классе Crypto ++ RSAES ...

Если запустить программу cryptest.exe, то вы увидите 60 или 80 утечек сообщили. Я пытался найти решение этой ошибки в течение 10 или 15 лет. Совсем недавно был How to remediate Microsoft typeinfo.name() memory leaks? на переполнение стека.

EDIT также см Windows Debug build memory leaks cleared в списке пользователей и Commit 301437e693fe8bff. Для предотвращения проблем на платформах Microsoft библиотека перешла на статическую инициализацию из динамической инициализации. Доступ к списку статических инициализаторов осуществляется с помощью inti_seg в Windows; и constructor и init_priority атрибуты с GCC.

Его «лучшее усилие» для использования статической инициализации, если доступно. В противном случае все возвращается к динамической инициализации. Здесь «статическая инициализация» означает получение библиотеки в статический список инициализации CRT, который запускает функции конструктора и вызывает глобальные объекты ctors (а не статический объект ванильной C++).

+0

Спасибо за подтверждение. И да, я видел в других источниках, что люди обвиняют Microsoft-компилятор. Но почему, если я откажусь от «CryptoPP» v.5.6.5 до v.5.6.2, утечка памяти исчезнет? – c00000fd

+0

@ c00000fd - Я не уверен. Много изменилось между 5.6.2 и 5.6.5. Мы также не видели вашу полную программу. Но я уверен, что симптомы, которые вы показываете, являются ошибкой Microsoft. Во-первых, распределение *** 'N' *** сбрасывает внутренний (runtime) идентификатор' class CryptoPP :: '. Во-вторых, его сразу же следует на *** 'N + 1' *** с помощью дампа данных. Примечание: внутренняя схема отслеживания классов и имен изменилась на VS2015. Они больше не являются последовательными во время дампа памяти. – jww

+0

Как насчет того, чтобы мы прошли легкий путь, чтобы подтвердить вашу теорию. Можете ли вы опубликовать простой пример, чтобы продемонстрировать утечку typeinfo.name(), которую я могу скомпилировать в VS2008? Что-то вроде двух-трех строк кода. – c00000fd