1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.haxx.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22 #include "test.h"
23
24 #ifdef HAVE_SYS_RESOURCE_H
25 #include <sys/resource.h>
26 #endif
27 #ifdef HAVE_FCNTL_H
28 #include <fcntl.h>
29 #endif
30 #ifdef HAVE_LIMITS_H
31 #include <limits.h>
32 #endif
33
34 #include "warnless.h"
35 #include "memdebug.h"
36
37 #if !defined(HAVE_POLL_FINE) && \
38 !defined(USE_WINSOCK) && \
39 !defined(TPF) && \
40 !defined(FD_SETSIZE)
41 #error "this test requires FD_SETSIZE"
42 #endif
43
44 #define SAFETY_MARGIN (11)
45
46 #if defined(WIN32) || defined(_WIN32) || defined(MSDOS)
47 #define DEV_NULL "NUL"
48 #else
49 #define DEV_NULL "/dev/null"
50 #endif
51
52 #if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT)
53
54 static int *fd = NULL;
55 static struct rlimit num_open;
56 static char msgbuff[256];
57
store_errmsg(const char * msg,int err)58 static void store_errmsg(const char *msg, int err)
59 {
60 if(!err)
61 snprintf(msgbuff, sizeof(msgbuff), "%s", msg);
62 else
63 snprintf(msgbuff, sizeof(msgbuff), "%s, errno %d, %s", msg, err,
64 strerror(err));
65 }
66
close_file_descriptors(void)67 static void close_file_descriptors(void)
68 {
69 for(num_open.rlim_cur = 0;
70 num_open.rlim_cur < num_open.rlim_max;
71 num_open.rlim_cur++)
72 if(fd[num_open.rlim_cur] > 0)
73 close(fd[num_open.rlim_cur]);
74 free(fd);
75 fd = NULL;
76 }
77
fopen_works(void)78 static int fopen_works(void)
79 {
80 FILE *fpa[3];
81 int i;
82 int ret = 1;
83
84 for(i = 0; i < 3; i++) {
85 fpa[i] = NULL;
86 }
87 for(i = 0; i < 3; i++) {
88 fpa[i] = fopen(DEV_NULL, FOPEN_READTEXT);
89 if(fpa[i] == NULL) {
90 store_errmsg("fopen failed", ERRNO);
91 fprintf(stderr, "%s\n", msgbuff);
92 ret = 0;
93 break;
94 }
95 }
96 for(i = 0; i < 3; i++) {
97 if(fpa[i] != NULL)
98 fclose(fpa[i]);
99 }
100 return ret;
101 }
102
rlimit(int keep_open)103 static int rlimit(int keep_open)
104 {
105 int *tmpfd;
106 int nitems, i;
107 int *memchunk = NULL;
108 char *fmt;
109 struct rlimit rl;
110 char strbuff[256];
111 char strbuff1[81];
112 char fmt_u[] = "%u";
113 char fmt_lu[] = "%lu";
114 #ifdef HAVE_LONGLONG
115 char fmt_llu[] = "%llu";
116
117 if(sizeof(rl.rlim_max) > sizeof(long))
118 fmt = fmt_llu;
119 else
120 #endif
121 fmt = (sizeof(rl.rlim_max) < sizeof(long))?fmt_u:fmt_lu;
122
123 /* get initial open file limits */
124
125 if(getrlimit(RLIMIT_NOFILE, &rl) != 0) {
126 store_errmsg("getrlimit() failed", ERRNO);
127 fprintf(stderr, "%s\n", msgbuff);
128 return -1;
129 }
130
131 /* show initial open file limits */
132
133 #ifdef RLIM_INFINITY
134 if(rl.rlim_cur == RLIM_INFINITY)
135 strcpy(strbuff, "INFINITY");
136 else
137 #endif
138 snprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_cur);
139 fprintf(stderr, "initial soft limit: %s\n", strbuff);
140
141 #ifdef RLIM_INFINITY
142 if(rl.rlim_max == RLIM_INFINITY)
143 strcpy(strbuff, "INFINITY");
144 else
145 #endif
146 snprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_max);
147 fprintf(stderr, "initial hard limit: %s\n", strbuff);
148
149 /*
150 * if soft limit and hard limit are different we ask the
151 * system to raise soft limit all the way up to the hard
152 * limit. Due to some other system limit the soft limit
153 * might not be raised up to the hard limit. So from this
154 * point the resulting soft limit is our limit. Trying to
155 * open more than soft limit file descriptors will fail.
156 */
157
158 if(rl.rlim_cur != rl.rlim_max) {
159
160 #ifdef OPEN_MAX
161 if((rl.rlim_cur > 0) &&
162 (rl.rlim_cur < OPEN_MAX)) {
163 fprintf(stderr, "raising soft limit up to OPEN_MAX\n");
164 rl.rlim_cur = OPEN_MAX;
165 if(setrlimit(RLIMIT_NOFILE, &rl) != 0) {
166 /* on failure don't abort just issue a warning */
167 store_errmsg("setrlimit() failed", ERRNO);
168 fprintf(stderr, "%s\n", msgbuff);
169 msgbuff[0] = '\0';
170 }
171 }
172 #endif
173
174 fprintf(stderr, "raising soft limit up to hard limit\n");
175 rl.rlim_cur = rl.rlim_max;
176 if(setrlimit(RLIMIT_NOFILE, &rl) != 0) {
177 /* on failure don't abort just issue a warning */
178 store_errmsg("setrlimit() failed", ERRNO);
179 fprintf(stderr, "%s\n", msgbuff);
180 msgbuff[0] = '\0';
181 }
182
183 /* get current open file limits */
184
185 if(getrlimit(RLIMIT_NOFILE, &rl) != 0) {
186 store_errmsg("getrlimit() failed", ERRNO);
187 fprintf(stderr, "%s\n", msgbuff);
188 return -3;
189 }
190
191 /* show current open file limits */
192
193 #ifdef RLIM_INFINITY
194 if(rl.rlim_cur == RLIM_INFINITY)
195 strcpy(strbuff, "INFINITY");
196 else
197 #endif
198 snprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_cur);
199 fprintf(stderr, "current soft limit: %s\n", strbuff);
200
201 #ifdef RLIM_INFINITY
202 if(rl.rlim_max == RLIM_INFINITY)
203 strcpy(strbuff, "INFINITY");
204 else
205 #endif
206 snprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_max);
207 fprintf(stderr, "current hard limit: %s\n", strbuff);
208
209 } /* (rl.rlim_cur != rl.rlim_max) */
210
211 /*
212 * test 537 is all about testing libcurl functionality
213 * when the system has nearly exhausted the number of
214 * available file descriptors. Test 537 will try to run
215 * with a very small number of file descriptors available.
216 * This implies that any file descriptor which is open
217 * when the test runs will have a number in the high range
218 * of whatever the system supports.
219 */
220
221 /*
222 * reserve a chunk of memory before opening file descriptors to
223 * avoid a low memory condition once the file descriptors are
224 * open. System conditions that could make the test fail should
225 * be addressed in the precheck phase. This chunk of memory shall
226 * be always free()ed before exiting the rlimit() function so
227 * that it becomes available to the test.
228 */
229
230 for(nitems = i = 1; nitems <= i; i *= 2)
231 nitems = i;
232 if(nitems > 0x7fff)
233 nitems = 0x40000;
234 do {
235 num_open.rlim_max = sizeof(*memchunk) * (size_t)nitems;
236 snprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max);
237 fprintf(stderr, "allocating memchunk %s byte array\n", strbuff);
238 memchunk = malloc(sizeof(*memchunk) * (size_t)nitems);
239 if(!memchunk) {
240 fprintf(stderr, "memchunk, malloc() failed\n");
241 nitems /= 2;
242 }
243 } while(nitems && !memchunk);
244 if(!memchunk) {
245 store_errmsg("memchunk, malloc() failed", ERRNO);
246 fprintf(stderr, "%s\n", msgbuff);
247 return -4;
248 }
249
250 /* initialize it to fight lazy allocation */
251
252 fprintf(stderr, "initializing memchunk array\n");
253
254 for(i = 0; i < nitems; i++)
255 memchunk[i] = -1;
256
257 /* set the number of file descriptors we will try to open */
258
259 #ifdef RLIM_INFINITY
260 if((rl.rlim_cur > 0) && (rl.rlim_cur != RLIM_INFINITY)) {
261 #else
262 if(rl.rlim_cur > 0) {
263 #endif
264 /* soft limit minus SAFETY_MARGIN */
265 num_open.rlim_max = rl.rlim_cur - SAFETY_MARGIN;
266 }
267 else {
268 /* a huge number of file descriptors */
269 for(nitems = i = 1; nitems <= i; i *= 2)
270 nitems = i;
271 if(nitems > 0x7fff)
272 nitems = 0x40000;
273 num_open.rlim_max = nitems;
274 }
275
276 /* verify that we won't overflow size_t in malloc() */
277
278 if((size_t)(num_open.rlim_max) > ((size_t)-1) / sizeof(*fd)) {
279 snprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_max);
280 snprintf(strbuff, sizeof(strbuff), "unable to allocate an array for %s "
281 "file descriptors, would overflow size_t", strbuff1);
282 store_errmsg(strbuff, 0);
283 fprintf(stderr, "%s\n", msgbuff);
284 free(memchunk);
285 return -5;
286 }
287
288 /* allocate array for file descriptors */
289
290 do {
291 snprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max);
292 fprintf(stderr, "allocating array for %s file descriptors\n", strbuff);
293 fd = malloc(sizeof(*fd) * (size_t)(num_open.rlim_max));
294 if(!fd) {
295 fprintf(stderr, "fd, malloc() failed\n");
296 num_open.rlim_max /= 2;
297 }
298 } while(num_open.rlim_max && !fd);
299 if(!fd) {
300 store_errmsg("fd, malloc() failed", ERRNO);
301 fprintf(stderr, "%s\n", msgbuff);
302 free(memchunk);
303 return -6;
304 }
305
306 /* initialize it to fight lazy allocation */
307
308 fprintf(stderr, "initializing fd array\n");
309
310 for(num_open.rlim_cur = 0;
311 num_open.rlim_cur < num_open.rlim_max;
312 num_open.rlim_cur++)
313 fd[num_open.rlim_cur] = -1;
314
315 snprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max);
316 fprintf(stderr, "trying to open %s file descriptors\n", strbuff);
317
318 /* open a dummy descriptor */
319
320 fd[0] = open(DEV_NULL, O_RDONLY);
321 if(fd[0] < 0) {
322 snprintf(strbuff, sizeof(strbuff), "opening of %s failed", DEV_NULL);
323 store_errmsg(strbuff, ERRNO);
324 fprintf(stderr, "%s\n", msgbuff);
325 free(fd);
326 fd = NULL;
327 free(memchunk);
328 return -7;
329 }
330
331 /* create a bunch of file descriptors */
332
333 for(num_open.rlim_cur = 1;
334 num_open.rlim_cur < num_open.rlim_max;
335 num_open.rlim_cur++) {
336
337 fd[num_open.rlim_cur] = dup(fd[0]);
338
339 if(fd[num_open.rlim_cur] < 0) {
340
341 fd[num_open.rlim_cur] = -1;
342
343 snprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_cur);
344 snprintf(strbuff, sizeof(strbuff), "dup() attempt %s failed", strbuff1);
345 fprintf(stderr, "%s\n", strbuff);
346
347 snprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_cur);
348 snprintf(strbuff, sizeof(strbuff), "fds system limit seems close to %s",
349 strbuff1);
350 fprintf(stderr, "%s\n", strbuff);
351
352 num_open.rlim_max = num_open.rlim_cur - SAFETY_MARGIN;
353
354 num_open.rlim_cur -= num_open.rlim_max;
355 snprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_cur);
356 snprintf(strbuff, sizeof(strbuff), "closing %s file descriptors",
357 strbuff1);
358 fprintf(stderr, "%s\n", strbuff);
359
360 for(num_open.rlim_cur = num_open.rlim_max;
361 fd[num_open.rlim_cur] >= 0;
362 num_open.rlim_cur++) {
363 close(fd[num_open.rlim_cur]);
364 fd[num_open.rlim_cur] = -1;
365 }
366
367 snprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max);
368 fprintf(stderr, "shrinking array for %s file descriptors\n", strbuff);
369
370 /* we don't care if we can't shrink it */
371
372 tmpfd = realloc(fd, sizeof(*fd) * (size_t)(num_open.rlim_max));
373 if(tmpfd) {
374 fd = tmpfd;
375 tmpfd = NULL;
376 }
377
378 break;
379
380 }
381
382 }
383
384 snprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max);
385 fprintf(stderr, "%s file descriptors open\n", strbuff);
386
387 #if !defined(HAVE_POLL_FINE) && \
388 !defined(USE_WINSOCK) && \
389 !defined(TPF)
390
391 /*
392 * when using select() instead of poll() we cannot test
393 * libcurl functionality with a socket number equal or
394 * greater than FD_SETSIZE. In any case, macro VERIFY_SOCK
395 * in lib/select.c enforces this check and protects libcurl
396 * from a possible crash. The effect of this protection
397 * is that test 537 will always fail, since the actual
398 * call to select() never takes place. We skip test 537
399 * with an indication that select limit would be exceeded.
400 */
401
402 num_open.rlim_cur = FD_SETSIZE - SAFETY_MARGIN;
403 if(num_open.rlim_max > num_open.rlim_cur) {
404 snprintf(strbuff, sizeof(strbuff), "select limit is FD_SETSIZE %d",
405 FD_SETSIZE);
406 store_errmsg(strbuff, 0);
407 fprintf(stderr, "%s\n", msgbuff);
408 close_file_descriptors();
409 free(memchunk);
410 return -8;
411 }
412
413 num_open.rlim_cur = FD_SETSIZE - SAFETY_MARGIN;
414 for(rl.rlim_cur = 0;
415 rl.rlim_cur < num_open.rlim_max;
416 rl.rlim_cur++) {
417 if((fd[rl.rlim_cur] > 0) &&
418 ((unsigned int)fd[rl.rlim_cur] > num_open.rlim_cur)) {
419 snprintf(strbuff, sizeof(strbuff), "select limit is FD_SETSIZE %d",
420 FD_SETSIZE);
421 store_errmsg(strbuff, 0);
422 fprintf(stderr, "%s\n", msgbuff);
423 close_file_descriptors();
424 free(memchunk);
425 return -9;
426 }
427 }
428
429 #endif /* using a FD_SETSIZE bound select() */
430
431 /*
432 * Old or 'backwards compatible' implementations of stdio do not allow
433 * handling of streams with an underlying file descriptor number greater
434 * than 255, even when allowing high numbered file descriptors for sockets.
435 * At this point we have a big number of file descriptors which have been
436 * opened using dup(), so lets test the stdio implementation and discover
437 * if it is capable of fopen()ing some additional files.
438 */
439
440 if(!fopen_works()) {
441 snprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_max);
442 snprintf(strbuff, sizeof(strbuff), "fopen fails with %s fds open",
443 strbuff1);
444 fprintf(stderr, "%s\n", msgbuff);
445 snprintf(strbuff, sizeof(strbuff), "fopen fails with lots of fds open");
446 store_errmsg(strbuff, 0);
447 close_file_descriptors();
448 free(memchunk);
449 return -10;
450 }
451
452 /* free the chunk of memory we were reserving so that it
453 becomes becomes available to the test */
454
455 free(memchunk);
456
457 /* close file descriptors unless instructed to keep them */
458
459 if(!keep_open) {
460 close_file_descriptors();
461 }
462
463 return 0;
464 }
465
466 int test(char *URL)
467 {
468 CURLcode res;
469 CURL *curl;
470
471 if(!strcmp(URL, "check")) {
472 /* used by the test script to ask if we can run this test or not */
473 if(rlimit(FALSE)) {
474 fprintf(stdout, "rlimit problem: %s\n", msgbuff);
475 return 1;
476 }
477 return 0; /* sure, run this! */
478 }
479
480 if(rlimit(TRUE)) {
481 /* failure */
482 return TEST_ERR_MAJOR_BAD;
483 }
484
485 /* run the test with the bunch of open file descriptors
486 and close them all once the test is over */
487
488 if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
489 fprintf(stderr, "curl_global_init() failed\n");
490 close_file_descriptors();
491 return TEST_ERR_MAJOR_BAD;
492 }
493
494 if((curl = curl_easy_init()) == NULL) {
495 fprintf(stderr, "curl_easy_init() failed\n");
496 close_file_descriptors();
497 curl_global_cleanup();
498 return TEST_ERR_MAJOR_BAD;
499 }
500
501 test_setopt(curl, CURLOPT_URL, URL);
502 test_setopt(curl, CURLOPT_HEADER, 1L);
503
504 res = curl_easy_perform(curl);
505
506 test_cleanup:
507
508 close_file_descriptors();
509 curl_easy_cleanup(curl);
510 curl_global_cleanup();
511
512 return (int)res;
513 }
514
515 #else /* defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) */
516
517 int test(char *URL)
518 {
519 (void)URL;
520 printf("system lacks necessary system function(s)");
521 return 1; /* skip test */
522 }
523
524 #endif /* defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) */
525