Zeromq socket.RECV()提出了一个stack_overflow异常

ZeroMQ socket.recv() raised a STACK_OVERFLOW exception

本文关键字:stack 一个 异常 overflow RECV socket Zeromq      更新时间:2023-10-16

如果在 .dll中使用此代码呼叫 socket.recv() 提出了一个异常STACK_OVERFLOW,但是当此代码汇编时,>作为.exe 它有效。

为什么?

我运行了" C:windowssystem32rundll32.exe myDll.dll StartUp" .dll -test

void StartUp()
{
zmq::context_t context(1);
zmq::socket_t socket(context, ZMQ_REP);
socket.bind("tcp://127.0.0.1:3456");
zmq::message_t msgIN, msgOUT("test", 4);
while (true){

    socket.recv(&msgIN);
    socket.send(msgOUT);
};
}

Callstack:

libzmq-v120-mt-gd-4_2_2.dll!zmq::mailbox_t::recv(zmq::command_t * cmd_=0x0231f700, int timeout_=0x00000000) 
libzmq-v120-mt-gd-4_2_2.dll!zmq::io_thread_t::in_event() 
libzmq-v120-mt-gd-4_2_2.dll!zmq::select_t::loop() 
libzmq-v120-mt-gd-4_2_2.dll!zmq::select_t::worker_routine(void * arg_=0x002f1778) 
libzmq-v120-mt-gd-4_2_2.dll!thread_routine(void * arg_=0x002f17c0) 

主线程呼叫刻在:

libzmq-v120-mt-gd-4_2_2.dll!zmq::signaler_t::wait(int timeout_=0xffffffff)
libzmq-v120-mt-gd-4_2_2.dll!zmq::mailbox_t::recv(zmq::command_t * cmd_=0x0019f3c0, int timeout_=0xffffffff) 
libzmq-v120-mt-gd-4_2_2.dll!zmq::socket_base_t::process_commands(int timeout_, bool throttle_)
libzmq-v120-mt-gd-4_2_2.dll!zmq::socket_base_t::recv(zmq::msg_t * msg_=0x0019f628, int flags_=0x00000000)
libzmq-v120-mt-gd-4_2_2.dll!s_recvmsg(zmq::socket_base_t * s_=0x006f6c70, zmq_msg_t * msg_=0x0019f628, int flags_=0x00000000) 
libzmq-v120-mt-gd-4_2_2.dll!zmq_msg_recv(zmq_msg_t * msg_=0x0019f628, void * s_=0x006f6c70, int flags_=0x00000000)
mydll.dll!zmq::socket_t::recv(zmq::message_t * msg_=0x0019f628, int flags_=0x00000000)
mydll.dll!StartUp() 

更新:

此示例,也以相同的原因崩溃。有人知道有任何例外堆栈溢出的原因吗?

zmq::context_t context(1);
zmq::socket_t socket(context, ZMQ_REP);
socket.bind("tcp://*:7712");
while (1){
    Sleep(10);
}

反向问题 - 隔离MCVE:

这是如何工作的 myDll.dll -test 工作,
如果由C:windowssystem32rundll32.exe myDll.dll StartUp运行?发布屏幕输出。

void StartUp()
{
     std::cout << "INF:: ENTRY POINT ( C:windowssystem32rundll32.exe myDll.dll StartUp )" << std::endl;
     std::cout << "INF:: WILL SLEEP  ( C:windowssystem32rundll32.exe myDll.dll StartUp )" << std::endl;
     Sleep( 10 );
     std::cout << "INF:: SLEPT WELL  ( C:windowssystem32rundll32.exe myDll.dll StartUp )" << std::endl;
     std::cout << "INF:: WILL RETURN ( C:windowssystem32rundll32.exe myDll.dll StartUp )" << std::endl;
}

崩溃的原因是optional_header rundll32文件中的sizeofstackCommit值。它太小(0xc000),我将其更改为0x100000。现在所有人都起作用。

Zeromq对象需要某些尊重以与:

雷达下有许多功能,可能会破坏破坏,就像您已经在屏幕上看到的那样。

最佳读取适当的护理,Zeromq C 绑定参考文档以及原始的Zeromq API(在C 绑定中经常提到)。

都确实强调了永远不要直接处理zmq::message_t实例,而是通过使用"服务" - 函数(通常在C 中重新包装为实例方法)。

zmq::message_t messageIN,
               messageOUT;
bool successFlag;
while (true){
             successFlag  = socket.recv( &messageIN );
     assert( successFlag && "EXC: .recv( &messageIN )" );
                        /* The zmq_recv() function shall receive a message
                           from the socket referenced by the socket argument
                           and store it in the message referenced by the msg
                           argument.
                           Any content previously stored in msg shall be
                           properly deallocated.
                           If there are no messages available on the specified
                           socket the zmq_recv() function shall block
                           until the request can be satisfied.
                           */
                       messageOUT.copy(  messageIN );
             successFlag  = socket.send(  messageOUT );
     assert( successFlag && "EXC: .send(  messageOUT )" );
                        /* The zmq_send() function shall queue the message
                           referenced by the msg argument to be sent to
                           the socket referenced by the socket argument.
                           The flags argument is a combination of the flags
                           defined { ZMQ_NOBLOCK, ZMQ_SNDMORE }
                           The zmq_msg_t structure passed to zmq_send()
                           is nullified during the call.
                           If you want to send the same message to multiple
                           sockets you have to copy it using (e.g.
                           using zmq_msg_copy() ).
                           A successful invocation of zmq_send()
                           does not indicate that the message
                           has been transmitted to the network,
                           only that it has been queued on the socket
                           and ØMQ has assumed responsibility for the message.
                           */
};

我的怀疑是参考计数,添加了越来越多的实例,由zmq::message_t message;构造函数在无限的while( true ){...} -loop中产生,从未见过它自己的公平驱动器。该堆栈具有物理限制的容量,并且在DLL内部无堆栈管理护理,迟早会失败。

zmq::message_t 实例是一个非常昂贵的玩具,因此始终欢迎使用良好的资源管理实践(预分配,重复使用,受控破坏)来获得专业代码。

q.e.d。


尾声的清晰目的:

对Dijkstra关于错误狩猎和软件测试的看法有所释义:"如果我看不到错误,那并不意味着,代码中没有任何错误(除了链接到其他外部功能之外,任何外部功能也越少)。"

没有堆栈分配?

是,否可见一个。

Zeromq API将更多的光放入其中:

" zmq_msg_init_size()函数应分配存储消息大小的任何资源,并初始化MSG引用的消息对象以表示新分配的消息。

实施方式应选择是将消息内容存储在堆栈(小消息)还是在堆上(大消息)。出于绩效原因,zmq_msg_init_size()不得清除消息数据。"

多年来,到目前为止,自从V.2.1 以来,基于Zeromq API的跨平台分布式系统花费了很多年,这教会了我对明确资源控制的谨慎的经验。一旦您没有开发自己的语言对本机API的约束力。


在所有不受支持的批评之后,让我们再添加Zeromq的引文:

这添加了一个视图,即message_t内容的正确间接操作是由库C 绑定本身完成的,包裹在琐碎的助手功能中:

来自 zhelpers.hpp

//  Receive 0MQ string from socket and convert into string
static std::string
s_recv (zmq::socket_t & socket) {
    zmq::message_t message;
    socket.recv(&message);
    return std::string(static_cast<char*>(message.data()), message.size());
}
//  Convert string to 0MQ string and send to socket
static bool
s_send (zmq::socket_t & socket, const std::string & string) {
    zmq::message_t message(string.size());
    memcpy (message.data(), string.data(), string.size());
    bool rc = socket.send (message);
    return (rc);
}
//  Sends string as 0MQ string, as multipart non-terminal
static bool
s_sendmore (zmq::socket_t & socket, const std::string & string) {
    zmq::message_t message(string.size());
    memcpy (message.data(), string.data(), string.size());
    bool rc = socket.send (message, ZMQ_SNDMORE);
    return (rc);
}