C++ Boost::asio x64 async_send 失败并出现错误 10014 (WSAEFAULT)
C++ Boost::asio x64 async_send fails with error 10014 (WSAEFAULT)
我们有一个 C++ 程序,我将在 Visual Studio 2017 年移植到 x64。这个程序使用 boost asio 通过 TCP 连接发送数据。该代码在 32 位中运行良好。但是当我构建然后 运行 它用于 x64 时 async_send 失败并出现错误 10014 (WSAEFAULT),我调试了 boost asio 代码,可以预见的罪魁祸首是对 windows 方法的调用WSASend(在 boost\asio\detail\impl\win_iocp_socket_service_base.ipp 中):
https://msdn.microsoft.com/en-us/library/windows/desktop/ms742203(v=vs.85).aspx
这是我当前失败的相关代码(简化以排除其他可能的原因)。
此时连接已成功建立,我尝试通过连接发送第一个数据:
std::vector<unsigned char> testWriteBuffer(16,0);
boost::asio::async_write(m_Socket,
boost::asio::buffer(&testWriteBuffer[0], testWriteBuffer.size()),
boost::bind(&CTIPCTCPConnection::IOHandleWrite, boost::static_pointer_cast<CTIPCTCPConnection>(shared_from_this()), NextMessage->IsLowPriority(),boost::asio::placeholders::error));
其中 m_Socket 是这样的:
boost::asio::ip::tcp::socket m_Socket;
不确定这是否相关,这是编译器的命令行(我们使用相同的选项构建了 boost 库):
/GS /W4 /Zc:wchar_t /I"..\..\..\Export\Include" /I"..\Include" /I"..\..\Include" /I"..\..\..\Include" /I"..\..\..\Ref\Include" /ZI /Gm- /Od /sdl- /Fd"C:\Workspaces\grpMiddleware\gc_AsioCom_x64\AsioCommunication\Test\Vc150\Debug_x64\Test.pdb" /Zc:inline /fp:precise /Zp1 /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_WIN32_WINNT=0X603" /D "WINVER=0X603" /D "_MBCS" /D "_CRT_SECURE_NO_WARNINGS" /D "_TOKHEIM_FUELPOS" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /MDd /FC /Fa"C:\Workspaces\grpMiddleware\gc_AsioCom_x64\AsioCommunication\Test\Vc150\Debug_x64\" /EHsc /nologo /Fo"C:\Workspaces\grpMiddleware\gc_AsioCom_x64\AsioCommunication\Test\Vc150\Debug_x64\" /Fp"C:\Workspaces\grpMiddleware\gc_AsioCom_x64\AsioCommunication\Test\Vc150\Debug_x64\Testd.pch" /diagnostics:classic
从您发布的几行来看,似乎有点糟糕的是 std::vector<unsigned char> testWriteBuffer(16,0)
最有可能存在于堆栈中,因此在您调用 async_write
后被销毁,但它应该在完成例程之前一直存在运行。正如您在 boost::asio::buffer
的文档中所见
It is the responsibility of the application to ensure the memory region remains valid until it is no longer required for an I/O operation.
更新
嗯,是的,WSABUF 受到 /Zp1
的影响,请看这个简单的例子:
//#pragma pack(push, 1)
#include <Winsock2.h>
#include <cstdio>
int main(int argc, char** argv)
{
WSABUF buffer;
printf("size - %zu, offset of buf - %zu, offset of len - %zu", sizeof(buffer), offsetof(decltype(buffer), buf), offsetof(decltype(buffer), len));
return 0;
}
没有它给的包 - size - 16, offset of buf - 8, offset of len - 0
,
在 x64 上使用 - size - 12, offset of buf - 4, offset of len - 0
。你不能隔离 boost i/o 部分并在没有 /Zp1
的情况下编译 boost 吗?
显然这是因为 /Zp1 编译标志(结构成员对齐)。一旦我从项目中删除它及其所有依赖项,它就会再次正常工作。删除它确实会打开一个全新的蠕虫罐头,但具有向后兼容性。
我们有一个 C++ 程序,我将在 Visual Studio 2017 年移植到 x64。这个程序使用 boost asio 通过 TCP 连接发送数据。该代码在 32 位中运行良好。但是当我构建然后 运行 它用于 x64 时 async_send 失败并出现错误 10014 (WSAEFAULT),我调试了 boost asio 代码,可以预见的罪魁祸首是对 windows 方法的调用WSASend(在 boost\asio\detail\impl\win_iocp_socket_service_base.ipp 中): https://msdn.microsoft.com/en-us/library/windows/desktop/ms742203(v=vs.85).aspx
这是我当前失败的相关代码(简化以排除其他可能的原因)。 此时连接已成功建立,我尝试通过连接发送第一个数据:
std::vector<unsigned char> testWriteBuffer(16,0);
boost::asio::async_write(m_Socket,
boost::asio::buffer(&testWriteBuffer[0], testWriteBuffer.size()),
boost::bind(&CTIPCTCPConnection::IOHandleWrite, boost::static_pointer_cast<CTIPCTCPConnection>(shared_from_this()), NextMessage->IsLowPriority(),boost::asio::placeholders::error));
其中 m_Socket 是这样的:
boost::asio::ip::tcp::socket m_Socket;
不确定这是否相关,这是编译器的命令行(我们使用相同的选项构建了 boost 库):
/GS /W4 /Zc:wchar_t /I"..\..\..\Export\Include" /I"..\Include" /I"..\..\Include" /I"..\..\..\Include" /I"..\..\..\Ref\Include" /ZI /Gm- /Od /sdl- /Fd"C:\Workspaces\grpMiddleware\gc_AsioCom_x64\AsioCommunication\Test\Vc150\Debug_x64\Test.pdb" /Zc:inline /fp:precise /Zp1 /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_WIN32_WINNT=0X603" /D "WINVER=0X603" /D "_MBCS" /D "_CRT_SECURE_NO_WARNINGS" /D "_TOKHEIM_FUELPOS" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /MDd /FC /Fa"C:\Workspaces\grpMiddleware\gc_AsioCom_x64\AsioCommunication\Test\Vc150\Debug_x64\" /EHsc /nologo /Fo"C:\Workspaces\grpMiddleware\gc_AsioCom_x64\AsioCommunication\Test\Vc150\Debug_x64\" /Fp"C:\Workspaces\grpMiddleware\gc_AsioCom_x64\AsioCommunication\Test\Vc150\Debug_x64\Testd.pch" /diagnostics:classic
从您发布的几行来看,似乎有点糟糕的是 std::vector<unsigned char> testWriteBuffer(16,0)
最有可能存在于堆栈中,因此在您调用 async_write
后被销毁,但它应该在完成例程之前一直存在运行。正如您在 boost::asio::buffer
It is the responsibility of the application to ensure the memory region remains valid until it is no longer required for an I/O operation.
更新
嗯,是的,WSABUF 受到 /Zp1
的影响,请看这个简单的例子:
//#pragma pack(push, 1)
#include <Winsock2.h>
#include <cstdio>
int main(int argc, char** argv)
{
WSABUF buffer;
printf("size - %zu, offset of buf - %zu, offset of len - %zu", sizeof(buffer), offsetof(decltype(buffer), buf), offsetof(decltype(buffer), len));
return 0;
}
没有它给的包 - size - 16, offset of buf - 8, offset of len - 0
,
在 x64 上使用 - size - 12, offset of buf - 4, offset of len - 0
。你不能隔离 boost i/o 部分并在没有 /Zp1
的情况下编译 boost 吗?
显然这是因为 /Zp1 编译标志(结构成员对齐)。一旦我从项目中删除它及其所有依赖项,它就会再次正常工作。删除它确实会打开一个全新的蠕虫罐头,但具有向后兼容性。