2017-11-06 14 views
0

내 asio 기반 응용 프로그램에서 오류 처리에 문제가 있습니다. async_read/async_write 함수를 사용하여 asio 단일 스레드/단일 io_service를 사용하고 완성 처리기에서 나에게 전달 된 오류 코드가 null이 아닌 경우 오류가 발생하기 때문에 해당 .message() 메서드를 호출하면 segfault가 발생합니다. -category 포인터가 null을 가리 킵니다. 그러나 실제 값은 항상 정확합니다.부스트 asio 오류 범주가 null입니다.

이상하게도 테스트 응용 프로그램에서이를 재현 할 수 없습니다. 이것은 내가 여기에 예상대로 작동) (메시지를 호출하고 있지만, 오류의 경우에있어 어떤 본질적 :

void do_write(std::shared_ptr<std::vector<unsigned char>> , std::shared_ptr<boost::asio::ip::tcp::socket>); 

void do_read(std::shared_ptr<std::vector<unsigned char>> buf, std::shared_ptr<boost::asio::ip::tcp::socket> sock) 
{ 
    boost::asio::async_read(*sock, boost::asio::buffer(*buf), boost::asio::transfer_exactly(100000), 
          [sock, buf](const boost::system::error_code& ec, std::size_t bytes) 
    { 
     std::cout << "read\n"; 
     if (ec) { 
     std::cout << ec.message() << std::flush; 
     } else { 
     do_write(buf, sock); 
     } 
    }); 
} 

void do_write(std::shared_ptr<std::vector<unsigned char>> buf, std::shared_ptr<boost::asio::ip::tcp::socket> sock) 
{ 
    boost::asio::async_write(*sock, boost::asio::buffer(*buf), [sock, buf](const boost::system::error_code& ec, std::size_t bytes) 
    { 
     std::cout << "write\n"; 
     if (ec) { 
     std::cout << ec.message() << std::flush; 
     } else { 
     do_read(buf, sock); 
     } 
    }); 
} 

int main() 
{ 
    auto buf = std::make_shared<std::vector<unsigned char>>(100000); 

    unsigned short port = 1113; 
    boost::asio::io_service ios; 
    boost::asio::ip::tcp::acceptor acptr {ios, boost::asio::ip::tcp::endpoint{boost::asio::ip::tcp::v4(), port}}; 

    auto socket = std::make_shared<boost::asio::ip::tcp::socket>(acptr.get_io_service()); 
    acptr.async_accept(*socket, [socket, buf](const boost::system::error_code& ec) 
    { 
     do_read(buf, socket); 
    }); 
    ios.run(); 
} 

내가 생각하지 않는 내 응용 프로그램의 수명에 문제가, AddressSanitizer은 찾을 수 없습니다 잠재적 인 오류가 있으며 아무런 문제없이 수백 메가 바이트의 데이터를 이동할 수 있습니다. 또한 message()에 대한 주석 처리 만 제거하면 서버는 계속 실행되어 새로운 연결을 올바르게 처리합니다. 어쨌든 충돌이 발생할 때 콜 스택이 있습니다 :

https://gist.github.com/mariusherzog/82f24caf9eea4d94946706aa8c025ef1 범주는 프레임 11에서 null을 가리 킵니다.

나는 그 소리 3.9.1과 GCC와 부스트 1.62로 리눅스를 사용 5.4.0

답변

1

내가 생각할 수있는 유일한 것은 지금 코드 조각 글로벌 정적 데이터 구축의 일환으로 초기화한다는 것입니다. 그 당시에 카테고리 참조를 가져 왔고 번역 단위가 여러 개인 경우 카테고리 인스턴스가 아직 구성되지 않았을 수 있습니다.

이 상황을 애정 표현하면 Static Initialization Order Fiasco이라고합니다. 그 외에는


는 반대의 (글로벌 범주가 파괴 된) 마음에 온다. 이것은 약간 쉬울 것 같습니다. 왜냐하면 1. 당신이 종료시에 일어난다는 것을 깨달았 기 때문입니다. 2. 그러한 시나리오에서는 참조가 보통 null이되지 않습니다. - 구현이 가능할 수도 있습니다.

+0

팁 주셔서 감사합니다. 오류 범주 (get_misc_category)는 Meyer의 싱글 톤을 통해 액세스됩니다. 중단 점을 입력하면 실제 인스턴스는 처음부터 메모리에서 모두 null입니다. 이것이 asio의 버그일까요? –

+0

또한 내 응용 프로그램에서 여러 번 호출됩니다. 다른 번역 단위로 인한 것 같습니다 ... –

+0

더 중요한 것은'get_misc_category()'***가 **입니다. * Meyer의 싱글 톤. 그게 잘못되면 내가 잘못 가고 있다고 상상할 수있는 유일한 것은 런타임 링크입니다. – sehe