]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
runtests: support memory-limits per test
authorDaniel Stenberg <daniel@haxx.se>
Fri, 4 Jul 2025 21:57:03 +0000 (23:57 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 8 Jul 2025 08:14:45 +0000 (10:14 +0200)
The idea here is to set limits per test how many allocations and maximum
amount of memory it is allowed to use. This is a means to make sure the
number and total size of allocations are kept in check and don't
mistakenly "blow up".

If runtests.pl detects that the given limits have been exceeded it fails
the test case with an error.

The `<verify>` part now supports `<limits>`, and in this section two
limits can be set for each test (verified in debug builds only):

    Allocations: [number of allocation calls]
    Maximum allocated: [maximum concurrent memory allocated]

Default limits (used if nothing is set in the test file):

    Allocations: 1000
    Maximum allocated: 1000000

Closes #17821

22 files changed:
docs/tests/FILEFORMAT.md
tests/data/test1
tests/data/test1129
tests/data/test1156
tests/data/test1291
tests/data/test1559
tests/data/test1560
tests/data/test1651
tests/data/test2302
tests/data/test2303
tests/data/test2601
tests/data/test3207
tests/data/test440
tests/data/test442
tests/data/test445
tests/data/test497
tests/data/test500
tests/data/test575
tests/data/test747
tests/data/test751
tests/data/test993
tests/runtests.pl

index e6da32a5cfcbf8ecf9d6d75c5f4f7c55c215f162..992717b190c80b997dfa57e418689dc9c98dc906 100644 (file)
@@ -699,6 +699,14 @@ test.
 
 `loadfile="filename"` makes loading the data from an external file.
 
+### `<limit>`
+
+When this test runs and curl was built with debug enabled, runtests make sure
+that the set limits are not exceeded. Supported limits:
+
+    Allocations: [number of allocation calls]
+    Maximum allocated: [maximum concurrent memory allocated]
+
 ### `<file name="%LOGDIR/filename" [mode="text"]>`
 The file's contents must be identical to this after the test is complete. Use
 the mode="text" attribute if the output is in text mode on platforms that have
index 4aa4d1b81267feb3de725ba115b2f089602e045e..1fb3e05248d6b917043bd8237bae053a02c202e7 100644 (file)
@@ -49,5 +49,9 @@ User-Agent: curl/%VERSION
 Accept: */*
 
 </protocol>
+<limits>
+Allocations: 135
+Maximum allocated: 135415
+</limits>
 </verify>
 </testcase>
index 41b295563a4138f0950215a70a0a11a3b7f2bf3c..99e390c50023749cb738be47eeac7a78de7a90c7 100644 (file)
@@ -92,5 +92,8 @@ Content-Type: application/x-www-form-urlencoded
 Expect: 100-continue\r
 \r
 </protocol>
+<limits>
+Maximum allocated: 3200000
+</limits>
 </verify>
 </testcase>
index 94fa469dce62d851764357b0d3933f7f64f42142..34926942731833773738859117ea21e8d5577652 100644 (file)
@@ -67,5 +67,8 @@ http://%HOSTIP:%HTTPPORT/want/%TESTNUMBER
 <stdout>
 0
 </stdout>
+<limits>
+Allocations: 1300
+</limits>
 </verify>
 </testcase>
index 794ed22d020cd8705c5de2df816a19a6bf0f2d7d..8d51138da24a098a0e1927c7f789fa1590a8f83d 100644 (file)
@@ -38,5 +38,8 @@ XXXXXXXx
 <errorcode>
 1
 </errorcode>
+<limits>
+Allocations: 3100
+</limits>
 </verify>
 </testcase>
index c307f6447e4d75b74718a4f657c2b3ae370960ae..7217035317ce1d1adf93981d5077b42ce6fe8c07 100644 (file)
@@ -40,6 +40,9 @@ CURLUPART_URL 10000000 bytes URL == 3 (Malformed input to a URL function)
 CURLUPART_SCHEME 10000000 bytes scheme == 3 (Malformed input to a URL function)
 CURLUPART_USER 10000000 bytes user == 3 (Malformed input to a URL function)
 </stdout>
+<limits>
+Maximum allocated: 10010000
+</limits>
 </verify>
 
 </testcase>
index 8a991f9b9ed8d867594601908231900959064570..381faaa93ad4572baac788ace7be5457573b38f3 100644 (file)
@@ -38,5 +38,8 @@ lib%TESTNUMBER
 <stdout>
 success
 </stdout>
+<limits>
+Allocations: 3000
+</limits>
 </verify>
 </testcase>
index e552a8ad38cce6bdc6c10a57c4d1f5792c852990..e7b725763abc422bee5e71d7760f10714967912f 100644 (file)
@@ -18,5 +18,12 @@ unittest
 <name>
 x509 parsing
 </name>
+
+<verify>
+<limits>
+Allocations: 14000
+</limits>
+</verify>
+
 </client>
 </testcase>
index 9ade6a1e5254661b5ed13542e62106c1ed1afd0c..01a867536964e8f4f999ab25ff61d790024157fa 100644 (file)
@@ -66,5 +66,8 @@ Sec-WebSocket-Key: NDMyMTUzMjE2MzIxNzMyMQ==
 68 65 6c 6c 6f 
 RECFLAGS: 1
 </stdout>
+<limits>
+Maximum allocated: 1300000
+</limits>
 </verify>
 </testcase>
index 79cb4c2ad0be4125760e11fc35e916d3c6ce4682..f6ed9a5f670e6107e8c1981cbe7673a4114fccbd 100644 (file)
@@ -55,5 +55,8 @@ Sec-WebSocket-Key: NDMyMTUzMjE2MzIxNzMyMQ==
 <errorcode>
 22
 </errorcode>
+<limits>
+Maximum allocated: 1300000
+</limits>
 </verify>
 </testcase>
index 778f6c54a7d4fa4496b91b4a750e97b1305139b2..a6581a803fd3179359b187352e6c40f10601369b 100644 (file)
@@ -19,4 +19,9 @@ unittest
 bufq unit tests
 </name>
 </client>
+<verify>
+<limits>
+Allocations: 6300
+</limits>
+</verify>
 </testcase>
index fe2e38f97855f016fd48213f86b05d65f4632304..318f8c704a8038dde6b0efd76a9db26a7b40b8a8 100644 (file)
@@ -171,5 +171,8 @@ https://localhost:%HTTPSPORT/%TESTNUMBER %CERTDIR/certs/test-ca.crt
 
 # Verify data after the test has been "shot"
 <verify>
+<limits>
+Allocations: 13300
+</limits>
 </verify>
 </testcase>
index ce9892967c43f8c2c2017f9da805e0f454cb3de1..81cf738473bd668dc2760f1eb0794ff797e82e0f 100644 (file)
@@ -73,5 +73,8 @@ https://this.hsts.example./%TESTNUMBER
 <errorcode>
 56
 </errorcode>
+<limits>
+Allocations: 1100
+</limits>
 </verify>
 </testcase>
index 2787c02b6f14ad4c06d4cca03fbadc8659ac27a2..fb881d3b67f902e75f7d2220bb566b0785d8de89 100644 (file)
@@ -209,5 +209,8 @@ Accept: */*
 Cookie: name150=could-be-large-150; name149=could-be-large-149; name148=could-be-large-148; name147=could-be-large-147; name146=could-be-large-146; name145=could-be-large-145; name144=could-be-large-144; name143=could-be-large-143; name142=could-be-large-142; name141=could-be-large-141; name140=could-be-large-140; name139=could-be-large-139; name138=could-be-large-138; name137=could-be-large-137; name136=could-be-large-136; name135=could-be-large-135; name134=could-be-large-134; name133=could-be-large-133; name132=could-be-large-132; name131=could-be-large-131; name130=could-be-large-130; name129=could-be-large-129; name128=could-be-large-128; name127=could-be-large-127; name126=could-be-large-126; name125=could-be-large-125; name124=could-be-large-124; name123=could-be-large-123; name122=could-be-large-122; name121=could-be-large-121; name120=could-be-large-120; name119=could-be-large-119; name118=could-be-large-118; name117=could-be-large-117; name116=could-be-large-116; name115=could-be-large-115; name114=could-be-large-114; name113=could-be-large-113; name112=could-be-large-112; name111=could-be-large-111; name110=could-be-large-110; name109=could-be-large-109; name108=could-be-large-108; name107=could-be-large-107; name106=could-be-large-106; name105=could-be-large-105; name104=could-be-large-104; name103=could-be-large-103; name102=could-be-large-102; name101=could-be-large-101; name100=could-be-large-100; name99=could-be-large-99; name98=could-be-large-98; name97=could-be-large-97; name96=could-be-large-96; name95=could-be-large-95; name94=could-be-large-94; name93=could-be-large-93; name92=could-be-large-92; name91=could-be-large-91; name90=could-be-large-90; name89=could-be-large-89; name88=could-be-large-88; name87=could-be-large-87; name86=could-be-large-86; name85=could-be-large-85; name84=could-be-large-84; name83=could-be-large-83; name82=could-be-large-82; name81=could-be-large-81; name80=could-be-large-80; name79=could-be-large-79; name78=could-be-large-78; name77=could-be-large-77; name76=could-be-large-76; name75=could-be-large-75; name74=could-be-large-74; name73=could-be-large-73; name72=could-be-large-72; name71=could-be-large-71; name70=could-be-large-70; name69=could-be-large-69; name68=could-be-large-68; name67=could-be-large-67; name66=could-be-large-66; name65=could-be-large-65; name64=could-be-large-64; name63=could-be-large-63; name62=could-be-large-62; name61=could-be-large-61; name60=could-be-large-60; name59=could-be-large-59; name58=could-be-large-58; name57=could-be-large-57; name56=could-be-large-56; name55=could-be-large-55; name54=could-be-large-54; name53=could-be-large-53; name52=could-be-large-52; name51=could-be-large-51; name50=could-be-large-50; name49=could-be-large-49; name48=could-be-large-48; name47=could-be-large-47; name46=could-be-large-46; name45=could-be-large-45; name44=could-be-large-44; name43=could-be-large-43; name42=could-be-large-42; name41=could-be-large-41; name40=could-be-large-40; name39=could-be-large-39; name38=could-be-large-38; name37=could-be-large-37; name36=could-be-large-36; name35=could-be-large-35; name34=could-be-large-34; name33=could-be-large-33; name32=could-be-large-32; name31=could-be-large-31; name30=could-be-large-30; name29=could-be-large-29; name28=could-be-large-28; name27=could-be-large-27; name26=could-be-large-26; name25=could-be-large-25; name24=could-be-large-24; name23=could-be-large-23; name22=could-be-large-22; name21=could-be-large-21; name20=could-be-large-20; name19=could-be-large-19; name18=could-be-large-18; name17=could-be-large-17; name16=could-be-large-16; name15=could-be-large-15; name14=could-be-large-14; name13=could-be-large-13; name12=could-be-large-12; name11=could-be-large-11; name10=could-be-large-10; name9=could-be-large-9; name8=could-be-large-8; name7=could-be-large-7; name6=could-be-large-6; name5=could-be-large-5; name4=could-be-large-4; name3=could-be-large-3; name2=could-be-large-2; name1=could-be-large-1\r
 \r
 </protocol>
+<limits>
+Allocations: 1100
+</limits>
 </verify>
 </testcase>
index d573077b1510996732d14fb38a363b9a2d7395ad..ec0b0e61ed0b2e2b54af70bf90ed80b3210d3fd9 100644 (file)
@@ -57,5 +57,8 @@ Refuse tunneling protocols through HTTP proxy
 <errorcode>
 56
 </errorcode>
+<limits>
+Allocations: 1700
+</limits>
 </verify>
 </testcase>
index dec1808f9b666b822691bd8c422514c1300a03c8..02ec8e802f8e54b36ab7b9f5a8ee9c0e039e1420 100644 (file)
@@ -52,5 +52,8 @@ Accept: */*
 <errorcode>
 56
 </errorcode>
+<limits>
+Allocations: 1900
+</limits>
 </verify>
 </testcase>
index c215318bc51983fd2f957b0d8c9531f97e317b61..0534cae1e59658498675971a237911902d851f8b 100644 (file)
@@ -54,5 +54,9 @@ Host: %HOSTIP:%HTTPPORT
 Accept: */*\r
 \r
 </protocol>
+<limits>
+Allocations: 80
+Maximum allocated: 33400
+</limits>
 </verify>
 </testcase>
index 35b65a3d6f4fe81e0027a5aa58d7fa7ef97ee9b3..fbb7343d96705f8c7db6a35a9e6b6f18d8346c20 100644 (file)
@@ -120,5 +120,8 @@ This file should have permissions 777
 This is content of file "file.txt"
 Some junk ;-) This file does not really exist.
 </stdout>
+<limits>
+Allocations: 1500
+</limits>
 </verify>
 </testcase>
index 6b541a4337fcbac03a096f607b5c0d2df015007a..4397c7741ce7d23ac52fb2b1742729b7534afc46 100644 (file)
@@ -52,5 +52,8 @@ Accept: */*
 <errorcode>
 100
 </errorcode>
+<limits>
+Allocations: 6000
+</limits>
 </verify>
 </testcase>
index ffc6df512f83d58c2c6d52772350dd55aab439aa..21a3df25071044031c2acda0ff09a3e8b4677235 100644 (file)
@@ -27,7 +27,11 @@ multi - add many easy handles
 </file>
 </client>
 
-# Verify data after the test has been "shot"
+# 1000 easy handles needs memory
 <verify>
+<limits>
+Maximum allocated: 6000000
+Allocations: 7000
+</limits>
 </verify>
 </testcase>
index 01248de33953d97da16673b54fa260bc467fa216..2f5607b67935dce947947cb078c554976a135655 100644 (file)
@@ -38,5 +38,8 @@ PASS secret
 LIST\r
 QUIT\r
 </protocol>
+<limits>
+Allocations: 2200
+</limits>
 </verify>
 </testcase>
index db9054ba1f6585301902263ee04551b89d4247b9..39e9bca3f781b5200027dee6c125a47472000b53 100755 (executable)
@@ -1698,6 +1698,48 @@ sub singletest_check {
             else {
                 $ok .= "m";
             }
+            my @more=`$memanalyze -v "$logdir/$MEMDUMP"`;
+            my $allocs;
+            my $max;
+            for(@more) {
+                if(/^Allocations: (\d+)/) {
+                    $allocs = $1;
+                }
+                elsif(/^Maximum allocated: (\d+)/) {
+                    $max = $1;
+                }
+            }
+            my @limits = getpart("verify", "limits");
+            my $lim_allocs = 1000; # high default values
+            my $lim_max = 1000000;
+            for(@limits) {
+                if(/^Allocations: (\d+)/i) {
+                    $lim_allocs = $1;
+                }
+                elsif(/^Maximum allocated: (\d+)/i) {
+                    $lim_max = $1;
+                }
+            }
+            logmsg "did $allocs allocations, $lim_allocs allowed\n"
+                if($verbose);
+
+            logmsg "allocated $max maximum, $lim_max allowed\n"
+                if($verbose);
+
+            if($allocs > $lim_allocs) {
+                logmsg "\n** TOO MANY ALLOCS\n";
+                logmsg "$lim_allocs allocations allowed, did $allocs\n";
+                # timestamp test result verification end
+                $timevrfyend{$testnum} = Time::HiRes::time();
+                return -1;
+            }
+            if($max > $lim_max) {
+                logmsg "\n** TOO MUCH TOTAL ALLOCATION\n";
+                logmsg "$lim_max maximum allocation allowed, did $max\n";
+                # timestamp test result verification end
+                $timevrfyend{$testnum} = Time::HiRes::time();
+                return -1;
+            }
         }
     }
     else {