感谢网友:∮f(x)dx,徐冠鹏 提供的解决方法。
这份代码用于演示如何利用 dlopen 来避免 CTP GNU/Linux API 中 trader 和 mduser 两个库同时在一个进程中加载导致的 double free 问题。请注意,它只
用于演示如何避免 double free,其余为了能使这个程序能运行起来的代码没有任何实际意义,且不适合用于生产。所以这份代码仅供参考,因使用此代码引起
的任何损失,我不承担任何责任。
用于演示如何避免 double free,其余为了能使这个程序能运行起来的代码没有任何实际意义,且不适合用于生产。所以这份代码仅供参考,因使用此代码引起
的任何损失,我不承担任何责任。
精力所限,下述的步骤的测试环境包含:
- 64 位 Gentoo Linux,内核版本 3.17.7-gentoo
- GCC Gentoo 4.8.3 p1.1, pie-0.5.9
- CTP GNU/Linux 版 6.3.0_20140811
- GCC Gentoo 4.8.3 p1.1, pie-0.5.9
- CTP GNU/Linux 版 6.3.0_20140811
1. 下载 http://www.sfit.com.cn/DocumentDown/api/6.3.0_20140811_traderapi_linux.tar并解压至工作目录:
1
2
3
4
5
6
7
| $ mkdir work $ cd work work $ wget http: //www .sfit.com.cn /DocumentDown/api/6 .3.0_20140811_traderapi_linux. tar work $ tar xf 6.3.0_20140811_traderapi_linux. tar work $ ls 6.3.0_20140811_traderapi_linux. tar 6.3.0_20140811_traderapi_linux32 6.3.0_20140811_traderapi_linux64 |
2. 将 Makefile、md_test.cc、trader_test.cc、x.cc 复制至包含 CTP 头文件及共享库的目录。这里是 64 位 GNU/Linux 的目录:
1
2
| $ cd 6.3.0_20140811_traderapi_linux64 $ cp .../{Makefile,md_test.cc,trader_test.cc,x.cc} . |
这里需要把 "..." 换成包含这些文件的目录。
3. 重命名共享库文件:
1
2
| $ mv thostmduserapi.so libthostmduserapi.so $ mv thosttraderapi.so libthosttraderapi.so |
4. 编译。这可以用 make 完成:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| $ make g++ -g -fPIC -c -o x.o x.cc c++ -g -fPIC -o x x.o -ldl g++ -g -fPIC -c -o trader_test.o trader_test.cc trader_test.cc: In function 'void init()' : trader_test.cc:69:88: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings] ^ g++ -fPIC -shared -o libtrader_test.so trader_test.o -L. -lthosttraderapi -ldl g++ -g -fPIC -c -o md_test.o md_test.cc md_test.cc: In function 'void init()' : md_test.cc:75:88: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings] ^ g++ -fPIC -shared -o libmd_test.so md_test.o -L. -lthostmduserapi -ldl |
5. 运行:
1
2
3
4
5
6
7
8
9
| $ LD_LIBRARY_PATH=. . /x trader front connected wlp3s0: Success md front connected wlp3s0: Success TRADER: 3: 综合交易平台:不合法的登录 MD: 3: 综合交易平台:不合法的登录 CThostFtdcUserApiImplBase::OnSessionDisconnected[0x7f80300008c8][1510735873][ 0] CThostFtdcUserApiImplBase::OnSessionDisconnected[0x7f802c0008c8][1510735873][ 0] |
6. 说明:
trader_test.cc 中包含一个 trader SPI 的实现,编译后生成libtrader_test.so。md_test.cc 中包含一个 md SPI 的实现,编译后生成libmd_test.so。这两个文件各自使用 dlopen 加载对应的 CTP 共享库,并用RTLD_DEEPBIND 隔离两个共享库中冲突的符号。
x.cc 通过加载 libtrader_test.so 和 libmd_test.so 来使用 CTP 的功能。运行时,需要确保所有的共享库存在于系统搜索共享库的目录中,这可以通过配置ld.so.conf 或设置 LD_LIBRARY_PATH 环境变量来实现。配置 ld.so.conf 的方法请参考各发行版的手册,LD_LIBRARY_PATH 的设置方法见上面的例子。
Makefile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| CXXFLAGS += -g -fPIC all: x libtrader_test.so libmd_test.so x: x.o c++ $(CXXFLAGS) -o x x.o -ldl libtrader_test.so: trader_test.o $(CXX) -fPIC -shared -o libtrader_test.so trader_test.o -L. -lthosttraderapi -ldl libmd_test.so: md_test.o $(CXX) -fPIC -shared -o libmd_test.so md_test.o -L. -lthostmduserapi -ldl clean: rm -f x *.o |
md_test.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
| #include <cstdio> #include <cstdlib> #include <cstring> #include <unistd.h> #include <dlfcn.h> #include "ThostFtdcMdApi.h" using namespace std; volatile int child_finished = 0; volatile int logging_in = 0; class SimpleHandler: public CThostFtdcMdSpi { CThostFtdcMdApi *user_api; public : SimpleHandler (CThostFtdcMdApi *user_api): user_api (user_api) { } ~SimpleHandler () { } virtual void OnFrontConnected () { if (!logging_in++) { printf ( "md front connected\n" ); CThostFtdcReqUserLoginField user_login_req; strcpy (user_login_req.BrokerID, "test_uid" ); strcpy (user_login_req.UserID, "test_uid" ); strcpy (user_login_req.Password, "password" ); user_api->ReqUserLogin (&user_login_req, 0); } } virtual void OnFrontDisconnected ( int reason) { printf ( "md front disconnected: %d\n" , reason); } virtual void OnRspUserLogin (CThostFtdcRspUserLoginField *resp, CThostFtdcRspInfoField *info, int req_id, bool is_last) { printf ( "MD: %d: %s\n" , info->ErrorID, info->ErrorMsg); if (info->ErrorID != 0) child_finished = 1; } }; CThostFtdcMdApi *user_api; SimpleHandler *simple_handler; extern "C" { void init () { void *trader_user_handle = dlopen ( "libthostmduserapi.so" , RTLD_LAZY | RTLD_DEEPBIND); if (trader_user_handle == 0) { fprintf (stderr, "Cannot load libthostusermdapi.so\n" ); exit (-1); } user_api = CThostFtdcMdApi::CreateFtdcMdApi (); simple_handler = new SimpleHandler (user_api); user_api->RegisterSpi (simple_handler); user_api->Init (); } void finalize () { user_api->RegisterSpi (0); user_api->Release (); delete simple_handler; simple_handler = 0; } } |
trader_test.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
| #include <cstdio> #include <cstdlib> #include <cstring> #include <unistd.h> #include <dlfcn.h> #include "ThostFtdcTraderApi.h" using namespace std; volatile int child_finished = 0; class SimpleHandler: public CThostFtdcTraderSpi { CThostFtdcTraderApi *user_api; public : SimpleHandler (CThostFtdcTraderApi *user_api): user_api (user_api) { } ~SimpleHandler () { } virtual void OnFrontConnected () { printf ( "trader front connected\n" ); CThostFtdcReqUserLoginField user_login_req; strcpy (user_login_req.BrokerID, "test_uid" ); strcpy (user_login_req.UserID, "test_uid" ); strcpy (user_login_req.Password, "password" ); user_api->ReqUserLogin (&user_login_req, 0); } virtual void OnFrontDisconnected ( int reason) { printf ( "trader front disconnected: %d\n" , reason); } virtual void OnRspUserLogin (CThostFtdcRspUserLoginField *resp, CThostFtdcRspInfoField *info, int req_id, bool is_last) { printf ( "TRADER: %d: %s\n" , info->ErrorID, info->ErrorMsg); } }; CThostFtdcTraderApi *user_api; SimpleHandler *simple_handler; extern "C" { void init () { void *trader_user_handle = dlopen ( "libthosttraderapi.so" , RTLD_LAZY | RTLD_DEEPBIND); if (trader_user_handle == 0) { fprintf (stderr, "Cannot load libthosttraderapi.so\n" ); exit (-1); } user_api = CThostFtdcTraderApi::CreateFtdcTraderApi (); simple_handler = new SimpleHandler (user_api); user_api->RegisterSpi (simple_handler); user_api->SubscribePrivateTopic (THOST_TERT_RESUME); user_api->SubscribePublicTopic (THOST_TERT_RESUME); user_api->Init (); } void finalize () { user_api->RegisterSpi (0); user_api->Release (); delete simple_handler; simple_handler = 0; } } |
x.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| #include <cstdio> #include <cstdlib> #include <cstring> #include <unistd.h> #include <dlfcn.h> using namespace std; int main ( int argc, char *argv[]) { void *trader_handle = dlopen ( "libtrader_test.so" , RTLD_LAZY); if (trader_handle == 0) { fprintf (stderr, "Cannot load libtrader_test.so\n" ); exit (-1); } void (*trader_init)() = ( void (*)()) dlsym (trader_handle, "init" ); void (*trader_finalize)() = ( void (*)()) dlsym (trader_handle, "finalize" ); trader_init (); void *md_handle = dlopen ( "libmd_test.so" , RTLD_LAZY); if (md_handle == 0) { fprintf (stderr, "Cannot load libmd_test.so\n" ); exit (-1); } void (*md_init)() = ( void (*)()) dlsym (md_handle, "init" ); void (*md_finalize)() = ( void (*)()) dlsym (md_handle, "finalize" ); md_init (); sleep (3); md_finalize (); trader_finalize (); return 0; } |
沒有留言:
張貼留言