PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i WWWWWW
Current Directory: /opt/golang/1.22.0/src/testing
Viewing File: /opt/golang/1.22.0/src/testing/fuzz.go
// Copyright 2020 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package testing import ( "errors" "flag" "fmt" "io" "os" "path/filepath" "reflect" "runtime" "strings" "time" ) func initFuzzFlags() { matchFuzz = flag.String("test.fuzz", "", "run the fuzz test matching `regexp`") flag.Var(&fuzzDuration, "test.fuzztime", "time to spend fuzzing; default is to run indefinitely") flag.Var(&minimizeDuration, "test.fuzzminimizetime", "time to spend minimizing a value after finding a failing input") fuzzCacheDir = flag.String("test.fuzzcachedir", "", "directory where interesting fuzzing inputs are stored (for use only by cmd/go)") isFuzzWorker = flag.Bool("test.fuzzworker", false, "coordinate with the parent process to fuzz random values (for use only by cmd/go)") } var ( matchFuzz *string fuzzDuration durationOrCountFlag minimizeDuration = durationOrCountFlag{d: 60 * time.Second, allowZero: true} fuzzCacheDir *string isFuzzWorker *bool // corpusDir is the parent directory of the fuzz test's seed corpus within // the package. corpusDir = "testdata/fuzz" ) // fuzzWorkerExitCode is used as an exit code by fuzz worker processes after an // internal error. This distinguishes internal errors from uncontrolled panics // and other failures. Keep in sync with internal/fuzz.workerExitCode. const fuzzWorkerExitCode = 70 // InternalFuzzTarget is an internal type but exported because it is // cross-package; it is part of the implementation of the "go test" command. type InternalFuzzTarget struct { Name string Fn func(f *F) } // F is a type passed to fuzz tests. // // Fuzz tests run generated inputs against a provided fuzz target, which can // find and report potential bugs in the code being tested. // // A fuzz test runs the seed corpus by default, which includes entries provided // by (*F).Add and entries in the testdata/fuzz/<FuzzTestName> directory. After // any necessary setup and calls to (*F).Add, the fuzz test must then call // (*F).Fuzz to provide the fuzz target. See the testing package documentation // for an example, and see the [F.Fuzz] and [F.Add] method documentation for // details. // // *F methods can only be called before (*F).Fuzz. Once the test is // executing the fuzz target, only (*T) methods can be used. The only *F methods // that are allowed in the (*F).Fuzz function are (*F).Failed and (*F).Name. type F struct { common fuzzContext *fuzzContext testContext *testContext // inFuzzFn is true when the fuzz function is running. Most F methods cannot // be called when inFuzzFn is true. inFuzzFn bool // corpus is a set of seed corpus entries, added with F.Add and loaded // from testdata. corpus []corpusEntry result fuzzResult fuzzCalled bool } var _ TB = (*F)(nil) // corpusEntry is an alias to the same type as internal/fuzz.CorpusEntry. // We use a type alias because we don't want to export this type, and we can't // import internal/fuzz from testing. type corpusEntry = struct { Parent string Path string Data []byte Values []any Generation int IsSeed bool } // Helper marks the calling function as a test helper function. // When printing file and line information, that function will be skipped. // Helper may be called simultaneously from multiple goroutines. func (f *F) Helper() { if f.inFuzzFn { panic("testing: f.Helper was called inside the fuzz target, use t.Helper instead") } // common.Helper is inlined here. // If we called it, it would mark F.Helper as the helper // instead of the caller. f.mu.Lock() defer f.mu.Unlock() if f.helperPCs == nil { f.helperPCs = make(map[uintptr]struct{}) } // repeating code from callerName here to save walking a stack frame var pc [1]uintptr n := runtime.Callers(2, pc[:]) // skip runtime.Callers + Helper if n == 0 { panic("testing: zero callers found") } if _, found := f.helperPCs[pc[0]]; !found { f.helperPCs[pc[0]] = struct{}{} f.helperNames = nil // map will be recreated next time it is needed } } // Fail marks the function as having failed but continues execution. func (f *F) Fail() { // (*F).Fail may be called by (*T).Fail, which we should allow. However, we // shouldn't allow direct (*F).Fail calls from inside the (*F).Fuzz function. if f.inFuzzFn { panic("testing: f.Fail was called inside the fuzz target, use t.Fail instead") } f.common.Helper() f.common.Fail() } // Skipped reports whether the test was skipped. func (f *F) Skipped() bool { // (*F).Skipped may be called by tRunner, which we should allow. However, we // shouldn't allow direct (*F).Skipped calls from inside the (*F).Fuzz function. if f.inFuzzFn { panic("testing: f.Skipped was called inside the fuzz target, use t.Skipped instead") } f.common.Helper() return f.common.Skipped() } // Add will add the arguments to the seed corpus for the fuzz test. This will be // a no-op if called after or within the fuzz target, and args must match the // arguments for the fuzz target. func (f *F) Add(args ...any) { var values []any for i := range args { if t := reflect.TypeOf(args[i]); !supportedTypes[t] { panic(fmt.Sprintf("testing: unsupported type to Add %v", t)) } values = append(values, args[i]) } f.corpus = append(f.corpus, corpusEntry{Values: values, IsSeed: true, Path: fmt.Sprintf("seed#%d", len(f.corpus))}) } // supportedTypes represents all of the supported types which can be fuzzed. var supportedTypes = map[reflect.Type]bool{ reflect.TypeOf(([]byte)("")): true, reflect.TypeOf((string)("")): true, reflect.TypeOf((bool)(false)): true, reflect.TypeOf((byte)(0)): true, reflect.TypeOf((rune)(0)): true, reflect.TypeOf((float32)(0)): true, reflect.TypeOf((float64)(0)): true, reflect.TypeOf((int)(0)): true, reflect.TypeOf((int8)(0)): true, reflect.TypeOf((int16)(0)): true, reflect.TypeOf((int32)(0)): true, reflect.TypeOf((int64)(0)): true, reflect.TypeOf((uint)(0)): true, reflect.TypeOf((uint8)(0)): true, reflect.TypeOf((uint16)(0)): true, reflect.TypeOf((uint32)(0)): true, reflect.TypeOf((uint64)(0)): true, } // Fuzz runs the fuzz function, ff, for fuzz testing. If ff fails for a set of // arguments, those arguments will be added to the seed corpus. // // ff must be a function with no return value whose first argument is *T and // whose remaining arguments are the types to be fuzzed. // For example: // // f.Fuzz(func(t *testing.T, b []byte, i int) { ... }) // // The following types are allowed: []byte, string, bool, byte, rune, float32, // float64, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64. // More types may be supported in the future. // // ff must not call any *F methods, e.g. (*F).Log, (*F).Error, (*F).Skip. Use // the corresponding *T method instead. The only *F methods that are allowed in // the (*F).Fuzz function are (*F).Failed and (*F).Name. // // This function should be fast and deterministic, and its behavior should not // depend on shared state. No mutatable input arguments, or pointers to them, // should be retained between executions of the fuzz function, as the memory // backing them may be mutated during a subsequent invocation. ff must not // modify the underlying data of the arguments provided by the fuzzing engine. // // When fuzzing, F.Fuzz does not return until a problem is found, time runs out // (set with -fuzztime), or the test process is interrupted by a signal. F.Fuzz // should be called exactly once, unless F.Skip or [F.Fail] is called beforehand. func (f *F) Fuzz(ff any) { if f.fuzzCalled { panic("testing: F.Fuzz called more than once") } f.fuzzCalled = true if f.failed { return } f.Helper() // ff should be in the form func(*testing.T, ...interface{}) fn := reflect.ValueOf(ff) fnType := fn.Type() if fnType.Kind() != reflect.Func { panic("testing: F.Fuzz must receive a function") } if fnType.NumIn() < 2 || fnType.In(0) != reflect.TypeOf((*T)(nil)) { panic("testing: fuzz target must receive at least two arguments, where the first argument is a *T") } if fnType.NumOut() != 0 { panic("testing: fuzz target must not return a value") } // Save the types of the function to compare against the corpus. var types []reflect.Type for i := 1; i < fnType.NumIn(); i++ { t := fnType.In(i) if !supportedTypes[t] { panic(fmt.Sprintf("testing: unsupported type for fuzzing %v", t)) } types = append(types, t) } // Load the testdata seed corpus. Check types of entries in the testdata // corpus and entries declared with F.Add. // // Don't load the seed corpus if this is a worker process; we won't use it. if f.fuzzContext.mode != fuzzWorker { for _, c := range f.corpus { if err := f.fuzzContext.deps.CheckCorpus(c.Values, types); err != nil { // TODO(#48302): Report the source location of the F.Add call. f.Fatal(err) } } // Load seed corpus c, err := f.fuzzContext.deps.ReadCorpus(filepath.Join(corpusDir, f.name), types) if err != nil { f.Fatal(err) } for i := range c { c[i].IsSeed = true // these are all seed corpus values if f.fuzzContext.mode == fuzzCoordinator { // If this is the coordinator process, zero the values, since we don't need // to hold onto them. c[i].Values = nil } } f.corpus = append(f.corpus, c...) } // run calls fn on a given input, as a subtest with its own T. // run is analogous to T.Run. The test filtering and cleanup works similarly. // fn is called in its own goroutine. run := func(captureOut io.Writer, e corpusEntry) (ok bool) { if e.Values == nil { // The corpusEntry must have non-nil Values in order to run the // test. If Values is nil, it is a bug in our code. panic(fmt.Sprintf("corpus file %q was not unmarshaled", e.Path)) } if shouldFailFast() { return true } testName := f.name if e.Path != "" { testName = fmt.Sprintf("%s/%s", testName, filepath.Base(e.Path)) } if f.testContext.isFuzzing { // Don't preserve subtest names while fuzzing. If fn calls T.Run, // there will be a very large number of subtests with duplicate names, // which will use a large amount of memory. The subtest names aren't // useful since there's no way to re-run them deterministically. f.testContext.match.clearSubNames() } // Record the stack trace at the point of this call so that if the subtest // function - which runs in a separate stack - is marked as a helper, we can // continue walking the stack into the parent test. var pc [maxStackLen]uintptr n := runtime.Callers(2, pc[:]) t := &T{ common: common{ barrier: make(chan bool), signal: make(chan bool), name: testName, parent: &f.common, level: f.level + 1, creator: pc[:n], chatty: f.chatty, }, context: f.testContext, } if captureOut != nil { // t.parent aliases f.common. t.parent.w = captureOut } t.w = indenter{&t.common} if t.chatty != nil { t.chatty.Updatef(t.name, "=== RUN %s\n", t.name) } f.common.inFuzzFn, f.inFuzzFn = true, true go tRunner(t, func(t *T) { args := []reflect.Value{reflect.ValueOf(t)} for _, v := range e.Values { args = append(args, reflect.ValueOf(v)) } // Before resetting the current coverage, defer the snapshot so that // we make sure it is called right before the tRunner function // exits, regardless of whether it was executed cleanly, panicked, // or if the fuzzFn called t.Fatal. if f.testContext.isFuzzing { defer f.fuzzContext.deps.SnapshotCoverage() f.fuzzContext.deps.ResetCoverage() } fn.Call(args) }) <-t.signal if t.chatty != nil && t.chatty.json { t.chatty.Updatef(t.parent.name, "=== NAME %s\n", t.parent.name) } f.common.inFuzzFn, f.inFuzzFn = false, false return !t.Failed() } switch f.fuzzContext.mode { case fuzzCoordinator: // Fuzzing is enabled, and this is the test process started by 'go test'. // Act as the coordinator process, and coordinate workers to perform the // actual fuzzing. corpusTargetDir := filepath.Join(corpusDir, f.name) cacheTargetDir := filepath.Join(*fuzzCacheDir, f.name) err := f.fuzzContext.deps.CoordinateFuzzing( fuzzDuration.d, int64(fuzzDuration.n), minimizeDuration.d, int64(minimizeDuration.n), *parallel, f.corpus, types, corpusTargetDir, cacheTargetDir) if err != nil { f.result = fuzzResult{Error: err} f.Fail() fmt.Fprintf(f.w, "%v\n", err) if crashErr, ok := err.(fuzzCrashError); ok { crashPath := crashErr.CrashPath() fmt.Fprintf(f.w, "Failing input written to %s\n", crashPath) testName := filepath.Base(crashPath) fmt.Fprintf(f.w, "To re-run:\ngo test -run=%s/%s\n", f.name, testName) } } // TODO(jayconrod,katiehockman): Aggregate statistics across workers // and add to FuzzResult (ie. time taken, num iterations) case fuzzWorker: // Fuzzing is enabled, and this is a worker process. Follow instructions // from the coordinator. if err := f.fuzzContext.deps.RunFuzzWorker(func(e corpusEntry) error { // Don't write to f.w (which points to Stdout) if running from a // fuzz worker. This would become very verbose, particularly during // minimization. Return the error instead, and let the caller deal // with the output. var buf strings.Builder if ok := run(&buf, e); !ok { return errors.New(buf.String()) } return nil }); err != nil { // Internal errors are marked with f.Fail; user code may call this too, before F.Fuzz. // The worker will exit with fuzzWorkerExitCode, indicating this is a failure // (and 'go test' should exit non-zero) but a failing input should not be recorded. f.Errorf("communicating with fuzzing coordinator: %v", err) } default: // Fuzzing is not enabled, or will be done later. Only run the seed // corpus now. for _, e := range f.corpus { name := fmt.Sprintf("%s/%s", f.name, filepath.Base(e.Path)) if _, ok, _ := f.testContext.match.fullName(nil, name); ok { run(f.w, e) } } } } func (f *F) report() { if *isFuzzWorker || f.parent == nil { return } dstr := fmtDuration(f.duration) format := "--- %s: %s (%s)\n" if f.Failed() { f.flushToParent(f.name, format, "FAIL", f.name, dstr) } else if f.chatty != nil { if f.Skipped() { f.flushToParent(f.name, format, "SKIP", f.name, dstr) } else { f.flushToParent(f.name, format, "PASS", f.name, dstr) } } } // fuzzResult contains the results of a fuzz run. type fuzzResult struct { N int // The number of iterations. T time.Duration // The total time taken. Error error // Error is the error from the failing input } func (r fuzzResult) String() string { if r.Error == nil { return "" } return r.Error.Error() } // fuzzCrashError is satisfied by a failing input detected while fuzzing. // These errors are written to the seed corpus and can be re-run with 'go test'. // Errors within the fuzzing framework (like I/O errors between coordinator // and worker processes) don't satisfy this interface. type fuzzCrashError interface { error Unwrap() error // CrashPath returns the path of the subtest that corresponds to the saved // crash input file in the seed corpus. The test can be re-run with go test // -run=$test/$name $test is the fuzz test name, and $name is the // filepath.Base of the string returned here. CrashPath() string } // fuzzContext holds fields common to all fuzz tests. type fuzzContext struct { deps testDeps mode fuzzMode } type fuzzMode uint8 const ( seedCorpusOnly fuzzMode = iota fuzzCoordinator fuzzWorker ) // runFuzzTests runs the fuzz tests matching the pattern for -run. This will // only run the (*F).Fuzz function for each seed corpus without using the // fuzzing engine to generate or mutate inputs. func runFuzzTests(deps testDeps, fuzzTests []InternalFuzzTarget, deadline time.Time) (ran, ok bool) { ok = true if len(fuzzTests) == 0 || *isFuzzWorker { return ran, ok } m := newMatcher(deps.MatchString, *match, "-test.run", *skip) var mFuzz *matcher if *matchFuzz != "" { mFuzz = newMatcher(deps.MatchString, *matchFuzz, "-test.fuzz", *skip) } for _, procs := range cpuList { runtime.GOMAXPROCS(procs) for i := uint(0); i < *count; i++ { if shouldFailFast() { break } tctx := newTestContext(*parallel, m) tctx.deadline = deadline fctx := &fuzzContext{deps: deps, mode: seedCorpusOnly} root := common{w: os.Stdout} // gather output in one place if Verbose() { root.chatty = newChattyPrinter(root.w) } for _, ft := range fuzzTests { if shouldFailFast() { break } testName, matched, _ := tctx.match.fullName(nil, ft.Name) if !matched { continue } if mFuzz != nil { if _, fuzzMatched, _ := mFuzz.fullName(nil, ft.Name); fuzzMatched { // If this will be fuzzed, then don't run the seed corpus // right now. That will happen later. continue } } f := &F{ common: common{ signal: make(chan bool), barrier: make(chan bool), name: testName, parent: &root, level: root.level + 1, chatty: root.chatty, }, testContext: tctx, fuzzContext: fctx, } f.w = indenter{&f.common} if f.chatty != nil { f.chatty.Updatef(f.name, "=== RUN %s\n", f.name) } go fRunner(f, ft.Fn) <-f.signal if f.chatty != nil && f.chatty.json { f.chatty.Updatef(f.parent.name, "=== NAME %s\n", f.parent.name) } ok = ok && !f.Failed() ran = ran || f.ran } if !ran { // There were no tests to run on this iteration. // This won't change, so no reason to keep trying. break } } } return ran, ok } // runFuzzing runs the fuzz test matching the pattern for -fuzz. Only one such // fuzz test must match. This will run the fuzzing engine to generate and // mutate new inputs against the fuzz target. // // If fuzzing is disabled (-test.fuzz is not set), runFuzzing // returns immediately. func runFuzzing(deps testDeps, fuzzTests []InternalFuzzTarget) (ok bool) { if len(fuzzTests) == 0 || *matchFuzz == "" { return true } m := newMatcher(deps.MatchString, *matchFuzz, "-test.fuzz", *skip) tctx := newTestContext(1, m) tctx.isFuzzing = true fctx := &fuzzContext{ deps: deps, } root := common{w: os.Stdout} if *isFuzzWorker { root.w = io.Discard fctx.mode = fuzzWorker } else { fctx.mode = fuzzCoordinator } if Verbose() && !*isFuzzWorker { root.chatty = newChattyPrinter(root.w) } var fuzzTest *InternalFuzzTarget var testName string var matched []string for i := range fuzzTests { name, ok, _ := tctx.match.fullName(nil, fuzzTests[i].Name) if !ok { continue } matched = append(matched, name) fuzzTest = &fuzzTests[i] testName = name } if len(matched) == 0 { fmt.Fprintln(os.Stderr, "testing: warning: no fuzz tests to fuzz") return true } if len(matched) > 1 { fmt.Fprintf(os.Stderr, "testing: will not fuzz, -fuzz matches more than one fuzz test: %v\n", matched) return false } f := &F{ common: common{ signal: make(chan bool), barrier: nil, // T.Parallel has no effect when fuzzing. name: testName, parent: &root, level: root.level + 1, chatty: root.chatty, }, fuzzContext: fctx, testContext: tctx, } f.w = indenter{&f.common} if f.chatty != nil { f.chatty.Updatef(f.name, "=== RUN %s\n", f.name) } go fRunner(f, fuzzTest.Fn) <-f.signal if f.chatty != nil { f.chatty.Updatef(f.parent.name, "=== NAME %s\n", f.parent.name) } return !f.failed } // fRunner wraps a call to a fuzz test and ensures that cleanup functions are // called and status flags are set. fRunner should be called in its own // goroutine. To wait for its completion, receive from f.signal. // // fRunner is analogous to tRunner, which wraps subtests started with T.Run. // Unit tests and fuzz tests work a little differently, so for now, these // functions aren't consolidated. In particular, because there are no F.Run and // F.Parallel methods, i.e., no fuzz sub-tests or parallel fuzz tests, a few // simplifications are made. We also require that F.Fuzz, F.Skip, or F.Fail is // called. func fRunner(f *F, fn func(*F)) { // When this goroutine is done, either because runtime.Goexit was called, a // panic started, or fn returned normally, record the duration and send // t.signal, indicating the fuzz test is done. defer func() { // Detect whether the fuzz test panicked or called runtime.Goexit // without calling F.Fuzz, F.Fail, or F.Skip. If it did, panic (possibly // replacing a nil panic value). Nothing should recover after fRunner // unwinds, so this should crash the process and print stack. // Unfortunately, recovering here adds stack frames, but the location of // the original panic should still be // clear. f.checkRaces() if f.Failed() { numFailed.Add(1) } err := recover() if err == nil { f.mu.RLock() fuzzNotCalled := !f.fuzzCalled && !f.skipped && !f.failed if !f.finished && !f.skipped && !f.failed { err = errNilPanicOrGoexit } f.mu.RUnlock() if fuzzNotCalled && err == nil { f.Error("returned without calling F.Fuzz, F.Fail, or F.Skip") } } // Use a deferred call to ensure that we report that the test is // complete even if a cleanup function calls F.FailNow. See issue 41355. didPanic := false defer func() { if !didPanic { // Only report that the test is complete if it doesn't panic, // as otherwise the test binary can exit before the panic is // reported to the user. See issue 41479. f.signal <- true } }() // If we recovered a panic or inappropriate runtime.Goexit, fail the test, // flush the output log up to the root, then panic. doPanic := func(err any) { f.Fail() if r := f.runCleanup(recoverAndReturnPanic); r != nil { f.Logf("cleanup panicked with %v", r) } for root := &f.common; root.parent != nil; root = root.parent { root.mu.Lock() root.duration += time.Since(root.start) d := root.duration root.mu.Unlock() root.flushToParent(root.name, "--- FAIL: %s (%s)\n", root.name, fmtDuration(d)) } didPanic = true panic(err) } if err != nil { doPanic(err) } // No panic or inappropriate Goexit. f.duration += time.Since(f.start) if len(f.sub) > 0 { // Unblock inputs that called T.Parallel while running the seed corpus. // This only affects fuzz tests run as normal tests. // While fuzzing, T.Parallel has no effect, so f.sub is empty, and this // branch is not taken. f.barrier is nil in that case. f.testContext.release() close(f.barrier) // Wait for the subtests to complete. for _, sub := range f.sub { <-sub.signal } cleanupStart := time.Now() err := f.runCleanup(recoverAndReturnPanic) f.duration += time.Since(cleanupStart) if err != nil { doPanic(err) } } // Report after all subtests have finished. f.report() f.done = true f.setRan() }() defer func() { if len(f.sub) == 0 { f.runCleanup(normalPanic) } }() f.start = time.Now() f.resetRaces() fn(f) // Code beyond this point will not be executed when FailNow or SkipNow // is invoked. f.mu.Lock() f.finished = true f.mu.Unlock() }