Skip to content

Commit 6b0dbc5

Browse files
committed
fix FD_SET crash when fd exceeds 1024
1 parent f9493ea commit 6b0dbc5

File tree

2 files changed

+57
-45
lines changed

2 files changed

+57
-45
lines changed

executor.c

Lines changed: 55 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <sys/wait.h>
2+
#include <poll.h>
23
#include "common.h"
34
#include "sstring.h"
45
#include "executor.h"
@@ -75,46 +76,45 @@ fork_command(struct slot *pslot, void (*fn)(struct slot *, int, char **), int ar
7576
}
7677

7778
static void
78-
fdset_alive_slots(struct slot *pslot, fd_set *readfds) {
79+
poll_alive_slots(struct slot *pslot, struct pollfd *pfd, size_t *cnt) {
80+
*cnt = 0;
7981
while (pslot) {
8082
if (!pslot->alive) {
83+
pslot->poll_index = -1;
8184
pslot = pslot->next;
8285
continue;
8386
}
84-
FD_SET(pslot->io.out[PIPE_READ_END], readfds);
85-
FD_SET(pslot->io.err[PIPE_READ_END], readfds);
87+
pslot->poll_index = (int) *cnt;
88+
89+
pfd[*cnt].fd = pslot->io.out[PIPE_READ_END];
90+
pfd[*cnt].events = POLLIN;
91+
*cnt = *cnt + 1;
92+
93+
pfd[*cnt].fd = pslot->io.err[PIPE_READ_END];
94+
pfd[*cnt].events = POLLIN;
95+
*cnt = *cnt + 1;
96+
8697
pslot = pslot->next;
8798
}
8899
}
89100

90101
static void
91-
read_alive_slots(struct slot *pslot, fd_set *readfds, FILE *output) {
102+
read_alive_slots(struct slot *pslot, struct pollfd *pfd, FILE *output) {
92103
while (pslot) {
93-
if (!pslot->alive) {
104+
if (!pslot->alive || pslot->poll_index < 0) {
94105
pslot = pslot->next;
95106
continue;
96107
}
97-
if (FD_ISSET(pslot->io.out[PIPE_READ_END], readfds)) {
108+
if (pfd[pslot->poll_index].revents & POLLIN) {
98109
slot_read_line(pslot, STDOUT_FILENO, print_line, output);
99110
}
100-
if (FD_ISSET(pslot->io.err[PIPE_READ_END], readfds)) {
111+
if (pfd[pslot->poll_index + 1].revents & POLLIN) {
101112
slot_read_line(pslot, STDERR_FILENO, print_line, output);
102113
}
103114
pslot = pslot->next;
104115
}
105116
}
106117

107-
static void
108-
read_dead_slots(struct slot *pslot, struct slot *pslot_end, FILE *output) {
109-
while (pslot && pslot != pslot_end) {
110-
if (!pslot->alive) {
111-
slot_read_remains(pslot, STDOUT_FILENO, print_line, output);
112-
slot_read_remains(pslot, STDERR_FILENO, print_line, output);
113-
}
114-
pslot = pslot->next;
115-
}
116-
}
117-
118118
int
119119
exec_local_cmd(char *cmd) {
120120
return system(cmd);
@@ -177,9 +177,12 @@ reap_child_handler(int sig) {
177177
else
178178
exit_code = 255;
179179
pslot = slot_find_by_pid(slots, pid);
180-
if (pslot) {
181-
slot_close(pslot, exit_code);
180+
if (!pslot) {
181+
continue;
182182
}
183+
slot_read_remains(pslot, STDOUT_FILENO, print_line, pslot->output);
184+
slot_read_remains(pslot, STDERR_FILENO, print_line, pslot->output);
185+
slot_close(pslot, exit_code);
183186
if (pconfig->verbose) {
184187
printf("wait pid %d, status code %d\n", pslot->pid, pslot->exit_code);
185188
}
@@ -314,19 +317,17 @@ exec_scp_cmd(struct slot *pslot, int argc, char **argv) {
314317

315318
static int
316319
exec_command_foreach(struct slot *pslot_list, void (*fn_fork)(struct slot *, int, char **), int argc, char **argv) {
317-
fd_set readfds;
318-
struct slot *pslot = pslot_list->next;
319-
struct slot *pslot_head = pslot;
320-
struct timeval no_timeout;
321-
struct timeval *timeout;
320+
struct pollfd *pfd;
321+
struct slot *pslot_head = pslot_list->next;
322+
struct slot *pslot = pslot_head;
323+
int timeout;
322324
FILE *output;
325+
size_t cnt = 0;
323326

324-
if (!pslot) {
327+
if(!pslot) {
325328
return 0;
326329
}
327330

328-
memset(&no_timeout, 0, sizeof(struct timeval));
329-
330331
if (pconfig->output_file) {
331332
output = fopen(pconfig->output_file, "a");
332333
if (!output) {
@@ -337,6 +338,15 @@ exec_command_foreach(struct slot *pslot_list, void (*fn_fork)(struct slot *, int
337338
output = stdout;
338339
}
339340

341+
while (pslot) {
342+
// poll stdout & stderr
343+
cnt += 2;
344+
pslot->output = output;
345+
pslot = pslot->next;
346+
}
347+
pfd = calloc(cnt, sizeof(struct pollfd));
348+
pslot = pslot_head;
349+
340350
alive_children = 0;
341351

342352
while (pslot || alive_children) {
@@ -347,25 +357,21 @@ exec_command_foreach(struct slot *pslot_list, void (*fn_fork)(struct slot *, int
347357
usleep(10 * 1000);
348358
}
349359

350-
read_dead_slots(pslot_head, pslot, output);
351-
352-
FD_ZERO(&readfds);
353-
fdset_alive_slots(pslot_head, &readfds);
360+
poll_alive_slots(pslot_head, pfd, &cnt);
354361

355-
timeout = pslot ? &no_timeout : NULL;
362+
timeout = pslot ? 0 : -1;
356363

357-
if (select(MAXFD, &readfds, NULL, NULL, timeout) > 0) {
358-
read_alive_slots(pslot_head, &readfds, output);
364+
if (poll(pfd, (nfds_t) cnt, timeout) > 0) {
365+
read_alive_slots(pslot_head, pfd, output);
359366
}
360367
UNBLOCK_SIGCHLD;
361368
}
362369

363-
read_dead_slots(pslot_head, pslot, output);
364-
365370
if (output != stdout) {
366371
fclose(output);
367372
}
368373

374+
free(pfd);
369375
return 0;
370376
}
371377

@@ -392,30 +398,34 @@ download_file(struct slot *pslot_list, char *remote_filename, char *local_filena
392398

393399
int
394400
sync_exec_remote_cmd(struct slot *pslot_list, char *cmd, sstring *out, sstring *err) {
395-
396-
fd_set readfds;
401+
struct pollfd pfd[2];
397402
char *argv[1] = {cmd};
398403
struct slot *pslot = pslot_list->next;
399404

400405
if (!pslot) {
401406
return 0;
402407
}
403408

404-
FD_ZERO(&readfds);
409+
memset(&pfd[0], 0, sizeof(struct pollfd));
410+
memset(&pfd[1], 0, sizeof(struct pollfd));
411+
412+
alive_children = 0;
405413

406414
BLOCK_SIGCHLD;
407415
fork_command(pslot, exec_ssh_cmd, 1, argv);
408-
FD_SET(pslot->io.out[PIPE_READ_END], &readfds);
409-
FD_SET(pslot->io.err[PIPE_READ_END], &readfds);
416+
pfd[0].fd = pslot->io.out[PIPE_READ_END];
417+
pfd[0].events = POLLIN;
418+
pfd[1].fd = pslot->io.err[PIPE_READ_END];
419+
pfd[1].events = POLLIN;
410420
UNBLOCK_SIGCHLD;
411421

412422
while (alive_children) {
413423
BLOCK_SIGCHLD;
414-
if (select(MAXFD, &readfds, NULL, NULL, NULL) > 0) {
415-
if (FD_ISSET(pslot->io.out[PIPE_READ_END], &readfds)) {
424+
if (poll(pfd, 2, 0) > 0) {
425+
if (pfd[0].revents & POLLIN) {
416426
slot_read_line(pslot, STDOUT_FILENO, save_string, out);
417427
}
418-
if (FD_ISSET(pslot->io.err[PIPE_READ_END], &readfds)) {
428+
if (pfd[1].revents & POLLIN) {
419429
slot_read_line(pslot, STDERR_FILENO, save_string, err);
420430
}
421431
}

slot.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ slot {
2525
int pid;
2626
int exit_code;
2727
bool alive;
28+
int poll_index;
29+
FILE* output;
2830

2931
sstring out_buff;
3032
sstring err_buff;

0 commit comments

Comments
 (0)