]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
curl: --test-duphandle in debug builds runs "duphandled"
authorDaniel Stenberg <daniel@haxx.se>
Thu, 7 Nov 2024 09:22:32 +0000 (10:22 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Fri, 8 Nov 2024 12:22:47 +0000 (13:22 +0100)
Using this option (only available in debug builds) makes curl always
call curl_easy_duphandle() on the handle before using it.

To help us catch curl_easy_duphandle() mistakes better.

Add a CI job using this.

Bonus: the previous runtests option -e is now also supported as
--test-event

Closes #15504

19 files changed:
.github/workflows/linux.yml
.github/workflows/macos.yml
src/tool_cfgable.h
src/tool_getparam.c
src/tool_getparam.h
src/tool_operate.c
tests/FILEFORMAT.md
tests/data/test440
tests/data/test441
tests/data/test493
tests/data/test780
tests/data/test781
tests/data/test782
tests/data/test783
tests/globalconfig.pm
tests/runner.pm
tests/runtests.md
tests/runtests.pl
tests/test1139.pl

index 24257b8ef084e3a7bc3210643b145ef12949386c..d00b731ebed97367315c6071e1e1c352b7d4e08d 100644 (file)
@@ -248,7 +248,12 @@ jobs:
           - name: event-based
             install_packages: libssh-dev
             configure: --enable-debug --disable-shared --disable-threaded-resolver --with-libssh --with-openssl
-            tflags: -n -e '!TLS-SRP'
+            tflags: -n --test-event '!TLS-SRP'
+
+          - name: duphandle
+            install_packages: libssh-dev
+            configure: --enable-debug --disable-shared --disable-threaded-resolver --with-libssh --with-openssl
+            tflags: -n --test-duphandle '!TLS-SRP'
 
           - name: rustls valgrind
             install_packages: valgrind
index 40f6602941b9b3ae685cf745a78442ce231472cf..816c801be84187f7b85e17bdc989643dcf3231e3 100644 (file)
@@ -136,7 +136,7 @@ jobs:
             compiler: clang
             configure: --enable-debug --with-openssl=$(brew --prefix openssl)
             macos-version-min: '10.9'
-            tflags: -e
+            tflags: --test-event
           - name: 'OpenSSL libssh2 !ldap 10.15'
             compiler: clang
             configure: --enable-debug --disable-ldap --with-openssl=$(brew --prefix openssl)
index 46f47670d6ed612c42b61318d9ba81a6e5a1a835..09ea9edd19f2c97ab6ef6e0d0abb13f2bf361000 100644 (file)
@@ -330,6 +330,7 @@ struct GlobalConfig {
   long ms_per_transfer;           /* start next transfer after (at least) this
                                      many milliseconds */
 #ifdef DEBUGBUILD
+  bool test_duphandle;
   bool test_event_based;
 #endif
   bool parallel;
index 1231b3bd60d4dc3494db1ea0025c1aeeb9bda2f9..447046f72f866e040b75ec7e45fbd4c22eb5ee50 100644 (file)
@@ -312,7 +312,10 @@ static const struct LongShort aliases[]= {
   {"tcp-fastopen",               ARG_BOOL, ' ', C_TCP_FASTOPEN},
   {"tcp-nodelay",                ARG_BOOL, ' ', C_TCP_NODELAY},
   {"telnet-option",              ARG_STRG, 't', C_TELNET_OPTION},
+#ifdef DEBUGBUILD
+  {"test-duphandle",             ARG_BOOL, ' ', C_TEST_DUPHANDLE},
   {"test-event",                 ARG_BOOL, ' ', C_TEST_EVENT},
+#endif
   {"tftp-blksize",               ARG_STRG, ' ', C_TFTP_BLKSIZE},
   {"tftp-no-options",            ARG_BOOL, ' ', C_TFTP_NO_OPTIONS},
   {"time-cond",                  ARG_STRG, 'z', C_TIME_COND},
@@ -1653,13 +1656,14 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
     case C_SASL_IR: /* --sasl-ir */
       config->sasl_ir = toggle;
       break;
-    case C_TEST_EVENT: /* --test-event */
 #ifdef DEBUGBUILD
+    case C_TEST_DUPHANDLE: /* --test-duphandle */
+      global->test_duphandle = toggle;
+      break;
+    case C_TEST_EVENT: /* --test-event */
       global->test_event_based = toggle;
-#else
-      warnf(global, "--test-event is ignored unless a debug build");
-#endif
       break;
+#endif
     case C_UNIX_SOCKET: /* --unix-socket */
       config->abstract_unix_socket = FALSE;
       err = getstr(&config->unix_socket_path, nextarg, DENY_BLANK);
index c42f686a4820e34bfd91599b59f891d3ffd9a108..7d9abbd1417cd2e126c876412151e9d4fb576ff0 100644 (file)
@@ -267,6 +267,7 @@ typedef enum {
   C_TCP_FASTOPEN,
   C_TCP_NODELAY,
   C_TELNET_OPTION,
+  C_TEST_DUPHANDLE,
   C_TEST_EVENT,
   C_TFTP_BLKSIZE,
   C_TFTP_NO_OPTIONS,
index a1212c9dded073aaac9ec400b05964cfe1f4649a..354ecdedd74e30130a7e60e73157b93d1fd975eb 100644 (file)
@@ -2885,6 +2885,17 @@ static CURLcode serial_transfers(struct GlobalConfig *global,
       if(getenv("CURL_FORBID_REUSE"))
         (void)curl_easy_setopt(per->curl, CURLOPT_FORBID_REUSE, 1L);
 
+      if(global->test_duphandle) {
+        CURL *dup = curl_easy_duphandle(per->curl);
+        curl_easy_cleanup(per->curl);
+        per->curl = dup;
+        if(!dup) {
+          result = CURLE_OUT_OF_MEMORY;
+          break;
+        }
+        /* a duplicate needs the share re-added */
+        (void)curl_easy_setopt(per->curl, CURLOPT_SHARE, share);
+      }
       if(global->test_event_based)
         result = curl_easy_perform_ev(per->curl);
       else
index aa80b81687b7f8dc9e360dc86526aace228731f0..b15274e17ae9b455a09086afc6f2e644b7ff8115 100644 (file)
@@ -522,6 +522,7 @@ the `unit/` directory (if the tool name starts with `unit`).
 Brief test case description, shown when the test runs.
 
 ### `<setenv>`
+
     variable1=contents1
     variable2=contents2
     variable3
@@ -606,6 +607,11 @@ Pass this given data on stdin to the tool.
 If `nonewline` is set, we cut off the trailing newline of this given data
 before comparing with the one actually received by the client
 
+## `<disable>`
+
+If `test-duphandle` is a listed item here, this is not run when
+`--test-duphandle` is used.
+
 ## `<verify>`
 ### `<errorcode>`
 numerical error code curl is supposed to return. Specify a list of accepted
index a77ef606d9dc80e8e29b1dc94dc3c21c5f2ee181..ce9892967c43f8c2c2017f9da805e0f454cb3de1 100644 (file)
@@ -44,6 +44,10 @@ HSTS with trailing-dot host name in URL but none in hsts file
 <command>
 -x http://%HOSTIP:%HTTPPORT http://this.hsts.example./%TESTNUMBER --hsts %LOGDIR/input%TESTNUMBER -w '%{url_effective}\n'
 </command>
+
+<disable>
+test-duphandle
+</disable>
 </client>
 
 <verify>
index 29b990b891b6b5451f71e2dff29653bf77d0871d..02aca4d0e0f6690f2040f474bde1171989a4a756 100644 (file)
@@ -44,6 +44,9 @@ HSTS with no t-dot host name in URL but t-dot in file
 <command>
 -x http://%HOSTIP:%HTTPPORT http://this.hsts.example/%TESTNUMBER --hsts %LOGDIR/input%TESTNUMBER -w '%{url_effective}\n'
 </command>
+<disable>
+test-duphandle
+</disable>
 </client>
 
 <verify>
index 1a677d32958c373dcf2ca743c1e6865947c2b522..d157f0355fa9c508e96f408b9a8648421b96a844 100644 (file)
@@ -43,6 +43,9 @@ HSTS and %{url_effective} after upgrade
 <command>
 -x http://%HOSTIP:%HTTPPORT http://this.hsts.example/%TESTNUMBER --hsts %LOGDIR/input%TESTNUMBER -w '%{url_effective}\n'
 </command>
+<disable>
+test-duphandle
+</disable>
 </client>
 
 <verify>
index cdb8b711f78bd58d9d005ec5e2ea2199042f2850..567b6684d08bcedd09a798c5f224478fbeabde9d 100644 (file)
@@ -55,6 +55,9 @@ HSTS with updated expiry in response
 <command>
 -x http://%HOSTIP:%PROXYPORT http://this.hsts.example:%HTTPSPORT/%TESTNUMBER --hsts %LOGDIR/input%TESTNUMBER -k
 </command>
+<disable>
+test-duphandle
+</disable>
 </client>
 
 <verify>
index e931da4f5effb66df5d63148157af5d1897800e8..4892415bf46b4b3c7cab7f186fd5a3e7fdf101c9 100644 (file)
@@ -57,6 +57,9 @@ HSTS update expiry, with parent includeSubDomains domain present
 <command>
 -x http://%HOSTIP:%PROXYPORT http://this.hsts.example:%HTTPSPORT/%TESTNUMBER --hsts %LOGDIR/input%TESTNUMBER -k
 </command>
+<disable>
+test-duphandle
+</disable>
 </client>
 
 <verify>
index ae0d7474706f082d950169fe18e783bfbf40903d..6a53081ab66aa2c1a1daedbd02ca602fdf78742d 100644 (file)
@@ -57,6 +57,9 @@ HSTS update expiry, with two includeSubDomains domains present
 <command>
 -x http://%HOSTIP:%PROXYPORT http://this.hsts.example:%HTTPSPORT/%TESTNUMBER --hsts %LOGDIR/input%TESTNUMBER -k
 </command>
+<disable>
+test-duphandle
+</disable>
 </client>
 
 <verify>
index dc58fa4fb3a7d83ba114e4b02d575c71888e30b9..f12cc4507d5b1bf2501375fb8fcf3f0d8e7ae425 100644 (file)
@@ -57,6 +57,9 @@ HSTS update expiry, removing includesubdomains in update
 <command>
 -x http://%HOSTIP:%PROXYPORT http://this.hsts.example:%HTTPSPORT/%TESTNUMBER --hsts %LOGDIR/input%TESTNUMBER -k
 </command>
+<disable>
+test-duphandle
+</disable>
 </client>
 
 <verify>
index dec828e01881eefe0dd507949ac7ac15e1eba159..08aff0ff3ee325b7eef61265f2e2a75b8fec1959 100644 (file)
@@ -54,6 +54,7 @@ BEGIN {
         $PROXYIN
         $pwd
         $randseed
+        $run_duphandle
         $run_event_based
         $SERVERCMD
         $SERVERIN
@@ -83,6 +84,7 @@ our $verbose;         # 1 to show verbose test output
 our $torture;         # 1 to enable torture testing
 our $proxy_address;   # external HTTP proxy address
 our $listonly;        # only list the tests
+our $run_duphandle;   # run curl with --test-duphandle to verify handle duplication
 our $run_event_based; # run curl with --test-event to test the event API
 our $automakestyle;   # use automake-like test status output format
 our $anyway;          # continue anyway, even if a test fail
index deb7920e79cd94adbe6ab1860e8e39f56318dfb0..3372eda8b71817c599e6f23d217e191794fea0fc 100644 (file)
@@ -894,6 +894,18 @@ sub singletest_run {
             $cmdargs .= "--test-event ";
             $fail_due_event_based--;
         }
+        if($run_duphandle) {
+            $cmdargs .= "--test-duphandle ";
+            my @dis = getpart("client", "disable");
+            if(@dis) {
+                chomp $dis[0] if($dis[0]);
+                if($dis[0] eq "test-duphandle") {
+                    # marked to not run with duphandle
+                    logmsg "test $testnum: IGNORED: can't run test-duphandle\n";
+                    return (-1, 0, 0, "", "", 0);
+                }
+            }
+        }
         $cmdargs .= $cmd;
         if ($proxy_address) {
             $cmdargs .= " --proxy $proxy_address ";
index e836911b91d2df8d7ff3f3f2f9ffb87386e675c2..4ac52a44601b36ebabd3c24a67423158096cf8f8 100644 (file)
@@ -118,7 +118,7 @@ exclusion, the second field contains a pattern and the final field contains
 the reason why matching tests should be skipped. The exclusion types are
 *keyword*, *test*, and *tool*.
 
-## `-e`
+## `-e` or `--test-event`
 
 Run the test event-based (if possible). This makes runtests invoke curl with
 --test-event option. This option only works if both curl and libcurl were
@@ -263,6 +263,19 @@ the allocation with that number to be set to fail at once instead of looping
 through everyone, which is handy when debugging and then often in combination
 with *-g*.
 
+## `--test-duphandle`
+
+Passes the `--test-duphandle` option to curl when invoked. This command line
+option only exists in debug builds and runs curl normally, but duplicates the
+easy handle before the transfer and use the duplicate instead of the original
+handle. This verifies that the duplicate works exactly as good as the original
+handle.
+
+Because of how the curl tool uses a share object to store and keep some data,
+not everything is however perfectly copied in the duplicate. In particular
+HSTS data is not. A specific test case can be set to avoid using
+`--test-duphandle` by disabling it on a per test basis.
+
 ## `-u`
 
 Error instead of warning on server unexpectedly alive.
index c02655b07e5d20da92ef5e0047d72167051b248d..4d4785b50b69f815931da6ed899e3acbb6ee0abe 100755 (executable)
@@ -871,7 +871,8 @@ sub checksystemfeatures {
                "*\n");
     }
 
-    logmsg sprintf("* Env: %s%s%s%s", $valgrind?"Valgrind ":"",
+    logmsg sprintf("* Env: %s%s%s%s%s", $valgrind?"Valgrind ":"",
+                   $run_duphandle?"test-duphandle ":"",
                    $run_event_based?"event-based ":"",
                    $bundle?"bundle ":"",
                    $nghttpx_h3);
@@ -2270,10 +2271,14 @@ while(@ARGV) {
         # have the servers display protocol output
         $debugprotocol=1;
     }
-    elsif($ARGV[0] eq "-e") {
+    elsif(($ARGV[0] eq "-e") || ($ARGV[0] eq "--test-event")) {
         # run the tests cases event based if possible
         $run_event_based=1;
     }
+    elsif($ARGV[0] eq "--test-duphandle") {
+        # run the tests with --test-duphandle
+        $run_duphandle=1;
+    }
     elsif($ARGV[0] eq "-f") {
         # force - run the test case even if listed in DISABLED
         $run_disabled=1;
index 6ecab78ecee1cc86186bcb1750593283dda08dc7..0c99ab6f3ad6f0471e3e38e5ac035681d3ed1be0 100755 (executable)
@@ -180,6 +180,7 @@ my %opts = (
     '--include' => 6,
 
     # for tests and debug only, can remain hidden
+    '--test-duphandle' => 6,
     '--test-event' => 6,
     '--wdebug' => 6,
     );