lib537.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 #include "test.h"
00023 
00024 #ifdef HAVE_SYS_RESOURCE_H
00025 #include <sys/resource.h>
00026 #endif
00027 #ifdef HAVE_FCNTL_H
00028 #include <fcntl.h>
00029 #endif
00030 #ifdef HAVE_LIMITS_H
00031 #include <limits.h>
00032 #endif
00033 
00034 #include "warnless.h"
00035 #include "memdebug.h"
00036 
00037 #if !defined(HAVE_POLL_FINE)    && \
00038     !defined(USE_WINSOCK)       && \
00039     !defined(TPF)               && \
00040     !defined(FD_SETSIZE)
00041 #error "this test requires FD_SETSIZE"
00042 #endif
00043 
00044 #define SAFETY_MARGIN (11)
00045 
00046 #if defined(WIN32) || defined(_WIN32) || defined(MSDOS)
00047 #define DEV_NULL "NUL"
00048 #else
00049 #define DEV_NULL "/dev/null"
00050 #endif
00051 
00052 #if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT)
00053 
00054 static int *fd = NULL;
00055 static struct rlimit num_open;
00056 static char msgbuff[256];
00057 
00058 static void store_errmsg(const char *msg, int err)
00059 {
00060   if(!err)
00061     snprintf(msgbuff, sizeof(msgbuff), "%s", msg);
00062   else
00063     snprintf(msgbuff, sizeof(msgbuff), "%s, errno %d, %s", msg, err,
00064              strerror(err));
00065 }
00066 
00067 static void close_file_descriptors(void)
00068 {
00069   for(num_open.rlim_cur = 0;
00070       num_open.rlim_cur < num_open.rlim_max;
00071       num_open.rlim_cur++)
00072     if(fd[num_open.rlim_cur] > 0)
00073       close(fd[num_open.rlim_cur]);
00074   free(fd);
00075   fd = NULL;
00076 }
00077 
00078 static int fopen_works(void)
00079 {
00080   FILE *fpa[3];
00081   int i;
00082   int ret = 1;
00083 
00084   for(i = 0; i < 3; i++) {
00085     fpa[i] = NULL;
00086   }
00087   for(i = 0; i < 3; i++) {
00088     fpa[i] = fopen(DEV_NULL, FOPEN_READTEXT);
00089     if(fpa[i] == NULL) {
00090       store_errmsg("fopen failed", ERRNO);
00091       fprintf(stderr, "%s\n", msgbuff);
00092       ret = 0;
00093       break;
00094     }
00095   }
00096   for(i = 0; i < 3; i++) {
00097     if(fpa[i] != NULL)
00098       fclose(fpa[i]);
00099   }
00100   return ret;
00101 }
00102 
00103 static int rlimit(int keep_open)
00104 {
00105   int *tmpfd;
00106   int nitems, i;
00107   int *memchunk = NULL;
00108   char *fmt;
00109   struct rlimit rl;
00110   char strbuff[256];
00111   char strbuff1[81];
00112   char fmt_u[] = "%u";
00113   char fmt_lu[] = "%lu";
00114 #ifdef HAVE_LONGLONG
00115   char fmt_llu[] = "%llu";
00116 
00117   if(sizeof(rl.rlim_max) > sizeof(long))
00118     fmt = fmt_llu;
00119   else
00120 #endif
00121     fmt = (sizeof(rl.rlim_max) < sizeof(long))?fmt_u:fmt_lu;
00122 
00123   /* get initial open file limits */
00124 
00125   if(getrlimit(RLIMIT_NOFILE, &rl) != 0) {
00126     store_errmsg("getrlimit() failed", ERRNO);
00127     fprintf(stderr, "%s\n", msgbuff);
00128     return -1;
00129   }
00130 
00131   /* show initial open file limits */
00132 
00133 #ifdef RLIM_INFINITY
00134   if(rl.rlim_cur == RLIM_INFINITY)
00135     strcpy(strbuff, "INFINITY");
00136   else
00137 #endif
00138     snprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_cur);
00139   fprintf(stderr, "initial soft limit: %s\n", strbuff);
00140 
00141 #ifdef RLIM_INFINITY
00142   if(rl.rlim_max == RLIM_INFINITY)
00143     strcpy(strbuff, "INFINITY");
00144   else
00145 #endif
00146     snprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_max);
00147   fprintf(stderr, "initial hard limit: %s\n", strbuff);
00148 
00149   /*
00150    * if soft limit and hard limit are different we ask the
00151    * system to raise soft limit all the way up to the hard
00152    * limit. Due to some other system limit the soft limit
00153    * might not be raised up to the hard limit. So from this
00154    * point the resulting soft limit is our limit. Trying to
00155    * open more than soft limit file descriptors will fail.
00156    */
00157 
00158   if(rl.rlim_cur != rl.rlim_max) {
00159 
00160 #ifdef OPEN_MAX
00161     if((rl.rlim_cur > 0) &&
00162         (rl.rlim_cur < OPEN_MAX)) {
00163       fprintf(stderr, "raising soft limit up to OPEN_MAX\n");
00164       rl.rlim_cur = OPEN_MAX;
00165       if(setrlimit(RLIMIT_NOFILE, &rl) != 0) {
00166         /* on failure don't abort just issue a warning */
00167         store_errmsg("setrlimit() failed", ERRNO);
00168         fprintf(stderr, "%s\n", msgbuff);
00169         msgbuff[0] = '\0';
00170       }
00171     }
00172 #endif
00173 
00174     fprintf(stderr, "raising soft limit up to hard limit\n");
00175     rl.rlim_cur = rl.rlim_max;
00176     if(setrlimit(RLIMIT_NOFILE, &rl) != 0) {
00177       /* on failure don't abort just issue a warning */
00178       store_errmsg("setrlimit() failed", ERRNO);
00179       fprintf(stderr, "%s\n", msgbuff);
00180       msgbuff[0] = '\0';
00181     }
00182 
00183     /* get current open file limits */
00184 
00185     if(getrlimit(RLIMIT_NOFILE, &rl) != 0) {
00186       store_errmsg("getrlimit() failed", ERRNO);
00187       fprintf(stderr, "%s\n", msgbuff);
00188       return -3;
00189     }
00190 
00191     /* show current open file limits */
00192 
00193 #ifdef RLIM_INFINITY
00194     if(rl.rlim_cur == RLIM_INFINITY)
00195       strcpy(strbuff, "INFINITY");
00196     else
00197 #endif
00198       snprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_cur);
00199     fprintf(stderr, "current soft limit: %s\n", strbuff);
00200 
00201 #ifdef RLIM_INFINITY
00202     if(rl.rlim_max == RLIM_INFINITY)
00203       strcpy(strbuff, "INFINITY");
00204     else
00205 #endif
00206       snprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_max);
00207     fprintf(stderr, "current hard limit: %s\n", strbuff);
00208 
00209   } /* (rl.rlim_cur != rl.rlim_max) */
00210 
00211   /*
00212    * test 537 is all about testing libcurl functionality
00213    * when the system has nearly exhausted the number of
00214    * available file descriptors. Test 537 will try to run
00215    * with a very small number of file descriptors available.
00216    * This implies that any file descriptor which is open
00217    * when the test runs will have a number in the high range
00218    * of whatever the system supports.
00219    */
00220 
00221   /*
00222    * reserve a chunk of memory before opening file descriptors to
00223    * avoid a low memory condition once the file descriptors are
00224    * open. System conditions that could make the test fail should
00225    * be addressed in the precheck phase. This chunk of memory shall
00226    * be always free()ed before exiting the rlimit() function so
00227    * that it becomes available to the test.
00228    */
00229 
00230   for(nitems = i = 1; nitems <= i; i *= 2)
00231     nitems = i;
00232   if(nitems > 0x7fff)
00233     nitems = 0x40000;
00234   do {
00235     num_open.rlim_max = sizeof(*memchunk) * (size_t)nitems;
00236     snprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max);
00237     fprintf(stderr, "allocating memchunk %s byte array\n", strbuff);
00238     memchunk = malloc(sizeof(*memchunk) * (size_t)nitems);
00239     if(!memchunk) {
00240       fprintf(stderr, "memchunk, malloc() failed\n");
00241       nitems /= 2;
00242     }
00243   } while(nitems && !memchunk);
00244   if(!memchunk) {
00245     store_errmsg("memchunk, malloc() failed", ERRNO);
00246     fprintf(stderr, "%s\n", msgbuff);
00247     return -4;
00248   }
00249 
00250   /* initialize it to fight lazy allocation */
00251 
00252   fprintf(stderr, "initializing memchunk array\n");
00253 
00254   for(i = 0; i < nitems; i++)
00255     memchunk[i] = -1;
00256 
00257   /* set the number of file descriptors we will try to open */
00258 
00259 #ifdef RLIM_INFINITY
00260   if((rl.rlim_cur > 0) && (rl.rlim_cur != RLIM_INFINITY)) {
00261 #else
00262   if(rl.rlim_cur > 0) {
00263 #endif
00264     /* soft limit minus SAFETY_MARGIN */
00265     num_open.rlim_max = rl.rlim_cur - SAFETY_MARGIN;
00266   }
00267   else {
00268     /* a huge number of file descriptors */
00269     for(nitems = i = 1; nitems <= i; i *= 2)
00270       nitems = i;
00271     if(nitems > 0x7fff)
00272       nitems = 0x40000;
00273     num_open.rlim_max = nitems;
00274   }
00275 
00276   /* verify that we won't overflow size_t in malloc() */
00277 
00278   if((size_t)(num_open.rlim_max) > ((size_t)-1) / sizeof(*fd)) {
00279     snprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_max);
00280     snprintf(strbuff, sizeof(strbuff), "unable to allocate an array for %s "
00281              "file descriptors, would overflow size_t", strbuff1);
00282     store_errmsg(strbuff, 0);
00283     fprintf(stderr, "%s\n", msgbuff);
00284     free(memchunk);
00285     return -5;
00286   }
00287 
00288   /* allocate array for file descriptors */
00289 
00290   do {
00291     snprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max);
00292     fprintf(stderr, "allocating array for %s file descriptors\n", strbuff);
00293     fd = malloc(sizeof(*fd) * (size_t)(num_open.rlim_max));
00294     if(!fd) {
00295       fprintf(stderr, "fd, malloc() failed\n");
00296       num_open.rlim_max /= 2;
00297     }
00298   } while(num_open.rlim_max && !fd);
00299   if(!fd) {
00300     store_errmsg("fd, malloc() failed", ERRNO);
00301     fprintf(stderr, "%s\n", msgbuff);
00302     free(memchunk);
00303     return -6;
00304   }
00305 
00306   /* initialize it to fight lazy allocation */
00307 
00308   fprintf(stderr, "initializing fd array\n");
00309 
00310   for(num_open.rlim_cur = 0;
00311       num_open.rlim_cur < num_open.rlim_max;
00312       num_open.rlim_cur++)
00313     fd[num_open.rlim_cur] = -1;
00314 
00315   snprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max);
00316   fprintf(stderr, "trying to open %s file descriptors\n", strbuff);
00317 
00318   /* open a dummy descriptor */
00319 
00320   fd[0] = open(DEV_NULL, O_RDONLY);
00321   if(fd[0] < 0) {
00322     snprintf(strbuff, sizeof(strbuff), "opening of %s failed", DEV_NULL);
00323     store_errmsg(strbuff, ERRNO);
00324     fprintf(stderr, "%s\n", msgbuff);
00325     free(fd);
00326     fd = NULL;
00327     free(memchunk);
00328     return -7;
00329   }
00330 
00331   /* create a bunch of file descriptors */
00332 
00333   for(num_open.rlim_cur = 1;
00334       num_open.rlim_cur < num_open.rlim_max;
00335       num_open.rlim_cur++) {
00336 
00337     fd[num_open.rlim_cur] = dup(fd[0]);
00338 
00339     if(fd[num_open.rlim_cur] < 0) {
00340 
00341       fd[num_open.rlim_cur] = -1;
00342 
00343       snprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_cur);
00344       snprintf(strbuff, sizeof(strbuff), "dup() attempt %s failed", strbuff1);
00345       fprintf(stderr, "%s\n", strbuff);
00346 
00347       snprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_cur);
00348       snprintf(strbuff, sizeof(strbuff), "fds system limit seems close to %s",
00349                strbuff1);
00350       fprintf(stderr, "%s\n", strbuff);
00351 
00352       num_open.rlim_max = num_open.rlim_cur - SAFETY_MARGIN;
00353 
00354       num_open.rlim_cur -= num_open.rlim_max;
00355       snprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_cur);
00356       snprintf(strbuff, sizeof(strbuff), "closing %s file descriptors",
00357                strbuff1);
00358       fprintf(stderr, "%s\n", strbuff);
00359 
00360       for(num_open.rlim_cur = num_open.rlim_max;
00361           fd[num_open.rlim_cur] >= 0;
00362           num_open.rlim_cur++) {
00363         close(fd[num_open.rlim_cur]);
00364         fd[num_open.rlim_cur] = -1;
00365       }
00366 
00367       snprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max);
00368       fprintf(stderr, "shrinking array for %s file descriptors\n", strbuff);
00369 
00370       /* we don't care if we can't shrink it */
00371 
00372       tmpfd = realloc(fd, sizeof(*fd) * (size_t)(num_open.rlim_max));
00373       if(tmpfd) {
00374         fd = tmpfd;
00375         tmpfd = NULL;
00376       }
00377 
00378       break;
00379 
00380     }
00381 
00382   }
00383 
00384   snprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max);
00385   fprintf(stderr, "%s file descriptors open\n", strbuff);
00386 
00387 #if !defined(HAVE_POLL_FINE)    && \
00388     !defined(USE_WINSOCK)       && \
00389     !defined(TPF)
00390 
00391   /*
00392    * when using select() instead of poll() we cannot test
00393    * libcurl functionality with a socket number equal or
00394    * greater than FD_SETSIZE. In any case, macro VERIFY_SOCK
00395    * in lib/select.c enforces this check and protects libcurl
00396    * from a possible crash. The effect of this protection
00397    * is that test 537 will always fail, since the actual
00398    * call to select() never takes place. We skip test 537
00399    * with an indication that select limit would be exceeded.
00400    */
00401 
00402   num_open.rlim_cur = FD_SETSIZE - SAFETY_MARGIN;
00403   if(num_open.rlim_max > num_open.rlim_cur) {
00404     snprintf(strbuff, sizeof(strbuff), "select limit is FD_SETSIZE %d",
00405              FD_SETSIZE);
00406     store_errmsg(strbuff, 0);
00407     fprintf(stderr, "%s\n", msgbuff);
00408     close_file_descriptors();
00409     free(memchunk);
00410     return -8;
00411   }
00412 
00413   num_open.rlim_cur = FD_SETSIZE - SAFETY_MARGIN;
00414   for(rl.rlim_cur = 0;
00415       rl.rlim_cur < num_open.rlim_max;
00416       rl.rlim_cur++) {
00417     if((fd[rl.rlim_cur] > 0) &&
00418        ((unsigned int)fd[rl.rlim_cur] > num_open.rlim_cur)) {
00419       snprintf(strbuff, sizeof(strbuff), "select limit is FD_SETSIZE %d",
00420                FD_SETSIZE);
00421       store_errmsg(strbuff, 0);
00422       fprintf(stderr, "%s\n", msgbuff);
00423       close_file_descriptors();
00424       free(memchunk);
00425       return -9;
00426     }
00427   }
00428 
00429 #endif /* using a FD_SETSIZE bound select() */
00430 
00431   /*
00432    * Old or 'backwards compatible' implementations of stdio do not allow
00433    * handling of streams with an underlying file descriptor number greater
00434    * than 255, even when allowing high numbered file descriptors for sockets.
00435    * At this point we have a big number of file descriptors which have been
00436    * opened using dup(), so lets test the stdio implementation and discover
00437    * if it is capable of fopen()ing some additional files.
00438    */
00439 
00440   if(!fopen_works()) {
00441     snprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_max);
00442     snprintf(strbuff, sizeof(strbuff), "fopen fails with %s fds open",
00443             strbuff1);
00444     fprintf(stderr, "%s\n", msgbuff);
00445     snprintf(strbuff, sizeof(strbuff), "fopen fails with lots of fds open");
00446     store_errmsg(strbuff, 0);
00447     close_file_descriptors();
00448     free(memchunk);
00449     return -10;
00450   }
00451 
00452   /* free the chunk of memory we were reserving so that it
00453      becomes becomes available to the test */
00454 
00455   free(memchunk);
00456 
00457   /* close file descriptors unless instructed to keep them */
00458 
00459   if(!keep_open) {
00460     close_file_descriptors();
00461   }
00462 
00463   return 0;
00464 }
00465 
00466 int test(char *URL)
00467 {
00468   CURLcode res;
00469   CURL *curl;
00470 
00471   if(!strcmp(URL, "check")) {
00472     /* used by the test script to ask if we can run this test or not */
00473     if(rlimit(FALSE)) {
00474       fprintf(stdout, "rlimit problem: %s\n", msgbuff);
00475       return 1;
00476     }
00477     return 0; /* sure, run this! */
00478   }
00479 
00480   if(rlimit(TRUE)) {
00481     /* failure */
00482     return TEST_ERR_MAJOR_BAD;
00483   }
00484 
00485   /* run the test with the bunch of open file descriptors
00486      and close them all once the test is over */
00487 
00488   if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
00489     fprintf(stderr, "curl_global_init() failed\n");
00490     close_file_descriptors();
00491     return TEST_ERR_MAJOR_BAD;
00492   }
00493 
00494   curl = curl_easy_init();
00495   if(!curl) {
00496     fprintf(stderr, "curl_easy_init() failed\n");
00497     close_file_descriptors();
00498     curl_global_cleanup();
00499     return TEST_ERR_MAJOR_BAD;
00500   }
00501 
00502   test_setopt(curl, CURLOPT_URL, URL);
00503   test_setopt(curl, CURLOPT_HEADER, 1L);
00504 
00505   res = curl_easy_perform(curl);
00506 
00507 test_cleanup:
00508 
00509   close_file_descriptors();
00510   curl_easy_cleanup(curl);
00511   curl_global_cleanup();
00512 
00513   return (int)res;
00514 }
00515 
00516 #else /* defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) */
00517 
00518 int test(char *URL)
00519 {
00520   (void)URL;
00521   printf("system lacks necessary system function(s)");
00522   return 1; /* skip test */
00523 }
00524 
00525 #endif /* defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) */


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:05