Skip to content

Commit c690dc0

Browse files
author
Paweł Andruszkiewicz
committed
Replace select() with poll()
select() can monitor only file descriptors numbers that are less than FD_SETSIZE, poll() does not have this limitation. Using a file descriptor greater than or equal to FD_SETSIZE results in buffer overflow. Change-Id: I803f8dae37303598c64dbb5d50483d287175c08d (cherry picked from commit e5b2c929da88469ea651757d8a19fc871f1d57a9)
1 parent 24bc986 commit c690dc0

File tree

3 files changed

+59
-47
lines changed

3 files changed

+59
-47
lines changed

modules/util/json_importer.cc

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2022, Oracle and/or its affiliates.
2+
* Copyright (c) 2018, 2023, Oracle and/or its affiliates.
33
*
44
* This program is free software; you can redistribute it and/or modify
55
* it under the terms of the GNU General Public License, version 2.0,
@@ -25,7 +25,7 @@
2525
#ifdef _WIN32
2626
#include <Winsock2.h>
2727
#else
28-
#include <sys/select.h>
28+
#include <poll.h>
2929
#endif
3030
#include <deque>
3131
#include <istream>
@@ -317,19 +317,28 @@ void Json_importer::update_statistics(xcl::XQuery_result *xquery_result) {
317317

318318
void Json_importer::recv_response(bool block) {
319319
if (m_pending_response > 0) {
320-
my_socket fd = m_session->get_driver_obj()
321-
->get_protocol()
322-
.get_connection()
323-
.get_socket_fd();
324-
fd_set rfds;
325-
FD_ZERO(&rfds);
326-
FD_SET(fd, &rfds);
327-
timeval timeout;
328-
timeout.tv_sec = 0;
329-
timeout.tv_usec = 0;
330-
auto ready = select(fd + 1, &rfds, nullptr, nullptr, &timeout);
331-
bool fd_ready = FD_ISSET(fd, &rfds);
332-
if (block || (ready > 0 && fd_ready)) {
320+
bool should_receive = false;
321+
322+
if (block) {
323+
should_receive = true;
324+
} else {
325+
pollfd rfds;
326+
rfds.fd = m_session->get_driver_obj()
327+
->get_protocol()
328+
.get_connection()
329+
.get_socket_fd();
330+
rfds.events = POLLIN;
331+
rfds.revents = 0;
332+
333+
#ifdef _WIN32
334+
const auto poll = WSAPoll;
335+
#endif // _WIN32
336+
337+
const auto ready = poll(&rfds, 1, 0); // return immediately
338+
should_receive = (ready > 0) && (rfds.revents & POLLIN);
339+
}
340+
341+
if (should_receive) {
333342
xcl::XError error;
334343
auto result =
335344
m_session->get_driver_obj()->get_protocol().recv_resultset(&error);

mysqlshdk/libs/utils/process_launcher.cc

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2014, 2022, Oracle and/or its affiliates.
2+
* Copyright (c) 2014, 2023, Oracle and/or its affiliates.
33
*
44
* This program is free software; you can redistribute it and/or modify
55
* it under the terms of the GNU General Public License, version 2.0,
@@ -773,42 +773,44 @@ std::string Process::read_from_terminal() {
773773

774774
return output;
775775
#else // ! __APPLE__
776-
fd_set input;
777776
char buffer[512];
778-
struct timeval timeout;
779777
int64_t retry_count = 0;
780778

781-
do {
782-
timeout.tv_sec = 0;
783-
timeout.tv_usec = 500 * 1000; // 500ms
779+
pollfd input;
780+
input.fd = m_master_device;
781+
input.events = POLLIN;
784782

785-
FD_ZERO(&input);
786-
FD_SET(m_master_device, &input);
783+
do {
784+
input.revents = 0;
787785

788-
int ret = ::select(m_master_device + 1, &input, nullptr, nullptr, &timeout);
786+
int ret = ::poll(&input, 1, 500); // 500ms
789787

790788
if (ret == -1) {
791789
report_error(nullptr);
792790
} else if (ret == 0) {
793-
report_error("Timeout on select()");
794-
} else {
791+
report_error("Timeout on poll()");
792+
} else if (input.revents & POLLIN) {
795793
int n = ::read(m_master_device, buffer, sizeof(buffer));
796794

797795
if (n >= 0) {
798796
return std::string(buffer, n);
799-
} else if (errno == EIO) {
800-
// This error means that the other side of pseudo terminal is closed.
801-
// Since child does not duplicate it to stdin/stdout/stderr, it will
802-
// remain closed until the child process opens the controlling terminal
803-
// (i.e. writes the password prompt and waits for user input).
804-
if (++retry_count > 1000000) {
805-
report_error("Controlling terminal seems to be closed");
806-
} else {
807-
continue;
808-
}
809797
} else {
810798
report_error(nullptr);
811799
}
800+
} else if (input.revents & POLLHUP) {
801+
// This event means that the other side of pseudo terminal is closed.
802+
// Since child does not duplicate it to stdin/stdout/stderr, it will
803+
// remain closed until the child process opens the controlling terminal
804+
// (i.e. writes the password prompt and waits for user input).
805+
if (++retry_count > 1000000) {
806+
report_error("Controlling terminal seems to be closed");
807+
} else {
808+
continue;
809+
}
810+
} else {
811+
const auto msg = "No data to read, poll() returned an error event: " +
812+
std::to_string(input.revents);
813+
report_error(msg.c_str());
812814
}
813815
} while (true);
814816

mysqlshdk/libs/utils/utils_net.cc

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include <ifaddrs.h>
3939
#include <net/if.h>
4040
#include <netdb.h>
41+
#include <poll.h>
4142
#include <sys/socket.h>
4243
#include <sys/types.h>
4344
#include <unistd.h>
@@ -602,32 +603,30 @@ bool Net::is_port_listening_impl(const std::string &address, int port) const {
602603
}
603604

604605
#ifdef _WIN32
606+
const auto poll = WSAPoll;
605607
auto last_error = []() { return WSAGetLastError(); };
606608
const int connection_refused = WSAECONNREFUSED;
607-
auto would_block = [](int err) {
609+
const auto would_block = [](int err) {
608610
return err == WSAEWOULDBLOCK || err == WSAEINPROGRESS;
609611
};
610612
#else
611613
auto last_error = []() { return errno; };
612614
const int connection_refused = ECONNREFUSED;
613-
auto would_block = [](int err) {
615+
const auto would_block = [](int err) {
614616
return err == EWOULDBLOCK || err == EINPROGRESS;
615617
};
616618
#endif
617619
int err;
618620

619-
struct timeval timeout;
620-
timeout.tv_sec = k_port_check_timeout;
621-
timeout.tv_usec = 0;
621+
pollfd fds;
622+
fds.fd = sock;
623+
fds.events = POLLIN | POLLOUT;
622624

623625
while (would_block((err = last_error()))) {
624-
fd_set wfds, efds;
625-
FD_ZERO(&wfds);
626-
FD_SET(sock, &wfds);
627-
FD_ZERO(&efds);
628-
FD_SET(sock, &efds);
626+
fds.revents = 0;
627+
628+
err = poll(&fds, 1, k_port_check_timeout * 1000); // milliseconds
629629

630-
err = select(sock + 1, nullptr, &wfds, &efds, &timeout);
631630
if (err == 0) {
632631
// timeout
633632
closesocket(sock);
@@ -636,6 +635,7 @@ bool Net::is_port_listening_impl(const std::string &address, int port) const {
636635

637636
if (err > 0) {
638637
socklen_t len = sizeof(err);
638+
639639
if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&err, &len) < 0) {
640640
err = last_error();
641641
} else {
@@ -644,6 +644,7 @@ bool Net::is_port_listening_impl(const std::string &address, int port) const {
644644
return true;
645645
}
646646
}
647+
647648
break;
648649
}
649650
}

0 commit comments

Comments
 (0)