This repository was archived by the owner on Feb 14, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 27
This repository was archived by the owner on Feb 14, 2025. It is now read-only.
Collecting dumps can cause process termination with "*** buffer overflow detected ***" message #5
Copy link
Copy link
Open
Description
When using this (great!) library I ran into a buffer overflow because my process was using more than 1024 file handles. The crash happened in signal_handler.cc, line 391/392:
FD_SET(pipe_fd[0], &read_fds);
FD_SET(timer_fd, &read_fds);
The 'fd_set' is a simple bitset supporting up to 1024 entries (i.e. file handle 0 .. file handle 1023).
The fix is quite simple. Instead of using fd_set / select() you can change the following code section to use pollfd / poll().
Just replace:
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(pipe_fd[0], &read_fds);
FD_SET(timer_fd, &read_fds);
auto max_fd = std::max(pipe_fd[0], timer_fd) + 1;
auto ret = select(max_fd, &read_fds, nullptr, nullptr, nullptr);
if (ret == -1) {
std::cerr << "select(...) failed, will try again" << std::endl; // errno
} else if (ret == 0) {
// We should never encounter this case as we use an infinite timeout in
// the select syscall.
std::cerr << "No file descriptors ready, will try again"
<< std::endl; // errno
} else if (FD_ISSET(timer_fd, &read_fds)) {
std::cerr << "Failed to get all (" << tids.size()
<< ") the stacktrace acks within timeout. Got only " << acks
<< std::endl; // errno
error->assign("Failed to get all (" + std::to_string(tids.size()) +
") stacktraces within timeout. Got only " +
std::to_string(acks));
return {};
} else if (FD_ISSET(pipe_fd[0], &read_fds)) {
char ch;
auto num_read = read(pipe_fd[0], &ch, sizeof(ch));
if (-1 == num_read) {
std::cerr << "Failed to read from pipe" << std::endl;
} else if (sizeof(ch) != num_read) {
std::cerr << "Read unexpected number of bytes. Expected: " << sizeof(ch)
<< ", got: " << num_read << std::endl;
} else {
++acks;
}
}
with
pollfd pipeAndTimerPollFd[2];
pipeAndTimerPollFd[0].fd = pipe_fd[0];
pipeAndTimerPollFd[0].events = POLLIN;
pipeAndTimerPollFd[1].fd = timer_fd;
pipeAndTimerPollFd[1].events = POLLIN;
const int noTimeout = -1;
auto ret = poll(pipeAndTimerPollFd, 2, noTimeout);
if (ret == -1)
{
std::cerr << "poll(...) failed, will try again" << std::endl;
}
else if (ret == 0)
{
// This should never happen as 0 means timeout but no timeout has been given!
std::cerr << "poll() returned 0 even though no timeout was given, will try again" << std::endl;
}
else if(pipeAndTimerPollFd[1].revents == POLLIN)
{
std::cerr << "Failed to get all (" << tids.size()
<< ") the stacktrace messages within timeout. Got only " << acks
<< std::endl;
error->assign("Failed to get all (" + std::to_string(tids.size()) +
") stacktraces within timeout. Got only " +
std::to_string(acks));
return {};
}
else
{
if(pipeAndTimerPollFd[0].revents != POLLIN)
{
std::cerr << "Error calling poll(), expected the pipe to be ready for reading!" << std::endl;
}
char ch;
auto num_read = read(pipe_fd[0], &ch, sizeof(ch));
if (-1 == num_read)
{
std::cerr << "Failed to read from pipe" << std::endl;
}
else if (sizeof(ch) != num_read)
{
std::cerr << "Read unexpected number of bytes. Expected: " << sizeof(ch)
<< ", got: " << num_read << std::endl;
}
else
{
++acks;
}
}
Let me know if this project is still maintained and in this case I am happy to create a pull request.
Marc
Metadata
Metadata
Assignees
Labels
No labels