Skip to content

Commit 3d50f5a

Browse files
author
yuyangzi
committed
修复std::fstream无法hook到close的问题
1 parent 067a053 commit 3d50f5a

File tree

7 files changed

+114
-4
lines changed

7 files changed

+114
-4
lines changed

libgo/disable_hook/disable_hook.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ setsockopt_t setsockopt_f = &setsockopt;
4949
dup_t dup_f = &dup;
5050
dup2_t dup2_f = &dup2;
5151
dup3_t dup3_f = &dup3;
52+
fclose_t fclose_f = &fclose;
5253

5354
} //extern "C"
5455

libgo/linux/fd_context.cpp

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,8 @@ bool FileDescriptorCtx::closed()
137137
{
138138
return closed_;
139139
}
140-
int FileDescriptorCtx::close(bool call_syscall)
140+
int FileDescriptorCtx::close_without_lock(bool call_syscall)
141141
{
142-
std::unique_lock<mutex_t> lock(lock_);
143142
if (closed()) return 0;
144143
DebugPrint(dbg_fd_ctx, "close fd(%d) [%p] call_syscall:%d", fd_, this, (int)call_syscall);
145144
closed_ = true;
@@ -169,6 +168,19 @@ int FileDescriptorCtx::close(bool call_syscall)
169168
}
170169

171170
return ret;
171+
172+
}
173+
int FileDescriptorCtx::close(bool call_syscall)
174+
{
175+
std::unique_lock<mutex_t> lock(lock_);
176+
return close_without_lock(call_syscall);
177+
}
178+
int FileDescriptorCtx::fclose(FILE* fp)
179+
{
180+
std::unique_lock<mutex_t> lock(lock_);
181+
int ret = fclose_f(fp);
182+
close_without_lock(false);
183+
return ret;
172184
}
173185
void FileDescriptorCtx::set_user_nonblock(bool b)
174186
{
@@ -483,6 +495,24 @@ int FdManager::close(int fd, bool call_syscall)
483495
pptr = nullptr;
484496
return ret;
485497
}
498+
int FdManager::fclose(FILE* fp)
499+
{
500+
if (!fp) return 0;
501+
int fd = fileno(fp);
502+
if (fd < 0) return 0;
503+
504+
FdPair & fpair = get_pair(fd);
505+
std::unique_lock<LFLock> lock(fpair.second);
506+
FdCtxPtr* & pptr = fpair.first;
507+
if (!pptr) {
508+
return fclose_f(fp);
509+
}
510+
511+
int ret = (*pptr)->fclose(fp);
512+
delete pptr;
513+
pptr = nullptr;
514+
return ret;
515+
}
486516
bool FdManager::dup(int src, int dst)
487517
{
488518
FdPair & src_fpair = get_pair(src);

libgo/linux/fd_context.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class FileDescriptorCtx
7676
bool is_epoll();
7777
bool closed();
7878
int close(bool call_syscall);
79+
int fclose(FILE* fp);
7980

8081
void set_user_nonblock(bool b);
8182
bool user_nonblock();
@@ -118,6 +119,8 @@ class FileDescriptorCtx
118119

119120
int GetEpollFd();
120121

122+
int close_without_lock(bool call_syscall);
123+
121124
// debugger interface
122125
public:
123126
std::string GetDebugInfo();
@@ -169,6 +172,8 @@ class FdManager
169172

170173
int close(int fd, bool call_syscall = true);
171174

175+
int fclose(FILE* fp);
176+
172177
private:
173178
FdPair & get_pair(int fd);
174179

libgo/linux/linux_glibc_hook.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,7 @@ setsockopt_t setsockopt_f = NULL;
593593
dup_t dup_f = NULL;
594594
dup2_t dup2_f = NULL;
595595
dup3_t dup3_f = NULL;
596+
fclose_t fclose_f = NULL;
596597

597598
int connect(int fd, const struct sockaddr *addr, socklen_t addrlen)
598599
{
@@ -1110,6 +1111,12 @@ int dup3(int oldfd, int newfd, int flags)
11101111
return ret;
11111112
}
11121113

1114+
int fclose(FILE* fp)
1115+
{
1116+
if (!fclose_f) coroutine_hook_init();
1117+
return FdManager::getInstance().fclose(fp);
1118+
}
1119+
11131120
#if WITH_CARES
11141121
struct hostent* co_gethostbyname2(const char *name, int af)
11151122
{
@@ -1267,6 +1274,7 @@ extern int __dup(int);
12671274
extern int __dup2(int, int);
12681275
extern int __dup3(int, int, int);
12691276
extern int __usleep(useconds_t usec);
1277+
extern int __new_fclose(FILE *fp);
12701278

12711279
// 某些版本libc.a中没有__usleep.
12721280
__attribute__((weak))
@@ -1313,6 +1321,7 @@ void coroutine_hook_init()
13131321
dup_f = (dup_t)dlsym(RTLD_NEXT, "dup");
13141322
dup2_f = (dup2_t)dlsym(RTLD_NEXT, "dup2");
13151323
dup3_f = (dup3_t)dlsym(RTLD_NEXT, "dup3");
1324+
fclose_f = (fclose_t)dlsym(RTLD_NEXT, "fclose");
13161325
#else
13171326
connect_f = &__connect;
13181327
read_f = &__read;
@@ -1339,12 +1348,13 @@ void coroutine_hook_init()
13391348
dup_f = &__dup;
13401349
dup2_f = &__dup2;
13411350
dup3_f = &__dup3;
1351+
fclose_f = &__new_fclose;
13421352
#endif
13431353

13441354
if (!connect_f || !read_f || !write_f || !readv_f || !writev_f || !send_f
13451355
|| !sendto_f || !sendmsg_f || !accept_f || !poll_f || !select_f
13461356
|| !sleep_f|| !usleep_f || !nanosleep_f || !close_f || !fcntl_f || !setsockopt_f
1347-
|| !getsockopt_f || !dup_f || !dup2_f
1357+
|| !getsockopt_f || !dup_f || !dup2_f || !fclose_f
13481358
// 老版本linux中没有dup3, 无需校验
13491359
// || !dup3_f
13501360
)

libgo/linux/linux_glibc_hook.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ extern dup2_t dup2_f;
8484
typedef int(*dup3_t)(int, int, int);
8585
extern dup3_t dup3_f;
8686

87+
typedef int (*fclose_t)(FILE *fp);
88+
extern fclose_t fclose_f;
89+
8790
// DNS by libcares
8891
// gethostent
8992
// gethostbyname

test/gtest_unit/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ add_subdirectory(${PROJECT_SOURCE_DIR}/../../third_party/gtest ${PROJECT_BINARY_
2828
aux_source_directory(${PROJECT_SOURCE_DIR} SRC_LIST)
2929

3030
if (UNIX)
31-
set(STATIC_LINK_ARG -Wl,--whole-archive -lpthread -Wl,--no-whole-archive -static)
31+
set(STATIC_LINK_ARG -Wl,--whole-archive -lpthread -Wl,--no-whole-archive -static -static-libstdc++)
3232
set(LINK_ARGS libgo dl gtest_main gtest boost_coroutine boost_context boost_system boost_thread)
3333
if (WITH_CARES)
3434
set(LINK_ARGS ${LINK_ARGS} cares)

test/gtest_unit/fd_manager.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#include <iostream>
2+
#include <unistd.h>
3+
#include <gtest/gtest.h>
4+
#include "coroutine.h"
5+
#include <poll.h>
6+
#include <sys/types.h>
7+
#include <sys/socket.h>
8+
#include <sys/file.h>
9+
#include <fstream>
10+
#include <stdio.h>
11+
using namespace std;
12+
using namespace co;
13+
14+
void foo()
15+
{
16+
// int fd = open("/dev/null", O_WRONLY);
17+
// write(fd, "1", 1);
18+
// close(fd);
19+
20+
std::ofstream ofs("/dev/zero");
21+
ofs << "123";
22+
ofs.close();
23+
24+
int fds[2];
25+
int res = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds);
26+
EXPECT_EQ(res, 0);
27+
28+
pollfd pfd;
29+
pfd.fd = fds[0];
30+
pfd.events = POLLIN;
31+
res = poll(&pfd, 1, 1000);
32+
EXPECT_EQ(errno, 0);
33+
EXPECT_EQ(res, 0);
34+
}
35+
36+
void foo2()
37+
{
38+
FILE * f = fopen("/dev/zero", "r");
39+
fwrite("a", 1, 1, f);
40+
fclose(f);
41+
42+
int fds[2];
43+
int res = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds);
44+
EXPECT_EQ(res, 0);
45+
46+
pollfd pfd;
47+
pfd.fd = fds[0];
48+
pfd.events = POLLIN;
49+
res = poll(&pfd, 1, 1000);
50+
EXPECT_EQ(errno, 0);
51+
EXPECT_EQ(res, 0);
52+
}
53+
54+
TEST(fdmanager, fdmanager)
55+
{
56+
go foo;
57+
co_sched.RunUntilNoTask();
58+
59+
go foo2;
60+
co_sched.RunUntilNoTask();
61+
}

0 commit comments

Comments
 (0)