以下是我能得到的最小例子。它确实需要在单独的文件中,因为这似乎是导致分段错误错误的原因。
我使用Mingw x32 4.8.1和Asio独立1.10.6。我还测试了TDM GCC 4.7.1和Mingw x64 4.8.1。 Windows下的所有这些都产生相同的段错误。在Linux下使用最新版本的GCC没有这样的问题。
编辑:我刚刚完成了对Mingw-w64 5.2.0(Mingw-Builds版本的测试)的测试。同样的问题。
我还测试了在新虚拟机上使用TDM GCC 4.8.1进行编译并获得相同的段错误。编辑:我现在也在使用TDM GCC 4.8.1的完全不同的机器上进行了测试
在所有情况下,我都使用-std=c++11
,-g
和-Wall
。我也用-g
编译并得到了相同的结果。我需要C ++ 11标志,因为我不想依赖boost,只是asio。
在单个main.cpp
文件中使用以下代码,没有问题,程序似乎按预期运行。但是,如果我将每个类放入其自己的*.hpp
和*.cpp
文件中,我会在Server
类构造函数中获得段错误。
我进一步回去把所有东西都放回main.cpp
并开始逐个移动每个班级。最终课程结束后,段错误开始发生,Client
被放入其自己的文件中。
此外,由于我将所有类放入一个文件并移动它们等,我确保任何不需要的目标文件都没有链接到我的.exe。
这段代码开始变得更大,但它已缩小到这个范围。
Server.hpp
#ifndef SERVER_HPP_INCLUDED
#define SERVER_HPP_INCLUDED
#include <string>
#include <memory>
#define ASIO_STANDALONE
#include <asio.hpp>
using namespace asio::ip;
namespace network
{
class Server
{
public:
Server(asio::io_service& ioService, uint16_t port);
private:
tcp::acceptor m_acceptor;
};
}
#endif // SERVER_HPP_INCLUDED
Server.cpp
#include "Server.hpp"
using namespace network;
#include <iostream>
Server::Server(asio::io_service& ioService, uint16_t port)
: m_acceptor(ioService, tcp::endpoint(tcp::v4(),port))
{
}
Client.hpp
#ifndef CLIENT_HPP_INCLUDED
#define CLIENT_HPP_INCLUDED
#include <vector>
#define ASIO_STANDALONE
#include <asio.hpp>
using namespace asio::ip;
namespace network
{
class Client
{
public:
Client(asio::io_service& ioService);
private:
asio::steady_timer m_timer;
};
}
#endif // CLIENT_HPP_INCLUDED
Client.cpp
#include "Client.hpp"
using namespace network;
#include <iostream>
Client::Client(asio::io_service& ioService)
: m_timer(ioService)
{
}
的main.cpp
#include <iostream>
#define ASIO_STANDALONE
#include <asio.hpp>
using namespace asio::ip;
#include "Server.hpp"
int main()
{
try
{
uint16_t peerRequestPort = 63000;
asio::io_service io_service;
network::Server server(io_service,peerRequestPort);
}
catch(std::exception& e)
{
std::cout << e.what() << std::endl;
}
return 0;
}
这是来自GDB的callstack:
#0 00406729 asio::detail::service_registry::keys_match(key1=..., key2=...) (F:/GameDev/asio-1.10.6/asio-1.10.6/include/asio/detail/impl/service_registry.ipp:89)
#1 ?? 0x0040696e in asio::detail::service_registry::do_use_service (this=0x5d2f10, key=..., factory=0x406b44 <asio::detail::service_registry::create<asio::socket_acceptor_service<asio::ip::tcp> >(asio::io_service&)>) (F:/GameDev/asio-1.10.6/asio-1.10.6/include/asio/detail/impl/service_registry.ipp:113)
#2 004068B6 asio::detail::service_registry::use_service<asio::socket_acceptor_service<asio::ip::tcp> >(this=0x5d2f10) (F:/GameDev/asio-1.10.6/asio-1.10.6/include/asio/detail/impl/service_registry.hpp:47)
#3 00403857 asio::use_service<asio::socket_acceptor_service<asio::ip::tcp> >(ios=...) (F:/GameDev/asio-1.10.6/asio-1.10.6/include/asio/impl/io_service.hpp:32)
#4 004039B3 asio::basic_io_object<asio::socket_acceptor_service<asio::ip::tcp>, true>::basic_io_object(this=0x28fe48, io_service=...) (F:/GameDev/asio-1.10.6/asio-1.10.6/include/asio/basic_io_object.hpp:182)
#5 00403B29 asio::basic_socket_acceptor<asio::ip::tcp, asio::socket_acceptor_service<asio::ip::tcp> >::basic_socket_acceptor(this=0x28fe48, io_service=..., endpoint=..., reuse_addr=true) (F:/GameDev/asio-1.10.6/asio-1.10.6/include/asio/basic_socket_acceptor.hpp:137)
#6 00401D3B network::Server::Server(this=0x28fe48, ioService=..., port=63000) (F:\GameDev\Dischan\Tests\Server.cpp:7)
#7 004018F1 main() (F:\GameDev\Dischan\Tests\main.cpp:17)
最后,这是记忆博士的输出:
Dr. Memory version 1.8.0 build 8 built on Sep 9 2014 16:27:02
Dr. Memory results for pid 5296: "tests.exe"
Application cmdline: "tests.exe"
Recorded 108 suppression(s) from default C:\Program Files (x86)\Dr. Memory\bin\suppress-default.txt
Error #1: UNADDRESSABLE ACCESS: reading 0x00000007-0x0000000b 4 byte(s)
# 0 asio::detail::service_registry::keys_match [F:/GameDev/asio-1.10.6/asio-1.10.6/include/asio/detail/impl/service_registry.ipp:89]
# 1 asio::detail::service_registry::do_use_service [F:/GameDev/asio-1.10.6/asio-1.10.6/include/asio/detail/impl/service_registry.ipp:113]
# 2 asio::detail::service_registry::use_service<> [F:/GameDev/asio-1.10.6/asio-1.10.6/include/asio/detail/impl/service_registry.hpp:47]
# 3 asio::use_service<> [F:/GameDev/asio-1.10.6/asio-1.10.6/include/asio/impl/io_service.hpp:32]
# 4 asio::basic_io_object<>::basic_io_object [F:/GameDev/asio-1.10.6/asio-1.10.6/include/asio/basic_io_object.hpp:182]
# 5 asio::basic_socket_acceptor<>::basic_socket_acceptor [F:/GameDev/asio-1.10.6/asio-1.10.6/include/asio/basic_socket_acceptor.hpp:137]
# 6 network::Server::Server [F:/GameDev/Dischan/Tests/Server.cpp:7]
# 7 main [F:/GameDev/Dischan/Tests/main.cpp:17]
Note: @0:00:00.780 in thread 7464
Note: instruction: mov 0x04(%eax) -> %eax
Error #2: LEAK 36 direct bytes 0x02530860-0x02530884 + 124 indirect bytes
# 0 replace_operator_new [d:\drmemory_package\common\alloc_replace.c:2609]
# 1 asio::io_service::io_service [F:/GameDev/asio-1.10.6/asio-1.10.6/include/asio/impl/io_service.ipp:39]
# 2 main [F:/GameDev/Dischan/Tests/main.cpp:15]
===========================================================================
FINAL SUMMARY:
DUPLICATE ERROR COUNTS:
SUPPRESSIONS USED:
ERRORS FOUND:
1 unique, 1 total unaddressable access(es)
0 unique, 0 total uninitialized access(es)
0 unique, 0 total invalid heap argument(s)
0 unique, 0 total GDI usage error(s)
0 unique, 0 total handle leak(s)
0 unique, 0 total warning(s)
1 unique, 1 total, 160 byte(s) of leak(s)
0 unique, 0 total, 0 byte(s) of possible leak(s)
ERRORS IGNORED:
14 potential error(s) (suspected false positives)
(details: C:\Users\User\AppData\Roaming\Dr. Memory\DrMemory-tests.exe.5296.000\potential_errors.txt)
12 potential leak(s) (suspected false positives)
(details: C:\Users\User\AppData\Roaming\Dr. Memory\DrMemory-tests.exe.5296.000\potential_errors.txt)
24 unique, 24 total, 2549 byte(s) of still-reachable allocation(s)
(re-run with "-show_reachable" for details)
Details: C:\Users\User\AppData\Roaming\Dr. Memory\DrMemory-tests.exe.5296.000\results.txt
我只是看不出为什么我会遇到段错误。即使在评论出所有有意义的代码之后,它仍然会发生。
修改
我已经编辑了上面的代码,表明只有Server
构造函数似乎会导致问题和每个文件的内容。 (我再次确保只编译和链接这些目标文件)。
编辑2
我已经使用TDM GCC 4.7.1,Mingw Builds x64 4.8.1和Mingw Builds x32 4.8.1对此进行了测试。所有这些都有相同的结果。
编辑3
我进一步减少了代码方式。现在,在Client
中,如果删除任何需要构造asio
的{{1}}个对象,则不存在段错误。但到目前为止我尝试的任何asio::io_service&
类型都产生了相同的段错误。例如,这不是asio
类中的问题,其具有Server
。最重要的是没有创建asio::acceptor
的实例,所以为什么它影响程序并在Client
的构造函数中产生段错误是很奇怪的。
编辑4
我现在已完全删除了Server
和Server.hpp
,并将Server.cpp
更新为:
的main.cpp
main.cpp
我仍然得到段错误,而callstack反映了#include <iostream>
#define ASIO_STANDALONE
#include <asio.hpp>
using namespace asio::ip;
int main()
{
try
{
uint16_t peerRequestPort = 63000;
asio::io_service io_service;
auto protocol = tcp::v4();
tcp::endpoint endpoint(protocol,peerRequestPort);
tcp::acceptor m_acceptor(io_service, endpoint);
}
catch(std::exception& e)
{
std::cout << e.what() << std::endl;
}
return 0;
}
构造函数的缺失。段错仍然在同一个地方。 DrMemory的结果看起来也一样。
与以前一样,如果我没有链接Server
目标文件,我没有问题。
编辑5
根据要求,这是来自Code :: Blocks
的构建日志Client
编辑6
我现在开始超越自己的能力但是我设法找到了一些问题(我正在学习一些很酷的新东西)。
当创建一个需要g++.exe -std=c++11 -Wall -D_WIN32_WINNT=0x0501 -g -I..\..\asio-1.10.6\asio-1.10.6\include -c F:\GameDev\Dischan\Tests\Client.cpp -o obj\Debug\Client.o
g++.exe -std=c++11 -Wall -D_WIN32_WINNT=0x0501 -g -I..\..\asio-1.10.6\asio-1.10.6\include -c F:\GameDev\Dischan\Tests\main.cpp -o obj\Debug\main.o
g++.exe -o Build\Debug\Windows\Tests.exe obj\Debug\Client.o obj\Debug\main.o -lws2_32 -lwsock32
Output file is Build\Debug\Windows\Tests.exe with size 723.02 KB
Process terminated with status 0 (0 minute(s), 3 second(s))
0 error(s), 0 warning(s) (0 minute(s), 3 second(s))
的对象时,它会添加&#34; services&#34;到asio::io_service&
。它们在所有io_service
个实例中都是静态的。因此,当发出服务请求时,会有一个迭代循环,通过该循环看起来是已创建服务的链接列表。如果已经创建了所请求的服务;然后创建它。
此信息来自reference for io_service
和查看io_service
(第111行)。
这是通过调用service_registry.ipp
在内部完成的。 service_registry::do_use_service
的成员service_registry
的成员名为first_service_
。第一个服务应该有一个名为asio::io_service::service*
的成员,这是我提到的链接列表部分。
首次调用next_
时(构建service_registry::do_use_service
时),asio::acceptor
成员的值first_service_
显然不对。所以我认为这是段错误的根源。
为什么这个成员的值0xffffffff
超出了我的范围。我的理解是,只有旧的/古怪的机器为0xffffffff
指针保留了这个地址......但我承认我可以离开。
我通过这样做很快检查了一下:
null
并设置断点以读取值。 int* p = nullptr;
if(p)
std::cout << "something" << std::endl;
的值为p
,而不是0x0
。
因此,我在0xffffffff
(service_registry
)的构造函数和析构函数(如果它显式调用某处)和三种方法asio/detail/impl/service_registry.hpp
上设置了一个断点,{ {1}}和do_has_service
。我的想法是尝试跟踪do_use_service
获得不良价值的时间点。
我没有运气。这些是唯一可能改变do_add_service
的价值的地方。
我认为这意味着某些内容已损坏堆栈并更改了first_service_
的地址。但是,我只是一个业余爱好者......
我确实检查了构造函数的first_service_
指针的地址与用于调用first_service_
的地址相同,以确保没有创建两个实例或类似的东西。
编辑7
好的,我现在发现,如果我使用this
进行编译,我就不会再遇到段错!
但是,这会导致抛出异常,因为我尝试使用线程,即使我已禁用它们。我认为这意味着我将被限制为同步调用和没有异步调用。 (即,使用asio的重点是什么?)
reference material here确实说do_use_service
明确禁用Asio的线程支持,无论Boost是否支持线程。
所以我认为这意味着这个定义会阻止asio使用线程而不管是否提升;这是有道理的。
为什么线程会导致问题,我不知道。我并不热衷于钻研这么远。
我放弃了asio。在查看代码和文档之后,它似乎已经开发出来了,而不是作为一个独立的库。显然你需要使用Boost而不是C ++ 11,我只是不在乎。
Best C/C++ Network Library看起来有很多其他选择。
老实说,在我自己的线程中运行我自己的同步套接字调用听起来更好的主意,考虑到我将获得的控制权。至少直到asio进入标准库并在Mingw-w64中实现。
考虑到asio看起来像是标准库中的主要候选者,或者至少它的味道,坚持下去可能是一个好主意。
答案 0 :(得分:5)
我认为由于Server.hpp
和Client.hpp
之间的asio类型定义不匹配而发生分段错误。在您的情况下,只有当boost根据<string>
,<memory>
或<vector>
设置的定义更改typedef时,才会发生这种情况。
我建议尝试的是:
在包含asio.hpp之前,在Server / Client.hpp和main.cpp中包含相同的标题:
#include <string>
#include <memory>
#include <vector>
#define ASIO_STANDALONE
#include <asio.hpp>
或者只是在头文件中的任何其他包含之前包含asio.hpp,并从main.cpp中删除include。
答案 1 :(得分:1)
从我的POV,这是一个gcc bug。如果您使用clang++
代替g++.exe
,则即使没有摆弄#include
的排序,崩溃也会消失。在单个调用中将所有源文件传递给g++
也会导致崩溃消失。这让我认为 gcc的COFF目标文件发射有问题,因为clang使用来自相同mingw发行版的链接器。
所以,要么使用clang,要么从@Wouter Huysentruit的答案中应用解决方法。
请注意,最新的clang发行版(3.7.0)还有另一个错误,与您的问题无关,导致链接失败。我不得不使用nightly snapshot,无论如何都非常稳定。
答案 2 :(得分:0)
我有类似的问题。我的应用程序在win_lock :: lock()上崩溃,但win_lock :: win_lock()构造函数从未被调用过!
将-D_POSIX_THREADS添加到编译器标志时,它只是开始工作。
我在win7上使用mingw-w64-i686-7.1.0-posix-dwarf-rt_v5-rev0