2014-09-25 6 views
1

Я вижу утечку при использовании set_verify_callback в ssl-сокете. У меня есть класс «CClientSock» с элементом «boost :: asio :: ssl :: stream m_socket;»boost asio set_verify_callback leaks shared_ptr

Мой класс CClientSock происходит от «enable_shared_from_this

 

    class CClientSock : public boost::enable_shared_from_this 

Если я позвоню:

 

    m_socket.set_verify_callback(
     boost::bind(&CClientSock::verify_certificate, 
     shared_from_this(), 
     _1, 
     _2)); 

тогда мой экземпляр CClientSock никогда не разрушается.

Если я не вызываю «m_socket.set_verify_callback», тогда мой экземпляр CClientSock будет уничтожен правильно.

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

 

    void CClientSock::StartPoll() 
    { 
    m_socket.set_verify_mode(boost::asio::ssl::verify_peer | 
     boost::asio::ssl::verify_fail_if_no_peer_cert); 

    m_socket.set_verify_callback(
     boost::bind(&CClientSock::verify_certificate, 
     shared_from_this(), 
     _1, 
     _2)); 


    boost::asio::ip::tcp::resolver::iterator endpoint_iterator; 
    endpoint_iterator = ResolveAddress("xxx.xxx.xxx.xxx", nPort); 

    boost::asio::async_connect(
     m_socket.lowest_layer(), 
     endpoint_iterator, 
     boost::bind(&CClientSock::handle_connect, 
     shared_from_this(), 
     boost::asio::placeholders::error)); 
    } 

    bool CClientSock::verify_certificate(
     bool preverified, 
     boost::asio::ssl::verify_context& ctx 
    ) 
    { 
    char subject_name[256]; 
    X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); 
    X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256); 

    SYSTEMTIME st; 
    GetLocalTime(&st); 
    CString s; 
    s.Format("%02d SSL Verify: %s", m_nId, subject_name); 
    LogMsg(m_dwThreadId, &st, s, 0, NULL); 

    return preverified; 
    } 

Есть ли что-то, что должно быть сделано в «set_verify_callback», чтобы освободить ссылку?

ответ

1

У вас есть циклическая ссылка на сохранение в проверках обратного вызова в shared_ptr<CClientSock>. Контекст поддерживает элемент boost::asio::ssl::detail::verify_callback, который содержит общий указатель. Чтобы разорвать порочный круг, использовать слабый указатель с лямбда

std::weak_ptr<CClientSock> weak(shared_from_this()); 
m_socket.set_verify_callback([weak](bool p, boost::asio::ssl::verify_context& context) { 
    std::shared_ptr<CClientSock> strong(weak); 
    if (strong) { 
     strong->verify_certificate(p, context); 
    } 
}); 
+0

Спасибо Сэм - Я пробовал это, но не могу его скомпилировать, используя различные режимы захвата ([], [&] знак равно Я вижу различные формы: «ошибка C3493:« слабый »не может быть неявно захвачен, потому что не был задан режим захвата по умолчанию». Я не слишком хорошо знаком с лямбдами, поэтому возможны и другие варианты. Есть что-то, что мне не хватает? – Ken

+0

@ Ken необходимо явно захватить 'weak_ptr' в лямбда, ответ был обновлен –

0

У меня есть подозрение, что контекст SSL может быть повторно использован.

В этом случае, вы можете явно управлять контекстом, так что вы знаете, когда она разрушается:

Или, там может быть общий указатель цикла, созданный контекст холдинга на сокет, чтобы ни один из контекста или обработчика не был освобожден. (В этом случае вы должны увидеть больше проблем). Попробуйте разорвать порочный круг, явно отпуская обработчик:

s.set_verify_callback([](bool p, verify_context&) { return p; }); 
+0

Спасибо, но я не совсем понимаю, как использовать ваш пример. Не могли бы вы показать, как это будет реализовано в контексте моего примера? – Ken

+0

Вы должны будете проявлять терпение, так как я буду работать и всю ночь :) – sehe

0

После ответов sehe и Сэм Миллер, я получил эту работу. В итоге я использовал большую часть кода, показанного Сэмом, используя идею «общий цикл указателей», впервые опубликованный sehe.

Я изменил выражение лямбда, чтобы использовать предложение захвата 'по значению' ([=]). Это сообщило компилятору, как обрабатывать переменную weak_ptr. Затем я изменил выражение для функции, возвращающей логическое значение. Я закончил с этим, что позволяет уничтожить экземпляр объекта.

 
    boost::weak_ptr weak(shared_from_this()); 
    m_socket.set_verify_callback([=](bool p, boost::asio::ssl::verify_context& context)->bool { 
     boost::shared_ptr strong(weak); 
     if (strong) { 
      p = strong->verify_certificate(p, context); 
     } 
     return p; 
    }); 

Смежные вопросы