From 164d50889ab47c7381b86bec1f6fa7bb9ec26c30 Mon Sep 17 00:00:00 2001 From: kp2pml30 Date: Fri, 14 Aug 2026 17:45:58 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20harden=20VM=20execution=20without=20runn?= =?UTF-8?q?er=20hash=20changes=20=F0=9F=94=92=EF=B8=8F=E2=9C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/settings.local.json | 3 + .claude/skills/agentic-fuzzing/SKILL.md | 4 +- .claude/skills/commit-style/SKILL.md | 3 + .claude/skills/rust-test-style/SKILL.md | 2 +- .claude/skills/spec/SKILL.md | 8 +- .claude/skills/test/SKILL.md | 11 + .genvm-monorepo-root | 1 + .genvm-tool.py | 135 +- .../incl_release_build_test_cell_build.yaml | 1 + AGENTS.md | 54 + CLAUDE.md | 54 +- SECURITY.md | 13 +- crates/fuzzing/Cargo.lock | 177 +++ crates/fuzzing/Cargo.toml | 17 + crates/fuzzing/preload/Cargo.lock | 7 + crates/fuzzing/preload/Cargo.toml | 10 + crates/fuzzing/preload/src/lib.rs | 78 ++ crates/fuzzing/src/depth_limit.rs | 408 ++++++ crates/fuzzing/src/lib.rs | 177 +++ crates/modules-interfaces/Cargo.lock | 7 - crates/modules-interfaces/Cargo.toml | 2 - .../codegen/data/host-fns.json | 20 +- crates/modules-interfaces/src/abi_stub.rs | 36 - crates/modules-interfaces/src/domain.rs | 10 +- .../modules-interfaces/src/domain/fees/mod.rs | 10 +- crates/modules-interfaces/src/host_fns.rs | 87 +- crates/modules-interfaces/src/manager_api.rs | 2 +- crates/modules-interfaces/src/nested.rs | 6 +- docs/adr/012. runner memory accounting.md | 2 +- ...pre-validating untrusted decoded inputs.md | 96 +- docs/adr/015. cross-major contract calls.md | 2 +- docs/contributing/explanation/README.md | 1 + docs/contributing/explanation/fuzz.md | 39 + docs/contributing/howto/README.md | 2 +- docs/contributing/howto/genvm-tool.md | 23 +- docs/contributing/howto/testing/README.md | 9 +- docs/contributing/howto/testing/fuzzing.md | 162 ++- .../contributing/howto/testing/integration.md | 22 +- docs/contributing/howto/testing/rust.md | 21 + docs/schemas/default-config.json | 34 +- docs/schemas/runners.json | 38 +- docs/website/generate.py | 6 +- docs/website/merge_txts.py | 3 +- .../01-core-architecture/01-components.rst | 2 +- .../src/impl-spec/02-vm/03-consensus.rst | 4 +- .../src/impl-spec/appendix/manager-api.yaml | 33 +- .../spec/02-execution-environment/01-wasm.rst | 22 +- .../02-execution-environment/02-wasip1.rst | 127 +- .../03-wasi_genlayer_sdk/02-gl_call.rst | 34 +- .../03-wasi_genlayer_sdk/03-schemas.rst | 29 +- .../02-execution-environment/04-runners.rst | 79 +- docs/website/src/spec/03-vm/01-startup.rst | 13 +- .../src/spec/03-vm/03-ram-limiting.rst | 29 +- docs/website/src/spec/03-vm/05-result.rst | 67 +- .../src/spec/04-contract-interface/02-abi.rst | 8 +- .../src/spec/appendix/constants-pending.rst | 31 - docs/website/src/spec/appendix/constants.rst | 181 +-- docs/website/src/spec/appendix/index.rst | 1 + .../src/spec/appendix/internal-constants.rst | 156 +++ docs/website/src/spec/changelog.rst | 54 + docs/website/src/spec/index.rst | 1 + executors/v0.2.x | 2 +- executors/v0.3.x | 2 +- flake.nix | 6 +- implementation/.ya-test-config.json | 9 +- implementation/Cargo.lock | 17 - implementation/default.nix | 20 +- .../1 | 0 .../2 | 3 + ...3ga150hdc2vahv7sek5vhev60wgxrqmchnxqg3tkgj | 1 + ...sba677v1ndtj0816kwhjph61a9mtjqrhqp45j4pn8j | 54 + ...6tt8xf34nkv5f4jvcv7t5qnbvq8e6vspmf0we96ydt | 3 + ...3bt3yk923gfp1a4cnxp8n9k0nqjsd6003qrspy8ng0 | 4 + ...gtrmf50h7edgb1jvdpp767qs4j6vjfp33ty9rr9w1t | 1 + ...698ck5t9h0fn9dbv9x26q7gxekqbn9chzzbskfp53c | 1 + ...1ay1bw7ngb8zmtkdfkyvrka6qbjs9jwv46mt3cbgde | 1 + ...7425x8bd6nvkk4kgq4f2499n09vpv1paeafe025c6c | 1 + ...658bdw9cssdkncjmxvzbhmff4n1j4pwhntw0n9mj2t | 3 + ...7nh5jet076pmv9f8pqe6swkjsqdqc9yxw67105wrnc | 1 + ...4bxzvvbkk9zdf1wh22spsbdwbqeqerm0e43pv2ngct | 2 + ...2mzaj1hv1tb2txtrjrs0ejszt3fgn469604sqnqj6w | 1 + ...d5brepkxdgktr1f7xwgdg5swstym8vsx6fg3ncrmp4 | 1 + ...fwrht8gf6bz9tf3ag2ah4sdtaexyeeaatfy86cfbse | 2 + ...cwmc836hmvcx4tcsgxjt88gfqgr6crja3s08qjb2em | 2 + ...zfjthc54aqca5f5q9776emq6rtmc4psze4xt987swm | 1 + ...bwhymbmwe8yfb2af3mdmd6sreg4w60t8km5ctnghr8 | 16 + ...2aedsc1y7xgr695dmyvyf4zm587ab3yd1acdhrvr9a | 2 + ...wbfz1w1wys0ckdwxg5y4tvhshzwmq46h9mh79qw1ae | 4 + ...dp76k6cfjc5zkzec3cn0t5h0t58w96yyzeyhzsm6he | 3 + ...9xg8cfb3xb62hhx33xhhd813c2qrfrwjjgj5ebsw7w | 5 + ...rse79871djv54arat6a564d9wk6b32et8xfaatccqr | 19 + ...xqyra4jsre5cw5fmk3fg3y4gx74fc32dxwggnkqz6} | 9 +- ...26d1454cv5768t5j9se7txfecpxxsm9x8s7r91qf1e | 1 + ...a3j6967xv5d1a2074nyqtnbbtv76pvbpzgevzfgy54 | 1 + ...jncdjcy75m9m6q0qk6ezw8zj1596rhj36e402ew754 | 2 + ...2kcn21t453s1b2ngz23bwnbzkm23e5ks6x0v2z5td0 | 7 + ...kxs54nn6ex33a27wg1ppmthvkknkp3mep8f5b98k50 | 2 + ...jkt9cpff1d660acdtdzdpfv43mfctgbpy3he9beysw | 1 + ...ka8ved58jyqtjbr88vpkg80h3sbf3pjyznxq7j1904 | 1 + ...4j1rns05r9jsbwe40h08etjq468myc7zyqnr06d3et | 1 + ...j4895jyafkpw0jnvzmxdnhkv2p5jz9p6kc483sgk50 | 1 + ...z7rfp162bvpwtqdcsjfcte6gnaqhbn0brtbqmrfeyy | 17 + ...1440bpgmpf20twrkek8mv0d8005q3q499gz8acnzmm | 1 + ...cmt9ms89v020yrryvpa8jvmc20h657s4n8p4ypamy0 | 1 + ...yfsbfxsjvhq4h4px6vne04dr3tedqcnk65kx1h0x5a | 2 + ...sp9r1b3r2ws1hk69wtkfwp9rrxedhcyss8bdcnvaha | 17 + ...p4vcf7xkp37ac1718tt0rxvgts1agh64p5aw1fhxbj | 1 + ...f0t7k419d92gz7xhsav1gcmq07n07wydnnwsrgphym | 20 + ...z2hbxc3cj4tw3tje2j8d5ty7kc6kfpsmfte6p2twm2 | 1 + ...jstbv6j02k45pq0cvc2v78est9zdsmbnrffr0r7nv2 | 2 + ...p9v5s7zg0r44q1q10j4cw9xczdd69pvt8v340a6f8c | 1 + ...aehj72a3q4n0svg1mw6sr73c755f4fs585a33prhzp | 22 + ...0wvbm2cwde34147rf5ha82ry271c5rc0agxjrc47x4 | 1 + ...gxbt71nyw23zrd1qy323jtwynep5d2pdaav2tffxp8 | 1 + ...evrr1ecfjkt9k5kg0tk3xh25s33wx4ww96573naghw | 1 + ...h9wc8w0a8z0w2028vtcx5xs4dgyzf5w1s7jdppr3xy | 1 + ...2s7zs5t4wmrbvk0yg71wxveqe55ztfpg8jbsa3bqmg | 3 + ...hdv1x7bnfg9pavb755sf0sc40qmhsbcwqf5nrs7ae4 | 15 + ...cx4dk7z22dava03ptrv3ymfjycm4m4ffx7j0d98m4p | 1 + ...15a1rq85qvscnan6she76mdje40y78df623nha4fyj | 3 + ...r491j8kg26xvpnfe3a0yb3ve9wvy43c3n09dgv7ctw | 1 + ...ejvhs0c6k96dxf9zspqgns0xwvzn3ntmnc3m7hfgbw | 1 + ...myw0naed8mgex7ss57qmqbfwapn427xst8jsqe3ngj | 15 + ...m9pj961n1pq2vsy22xpbxw0nhyq93px4r60hahzjma | 2 + ...4137gha4gmqm24trscfjqc7jm4479w6qj1mex11fry | 1 + ...k1nwfyggr3b0wc35azwddz7t89e408jvrrapd5edrw | 12 + ...xfq59pf73na9hbcz0b6vdm97rwqjegsmyfg1vqsm82 | 17 + ...4f8x8hn228h57pkdye6wysbhsrrhjw49z4gepbqzvj | 1 + ...qg1fmemq3efa31gttwkc9ks89mdx2dbzc5qhgj92s4 | 1 + ...xn03hxa23gxe1md3gbn3zv7cngzcerj1j675n9780a | 1 + ...3w7v3kk9wzmhsayk4at70qkrajx55jgnepk7z6hr0r | 1 + ...xq1kcqh6mwx1jv8e4m8p45ep59sdmv28pmzy4pw1a4 | 2 + ...a1p19ay28psnn5f4zhyd2t4kfvda8a4y3dpc14v5f4 | 5 + ...z35x95rw4mrq1a5fxzy55qjks164pc29znrc45cdtp | 1 + ...2p7k1zb2gkvyfdaz725jw76qrm1wncjwqkqc4kk1m8 | 2 + ...a4awjzxj0n7cxbv03m54mfedmavr2f6m01vv3zvtte | 1 + ...p9v5282spx6x5aagjzrpyypvmtpkq3r0rrfdg4m67c | 3 + ...bs58b5a87gfxksxtm649ypqgmkacmejzry836t92k0 | 1 + ...5ns6xkaakcy132nmxmq4x2zgqr90x0dmsnz627ed66 | 2 + ...qwhcyefn0frp5r1ca0x7c5fx7z73799v9jgh5kznrm | 1 + ...6zv22vbtxd1h5fyy6aqs1709dm2kcner8xgmdjw3gy | 10 + ...tt4mqq71y2pvf4twdsffeyvc71wp3h2hvs5ahme1nr | 1 + ...g17dez65x6wswjp25acskmrx7b5tcmq386s35axwnc | 1 + ...fqq0x171fhs9f654mhmhzdam101sx78y1pg4xvzj2e | 1 + ...xsdkrcj75gxj5bh515daqdr49gxas5gq4w3mne8fxe | 2 + ...jwfv96hh6722m749ghsxbesbbkgqgajvx8czn183fa | 1 + ...t3zk62tgnhnhvqgzvfw352g9yy662b1fn2087cqc18 | 1 + ...k398b7qp548psbch15wvnbqehqgkz4pf2gtj1tpb7m | 1 + ...3p5fxq3fpxt5g0j5tpje93fn9r6c4b4qz0zmfn1df2 | 1 + ...95hbtgbyx52kbb43mdbrmt6gzsc3693yd49g1j2jga | 1 + ...tbeedk3mnayqb6z0dj77583dh0arvgz4456d2yp2wy | 1 + ...as110gqppmf984s9600v742ztpwrbf4gkgkrayw2q0 | 3 + ...ftjj6197wjb7dqch5ammz2f5esnh0zrw4fh1vzk35e | 1 + ...6p7whcvzg482hfct6tzax39zggc7bt3qqxj393awqr | 2 + ...502ckstahndqb4bqhxdwq7hzsxbw4a3dh9008n5grr | 2 + ...bambjhke293td0wnyhmqnprz3dr3kckw2t81vdeq32 | Bin 0 -> 129 bytes ...p4rpamny067vhq88ke789xdnyt23zn2ywjq7sbxy6p | 1 + ...zarnhgndp91dxsf8m775r96x1hb59bpaa1942fe22p | 1 + ...131f7jpbsdzp0t3f3ry9shwecm2mbn3sfxqy4vxqrt | 1 + ...had75c83y5s8a6z9ftdbnnmatgktgsasr18av2cj36 | 6 + ...vkc6r7q84h3g63whr2hdc69chys6bafjqyr21vd556 | 16 + ...c7343p2qsgg1vr2c8cfxf29rxjte6xaf1j3kqrthp2 | 2 + ...vz3ffjf0rsaayrf4drj4x6a87162a5dxa9x5gbyy40 | 4 + ...qkpa6a6a55kg78v14wk3yyesena6v3304gw7mp792t | 7 + ...w3bbq8bsesg4jf189jf9ard8cnp9m4sxsxsb96q3fj | 21 + ...z17sfvejgr7dfczk6w4qbt77qwanv1307w4b8ja0ma | 1 + ...4w84w1cnqb7cr41p52saatagrqsxk8wj2ehhbpc7fw | Bin 0 -> 127 bytes ...37jnwf7qj4e3jy7dngv203sb8da6za3tmdtaz8m71y | 5 + ...d5p3vpd27tw2r15btrpq06gt1b708brb74z1z6k5f8 | 1 + ...hwstm4ezxvnsem3n9rkbwe5971cq5r9eyvt51n1ca4 | 2 + ...23ehxrzsjx4h98n1t8tzxdeez2q54n4ghv7y87h99y | 3 + ...pan24avchbwj139h8gwrgrn168hpdn6wctp4w3kvnw | 2 + ...9f41n2ynf9n1r6yq9wv9h9zygjpz50ghzy7qzfxb4e | 1 + ...hye51bpxdznqxjc3n7txbqtdxw8tk999evs6pe6pty | 13 + ...snsywt1yg9608yk9dtkzcsw8j226873xmgrbtx5e2w | 7 + ...93yvqp1d1zes49sk9vwyf8enqcmkfectpyjg700p5r | 1 + ...357mm22rrbcdb29bv4883ajrnye3p05wh3p4e9vvde | 29 + ...gjt8z5jp6gss3nfv19ht36jhan7xc4x46dh9wxxb14 | 16 + ...nm2369k6hgrghespqr1pe0qdxrwv8yqrwjpevdvk68 | 16 + ...drvgpzq462t4wsnd5k20xxfvpwckw3b1gg9077ey4t | 2 + ...w69mppz8dkd8kkysh4gc00j3021v0zv38sy6nhq02p | 3 + ...p0893yw33esbfnsx3vtpn03jw2f2kav5261w8tk8fj | 1 + ...z0gcyv9ydzwdszy7q1c4ktka3rfn4d8pk9e4318etr | 10 + ...8nxj26hfm5ez2vrp38j59q0rpgvxffcvd8x0vme6n4 | 4 + ...xxf03629wvddwgvezn1r428tykhd7spzdd5hn2fcmm | 22 + ...v6wqxrtgkh6rbsmf4n7ta1xyndvfaedd6rbk08peap | 1 + ...fgm5c9jtkw8ae8gwh01s6tkk18my2ag0y7epc1ckd2 | 1 + ...fn4qcz970rxcapmbg7axet37yk0c30pden7zfnbrcp | 1 + ...2a7qvwfc8df5hzpjcyhkc65hvjwfk4b9v649x59n46 | 1 + ...w2k51qnmw7z4j79g0dngx0x3xv81fqx11rmktjvd5w | 1 + ...na3xrtgxct2en27tz1pb3v7dvtt5qh2fynhyvmhwew | 4 + ...9y0m4gwtzm6ybeecvxq6d297w7h1h3zwfpqeqwejp6 | 1 + ...kpme1rg6chpv2jg81r2mp6a1pqeb7jnpxkrj1zvvz0 | 18 + ...xhvm8f01c4cdcaymqg3nmjsbc91sxz2xryj3nmng3a | 1 + ...kn4y353ss52zenyq9e8gr7vcarz4y36dtff3nd9af8 | 9 + ...pdwe2qc8f6ck1zfkd4czrtxzbgf92qywfftqgxjhr0 | 1 + ...zz84st57awtf74kqg6x1ph1nc1b550hxnn8ky5e46p | 3 + ...556f8ke1g4dtjahxs94mzecqzw1n3twh8m9vtxdk5c | 1 + ...21mjw0h89fdx7t27e856cxrbv2ahsh3xybqjfqrq36 | 2 + ...enj50bwcb52ts5me0mptej88cabpzew64b22ncw82m | 1 + ...dxfswt8ax6ccwdq71k2wzyr2pv2sd7hcpcb3yes5rm | 2 + ...rdf9z0bqhr2s4f0s7yw5gawhafpd26csq0xrn78ehe | 2 + ...m98q123vvxhqx0aagr7fptytjjm2sesvzstq7vnjd4 | 2 + ...76gsq2b7p3hqv2h0fssazfg0mbppj9hr8yxyhbykwg | 8 + ...38ym1f018m8ctq0gbb06cgkamh1yb5yhztnt2sbgwm | 2 + ...m73vd7pqnte9f4dmahm7eddc8n3nb78hf0f9d14b9j | 1 + ...2mbvdzrxewmjfyk3g5xg07xn8j49tc92n845861rty | 1 + ...nmrht3baacq1spykfq06esnj3smp0rd5e7jp79eyc} | Bin 48 -> 35 bytes ...2107rfefkdjabs9rhdsw49zx8y2gx8p2c0qgt21926 | 1 + ...8k38eg2vs9bccsw8mnjcnx5te4y1g11rgme8h3gybg | 4 + ...js7hxbkmv5bb8nk2ey2d0wjx8k82f81c6768pc92ge | 1 + ...2afa7b9e3hmb9et592k41sh0f15patxjf2v5y5ax28 | 1 + ...kbm0kf3s0n4adszk893w6w8wnyjvf1e76ye91gg6tw | 1 + ...4fhxdd75yrzwqrt2e1e9wewtthq7qdsxqqdng0b060 | 2 + ...hs07vxp9p01tfz7pvd0jraxfs0jee1nw0cwkehxx94 | 2 + ...y7y6s511635spzptgtg0zhbcsa537xqby99h0nv250 | 1 + ...f3sj3zza00020bnq6r03axvz1vksraj1573jebfd6g | 17 + ...bbrs4vynrjpt7pmjj4897n9mfpbe50b7rwn7x9pgk2 | 2 + ...z1xs6nywx9v858m9bnd8ast8y973mrmt6s2kgtp9we | 1 + ...ask5rah2rmhtk8w53w5dvfptr9anhetwce58yktk1e | 1 + ...stbc50pvj2vw2nave0q2ry661kggrh2xrzfbnabzeg | 2 + ...2hjx36v13jedse38grc2h9jcqcrq3panpry2b2cq5p | 1 + ...m4s9k7pjvttjg3vmhhwkvgtp5rt9rren3884mtychm | 1 + ...8fgk28sjsw9kc4ct5vaw0nscda5yjqb3wxn81bjdpj | 1 + ...0p1x6sm52v6sgcw3k06afpbfxmb9d3xhzjretpzxhy | 1 + ...7gt19ynvbezapg0t7ercqeqbyetjdb4h3f7xy7s28y | 1 + ...0e8msvtg6fh2rgj738kh0zrmsnr65xhp8sknvdaf0g | 20 + ...6jqed3mz3m6eaqe529dqf6qrbr9pzx13mer6gwwnvy | 1 + ...82thpv82fgbs86s3dtzsz5wnxt0yqz4dvhhwz3r1ye | 1 + ...7bygx5f8z6r1s2a2519a6c625ytcfwmz4q9nt641qr | 3 + ...z0981gspjax26nkh652wc7tcb54w7fy5csjms0d66e | 1 + ...g0chm9b3g0gtyv3vwa5125zj6h9wpewa1d9ttasjcc | 3 + ...sncn3nmnesyx8kpmqmvfkvkj44xzebssp7xnczq6hr | 1 + ...yksckw2vp4xrca0xy5xnsa8sy9ytjw2wt1zhhndx36 | Bin 0 -> 32 bytes ...ca34p8jvyyv4r4t9aq8fqz0wyr6c5w6a5j1cns3wtj | 5 + ...3t0nyge0w12tkmwt21zv8gphpckwv79ky7syc8fz04 | 1 + ...q1wankjerhv937773xend4eakwq3xfyaescec2yy54 | 1 + ...msy3nbk3n9x2eezrgbjj21j80xj62n9c8svwt2weva | 1 + ...kgwrwycj09hfrjtmyfhpgmnerkapbh6xhp55gskj9w | 1 + ...611whwhv6gmbtrtwm09b0cbpnjr0mcnrvfas0ky1ma | 1 + ...hmvfczvhj7ba6jaxjqhx7d44drdy8nv5ypw3przvme | 2 + ...mmjcchvtx07q0s65jd41npa39zadh6pdfavdebrk3a | 1 + ...9vnef87wq5077p90tfrqwq4zwa7seh3erqrztx5xt} | Bin 47 -> 42 bytes ...51hcwchb3mvj75w58m2grm3dm3n82nvv3c0e6mwv0m | 1 + ...rg5k6rz6vg0cmfwbrnmbzybvxptypmp4ghactbwkzm | 4 + ...drhkddcaqa06fhrjy51knjj279hx2a87rtc9rwgs7c | 1 + ...vwve9j7bc3f8x0jb6z5qtff5tqedkwkad3zr0g7y5t | 1 + ...k3vxza1nxqkpp32q8r5027bbbv4qbfy37ad1knt6w4 | 2 + ...xpcxncfjgm9e5bff4v1wbh7pny1gd26hqybg84sabg | 6 + ...n879zp21139g3x4ra4m07sh9s2gn1fwwnn1m1sn1br | 1 + ...gmc6sv8n8tzcz1s8j5cpzq2n7a26ermg60hyz4t1h4 | 1 + ...srznj4t6bk5w9x4pcr0zwxmh6avsnt7gpn0fm7ak3c | 2 + ...g3wx92025zvx1dnn197sr2sxja0yvrdy1p97xdxthw | 1 + ...ta1s9373nq89nvskpew6nssr5b9gvk6dyv1r0jrcz0 | 2 + ...n716s2sn0567k9wwcq1vs380t3ap6m3526mkcgdhtt | 1 + ...48mftv5xr6nej0mnpbg4eygjz8mqgfgnt0qsve1pt4 | 16 + ...ak2fjfc2q7p4515s3gt8c42n443gqq58qt9hwcnzs0 | 1 + ...3kq1c31cejcj9qtn0rz5k7pzevbjyah0t1jsj84cbt | 1 + ...h0f2sd99x7d18esapxv0x0gvqmzzz8r3fw4sg1gvw0 | 1 + ...a1qexyqvggrsm11r04zrg8bt4ygm1c5jr683y1xvk6 | 1 + ...cfc2vbwxfdptecap1mxfgd5xeprwj203yq0fj9smhp | 1 + ...qj9g5qak95p6mw2p3p7814bgwesxeceqwd97f83464 | 21 + ...r9rqrptwd0md4bppt1jr9vpf9r4b77a74wzqc1e0pt | 1 + ...wq1t7yq53h7rpn35n04399zqvqkar42gebmqmbefmc | 2 + ...krjdvvw5pmgfnbbh5tyhw5hfpbtfpk72x35bcvyb0c | 12 + ...21spbt5fm52anbs9a3b7dj3s86f40gg6cz81acrt7t | 23 + ...dx92zmptj4h2j7zf3r3e42w3zh6bvbrz5z2p2e3h2c | 1 + ...g78eczceasp09agz77gav04w2cmqttcb1a1z89k7rg | 2 + ...xkpezne5pp3m6z8age604q7cpv1x920qnkvz1bkwyp | 8 + ...gag5enzvbfj1jj3p1h9vnbqe748dq2ppejheajd5ng | 1 + ...bsr64qxtbfwjkrca2mcwecqydf7daxy28pc0vfe7ga | 1 + ...78x0s7vpt01c4jm93bcz1b34cy3fr0tqwv7tr549er | 5 + ...deg4erafb4pzb2901wkjqtdds2c1xdb7fv3hxmfy08 | 1 + ...35dbxwq0p8n3ms3tvtmkqeb60fef4pnkwz0fvagavg | 7 + ...5gqqwqynzs9x0hw765emeg89cewjz87h01btpt6hsm | 15 + ...wzpqkyc3m2nervjxc7xrff5by8m334by2ehynfa566 | 17 + ...2d0dafx3tczd8ba0d3q08tdben51y533v9nfbp9tt} | 4 +- ...xjzt801waqf7pynga8dtztvf33cxav6gnakf3drksj | 1 + ...qet48avcywyfmwdxfve36a9ghbr9wsa51d35cydp2c | 3 + ...1rznx8wf9tt6fyrps4510fq9zj0d5d4634jyyevnq0 | 2 + ...3r8mjwycqk3cc19tk6vz6v0mpx5b1skh4619860kcy | 1 + ...rd7rbzfmpqy99m87rakngp591kxkjb6npwzhyetr0g | 2 + ...4fjc4187d9vgnra9sgq9mms214txwpsp3kvqgd3cvj | 2 + ...t19scjh8kgqscps8x2f1rz3e4jbc9aasct5hsk1s72 | 1 + ...a57zfe11k63pk5mdzqwqh9q4wnhr3rjsqsvpsd56b2 | 3 + ...x97mnxq79jxx3p6v1ash40kmtc2sg8rb0pkxga505p | 1 + ...7xgc4drd8e67mde018kypayx07c8vb8vh8j7vpd57r | 1 + ...hxytcf4491x4ydx46vqpyacj3205hsb3brs7p7n4ty | 6 + ...e6g98xw74xt2m44tza0kca6t24qsaqm5cmrgw0xf86 | 1 + ...p7skkfw1b68nrs3sq5zxtr9axxaxd01nrkkgbqebw0 | 4 + ...bhyqcknm6pyt1f7j8jd61q4yrzhmvhy353v23257tr | 1 + ...swdcbj9e7djcah0pmjvtxsd7m588966stts93xg9yg | 17 + ...y027n4v93kp4s0qh20fx4gkved3fw15n7r18yq07ha | 1 + ...bt1he8ntbggfw9tse48emwb2kbycj77jgz76ddeyfg | 1 + ...77qz80hpxtgnynsqmqj74byzc144gtxq76kwyrmad6 | 2 + ...jbvhqx45fv2n0r972app5mqy1hrq1xdk2bnq3he5qj | 2 + ...vedsdq879bn98wspeyrsn6dvzagxmryh2y5r1d1c9w | 2 + ...5fmyk9fhwvtzx0qcm8p3hc0z75ys0dtvtpqnvcyw52 | 1 + ...cdbfdsm22fw79j8b0h99d158d59af312qf7xembhzr | 2 + ...rja2fjxnemgfffhcbwms91t3nct5hha8x28py326y8 | 1 + ...ygmpq420qqgrshs10nenpk20mnzqtqz3mt22jhm9zw | 2 + ...tmxbfh43pa7xerzq5gzg15ad9hz007etcbz5fm0g7c | 1 + ...z7fcaqtq179b6m9pjb88yd9ge48fcq98mz0z7z04jm | 1 + ...41e9f692tk3awzkp4y3mfm8tz4tzk9mqdrydn4jwh8 | Bin 0 -> 33 bytes ...bar4weepxqm36gjtmngd0s4s87t0zs71gras1azkja | 1 + ...wync6tykyywar2shdyswn9r1re8ta4x7kxc21586p0 | 1 + ...bc8ad66w2zzn4rpff9ntkjw5r6g7rsqa16hgy3at1g | 1 + ...bwdmzca793m5jvdh96qbx9kmsq4ydvyg3e6yqny8k2 | 1 + ...hes7r132gs7dr83w6w7q2x33ce0h82vffctfn6eqv0 | 1 + ...rvjnahynn25ac14cwvt9t6jzvggz372ydp8fqswv2a | 2 + ...3v2zfg6c9n6n90t48dxem8619svqp59wxtvej6c5ha | 2 + ...2ghfrhxs1ahgdn3fw4m2y492x836wf7k46sr5err0m | 1 + ...btm14hgyxeyn8ey5dgnxtggr212adw4kwvzbnybdct | 1 + ...pzscez3h4q8sxq7dmxcqvnfn5pgkdfxrqq1gr9csvt | 1 + ...y8ft3qegkfnscpfrx977aq71fvfkfggktv1q8f7f78 | 5 + ...a62pfbntw5ftd5xs2v8rrcdsmt2s84vc608cfn9efy | 1 + ...5edm56x6y688pfpkvrm2m67q4j9xxaw2twbsbkbyec | 16 + ...ck26hk0rmgzpwed603cmmqm6wzhp1e3aarwg34r7xg | 6 + ...ah1hcnmr8captbmxmrvjxs1dn8gbn0v7a10jf9msfp | 16 + ...zvhamg4x4p2dc22wt60w0stt38wpk0re71drs2dajr | 1 + ...98q0hhqgn55z6vczfxgp42qb5awzyjd131cz51zwbg | 1 + ...j3fy8nbnk194bxprz80a7yfmdhdkqtgtd6s8zk138w | 1 + ...qdka9j6w1fg7mg0wn0tb355jkbatrnzv6n7nmw4skt | 1 + ...hrxsbftvpfmavg3smrgjc4hh6ezkawrfcepxk2jmde | 2 + ...w56dbhmxvhk9fhkmk8y0p0gwa88vszgnchgenysxh6 | 1 + ...3zk4k8vtbbkpxa5q0sp8fch71gka8tv8bny9kdktm2 | 2 + ...hp2xf71j0b3sxjm9mkbwvpyf8jff8n64n6wkjr6368 | 2 + ...mh4hmmgpgm7dxwht1cp1amvsd0qxnc23tdgfdh8k9g | 1 + ...d98pan04nx6q9q9n5mkqtz86cg7hnkm1mkcq44qjmt | 4 + ...r3qc3h1anzm3hkwr6j3r6rmad853tc0ds25hrc2fb2 | 21 + ...r6yembj5xj2bm2cyg20q57cj4hrf1p8x80ndymj4aw | 1 + ...643cjwk8wfh0004edbbst8wa1b73aywaqfc0mcf0kp | 5 + ...j6pprejy2v5shedeb0xq7dqfchsdcjy9tt523dz5mc | 1 + ...r1bp9z55bqng865rp8s6wx7w7hc6n2jk0wanp61062 | 1 + ...w61hvabmpf0a96abnadvjsnn6q53zwxatx2t7d0tw6 | 1 + ...ard33ab13sqxf820qr4xb9cgscj55spqa0neg7epe4 | 1 + ...amzadf8rnaf6j7g1t39dft2r9tm3b9rkj28d3edhhp | 2 + ...54yqfez4decm5rhrdrs2bxfdjmcge4tgd9wygtgh10 | 1 + ...c9e1wemy51xq2xpwm52cc7pjda593acq5vtwd1bfd4 | 1 + ...qrp6srq0pd6vccjfkfymafvrh4qg32cx1br2exnd5a | 20 + ...8e15aj1a7yp124h139794c8we0wdnmp7jrtepj9zzt | 5 + ...6vx30habsa70mpy6c1mtqscca4q0q70695yqxx3578 | 1 + ...gssx6eqdc4ktnadb6t92gz3g3veep8a5fqkeve8jsy | 1 + ...b5xm7mmt0whe7p2yqrr46d84j7tphrj202tazvzgej | 1 + ...7me5gr10qg7qmhs49aqy7ymgpef4b6y8j5tp56p6ke | 1 + ...2pz5srn6gthdq019taegmadr7pfwxv24e5qajd5cbe | 1 + ...zvf0969q6r8nwnmr7yhwyegx8m8vffgnbjh8darjcj | 1 + ...crh1twhkb756ves35p72ydzvds4v9a58ckxv4ccjhy | Bin 0 -> 20 bytes ...cjbaa7kxnvt61ysr5aa9a1htsgsc5akc4w41k3y6ht | 1 + ...eytr2fzvg7ep4x96tzbq20tv1b9mfv6q6q9bbrakrr | 16 + ...y4weyyekrmefx9xx4jcsfnf1dj0vy1e5vp1zsyyzny | 1 + ...jhwp88r17fndf8a6mw93spgxbzcv3bgyvnhv70ca5g | 3 + ...8bc75k3bzqhjeqpwkyv29kzt7p8bazzx3ty7artsk8 | 1 + ...w4120f7nv6dvvhmsyb1khrxmwbqkgs22k838edwedj | 1 + ...bvcxcy4p2925nytewgyq3wh3tjbn6mp8d0cap1n7jw | 17 + ...tbsr7qeshkz69p2kgshe0xsa45ntjw6ypx6a3142by | 2 + ...e52cvp0d2ebjhvbb9gfcyjss12qtv2kr0cdjkcang4 | 1 + ...2apb41f7ev2vzwfh5002wp8jq1t9hgycz9b913znx2 | 5 + ...fg7md78205facm1zrbcwazzg87wrxkg6nhhyc7242p | 1 + ...bx5dcssbk9fgs3250tt06s57txd90ddpdevz64y7kt | 21 + ...wvhjaq25kg1r9489qdcrbdp051mxnyexd4r98zcxw8 | 1 + ...d3q0q8nty2kamzc30yd3yrsca6cv5p1qwzb5jkkh2m | 1 + ...jjd8tqccyt151zdc50zv32f9v7e9x39qmxrf50pswy | 1 + ...64smhx7gpf3pf0ztfjdp4cqr4fjdcgdwjzgdzxnbf2 | 2 + ...dsw5z4095vy5a9nrzbbmctqj1s60t8a4nx4z5masbw | 2 + ...v323xdcfz69fkq3hdepy0014265agv95f8v9685n56 | 1 + ...f2j2cp06v3pxabfw8a6qfz1gzxpvnzm06d4rt8qtmw | 2 + ...16nf5284aa24r0spdgrph37mpb4d7ws7ez4qwqzt3t | 1 + ...gmyzxnswhedm95ey6jmpa2egzn9jceyd74zjj8ep8t | 2 + ...gep5rgg42hdagzzcaqcwkq8dnq5xywq41p8yzhjhxr | 1 + ...3jgfgacqbyp0e0hw5w3bw7ne6fqnsbymaw99qvym9a | 1 + ...rh55v0g8j79j5bb7267tzqgdjrqzhpbvde5qp98sxt | 2 + ...dkkddzftkjddb7ztsdbjz6dmpjjn6x3y295gq39n98 | 1 + ...r0t9ghya12j6htrh77pjte2jeq23ftqyw4b2qjej52 | 1 + ...12egc4y89qq05pep6z4f2y6mxw2xrc5yw0q9b25nd4 | 13 + ...dhzv05hc0sxkg8vgjmvymaqw3f6q26mwmty8vygs48 | 31 + ...gc8zcqrbh0f5yzpjrqts7ganxrw1b6bpcvm9d3g1wm | 1 + ...pzxjkayxkqzjsefhdxc96qbm94etg252p41fx214pt | 1 + ...knp9mtyb13s8xzb43p22w4g6hasm6s9xn96z93hhh0 | 2 + ...adfvkr5t4afqhfb6tbtgg4heqcv34z860ftazx8f1e | 1 + ...7204a9gvnrwhsfs6gw3wd9dgp53k6wcj5v7t5vt39g | 2 + ...khvdfpwcw9t9dhmdggn32aycqwaftsqjc93ph6f9mr | 1 + ...dm8vrs55qdq3mbmh9s1rr4x1qyhfb9hz91w0fg6am6 | 1 + ...2ade597qyvp0q44d1pnbj9yrxc2aegmjtzxw2g6cwr | 1 + ...2m26p9tjmqpcgjmm15a87y3q6ge5vr12vfd5cegjza | 2 + ...jk64ptxd1rqjsh0g7yg9bwc3vr6jay0rqjnb2cgq3g | 7 + ...nahc097sf7wfdz84yntp9h8xhb1cyntp5mtfbh0bcr | 1 + ...pdd7znb1h88w52fyf4ss16j6g5x6y1xdrbch3f2498 | 1 + ...m55ahtbz3bstsb7wa1zc5cwe8j0kf1ac6kn2b3c9e0 | 1 + ...ptbbyxjbtzx5r683vg13k1gv4c428jbfk27m58vwca | 2 + ...pj4v790fdb76zgnp1h74skr5nv7mcty01stnyj86dc | 21 + ...jkqvqr89xn9f94n91n25rqzs58s7gkq12c4qb19n82 | 1 + ...hcrg11qye6fygr8ve1jrv75z6vxzgwpc10ykare34p | 1 + ...5jcbq1bh9rmwq2arjsd3nbkfj9cabtkjc6rytb707y | 1 + ...8y3t1ypcbv2r80jsymm5yqtkbx41kqb7yax0dag4rp | 4 + ...tg4v8q8489zy60xa9kjwfn9dtnf6f5841aw9mbz84j | 1 + ...kydcqpd8k65kkc18gahhkr8ckmc2tfs4fsc3rx54mw | 1 + ...h1asmc9q9qptsthtjgw247pyeasgpcy17gx32ka5kc | 1 + ...1bfa4kh47929dmgnee4d1f05hgv6js583hxnzacqat | 1 + ...te430cppsj8f0n1tr69zgme8zm3zdctwkts89tqkgj | 2 + ...d1xq1cbjw4bv28vrdaptenxn31d03qfycsxd94dztw | 1 + ...p7ykhgax3jbh9pm9v832kxgfpc8yj2wdqnj0dnbshc | 1 + ...nbfz83cjp98eh9qrz4e7baqbcfr8w07c9mr8h8h76r | 1 + ...d8pnyd810hns19dkvp0pm6mbctydr6nxh2h5bj28f2 | 1 + ...dcsdt837x02eq88kajab91nq0ctkmc5fja6s14x49g | 19 + ...vf31j6shg87ajmc19gh3f36tc4vr6b7v81n73f21cg | 1 + ...04cjxa879cfr3mkp8j5v99ewqdh1ka3bqptc3r7248 | 1 + ...d75zm9sz89vs3pnwfs94sn7rxdxg25tyqgx5jbdbp0 | 1 + ...fgsxp69zhyth69xdj5wvrsj2v898bb12r1xvcpg390 | 2 + ...4rfdgtkkcy6efj3fyz1excf7pww2x15239qk3etjpy | 1 + ...zvzad8fpgnp25t9ea96c4nbkmts8gxsdkq301t1sbr | 1 + ...bgpf2hrga2ja9gan85nve6vs8ndygv9atc4gvx9zr} | Bin 2 -> 2 bytes ...qzg4fntq5azg6h5f1n3k89v7c3zkd79a68gvqpa9jy | 1 + ...jgg28j8qmpnrxvgwqwhy9rsa3qzrnqmzj9ppdafjag | 1 + ...5t75s30qs8f06japgnm7sc9vq1m1qwrqs634edemx6 | 3 + ...jcc0akvqmxres0ak235a7j1g5x8af42gvewk0w0ary | 5 + ...wa6f4rx04dgwghpam5zkxp9c4yvnry1a9dm6708hcr | 16 + ...q5vbgw31nc3nvdrve6xhx519nntpfp466y772cd562 | 1 + ...wctsh5htv0fhkw46ab49ws2dqrng17h3panefejg3c | 15 + ...826zbpsn5r4wex6spd3043c4y5gcnbvyxmfpgj97w2 | 1 + ...v9q3a817bjvgqk19qhsrmre8hr82mhrjc2zq2m19gr | 7 + ...mhak8fj2023hsbnd500aknqbzpvx1gghaxdfbmx9mr | 14 + ...d3zk59t022ennk6sne1h1m5jzkv16e7tcqaaeh4ngc | 1 + ...62jc16td8pgmwkmpb887sccg89r05ph3n0k2emj4jw | 1 + ...ndvgd652rw5bfgenmkatrxbypkxm658ykfnq29h4g0 | 1 + ...3f07z6bfh43433v3t4sfrg22ybgsyfy42fqm6x1v3r | 18 + ...41vh54xd59bpg48hmrjgz890q69jmejh756a0q8nnt | 1 + ...thskpwwnmrm8g6khj3j8hxs5yfvhxgf086pq30jhtr | 1 + ...cfp9bdvcqkqg5tm08ggrc5bda7zmqz8xq3k3d6ysam | 2 + ...v9r7a7eysaxd0fpm6d58tbdg981d7z1jdjvcy9xmj6 | 1 + ...33vsd7h36xx5pzk5wzyk4hnn9ha7y87eh90vszdtwc | 1 + ...pyftwdby1bddzawz9ee6bavbfagjwem3n3yvsa5936 | 1 + ...fsvp41g06qv09d387sz4kknemgat7pv72apmrvav5r | 2 + ...vbtddm9r6x9jq3wdgpckfe4xzxgp19bh2x9ncjqwnc | 2 + ...9ctz9pyrpym136n3yra4fhxqvzjks22hjm9y2errxy | 16 + ...grm16kjp4rfzwbzk3p7sda804ykfma4wmb53ar4998 | 3 + ...ttf0zq9pvmgs3qjpdegznawqw1ndzbtbvs40the3h6 | 1 + ...qgr1jgbkmebh826wq0heyv6071h8j84qw4xmjdcrap | 4 + ...sbgnjd6mtrdw1nsn4p31s2arbkw7gy8manf8vp4tz4 | 2 + ...hxbrtkmkz7zt2vg3zq107ez9g017egpmcac6w50vbm | 2 + ...jv8nn4e18xh44q9kswsggmy91vy11ykx85ttpc6a7g | 1 + ...mqvmwkazrrm0gzftmzw2604x4pkpner8a4g52rgnhc | 53 + ...pvb2zt2hrkg19mkfqc9h9sk8yz3rxj95z6y2n6tbee | 1 + ...0hek7tx48svhkcmgtr4jp6cp0nmzsgzqdp0qkrbjz0 | 3 + ...bqrqshc4a4e544gy7bra0cc7ngwb8nk98zwexz4ek2 | 1 + ...6b8jk1e8d8gg6n97s15b4h6y9q8n0r5yp0r9wsmzgc | 1 + ...ye8hftb4hf441w1rsnrk9zhps2tfwfm6xdz6v8497a | 1 + ...a0gfw61g6810w4p3njyk0d0wh0xf498g53ntcj4rjt | 1 + ...henq6tnsbsncefwrtcxcj2zc3h3jkdmcb7f95skgny | Bin 0 -> 47 bytes ...nvqbr2pm9vaagx1nkz146334pgeaqhwkvdsw3pv9wy | 2 + ...4ywfh2ctkm2tm83xfhj4nv0a6hph0220eznt31rf9t | 10 + ...fw3gwg4st7g6jsby4tqa9b6b8qz8yfsy3wxcqa8m9m | 3 + ...jhhgnmdp394wyrsrdhhaarc93anpyxdb722st357r0 | 1 + ...tqa29astpjxqb9qb9nqy7a9p2yp7jff7ewbyqj4jjt | 1 + ...djb7j6ykqpqp5xkznbzx0fx4j0fv9eeb86t21ngqc8 | 1 + ...11rn82hs4z3c99f5kvs8e08skq9frctwpbtgj6vxzw | 1 + ...6az1bt52tr38crbmgm9ffvsaqm9me6x8w8z62qca6w | 1 + ...zes6wrn2rt75rrgmvsx54ep3zb3e2psa7fvyghhd28 | 1 + ...40rh8bnnba51n7mg5cgxjhd6m83qazmq7w4yp7b13r | 1 + ...vsbkhabpazvdv8bwezwexe2e88n4dn8ve59wy3dkfp | 1 + ...7785fpwp0z6r9he4bbkpk3xqjndx2yanmy2d4qdvcp | 2 + ...pvtd5v0g86azye9vbwtdfeq00p1sseg096m3j9cs80 | 2 + ...mg4qtd0ezmtb4bf6beemmaqh9h76hkfx8th8y94mey | 2 + ...857bs4stbmpedvjgn6avmv6weje9x8gk386v9jrspt | 1 + ...xf7j5hfttj5g4d8e2hzb90pmtfb16brhwm4v6gx11p | 19 + ...jccxftrntwr3se574eq9e7ykcpcapyewr1rsa5kf6g | 2 + ...046tvy72ss2g7vv16ppqtgy8nrq349ajkt5esk7j60 | 1 + ...d5j0jb6rj91rnf8vdfv5mj7frgnh6b3q6ty1nff452 | 1 + ...4svg8jmemyt4177w80xen3bs5fstgc8jbkb6ttcrqg | 1 + ...zw9ba8amkm74msqq0012txz5aqq9q9qe99f8csqr1c | 1 + ...x24jfe7r8jg011g5j6z871zjjqc0hvtcsf8bksf9rp | 10 + ...rj3me5g573cnrzgk30d8350x3e8tdtkqn6banswm2y | 1 + ...8n6g0e3b9b31ptzy2zdmf8q7xp9txsqhqhkhj78hp8 | 3 + ...4tg672179s8epq9vjc1t8xc7p426bjcz5arcz9p9py | 1 + ...27pt6r50fwsjxvtcvtgrqqyjskvzraqnmbz5c4nhs8 | 1 + ...pt36hmn1raq16m83ywr2v1hfksbc677j05jz3a5cta | 1 + ...503723z2emxs30rr989mgg7jcw5597bgjzdtbsn43y | 9 + ...0ny12mz2f64ah46mqt4h1244vn25gtjdh4rcp40yxr | 14 + ...n23yd7cbe5zk7fasp1c8h7h6r9pqx84kf59kkq9t6j | 1 + ...dpx0fdp3t2b9f0dq8tkyjz7bb17wp7qek6c5j2wbpy | 1 + ...fma1cype1bcfa17gp8y8mzvsqb7r09f6trh09sv72y | 1 + ...2jxcnb53f4y97p9a8rgypqezdfap98c3wgneg7k3fg | 3 + ...wnq7kzhv187n0eefn36fxjqqkh811hpe5mschmt682 | 12 + ...sza8ysntt59aawddf8nrjfz11yr5avv3mfzjpa4cct | 2 + ...fmbd7qgdmfcmx9gnpypcabepgxw28cyk07c90xqzkg | 1 + ...hb1cez1ecc2v4ft3g9br7hgm9pn19295v93vj7xd98 | 2 + ...nv6b036px26c1pfxdyetr2ke0t5k19q9x0697h0620 | 1 + ...1vwn92g566pqhj4psd63yh1t2mmrty1xvfba4v2dmg | 27 + ...8e6jejmqxgs5feynsczrd46hhyhh4w8kr21xx78fs2 | 1 + ...32e17fbw05ezyr972xx9kp3yv30jgk5fk31yhwhhye | 1 + ...venxzh25x3nhg28jjsvkz3r9vdwrmn3mp51n9hjscc | 1 + ...fpyb5ted5r0ydph71yvwk92w9ad8jc7cwdey5d1wt8 | 1 + ...zxzy6c0se61kh6fw955s9q7c74r6dqrn29pq7j7nva | 1 + ...g0z2n7emt92qnkhvn9e40mre0cm7fj6cavcg3fa8pt | 1 + ...ebm6z9e8603wab4pna1mf1cdec3wrp32jem3aw64zy | Bin 0 -> 291 bytes ...frz98yn558h2wzg6a1q9m9mna6h73tfa0bazs7sn8j | 2 + ...p1rtsrfr2e8b3kkp860q87jekvsmh09s5yh461kebm | 2 + ...kjt3y2enqdjd79k21h1c0knams8se5fehqmjz3ezmj | 12 + ...1wp4f4g2j3eev35nwd693ztg9rywxbf2xz2sw97efc | 2 + ...77sr15mekm241hw6307vdxw6jfpvtzcv96e0kpb30t | 1 + ...w7jkye43zq3m8tcjfavsyxb0ydpfvhecr88cct7qqy | 1 + ...xash0dv9x92eban9n4bja4a9f02re6s0cfdvgxggsg | 1 + ...2yfy9gpzwpkyd441q5bxa9d6q0znw8cn5c38yakb8j | 2 + ...4kk1aszm9zrt7r2rk33emns5jh7mt8v9ma5atbwd3t | 1 + ...838tn0zrencezbxme6vs2k4ehm2m25vpvaakhz7ger | 1 + ...j2956qabnb1858sgp1x5fqec9f81j796pe84cd0fnr | 62 + ...5975x2xbt7q49nejc75g2gkgq1sazyfz2g4s7dbza0 | 1 + ...rbet0j38wtdpacqvcedcp5nskf95r02gek39rmg8qw | 1 + ...w7s5sstzbwkzhcmrd55mrgw5ydy3kwys6cpx1znspy | 34 + ...08rz29x6xjyhzyt3cdtz1btr6tgatnyhnc07a2d5vg | 1 + ...bam1yxkm107he6rdbwpthe7npazfph718gv3802qy8 | 2 + ...br34j2epdjf3hm6gs0bn44dkv64q71s8vxrwn4ghfy | 17 + ...qwc9ng2a7y42dae5ax8bv7zvms6s4jqb3ms9q1062a | 1 + ...01nxpr25fjkpb44v57kfxy22jbhre9jk9xmz903st6 | 1 + ...2tx60pfkvq45nsmz9b71pp579pdqd5g9njtv0bnw90 | 3 + ...35tsas864bn4tkwtkbxf623k66fnffb27x07czte6t | 2 + ...d11vja9g02rct4rgk4sbyz2pq8g6ce8sv4hc7wwbtr | 19 + ...42ng8jwjq002dmsatnmn21as2fd1g5h4srjywym9g2 | 1 + ...nwfm2teefsk6cqhaahqvmaeppjcdzgfyph7y64cs06 | 6 + ...0dxa6py99hk9vmne6g5w317jh1spjt90vf5pkq904c | 2 + ...sd04pp0ek735a5d3fzbxnxhpvbafw9hvh99kvbwz8p | 2 + ...tj4zjgtrxfvw4hmnbkzdp6bdh1j0x9rrj0804xz2g6 | 1 + ...2wz64dne91ntf7e90dhbf9srktb5p29aq26jzwk0bg | Bin 0 -> 76 bytes ...q0tjf2yp04axpjztgdrg2q1m1rvzsvp351nc80dpam | 19 + ...jkd2759bpn5f461dkws3h2j15yy7keerbyspd857b0 | 1 + ...21bx76yg9g3vd6kmxcnkh2dg6q0pctj5bhngfannba | 1 + ...74w7s5gapgnshxyn15401mxhzm5hh3fve4cdmjwncr | 16 + ...z13a134phq13pmsjfmm4a8jzb5n2nbzjaq0bvj78ja | 1 + ...wdm2hqypr8xfsgwq6cgekw1wqsrzpww5nwscttq46p | 1 + ...3at38nnnj5pbjqbfs84vekef7cz8w0hppz1egw5dwg | 1 + ...a3ry1jg09wd47m2xwpvgae90wnxtr2rvwf8e146qg6 | 1 + ...tzypr7b7x9c00zgpnw90pch381j378ttszp1jfb658 | 3 + ...2dbqk4z17473cs581byf9df8452h86tz7r7vjja3er | 9 + ...q6gtnpe7dtegw8qsney5km59ma0yn4690y7qg2hq04 | 1 + ...wmvp49h1dt7259q310ypjasyxkq3fxs1svg1rr3c18 | 1 + ...t3ewgwe2zgrax02f99a2mz17c7mzej0zkhmc5sxz60 | 1 + ...prghszwxv6ppp3mrranea2ptkgwenp6h2gpyn03rsm | 1 + ...zy0ph9dzdwvdf02pvmmnb3z71fxqdzmk5tfcd95016 | 1 + ...dhbg2n4jtfvgpzkdrvag402km42qm3cvykssn1f7c2 | 1 + ...zrf6rdq7jav2mc6v518jtcs63dr389zfqj1awnmx82 | 1 + ...j4521be0c23ktwdyqs75esqbby40y7tc4ee40mg33e | 5 + ...61457rhjg8q1gtgwrxwmhv7fe4hd36n16x15e3zjmm | 4 + ...z8wygwa45hanm7s90tvaw890psc9tg15712zb3p7j4 | 1 + ...391srmekajtdzkg6xvyr4rd6ndvp5279vwc0xn2bcp | 1 + ...fwzkf15t5ab0xfzq7kwvzf9c3ej1vk3sdz9jpnykm8 | 2 + ...xy4531pmxv9847jz7perpg0cpz4wnkdkxgtydg3v60 | 17 + ...7p1xkxz9brkee1ea2ywawfgxqn5x8t9svnqt9244ea | 1 + ...baa8yz1ty6dywpg4xjeawgmehkk287m40ygkx6f6zp | 3 + ...8f4rk68hcfbeqdx4pk7bzjz07vg6e7a3cxzx3v9wft | 2 + ...g8stb3a070a7d4pg61a7rveqv0ccr5bhfpn7a4rstg | 1 + ...gq9ge6v81dz4ah04p7s2wmgpxxvzqwytpzbmwz7b3a | 4 + ...084c49th6y4ryysvh0027yvt77cfmxxn79qcyyhzgg | 1 + ...bayrg290j0f6myh3tt1p63zzjx1mf29k0rwewqqchw | 3 + ...3vzjvnvfx83c7abfycjh14x57afa1ceyznkx4tg0k8 | 2 + ...cbzae9g1dae8mbrgtcph3phzvn6xs0p4hgwcxnzeea | 20 + ...p3m70qztxm8dd5ftste6jege5zgy5t6j021833j7ej | 1 + ...hyy4pf9dk9sm960mm91qpnw8draq2q4mwvdngp56d2 | 1 + ...xz58hzw7pmvdgyt09dyarfk10n5g1rfxf5nep1531r | Bin 0 -> 260 bytes ...x0c4w7p7jsrz1h1ezka109ryjqetjtm9n6bth6ea4e | 1 + ...k8bqhfqc4qy61zpzberwejg3b5evkeq3dma3js2t0e | 1 + ...egm2adakfzwk3dh4hwkepwt67gpkyfw5x6ywrrs9jg | 1 + ...754wqsxw871nt24v192x2eck1jz9w9s8bk89m7657m | 20 + ...k3z20wf9ahpv6ttewhna2m0251hx8tvtsk13pdazb8 | 1 + ...grvyam74hae6x8wsw3an148qa9caw8cjx2jwxpyznr | 1 + ...wg34atrg7afqky1ajnxprcdzbbdqfg09fb92m063r2 | 2 + ...1j3r352wvahzbgnh8t449j3pm9kb4d1ax0ezky2b7j | 1 + ...6n5jgrsxe3aydj10cvq35ma4wsg7qczhz1r64d7hn0 | 1 + ...kz92b2h54dsc8s1vzbhfzenxw9r7hx740z41fexja0 | 1 + ...ddf8e6nbae84a2vgwbs0dcm847zgw3vctbsjd6j2ag | 2 + ...kfkn00xvw37f3t551t5tcemzfqe9jegt9wgftas6c2 | 16 + ...r8ycqfat197v4k1hxtkt0zcyrvhgx8tmzx326zrd0r | 2 + ...gy0dcn4srykfn7x9vabhne57j2x7y8dg4mhrjdw7wj | 1 + ...qfpe5y3st6etwykvvb01v697hvpsbzgpq98e44xvpy | 1 + ...mj82p5zpjpyzzvxe1ztgte2spnpdqet0gm82frhmda | 5 + ...5ncgkjyx1j6h3h5vw9x9m3nw6f6h5rnkv1e1qx55qp | 2 + ...njzsw0nb75195g8emmhk4tjw68n44xwvgkz4w8063p | Bin 0 -> 74 bytes ...xm7ybsmr740a6hbpeaavxczg1yq6eza16jvst2ppg0 | 27 + ...nzbxvyc2zgevg0344280fmx3ahkk1hnjzr1715g3j6 | 1 + ...v0zqe12ekgy8jzscfbwprhaj8nwpz70p11k1zwsmzg | 6 + ...gvt6d2g6613m3w203h288dzd2k6d92wn4kfvzbd7je | 2 + ...888ywyvy5fr83bdyj7dxjeq62mc10s4xshxsqhw7wp | 5 + ...04cp3v0gt2pjkkzmqd84nx5qfv1d90x6qtre0n9qcg | 3 + ...hadzgnrkbdch4ja8rjvc6yc6fdk5canytgzgr7qhs2 | 1 + ...vajs26edvpejqkc27syy0dqxttg0epvf1dbzfvce18 | 2 + ...zmgpapfbw9q5gd1r99hzchwqmnc130bv3e102xeekw | 14 + ...gfdkbdfjrbhyctrkkdwzyy6tv0xx7xdjd3syvq9pte | 1 + ...2m63pssmgd46emw3s4mrk88agm1pr3ykwkpxx5nhna | 3 + ...c0kzcgk2v3hq0ehgh1fcs2272ryyan83wm7p3gxa78 | 2 + ...hfvekz2y5g1jhg1ykyemphdhfyarhmwg7smgvy28w8 | 7 + ...b6d6578z22xtepbzrc67xhp4cr6c5azxex2p3m841y | 2 + ...tdmjfsm33pdkx1vneefqterd9ajy4w4caztg49m49r | 2 + ...e27vb4h8m64gn1qepw3kgrzm6ygdtgrr03nb685w3y | 10 + ...nh283dae76dtmhfkvq7nmd6qt8rva7y2hbz51fmdzy | 3 + ...ts9sxdjzpxdfkb3kape5azt6yde0se4f664h6tefke | 1 + ...keac33py9haf2ervq2ggmcwhen40aj4sc291x22xv6 | 2 + ...hqt7jp74v9e149zrv089cb812zcdqz9nsrvzyn54p4 | 1 + ...jbergqyrxdm309dnn4x1t085j601kvppjycgfam982 | 1 + ...wdf80q75qrbb8zbzgycmahpcbtyjzgm502764ee8tp | 1 + ...fx60td314ksyxv666k9awxntamx4zcnbxbyw8pvsrc | 1 + ...0zpc4dd7hc1cac6jydf05dyf59kv9g86pyygsmq76m | 17 + ...x8wb9rbc02j98tz450a1xkst7j3v185atgmtsbcvfm | 1 + ...53xadg9jt8grsvsh9a8bkceye8zr1rxx4wn1qh5gwp | 2 + ...7y97hwf2hespz771jydy0mxe1gbgqqj86q67z3bxw8 | 44 + ...4ta37vnr37zdj46hcvkxg3tzdbvv9hrkcmj98rhhy2 | 1 + ...rd5e0gr5evfwqz6n983xmpr1zqcpg53ap1gftvkx3p | 1 + ...dwkz0s5qa16xke0n9d4zkaefmp349kbwyjpd6nj1ry | 1 + ...tv9rzs0ewfa9c71aqc4t7qym7mjyywwxb0cjkm39tc | 4 + ...djkygzy5vt8e1yhtb9r0dhg19hxzxcdtp5whmpe6a0 | 19 + ...9ekbqz6ts2av7eb8n3yjv4wytdaarys3ed9gvnz5b4 | 4 + ...km3rtc76y4amxbq6a3bvj28wt28t9127hf7cverh92 | 3 + ...jtsqeqb0xm894bjt7vy73prmyhyhzpe9hg1nk349n4 | 1 + ...z7cgm8ra1sarnn2w689q42sed8xb9ve78mvj85knry | 4 + ...38jmv5xazrbrknbzv2w01bzfh74j3s7pw5wntdgzcg | 1 + ...ka9cctyna6x83rethzyb8d7vy6915xmv1xa90snb2c | 2 + ...gwrajz3mzbq960z8vb6sq1mf72n39dbja6a93mfqsy | 1 + ...q2vdertx5s0530v4cc7hf5932h40dhsz5wbkh6ac38 | 1 + ...xbt4vz15rxtvy75a2c7zrcqq80ywr682e36936shdy | 3 + ...dfh3hfn0b7cn92xd8fyrx6jx96e1sp3pwdq64wvpc8 | 1 + ...gas0n2fctkfdx4m1bevmrk333drnreerk4scwtmb0t | 17 + ...c8w3t0sa6bgt4hqfmk0s702fhw3aj2s23vrf113vhj | 17 + ...d1aeh2c5te4wzhqg19vgrt8xay96svegd8190h53fa | 2 + ...j8p56a7r8jrt40152sd7fcc4c90j1y2890rqat47kw | 2 + ...gxgmb7s36z7t5w0c13v2kz5m7bf4qw7bgcys380f08 | 33 + ...5phm9g9r65k34nf2bnbvktjcxarpnshyhss1hgzrcm | 2 + ...qsn694mxs46wv9pxk5wr0v7w32h7yq1am1qxnrq3a8 | 2 + ...z2tx173gmjdhbh0tkeg62s8n7kcsv9gktyt864mhnm | 2 + ...51mdw2h6myk3rettmc5nhmye9h8k67d8rd5s747qx2 | 26 + ...szcfjdy98emzg60xkmccxk3qdcsk6ads62zsf4vyqm | 1 + ...apxmj9qkwvszvqsrktmkcrkvss8wq7dfm9p462p064 | 2 + ...7nrbmhdc6556cy33hd5d3fqcw518m68q4gcbsmzpma | 1 + ...z5qnj4nkj1esk3m2v3tw4hzgcvd4aq2zcv0a0vv90a | 1 + ...jxhewcm04e4px2m2znvdxjbr686pmewxrstvaxz9he | Bin 0 -> 139 bytes ...4hj84agz7txk2hsapr4r7gbpxac5ttbdefme657ysg | 1 + ...dnet3e2y8ztax53q7hddaej4xqjgaz5kveh5eeyxbw | 1 + ...wttecepmpdjfnc0ht0x0gwb6a1jq03s3yj444kqjcy | 15 + ...fsc8tmnxj0cxxmr3jes8gz76p54fs8wzfqh7pz9274 | 1 + ...p59y4jd3yq8j6gz8zz668capv25c5ya0s58qydxcst | 1 + ...mbkfs19k1fmkfhx1ej4jqns8h1v8dyj58eg6j33dmt | 1 + ...t24ensy38wm2t0at68frg52g4g812hm20ws9ne1mde | 19 + ...60vyjpbs117mf2gz69h6enprvzm0hcwt3z641kf5xe | 1 + ...m9qrp2a5axfa9jy5h8ewtxanwygafwhx4r5fwbztce | 5 + ...mr0cmdm54pr7gsbxyskvymrvkdyh003phfftngp9dj | 3 + ...hqarrsg7mnv6d49q2ksgb6q2afqe8z16ct7dkxy9aw | 1 + ...t8fg331gpkvmxp9mkgyxyk8r1ndbqtfxxh7904mkda | 21 + ...hpq4mgferty6rhpdp79xvte4cfjmzwtf53kmsxaz4g | 3 + ...zkfk06j8qbanxvsdd0ctez8e8js8qq86w1n8s85kzj | 1 + ...3qx6671gfk42fjcpzapxgjv932b4najhcdcvb87vcy | 5 + ...72ey1t36ymxs03rc2yz80xavs5dfjfc8gy1zgsm2yc | 1 + ...has31kcvzdmf3rmzmc54tja0yk4ebs21kt9v1htm16 | Bin 0 -> 20 bytes ...bvdrjj88h71m40pamp9x2ty7p1v0h5afjcscnhfjvm | 21 + ...pad9g37xfp5826mapya0j9fjfasbja8fsz721k7hse | 1 + ...6a08a240xtex9khqvm8zkj6v4ane2yqvajq13a64q8 | 2 + ...pnkqd0fd7b89g1r8zw2sn6t1ffhc34chtkb4zt4g6p | 1 + ...k4cpr62tte8fpee0h93ej82ebadtdmzev02ankgxxc | 4 + ...qw3wvss3wv90ty3689ayg9bh3hm1yj1v81d7mmkmrm | 2 + ...6cytj7h2etyzm73q23gzwb3r3zzn46a26147c3ngtt | 20 + ...g13cjhwvkmnjkzhap1wv65s0d6mrsfnpvgqjd4d43t | 1 + ...p61x7qvhm54q7venkq2j0rxvcj8pkz54tktsmz696m | 18 + ...nvsew9f6adkessshmv0jp07cs9t1ammp05wfapy95w | 2 + ...bn1tkad4dcz38gynvv3b9vjjxa753a6smp4w0gq8fw | 1 + ...555xm1czdmsz55emnt639nhve81rb305236qf5cvw2 | 1 + ...4jnm2pgnprzney40fatb7pp46t42kb5fk5bwagzksy | 1 + ...ybwf9g3rm5g31dmygq0ksw3hdxwpmr2msqhz46581g | 20 + ...f0w63svmgw0k720qpmarnn3b7x1jfd6sxzfjrv0qsj | 3 + ...9vhjanjap5bqrg5n0y4awn9ey3b9hv04y0505ycf8m | 2 + ...kk8x1hczb24rycg0wk93k0n71vrkd129shee2kb770 | 2 + ...1caxe8khbx3femfbaeeqyf8rtjxxnvh7peyzvr6nr8 | 1 + ...w64nvaq0ek0d3n4trpsnkrx13bh73eexhqy3qz1n50 | 1 + ...qvqw6nxfk7ccsbfqbphcbtjm3chag6qdy7t667dvxw | 4 + ...7vyjk6cj3yh3k8f0rdzt65b7j6tp7vzhht4e8g3ed6 | 2 + ...bwkxt1sgswfqnxb2ksghfs930jn8wt94e4ftsrh84g | 1 + ...5h82x0xmdasfnqp69gzrv0kag7fyytg72g7wsqp1qe | 30 + ...wy5wqq8a78r9krk8bdrkc6dgy4rfwcjjjm0d6n04zm | 3 + ...s9rn0bks5a8stzkxj5z2e617qr56dn9r6y4amjf6aw | 1 + ...tcpmdyg4mv2echk5hmx1gw435cy74yzqe63rv3w2xe | 1 + ...5h883zt39y2k6qb2s6t6aj88pdr0f3vfs1fw18y5gr | 15 + ...7ztryqh0pqzj368wwbxqkvm7qbvs33n66hxx7nrqwm | 1 + ...mwrdvrc4nsc74704jejejj7axdre87g6zpggvrbd3r | 3 + ...89f9aqmhsv9bnyeqzn91bpdt7b98hfef1h55f3svva | 1 + ...9vf59rm5hmm5f7jxhc5st3mtygp36p0x9wwj2qtnbw | 2 + ...59m6kqnn4x3frndv6zm7acsqtt2abaknc1zk5px8ce | 2 + ...y1dsabxynmvt3x0c6gehwykk90p57sm0dw4yv30wn2 | 1 + ...y3d9a13g5dmxd7kahqes3eqy60fcv6v0xd2dhd783j | 1 + ...30495hyfzbhes4m5b24jh013b6wkyrb1nv59takz1e | 1 + ...fwk9mv069s48jzh27mv334kwn483b343g05psgg1h0 | 2 + ...dswqsnt0nz180w1njgh84rsevdd04qvzx737tqp4ny | 1 + ...y0bw3s81dq313y936cngh5v3vbxst6c4s91v444jr2 | 1 + ...6cm42qnjr54s0gwv2gehm9t0v2kq8p3fb84fdbq6wm | 2 + ...94atgazn4sqp0y06bfer99f5n9d0z47251b0t1nbrc | 1 + ...918nmttxgteyaykpskyqswf27byd6dv7v3c6mr9ce8 | 1 + ...srgc94jph3xbps9f1zmwdyb5z68rtbqmhx2j43rv54 | 6 + ...c3ayxsqq26r2y7ehk3t0x139cmem9fyjmx7q07yr70 | 1 + ...tmawhwhs2ha6c76dxh02gswf2h4vh6vham7m3sfdct | 2 + ...935cet85vqftahbkvazp0hy57ee73y1gccm9hf8gqc | 1 + ...3r5tp52qea2p58k13t20fp1y8z4y6sctkjf8bhmyec | 1 + ...v67fs6raebm8yy7tnxdrfn4nstrdcc7xtwj7ec4864 | 1 + ...ndd6wvxxe9pztv02yrhqsk0qhkk03hhsb6z4xqpqg6 | 1 + ...z15vspeftz6hvkdstfgdnmv7q9bh5v5tpasqshkx74 | 1 + ...naj2py5tjqqj394c5ndb89ycet34x94fw8dygjd4ew | 16 + ...01kbbdv8hwahc86r3tjncbce3gynjtrz5t02p99bqy | 1 + ...3c0xzs6tr5c3y2meepqx344ra5nnwzj5k4p3w197yw | 17 + ...szrpddaqfpf849d2mmygc3pa2w2j7canbcmvbvns8y | 2 + ...7mydv35s2xwtnrdnyc3pd56awqzh67157x8y6mpw9e | 2 + ...x30snm4efr2k1x8mqpej6xdv2hpwc13vv2njapmt3c | 1 + ...zpavsm0j6fx9mbn21b8126993m8mc8fkpmheapshac | 1 + ...8t8wtgrt740a0aeyfjjts65pyaw6w3sjpazhpt2h94 | 3 + ...4pv72mn0h9ekhe92x8zhn6r03n7j6fh0w6vz1spe9g | 1 + ...wkgjqjyja1vak6tv7yxyaygm73g4psv9pexeqr9v1c | 1 + ...8kv3f7ap1y7frhkfzjcxs3p4ja3za0e46vj4e245g6 | 3 + ...xxt64rh1qcbhctjpsbnhx1s8h1kt28aejhvs4nt71a | 1 + ...f6wcyfjdk2c23myaqx4sqbef6wsy8j3dvz3m449fzr | 1 + ...jrk8cbm11vcgfv0k9vbc3v6mhntmfevse94ddtx87j | 1 + ...78ck9a0kyxemegbagc2rjfedsha7z80gt6fztyht2w | 2 + ...74myh8qrgwatp0tvksqb3r6rze4am7zcerdfpbt95g | 1 + ...wz4qs3hsbf428b1mkem5f51drw08afybzybxz4kz24 | 3 + ...h16tn6nzr6s54fqys8twzwvt4nf3r1jnpjz1abaj6y | 21 + ...k1hwdpd06mahek2rzzrfqsmhng70qv6ttv0zfkva50 | 6 + ...81h7q6wx5z6s7b4mrma2mj26awddz79ve8mttxh7fg | 1 + ...5key1yebs99qhj5qr9paqvy0ck0w2y7ph9e63n4xyc | 15 + ...rsjzm5ffxrb7tjz9g2ttmbsg79bd399fgh3qffaxr0 | 15 + ...m0t56pfry6xsf9mvc4w1rkrzy7crwff5srqf7zz2a6 | 1 + ...0xew56vpdtmecqyd965zxgzke9tmb0tgj5nsbr6hke | 20 + ...1zkyxmscw8gfnprjyjz3s4mq07nb1ndg0bf4ptr5x6 | 16 + ...s76p2mngwb2g0s36t87nfw9771gnkbh88x64v3b9za | 1 + ...m2140kkdd3y52kv6da4r8r7vk6bhxk2nhhj2wrrx90 | 2 + ...kt9mh86k8rq8ksknbzsvptc3274n2n1zjgswg1ehqm | 1 + ...f8cpayztamyr7evqjfy6wga3zngxhk4kvx0dza4mv8 | 1 + ...rpmnjbk9d5ymty9jcby1093s57dkm118qcs250k05y | 4 + ...3epw20qqgp7shh42j9kbbeq79znh82r03bmv9jq832 | 16 + ...690xw3m4yzy85b9vb4t4cq42158d96rfd923m8aa2p | 32 + ...my1w9wtefsgpzdk6nvsz98z23k9wmz63w1ej6xe766 | 1 + ...f95x81dj1gn9tpbj8w8r0ht7c3w60hskcn6mgjtrme | 1 + ...ebjxz3vwfj4pd0dc1kerm6gq0egmy1mxr4g82zjg64 | 1 + ...59mn46kmhq246znnmh6wzajqcmngexwn2qhbepg02a | 1 + ...9n5fkfwsfdery7z1e7gsh5a9qdqmt0vfmkf185rp7p | 16 + ...1emsm4enja8d8gdxb0173t52zah1pm9rbbatghtg6a | 17 + ...dg1yxdy9fbywxyn689e3n8s17jqvs8vj3dm4c09f6p | 1 + ...8fxxg0886x5118vcn9hn9re95kjbm64m1mnv1v2yv8 | 1 + ...dzxmff201w13fv07e00kgx7y6xzk80dmf6h0n6e8he | 8 + ...rjc9gm33ymfwkpsw3pdm4bm7e38hyakp6m5rd3hdf6 | 1 + ...jdjb5ztvry0ky10ryyx6j3a0v84f4jcfwa8v3swn3j | 1 + ...c2ds26vf511s9ev9e0ymjbmw01an7s43nypap1yd2j | 2 + ...xyqbzsmnv7z2r12gtre42jtnn0evnz8sghsbzfbvty | 1 + ...a29n6vmqy1cmsdgn259sa2gear6ansyytb7dsnj380 | 1 + ...5gj9bemrbyaptz86xrsvkgrz43e5fd766v8sptck92 | 1 + ...qzbe79qkxy5zv5daw6m1x7kh2f68gnxz4k8rxr7bet | Bin 0 -> 256 bytes ...ws2y6pk25cgmf8fg74p3z1e8tw9g7h72m2x5am92tc | 18 + ...t88k7rhyt3jyq9174j4k059espkf5nnnvt1wn254ea | 1 + ...cheaygp5n2htj123hvsgfyfjdpmwb46v7yv8k9kbsp | 1 + ...v320wcgc0ydng7frvmm58x4az6r1w8j5knk9c8ejma | 1 + ...5wtb7jsahx35v0fgnd0d5cp3gnas1fv24jsbyt7fet | 3 + ...4z4m42s02q4ab3gezsvp1ytyfhhmxag9sdxdrsh3cr | 1 + ...dd04qajrp85sczjm8s2y26c7xyns3mwtypkx1n19y8 | 2 + ...4rs232s782j37a38v7f3cbgmxr8gw2450eq26f9732 | 1 + ...f3etsn2vgy2342p8ezq2bbbn5mgwqx5mb67eyre9hg | 2 + ...mdfagf8w7x7tfzqsgb5k4abcfmk3p1kmggc8ya37dg | 3 + ...803bhd7qf17s9aq8q5rxrh6384f5q48h7e3pbmn94y | 2 + ...wr3jct03x1hcdfyr9zc5de8kjzhqdftatb9p0txjy2 | 4 + ...m6axcx8mpe1qp1whakh1y0t0wgfahsvgwth5p7mwy4 | 1 + ...vb980qjve6cak095mg75awgrd5p14s3bqnccs3d9vp | 1 + ...68phs41hzs9gfadgbhm8jp91n9zbyb73cbmvhc8mhy | 1 + ...b48n0xygtvkx3nckbc9p4ky0kphkxj1b0zzpfa9bg4 | 1 + ...j6z0sr8yz063zzaxameqvq8kntp05bh1cp3tnefr06 | Bin 0 -> 11 bytes ...pj4jk38xv6fhpf1bbn2398bkvcgmkqq1crd55ja9ke | 1 + ...q6t50jp1c9gst4ek2j8r245e2hw5a7gwvvpgnfhf1t | 1 + ...mpfv58qes02wt4ktjxrwveypfwns9hne6hvk9mrd44 | 1 + ...1xj66vxs4qczheqy8ne3rtf5jsa0e84d787cfeh8xe | 2 + ...8yw6t9nqwhn9ygqqjfn42egqbmz9tvxwjj4wtvvp7j | Bin 0 -> 278 bytes ...m6vptf0pxp94z7dseek6j01pcsaxa669xmnj0gpy68 | 1 + ...ntzfd0n1t66793erxeqbgbp8etqkyfsg0m56gb19xe | 1 + ...m0dbv2tezpv8wtgzehd84x35bbqecq4r3pp1ss5s7y | 1 + ...qjmqw0ersskqb60kag18j2xj99gcz1caszeapaxv82 | 7 + ...qfegw5ybpp8qakdfc3k8gwf3jwx1e9jpm8nvyjaa2g | 1 + ...7j344ypcyv8zrwr98g3g5n8h3pr19p8mcmmg6n1avc | 21 + ...j1zs8cr9sxh03r64qr0y9rkmatt2qs2772k49fk6qt | 1 + ...6nrpbnsfjd33qy67epbwhnvf8rjr75dhcz9w85t8ta | 7 + ...x9h9xjstjgzmmj18r8g515kwvre8wrb9zr8btxhpyj | 1 + ...hk88m8twgs79ndsypq12yb3ab7ae4n2t3z45gy2ey8 | 4 + ...phk58zbbyr4dcgzymj9fvdwpyazrc9f0qkpgb17p5w | 8 + ...6bs5fkzz4rmvkf6p1sv8mhyafa5bgaar290ae37kxc | 3 + ...s82sf0h9mheve4rtr7et2yahhaapjhjfajk33b8kbc | 1 + ...tdgqz67sfj5ykcwv0fr8e3ssaesj6zxnfbb2pgjczw | 3 + ...cecva3rt0z8852gz1f9tgq7a7eebcfbs5dvhbp3hr4 | 1 + ...3smqnjfb2way9n0n9praqmjxjz6j87a2t6n04gzxha | 1 + ...s9nevz7ys78r8cyz6jhd7z2e50c8ve5npey393prya | 34 + ...pj46txknxehtjbtm2mf8xe42m810vdfw9ngf5e2p6j | 19 + ...z172q8pprzf70wxcd76nvqz816abpercv1m6d0tsje | 1 + ...jvn9nfee3kzs0w03f45814khxz0m70hns9mf3kbhrt | 2 + ...21yexdccy2rhr3w32q832kk62dbwj6rmj7wnnfsyj0 | 1 + ...5nna4pvs9azyhqsq3rqz5dxsr2m9n1a557zm3ejx1a | 1 + ...wj19zc6xv7kmsb087yrcrhdzb4hhvf3w65pxkmbkh8 | 1 + ...pevrk0tzwspssqan4ycb1pk0scekrjak5y8t6jm9e6 | 3 + ...1y9pevygw3shngyczkcfcxbmjv4fmf0tqzcgy9w5wy | 3 + ...1bx4mpgstvnv1fns60d9hrzswpt6s8fgmvr6pjtzd6 | 2 + ...yp22kyv11cm1njcbsxr0d0p9cnyaqjn8cpheqapv4c | 1 + ...pv417w2tcwf9p9n6sj8c5aa14eryvjt55q6m61byf0 | 1 + ...zkkv7z5sq8ejty3d85npfsypfnrtktm61ce75wm8gm | 1 + ...4ga1sjg4xj9mvqfbxq5a8g0rczv1p5hmpjj7m25fw6 | 3 + ...1n9487pkkys6qjqnwh3dxwnnfwwd3yrgg6cb49jjdc | 1 + ...d9gvse0wb83r7aqgkstv6gdcck4h94tej49q39tp7m | 1 + ...6k6yx46bcymgfhcmn1hbhej3km6yfr3c9wvh5xe63t | Bin 0 -> 127 bytes ...ydke73da5rnxnmpdn1sywrw0e9qw1z39rm8vw1875p | 15 + ...83sdtasgb2mw9aaaqtd2ag8bd8r8sg02e78e5nrhqr | 4 + ...3bsfmd8z424mnm6vnmqxxk2578bkzztxtxbw7td7a2 | 21 + ...jmb7kcpmjdfbwtqxt8mmfqwacc1ag8yprymdb8snep | 1 + ...c9q6nt579crjpv174n51wpjn43bn909zaxnaayb4sj | 17 + ...4ytb1yy66twvrgjyfvwhfnkxk2kx2b0tdx3pcbsxae | 2 + ...8pqkhmpd4zqgwev6da6th185z93cx5xdwgvjmwjtr8 | 1 + ...bs2ndsbvwv69rf6yrma4478m5tbq1rxaew320spk8c | 1 + ...x73x7d4skxrhkga3978tv1ftdjwa13gf35gxpb4mz6 | 1 + ...mw0n5g8krbh5mfk84gqvbstaw9hxayxjqf9q0zwsra | 4 + ...mye7nza29sez2a9029kn3h0g0f51yvm5ertx0cppyr | 16 + ...kg31h97m32mqp6qrs2p8f41cvr6y7f6qfkr7bcpzke | 1 + ...c5jyr3pe6v9bs5qeaf4khz36sn00g713mypkjvb7me | 1 + ...ehabpnf1n5b1znxw3tssraag8cb1z8ff0zscdtsgwt | 1 + ...0kr0xyk4tgzr9xmzgk85mw4abc3f7qw7hjrgyjhv9r | Bin 0 -> 284 bytes ...p7d81dhz89yhk5yk0pxn4jxj751g9yh1kvqwtpd5ww | Bin 0 -> 32 bytes ...0b0s3mn5gg6e6jjxn7fs8khj3jh9de89q75yjp2tt2 | 1 + ...8ppt850729b51y9nq4wkbkeczhyr1qbxdyekh7ggcr | 3 + ...d4c43m17kehn6f4gbvjv81512b7ma1ffaq1xm5e4vt | 33 + ...nrkkqzmrd17eh91gmtanm2hqs9jva7xed2a54cayd0 | 1 + ...dv403zxegm5pgexxxknh3xzd09f9s1zw488xfzab4r | 18 + ...t7a2mr57vzp3k7ydqxm7jdqg2xykadr6zbjkq1qys4 | 1 + ...rjfrctqnbnhkwyyjgkcfx3e93q9g42xfx6prq8mqg0 | 6 + ...vavtjyjphjx3r37e97cpexy5871p899xet1x7m3ht4 | 2 + ...krf36h9dg6rwsac79b4k61gw1vqv6kw8n84ambexj4 | 1 + ...9ftrgnt21xexwhtaznm62y4d0n39sgcey08s4pqn32 | Bin 0 -> 3 bytes ...szdz6rkktpz6712rj3jfh5x4by23nm5tyrkgabbxqr | 2 + ...sxtx5gy8fg6qqxy4fp89bd6j5p43r7k2rd53s0546m | 1 + ...hzsh2sy3ddcsg40ew1mwzk7t3ndxnx76b7rk8pcbza | 4 + ...m05gz4tfbkzy9d0x40p1cj1mpvv18yx53kpwk0hajm | 1 + ...gy5jc4ey7xqhd0pqgv9peh363c6rtzpqgzxr2j370j | 9 + ...9tph355x87s5cafd7358xfetzmna2jaje9tn63hnze | 1 + ...7yr8tr3r56kpmyh06mgde04kmepy0y78fxwkqbvya2 | Bin 0 -> 13 bytes ...b6ayrwvh5vxfdq3xv5m2qvx77r48zezsjedz6mmae2 | 1 + ...70yp56sq147e0zedx9kpbkqgceykbz4v2y6ga8wvjw | 2 + ...ccemyszf7rt08ae038h1y4j3eangvrjm1f0qgfzw18 | 2 + ...7wk4wrch8ce8vdw81g5azp09v462g422pxzsxn13jp | 1 + ...gkzzk97gb87zw8n0jxt3e1tm0af7ga1s127eg8y6g2 | 1 + ...hpm7n0mr8w9zvfjj77ja3dds7d3t4eykavvjyb9m18 | 21 + ...pmhw2nvq116a2mq66w5ac0t0n0rh9n803ws906ezt6 | 2 + ...4ehya912q5endeyjvppc7xk4a3p4pywpme4e8cm0f2 | 3 + ...bhk3wqc0516fwh3znyrpb8ccx98nb67ytedg78vz4w | 18 + ...6w6c43jv18cfeb1bnxkjc1dv6yvb16ghhpksdtdqam | 1 + ...dwb8kqxsbsft3xqrjr6ph3ppj99yhenczadg1b6ate | 8 + ...ny0ttw0wsmmhf0tt3qwz2w8n455h6ty27qjq0pwqxe | 20 + ...f8grtvs24scm7eht2f38dwpeffbmnxptb81yszkbh4 | 1 + ...x2wxpjc3ypdq1rfnjhg8jxg94pnfyzdsmkqq10vgz8 | 1 + ...0gwb56jzrre8y93et4mcv9x71s3takyq3bkf8kwagg | 1 + ...xkhpw15t9fyev7w2frdce2kzxtrbmpvrpm77cvz15e | 5 + ...zwvrh6qzg0q78njxekj5xg587hfb3x88dytjc91tqy | 2 + ...rzd9d9nszedymt6vd4b1nfyv5g3ne00k2cqf1d4zxe | 1 + ...ww77ga0fk0cdsxtckn180ensm0ns09dyavgvwky8r4 | 4 + ...kywx2ywv64776g163kf3cefzwz3694bxebr7svcyw8 | 1 + ...m0hhkv5f63jcf4j05zb3n78vd0qp63fex6qeq4xkp2 | 1 + ...3tt0qcnf44gpzmrtys7c6m0payywz0ebwd84xq28ky | 1 + ...a3yyr5zkyk7dg3xpn2rzrn42dgytz80he4m10560xy | 2 + ...rwxqf32axt398a08qrrvz9h90qzhjq4x86evknssbc | 8 + ...kkahbvyvb8sffh3rwmf7eq5bydnv3vx5gtap05a9z8 | 1 + ...8sf0fpgcf5nth6d4xkhjytxynyqpr8kp2z0nmxc0e6 | 1 + ...gxh7cnypmzrfphqxsy7qtxbqtsfnq1ep7ndksgww2e | 2 + ...j5q9vxs4g30xzwvsbz7hg6nb9dn00tpdc6qk9tyhg2 | 4 + ...xzq69qcqef54brey6fwpv7dh8fqmmgmbzq7a6n4j60 | 2 + ...g24hdjy5vwww4x7y5p44azbjrvzjn1717jas35cteg | Bin 0 -> 256 bytes ...wypz73cj0fkgaachvc33598qjb92j8ctd4j4ng3ndr | 16 + ...npjteafpchkcd19tsd63z67d4m1fxbrwy46skjamq0 | 1 + ...fz3gbm7k0mxgbew3vw5n5bmq6jhakqmttp3r5dbgrm | 4 + ...25bd73w9dazbw6jb2pgh84cpw34z4aga4jzn7b82ap | 1 + ...t44ytv2x4cagakbp8vyced6dxaffy35h6t2fsa3nk4 | Bin 0 -> 76 bytes ...29a8rvrkwbhyktew1xb3frek1atfrxzw33kq8ssgh2 | 1 + ...bwa2c3bmhgjnc1qmt5xrhnr96aarma0tk1n2dz8sft | 1 + ...ar75v78qkx3d928h0he832sqbkctbmcrk5fe9ws8ba | 1 + ...0vfcsy4ex7923x16y4wrhh0h70kenfhy215j09jf28 | 1 + ...wmgvasgfdha3k13fyf7h2m6mg00kd77waj719nhbfe | 1 + ...56dm9x1mzfj5g2th5wmys862hry0ryn5rde5xg3be8 | 2 + ...2pz4cpn6fxk22zay0d1g8k7nzbhffyf573ajvg3te6 | 6 + ...3zs63jsevc9x72va1apz2t0ynsktxdxryvsf8bpt10 | 1 + ...6hd1d29xjz910rz9haaxdj81atz1gpmk6a8910w5jj | 1 + ...166zk28n709g67hkqn9e4vb38t749q18srgb226yhy | 1 + ...dqfbtbahx5wngqwwzjrs59v7p10gfcndybp0d96j6j | 2 + ...7ssenrycdbatem6dtavfcxnyqs4qmaca3cnaxk1bya | 2 + ...8wqbx83fgq50mww2ect3a8j08189dy7v8663mrregr | 4 + ...w3wrjhp2ywmqdg8cbgedrjy9apfx30bvm0c4h4w9gm | 9 + ...dm8g9sepcbgchsj5gjfhqnn15r4xgxzv225hd94dqa | 2 + ...t61ess9kww0xvgsq35ej5new78w63pzkhfc252tchg | 3 + ...4mctxj9r2m4f7mp8cdmg1s776c0feyxn27h206yms6 | 5 + ...5qa0n4pp10ejqmt8qrzy6wvwkja36my7rhtc046q14 | 5 + ...3ttywnza76t2k3z4qvrbmyg2b9ptvr7ennmym1n59g | 1 + ...bj1ak3n7ercyw3x0f3nf884dja04kcbg7wey0kfvxc | 31 + ...tvvynb5h7hgm8py35yf9ta0r6psqww75yg99ypm26g | 2 + ...gkggtxf22b7w6d38faw092jf348v67vp78dc7esj1r | 1 + ...e036b3prr4germa9hy89g82j908yd9tn2pg7vds984 | 1 + ...0v8nk3akyvwhn06hwzz1b1ssz04n83wwzc1ex5p0tm | 1 + ...ksqp4rzj5czsyq8ad6dmr0zbw8mwqpzpyt5zgvs638 | 1 + ...fn9cmx58aw16edmv25m9p93zvvp2wx3y9fd0e9ktey | 4 + ...9wfbcss4wzg30xfctg28sang4r84taka353p2j7v3w | 2 + ...5t71dcjjsxgs535bvcjgn24hegspkjfzsdbajznj4c | 1 + ...ags1x4xer51704f72d0ymmk40kabm1eeezg84rf8r6 | 1 + ...st7rt4c9n8pqq0t14s83m0akm8cx594yv0fnc5zmg2 | 2 + ...5adm1pqs5928hf33j2sedc6j7try738exxnh6hypc0 | 2 + ...w4p18yyc3a01apa5qz0w31n0sbgbwj1jxvs3dwh8zc | 1 + ...3t34dgg13219xkkbakdj9wgrshqsg2vqmj82t9hxm8 | 2 + ...sr0jjm2qa355th3w231761y1s3cwy2bqzd7eam3wbp | 2 + ...9bjk8bhnjw5zvg8bmm9tbvfxjk0vp4ejy7yqn51cat | 17 + ...2wxzhvb64j5v9y1wsvw25wskfh6r4r41dhcjx9vf84 | 1 + ...bt75p0d02masjc7bb36dqz3w478hrp838z7vgnmkfc | 2 + ...n1mgbwk5sm1eksq5rdw36x3qs1s410zsd7fyz8tb7e | 1 + ...9y3rfa7r2p2as8e6cb9nd4mcze4ez61hrdc59bj774 | 17 + ...hhbw4nq8hp3bnekcxcgkxvmz213h30h866bw592m50 | 7 + ...bem843j8vaevc0551zcb60f8br7ezhwvyzfh8g9wdw | 1 + ...8061ezanp6hv7db2605w2r8v3r092yfcs6bnj4fxqy | 1 + ...9d9fqq2p5tbxy7bg0kkye1zhj9dg932bfny8h7j412 | 4 + ...wspeerh2t52fm38ngbcv1a0vy24k6j2hykbtf6g7vw | 1 + ...nec3t7xfrezaacqkt64v40xmbapa90ra07h5kqfj12 | 1 + ...nqjd3axjyy7vswtf683s63g7x4qbtynp1xjtpawrx0 | Bin 0 -> 266 bytes ...c2sv4nwbamhn2p6es0n4t1r292078dwe5w9mwr1j8t | 35 + ...re3dg37xp3988dzxnkeaezejnbejvjt93b72g20c5j | 1 + ...r14gk3a7rr65r5tk7hfat39pevmz8why3gn0tvh57c | 15 + ...wqaa2w39myhpa309a3b2hdr202f63jfbr343nzhmza | 1 + ...5ewyq17ta0sadjn489c4dpkgn5bnrmw6be2tmw0dw8 | 1 + ...sqt9zk6h6bt0tq2wf62xb1pck71qvn6r8d0g70mmja | 11 + ...wyb9ad0rfk3yjwtfjha05etx8te3peqbwddheh8fwc | 1 + ...tjskn8hg3ydkemexpfa75fvm46rasg29y7zjkd7za4 | 2 + ...45r3n70nw3wj6d638e448qf6zbrd0mt87j9698pyj0 | 1 + ...jyccjejyze9n80tsqf7xsjpq5nzt1c21g8rmsa1khr | 1 + ...ne8e51c1hch84yxk993218ykvmfp3gq4c66r4x22hw | 1 + ...de5sh1dmy64dvf4jjs30x34d291a6v6r2d03nqnpvj | 1 + ...w7nq6z3pdayphm1vyc5rq1xsd9fadnp8m3y6ykep1y | 2 + ...j9bnaksy94s17nvg4gef25kr6w1p125bq2ypdwv7ac | 1 + ...y1mf9z97wqwnxyrhj1qrt0tydh3cgttqwhpdxyk6by | 2 + ...4nfccdc4nxyk791qsyfeysmt4w73kr0t1xbffvyv76 | 1 + ...0k36mhsd91yaj4gkennz0hng2992z3wc1d2b7xh1b6 | 19 + ...exx9baft7b1mvwk8w7s45arqjmgph7gepxhyjyzfyp | 1 + ...jsfaczgb0t5ef708k00m489v4b8nrkhz4y6nnxcf40 | 1 + ...z6nb3rz8wx7y76cymb95zt6z691adqvfnpv80yvsy2 | 5 + ...k3gmkbgwb9fe497h121av0m23cnd6zk1rr3fyp7hjr | 2 + ...d6rzthp5zxm8jg5f6nh6yqs81fefzxdy874fmh6kg8 | 6 + ...964nbb5yb9ps6jtk72grm9y99dv2q7xc1nbk41h5fj | 1 + ...06rh07tncp10v3ck21ftg8esb1ez461dsrafy4b1cy | 2 + ...g712vt6x1b3zhcj1s1p8jxfen93gtd42fxtjktwykp | 1 + ...2htwvdcpehh55smk7n56fcmz7mmqcpfc2k83q51qkj | 4 + ...5xrkzh6cbr4afqcawsaredtfg9c5ape7seebsaax4m | 2 + ...8a1df23mmj32g64hykewsqzng41a5zkj006089msq8 | 1 + ...ec8gra9kkb9kp03kfsq32en9qf0xnq8e3628mk4msa | 1 + ...6r68778ggn6d8n6npcppzwrkfhzk84jxv5a4ty4rgr | 1 + ...exssab5tdnfx7511f6tk9p893yhkvfe0kw4scj03dw | 2 + ...85j4ftnhe1nvktt9j6dmch9hj2bhwcqzpjxvws2jrg | 3 + ...hkdhwqsd9t5eq7ks3wf602jf3bwt8eczx2vybh6zc0 | 4 + ...hyj7wq34fhptmx4amwpefx3nqsww494c8wyrz37eva | 1 + ...mh1pze8kkvezr7abqjr3tnhpqbbxp48kd2qwv0wk54 | 10 + ...k59m6rrgjabzhxmr32c09fh750e6k03zfa20k2vrxa | 1 + ...jsxa265sxqyb2cwx1thqtexxcar9egnjvnpcvkcrvj | 1 + ...kydgt59x46cdhf6vjhy39pe44ge3rvkhvb1nkwb2zr | 1 + ...qckb2scmz4kjf7qt1yztrsfky9qraatwe03x51h7k6 | 1 + ...vw1ngyxqxp5wn2km4cd12kbm9cye0pz29wcymqgwgp | 1 + ...2bjs2xxz4h1frvp4kewrt6hzem2ksne0k68c6w2478 | 1 + ...8bcx0bhxt4bc16ybcgjxgakyhz6081ej47wwb6yr6g | 1 + ...ryqvfm418005sc8r4bfm6v9ys4bbrmf0x5nnvsn1m0 | 2 + ...1q1k0181fd425hst88zjpc27fcjs81z16vp3f89rm6 | 1 + ...p3tct6s8eqh3eck88e5aw9sqj3ga4yzznm2m2j0604 | 2 + ...vjgwmv5q3vwyd58gkw4gc501v7zkwjx00pkmgkft22 | 18 + ...1ffmaw8crmjm9de5g8zqtarpbwr23epvv20t5bs8x8 | 1 + ...v083f1apdzf1kg8vbg2jjfnvxgz9z00xa1h4mf65sa | 1 + ...0xsh5caxhzqb9z8nwpjzsvr0q8g0fjkz3y4y43kdjg | 1 + ...xey2qy8j4gqm0rd91k8fbx1p23t4nwmc7gabhafhsm | 2 + ...65mn3xv8v3v6zetbedfg88vjcvffa19ebk98pc5t6e | 1 + ...c9yjnew3s8krzbcd9m8b567mmq3d92b7e6henf2nhj | 1 + ...gxjckb10wqsjcp91bmtqq9chq2qq5gpdyym87v6q1j | 1 + ...8204mejxydjsawbrhn7vje3xjgaar0cpk7zy64ws0r | 2 + ...vef7cvxgb2tybnypx352v6tdbpmr49vx29z97z5jtr | 3 + ...953c90pegf5s0v2ehgb286hxrsgzh77cv6mx6zrfa2 | 1 + ...jegx974khs3jmwa42r8h98wypp5gsv1ss4s8je0166 | 1 + ...qhjcy7hbng5ndn9f36zaxab33220jxj2d0q7rgt72j | 11 + ...fa3ehdtsn1djntnwmv4mn2jm17t3t659k2b3mn1ryj | 1 + ...y1chwm64dgy0t105pr72a9se3x4e75xennhgf7fct2 | 14 + ...1d2g9vv3w2s6eh0fgy6esppgtmhary97nfcjqgtfza | 16 + ...w7wxymampccdp97g9rzv76qwxk7vj05z145zenb364 | 2 + ...0apphqhr3g24550pxepzcyb5j2gp8px27fdjj1dt0r | 2 + ...zdf4ndsymnwtkeh8j0tztts0y186jq1bcw3wch8pe} | 0 ...z5en5ybbdkbh9axzqq7c4wgs8rt6mctebe7zf9kzy2 | 1 + ...6faf4876a11a92c2e045c0ad0fcc738399f61fc240 | 1 - ...35d3dfa3145613e296cb645884ffe0b885b63bd99b | 2 - ...6149d6c486e771088809bf02e59aa61ca3d1c3e2e1 | Bin 74 -> 0 bytes ...429fd729ffc1624caf063177229727e526f3dcbf1c | 1 - ...ka9q4c2mgw2zqpxgjpmtbrpcx3q4ywn28z3hh4ss9r | 1 + ...8fveg5getzbynkzmb3t77fh8g40qsq7xp2ebfm6ye6 | 1 + ...37vrcb0qn02pw3an43bzssvwsrc1e4t60fq0dknhc} | Bin 34 -> 33 bytes ...43def521c0bf14f754fa13984e8f6f4b25e3fe19fe | Bin 6 -> 0 bytes ...7fac90f1bababca6ec0095c6d7dc6fdb4680112804 | Bin 21 -> 0 bytes ...42d6aca8346cd197d647ed119cee4a6e5e95785183 | Bin 88 -> 0 bytes ...ph5gamd1qcg99hg1yc9c37h5ej81ny8m647z61vj0} | 0 ...e66a33a33b94a6e6fc11da8e0ac8dc684550637684 | 1 - ...4360e307c4f4b41dcf7a8fe4db7b82dde9103e1351 | 1 - ...265651102ad3f0d53bbada124914d102b92f2be068 | 1 - ...78f7092ae6217152bc42205385d0b5996721c6034b | Bin 22 -> 0 bytes ...5w22w0a3d2c5tddyy9qwdjg55hj6ve1xmfnpct7dj} | Bin 2962 -> 3036 bytes ...a99736fa4eae1ca1a646bf880d8b5894c955033450 | 1 - ...dbef5b5eb38c4c38d887618ff5e94a8d117d4973df | 1 - ...ap88t5te2mew2v7b9ekgkdy86ddj7kyg122q62qyrg | 1 + ...2gqsr02f3mbqpv5sb1arw5zcrvjptra0e18973v30m | 1 + ...0f4bwrk39hybvx8szvyvqyck9ad0aejq1zz34tgcby | 2 + ...wwcdggzxf2s57jye94rmc46zrnd8551hd6gaaf0t0r | 32 + ...d2gzh8zfzp34tyr6eh4jq6nyqev0nbgvtpswcybxrg | Bin 0 -> 8 bytes ...z1gbe2d7tkmrb5jab1m391vjpytdx7rgx8bne9ams6 | 1 + ...dd8596874c5d0b7fa33c9685fb77ac22738dbe9edf | 1 - ...70c99715c2701e115f3023b1e7893d335bf807d4c9 | 1 - ...38f98eed6e39312ebf0b61fa1f053b5cdb3c8869a0 | Bin 67 -> 0 bytes ...eb7973a5c90df1234758b5ee02c97755227a084e3f | 1 - ...e4phj2re52zkjrh1vj0vgh66t73e2870bhrrvey074 | 1 + ...c7bjwbwg1ycpwcfp5dpmmjhvm7jk2smf2eevwcsvjy | 1 + ...8b2017b11348cfd8bd0f591c2abc2bbef7b6e95134 | 1 - ...7a1141b4d6b3ee23fdde1151f799df7c3d14c86ca1 | 1 - ...ffd5ae2c195565e2e058ec518421272eb952dbd429 | 1 - ...0bb3247f783fb8fc33584238baeb1519ab70b426a1 | Bin 1990 -> 0 bytes ...42085ffcc424ebab149f1c85bdb6991de0b4ab86f6 | 1 - ...3816c93c0d9c830264b24ca58c386075072b388372 | 1 - ...f506e2660aa0352a11c83af4f9e58b01169ecb8ac9 | Bin 67 -> 0 bytes ...f697cve2978kqd9jby90x9ekg4m8m5nysp1jngy8jc | Bin 0 -> 18 bytes ...46f077b5751015cea9dc045849d65509918973b62d | 1 - ...8e7b03f3cc4cc9e948192cfd5e7d0cb77b31d069ef | 1 - ...nee7h4x050p29a485e3t21m37hsa5y7a1wn9amb3wc | 1 + ...qs9fgddtc4r3s7axbxz1hr61n8rtqp6nsqc0cd5me6 | Bin 0 -> 79 bytes ...6ksepb7j5k4q8t8e3p230agfvr357se20qa952dn2r | 17 + ...2bb5a2789bedcac8a5bd30820c7aac957d3c6e1684 | 7 - ...e97ecbf0812db63788b4eb8411bcddc4be7267e428 | 1 - ...9abf2fe09932db7ef15b4c939c079cf8fb0d275cbc | 1 - ...c684b6d3af75c26871dd228082e3f3171ebda3b5a4 | Bin 171 -> 0 bytes ...f9ebb138147e03034d9acbe149c2c1e93fba076dad | Bin 43 -> 0 bytes ...a53fbde2113736faefe5e5107d3d7da299369df1b0 | Bin 22 -> 0 bytes ...32338d9af447d0b4e17345b30d0874b8ecccc88535 | Bin 7 -> 0 bytes ...e5j750xjrn3kyfs8n3vgzt7389p5z7rnpxdw20mfrt | 7 + ...4fe2jqv1ktz8h03heqvtybz5zekjr3kzgmg73jyzzr | 164 +++ ...x1w6qq7hdrmawg8d8m32fccy4ft8jk32h57863qgc} | Bin 8832 -> 8759 bytes ...d366b028830ebe2391400b3d6658ac26f5dba36868 | Bin 24 -> 0 bytes ...tsxj7hgjqf2j6yrqfqcbqa85px7mms469p8j7n2bw} | Bin 1057 -> 1043 bytes ...ftywfhe3yc82jp0f4jad4wad9awev9gbq4px62c0gc | 1 + ...r5j8mde696580twqnhkvrkjg1b8b44pf9vvyhbyc7m | 1 + ...30caerhxjrabr6nxxp215bmmnzp576ds3n0fnd5qej | Bin 0 -> 4 bytes ...29ac9bea30c17dff4b027e19ec303d143d82cc3eb6 | 1 - ...cy15k37c4rk914aktt5fxp4z1wdv0sjzp0va05a3s0 | 2 + ...4e0c537a889e6d301c9de358ab1959ec04e80af57f | 1 - ...xhgpacrfh1aq74fkjnkd6qha0rp1z9zr22byttbgm} | Bin ...0dgbx4j5a96gazak55b9ekgvw4f0cgk2zbmtjjjkve | 2 + ...760a116fd4b1e13a3905ae812b4c4434484297ca53 | 1 - ...d50023edf88c026e39d5a407c1b7b9155704add33d | Bin 1195 -> 0 bytes ...4f35c608d9f2d2c8e9320b136bd312cf028400df4c | Bin 274 -> 0 bytes ...a3b4887a2672716b4ef446659f26d1c030acedd63d | Bin 96 -> 0 bytes ...c9cc73174b55c7a826833b26ab01a78cc5304725ea | Bin 63 -> 0 bytes ...8d835171514a94c3b3fee05e4cf9caae20e0d28df0 | Bin 36 -> 0 bytes ...92ckej8yvykkywjmdmz3y8k7062my5rk753watxfj0 | Bin 0 -> 326 bytes ...vwya7erng8g6r1xee9we5cjd7ys97ejb0yc1crfpzr | 3 + ...b8741b2c0cbac5e873876430bc8f6e41b5ad0209c8 | 1 - ...dd92358725c1c5603183da9733bb90a125f85ab9db | Bin 66 -> 0 bytes ...b6a225ef83020029066c04ad009ec529c273de0fa8 | 1 - ...7g71e7k6bcs5q565ze8z0f8xna7kpmt8j8kcp7t4rg | 1 + ...8aaza5he7xhhe0pff01yxcft748ycsfxjkz1p1pzw2 | 1 + ...p1b7ghxs3gbj8e6je6nc4bwqra5kpkd4exvremh62} | 0 ...371s3kcysrjp95yrvxpccg93687d7c8c7ypv3xadvg | 1 + ...e7ds6xt6f0mvqxw2gvqmwnsgb15fas67ge0wb0mbe0 | 1 + ...460ef3d4a1d5d7121d0ff0d8d6cdbc374ae9946c80 | Bin 1804 -> 0 bytes ...0223e06edd28d33945777415f169219fc560a6025b | Bin 23 -> 0 bytes ...04f448e90e33f72f377cf4fcc582fa70c9fbeec75a | Bin 4343 -> 0 bytes ...qrc9ajgg1n1dtv2p2v1qjxjgrh535tb5hwqkngyz00 | 1 + ...3nnr4swa87d0ztyyvvrvqb28vkagw6m9xs5vb9grsm | 4 + ...trgawv1nqn6hg52g9t04zpspzmdrakrktftpejfg4y | 1 + ...3xa25drwh4m46gdt9naav2gzf3yg450m3gtd5xhz4} | Bin ...syahmzmj5v16fek5xs8aa88g7nbe8n3mwbkpy4j1ce | 1 + ...w58ycvjfwcfsv728ky0ym67zwq5ghv97tr3gvs709w | Bin 0 -> 16 bytes ...rnbpw8tdkz7x7d88ksjpvma82a1eesd5kq3ma7cbma | Bin 0 -> 198 bytes ...zts2m7cnj5v0cwbp2tzeez12bya52tf8ff84vcx2a} | 3 +- ...4mt72pk0x462yncar39r2ztrbqa2hz12d6akabk92} | Bin 5544 -> 5004 bytes ...b3dwrfzdq3w7zdrmsf5e5ed4djp29a0a2khgaff4ky | 1 + ...qk5d7x3mfk4eh2r3erw2bcjvbb2a4tx5bmyg5h7gm} | 128 +- ...kv3gm079cr4xbqx5r88g7n89246m27dcckhwdrdn4} | Bin 2029 -> 1814 bytes ...xgdq2vw8r2zch1k1m1j8w8s48dtst8d6ckyj2hzg6} | Bin 4193 -> 4139 bytes ...pjfw6n0r4khj55ptpnx9cayycmwj6rb0hc1q6m8rb4 | 1 + ...4np5n178b82cn37w6wwwew2s3hbz2xgtawd732qm4} | 4 + ...9fnaja49pea92v7ynqbrmtv9fmeqp91kpvb5cxkqj6 | 3 + ...pp6xkygnwpdwe92026bywfvmxgwjmms4xp1p031gne | 1 + ...wpn2bs92fdxdgba32kgfqzy20eqysnv60tc2bdtw00 | 12 + ...n6cfvewh2w64bd0za74k56dm5w120w067p8e7s8zqe | 1 + ...eqw4f9cwxkxm8qjv999ydvxydehy9xfrw5x0pynjg} | Bin 1584 -> 1476 bytes ...1v0f123z425e6e676d6jxpx5depn9zy8mrncp32ky2 | 1 + ...0byn41gzhq0wqwfcs77e4kcmftqh4r11237dqpg8j4 | 1 + ...s2n5jd5yenchgmwk4zny08by0d7qtqq6paysg185h6 | 1 + ...9094vv8hx6rmr13g2ncxp0wjj2pbvd73t02498vdq8 | Bin 0 -> 4 bytes ...vp155d7b5sa8zbgqzc2x6176bgs69qz9g0hx99r79e | 18 + ...m9nh1znjv0nh4qcy272s9brgsz64pz4dq52sx0ajec | 1 + ...j76kpffjnykfqxcgx0925xen98vn3t09atfgxapbmp | 8 + ...0pbmdjev80ps4d0js812gzqa86q9jpa7rj5dn29rrp | Bin 0 -> 17 bytes ...zfk0mrj3zpzt3637hkx9zr4578xrbznyq6e2a7w91g | 1 + ...xj30614zv737b6tjpmtnce0992v52bzadh2rhxzjf0 | 1 + ...9arzd57h63sh653erphygbrm9xnq5t4e4yhs2yq5aj | 1 + ...sf6kzdrj1gay4k3mpkhwen689j0z2191zpt6qw1bm0 | 26 + ...edhhm3tshmxs05mtw2vsqenrw8wv4cvw7wae800jk0 | 1 + ...rp6nrpx9teh9vx8q52bwe8pz3gmzv2320qv3mttqtw | 1 + ...0m1ba2zgfd9y9bqvh13wfm83kqbqpsjwhv4mjmqebj | 1 + ...h60rdd803axv8pw9kh27xe1enmx1nhfhmjrags7jy8 | Bin 0 -> 212 bytes ...8cax2dvjwqrnpxdq5srdezdcfwjfsfx6bsfcf9sk78 | 4 + ...k58tjef594ycch1z76qwvtyms5e4rvj2989her6rey | Bin 0 -> 6 bytes ...1c9vqggbmfxm8shz7vrn24bvpvajg0wpdeym43vbym | Bin 0 -> 344 bytes ...trx14yq823m5wamqwvdrz61sh6vkhc4y3fps0m02w6 | 1 + ...bt1mp5mztw0q4nzhjezfq249br5779q1v51s6hk85e | 1 + implementation/src/lib.rs | 66 +- implementation/src/llm/handler.rs | 20 +- implementation/src/manager/handlers.rs | 6 +- implementation/src/manager/mod.rs | 142 +- implementation/src/manager/run.rs | 101 +- implementation/src/manager/run_test.rs | 47 + implementation/src/manager/socket.rs | 209 +-- implementation/src/manager/socket_test.rs | 3 +- implementation/src/scripting/ctx/dflt.rs | 3 +- implementation/tests/dflt_requests.rs | 2 + implementation/tests/manager_permits.rs | 66 + implementation/tests/merge.rs | 2 + implementation/tests/overloaded.rs | 2 + implementation/tests/policy_dispatch.rs | 2 + implementation/tests/providers.rs | 2 + implementation/tests/request_body_limit.rs | 2 + implementation/tests/request_localhost.rs | 2 + implementation/tests/signing_server.rs | 2 + implementation/tests/timeout.rs | 2 + implementation/tests/web_render_webdriver.rs | 2 + install/bin/genvm-post-install | 3 +- install/config/genvm-manager.yaml | 6 +- install/lib/python/post-install/__main__.py | 18 +- libs/iconv.nix | 2 +- libs/libc.nix | 2 +- libs/liblua.nix | 2 +- libs/lsqlite3.nix | 2 +- ruff.toml | 15 +- runners/default.nix | 3 - support/ci/pipelines/tests.py | 6 +- support/ci/tools/open_executor_prs.py | 2 +- support/manifest-base.yaml | 2 +- support/runner-script.py | 38 +- support/scripts/check-commit-message.py | 6 +- support/scripts/check-source-text.py | 3 +- support/scripts/ci-changes.py | 9 +- support/scripts/get-all-git.py | 21 +- support/scripts/md-local-links.py | 6 +- support/tools/genvm-tool/default.nix | 15 +- support/tools/genvm-tool/flake.lock | 61 + support/tools/genvm-tool/flake.nix | 65 + ...7zeewq0aqkcykz2bb1xwhdr99xh4w8sajwhz3k7t4c | Bin 0 -> 26 bytes ...zdpm0keqes0emct1z75fvxqefmg86rabh7f58b9j1t | Bin 0 -> 76 bytes ...m9gb15nqrbsf0s0yxnwkxw8bvjchzt3g3292nfh89r | Bin 0 -> 22 bytes ...k1b713h3b43wtnpxr3k4szgy779kkpt5fmmgk3k7r8 | Bin 0 -> 68 bytes ...6sfd3ce16mneqnza9a6k44q1q0b630bjyjsr0bay2t | 1 + ...9c6vjcr10k5mct810px4hwtvkjjmfap9g4v7vqw49m | 1 + ...a5kfma2ck2ptfr4vgf7x93035nc52ysw31vcmwz8kw | Bin 0 -> 87 bytes ...she2mqj9vscyc77m0xhsh0mv1syb797gssvxk2qgrg | Bin 0 -> 4 bytes ...n8db9k106dpsxg3p4safeddkwr8vyb46fzb42ycz6m | Bin 0 -> 30 bytes ...gh2n7349b26mbas03fnk883hbd8bfxkk3ta9gfzem8 | 2 + ...d4fq9jcf95wvg4fpk73h0ftkyg9dy285arxvgqft2j | Bin 0 -> 62 bytes ...jjf4c6xgejs3ntw83jbpakfa8y26hrka9d9ykpkt7y | Bin 0 -> 19 bytes ...fkg45vmckx2qj1gpm5tbke0cqedmvsgky5pa5fdhdj | Bin 0 -> 67 bytes ...9w8qmh1wz818jmnwnrd7aqq6f7y39hx1fqn6gret3a | Bin 0 -> 61 bytes ...e9wd637rp52z6bazc1ph9jbacfknb3mpkcwff8y8be | 1 + ...y9xan3xzj1vam3946gqbepe41p9471t8f5gw0gfn1a | 1 + ...dpj58bhnvv9zcqaxg1gyf6ty707k25avczqr13n414 | Bin 0 -> 3 bytes ...e39ergtbmmtvn8dwf5rts4c4k5aaac1t6rf7rypn1y | 1 + ...06nwh64gfav2jxv96hbmhrb1t03yqf5e61s7jf7tfm | 1 + ...bamrjk4e8cm6nc8qmp2jx8dkqqhfs13wkb1hb5rq90 | Bin 0 -> 44 bytes ...23ykykwfjgdmnsfxxtrqzfjx5r0b30frarwecm3rd8 | Bin 0 -> 19 bytes ...hqg28z4ergsgh57jkqfyx2p66pdby1r1zs5wth779p | 1 + ...g00cnvfa0gs77n0y1ww0tdn8908qnja4bxw9a7gpmw | Bin 0 -> 20 bytes ...7021ggw1rmd6qz9p3spjn266k328eh5vr8pg0pm2gm | Bin 0 -> 22 bytes ...dmacngtkjb9y93610yv1zh6a9rtd1s6dt3vjz00zcg | Bin 0 -> 21 bytes ...9117xzpdr731k488aawap9fa25kbg0yez0yxncp8r6 | Bin 0 -> 50 bytes ...t8a0r7d706fa7tnee39qz1rbdc92ekgbxtgejyntrc | 3 + ...wrvwgtw8a0xw2836gdfej6qxws1f66ej3hxtqf480m | 1 + ...7ypke6xjfbx2n9jpex04wy2rd0nh950vrteqpx6v4c | 3 + ...tb59xsy5bkg0vacd8wrqrhm8c5s10zd3xcpc7edtn4 | 1 + ...76h73qn7c9yh8r6xfzehdtvsbn0hkxvz5gz1w8cw6r | 1 + ...1mdgj72234c89gzj6k0cvw7vpb5v2n3c9327rmch3a | Bin 0 -> 5 bytes ...pxmbt1f6axs8fh7kz3mb4xhstcm3erhpx9nnsmb5c8 | 1 + ...19bz3ejma3sk5xyk9bhnz9yna4w7qwc5xvqt12n1nr | Bin 0 -> 30 bytes ...xem18j5vnd0db4gmheccjjrzp6114yjzv0rwpvkarr | 1 + ...56vzwq4xcp9g7ncsqmc1n0bpa2391kkjwa70anx5km | 1 + ...aq332qw2ef9kjhgknt5jgzqvq9959t18a9netpe7n2 | Bin 0 -> 79 bytes ...77sr15mekm241hw6307vdxw6jfpvtzcv96e0kpb30t | 1 + ...jgmhyf89bdtnk33sfphqeqh99a7bgnjm672d7491sp | Bin 0 -> 21 bytes ...9mwm00yyna4dgd0vfdd2xsz9tta24qqnb3a5j2fpb4 | Bin 0 -> 13 bytes ...k3np5dvfnrfhm0mp84qmkpbweyfyqtenpb9tybvv4r | Bin 0 -> 25 bytes ...62a9qzh27m009584enyxjpcgrydm3gpvh2pfgragvp | Bin 0 -> 19 bytes ...tthhttxra0bw9pr03wswx1zca0tasa30ban582d1ry | 1 + ...j8gfaf7y5xn1bd2f55dxj285rfmrv8ja0zypgzdjc2 | Bin 0 -> 46 bytes ...x2w3me566fak1gsq86nytqw7x2egsgqntxh4m811rp | 1 + ...06mw10v4v4hs3dd98gfqnpszmh7s2bfp3bgstpx1sc | Bin 0 -> 42 bytes ...62nwahseh6j9eb81qsbggf2k585jf9t01jf5s49cwt | Bin 0 -> 21 bytes ...xrb5teh8rxxejpttpqzwhthnpctfrnxma8fzf07zqt | 1 + ...d47bpcygzb55b6jsjwh3xb7nq5p5swwg52dv0je7qt | 3 + ...73qwy1mj50y89pkcasgkkm326mykrzx9yvx94ts4kw | Bin 0 -> 10 bytes ...cnqnb3bh8m1dtcd9wh20qxbyhggqhk559d4xafecb8 | Bin 0 -> 64 bytes ...2b2f1cvyd4nnep751pzhdh0fn48ga066nn3d2jpgs4 | 1 + ...0wbyzj59320tt8pbm99abg80w2v0spd0v1g1q2jxaa | 1 + ...wz2fcjyav4ksb0rcj53w0ansjt4gb9yh1ynhapkz0j | 4 + ...w2s5d2rq6ncbzmryxtzcc62jz09j2vzb1cs24t8mcg | 1 + ...e3xvpb0s9d1f7ffrnkwrg2h61dqqkgrn5sap51xkqm | 1 + ...apj6jkdsnskpkhbnpxhq75zq69msynk5mab9mgv54w | Bin 0 -> 21 bytes ...65bgt8wk77gp5pacydweetf153h40chbhpb5advvj8 | 1 + ...gb0ky8p285276zx7gnbyfd8ygy3t6r7vrv2x9y7rjt | Bin 0 -> 46 bytes ...mwgxfve8zjkwyag90ha2k573f1sfja9mcxttfmqkw0 | Bin 0 -> 10 bytes ...9xg001ksft36c10dn085qrsfwqv5q0414rnrpwtzgm | 1 + ...4nd9vqrwfx5hb6ve95gbakraz1e9xmqse6m6vyme7e | Bin 0 -> 12 bytes ...hh7c9j6r51vggk6ab360krd6x252xxgh3tdfp6rksa | Bin 0 -> 20 bytes ...dzpff11mgb0mtkjc166frrkre6smknejpqcpt7f22p | Bin 0 -> 27 bytes ...ykf5cbnv0n2r107km5yh0qqmx2vsjjp1qwybpjgy5t | Bin 0 -> 35 bytes ...exxw1y9681n735pv748t072w0qz7s9x23907cdjj68 | 2 +- ...j52m3a64ws7xxvx7qps9xsnhehfay1k6j88tr3ypke | 1 + ...1968q1gq2y6dbw2nbykrrendnqp1stprbxvd7mt558 | Bin 0 -> 28 bytes ...symeqpec56fp0mrr72150b33memf6nex59dhnbkqfg | Bin 0 -> 14 bytes ...red7xrw335kmfkv4px3sppvkjx8kff9ykcv0nfr1gg | Bin 0 -> 12 bytes ...8wzrej02f2qhyj478hsx7jzj55ge236qr4hz2zajdt | Bin 0 -> 6 bytes ...n5x7sxq15qm7yckys35008w0b0d4mp59gcp0th6hta | Bin 0 -> 36 bytes ...mbh2tkh0ce4nq474f49zrg0egdva3bxyhs2m0jhv7m | Bin 0 -> 51 bytes ...8068b46gp8ajd9xzv810kws9j84q5eb2rj5pgmn9t2 | 1 + ...xq2ds6v5amcy0sv3q7s2c8thhpb4tafjsmawb7f132 | 1 + ...mbw1dr6vxhxvmavvsa3zq0h4mm209am9qteesgyekg | 1 + ...a2rpj7esftmqkevjy248v1p0a13rawsz3cz6jg172a | 1 + ...fkpxc9em4mhhhymes72frtqxkjckgjbvwn5cdnzy4e | 3 + ...dmm6a6rbny7cwfsbxz7p2ccdjg3r42cfxqjaqj0vea | 1 + ...pbrm7ks6yytqpe4eye2n8zbhh15n3fnkng3p5m9a9w | Bin 0 -> 25 bytes ...b5rmw43mb4w66amzywjvy5hrdy2zj8s9wy15g2vfsc | 1 + ...bxpwxedbn894hgq2x212xe7nc1ky9brgnqpt9emw6y | Bin 0 -> 24 bytes ...hw0f8kdytdk9ww8p3pb17seayx23p73ye02px68sra | 1 + ...chygnfyvjc98mxcqa33pxqdtny51d3avkgy5rqrmbc | Bin 0 -> 53 bytes ...97drzaeq8r3a3tsb44s1xhd9rq5w34jceqcf0cnzk2 | Bin 0 -> 64 bytes ...n7080jpjd06ttd23q11f1gvf7e8x2vksq2987e74x6 | Bin 0 -> 8 bytes ...3jgagqpa7t8wm0p1cm563cqzs3t7bnma3b1c15ks70 | 1 + ...2zs7xpq5936mtf5cachrha72j0j1512g1c8hbgvmnm | 2 + ...qhn9hdmjz2f11dxm70nzrwmb4akc4rh536xmx8mkvj | Bin 0 -> 4 bytes ...px2ffwwzkhmysrgp72696z3nwm1b9c0w0rjqs21ge0 | 1 + ...qeb27pkvczyyz2b75c59yaa5c9sghmgrekcr80ea28 | Bin 0 -> 25 bytes ...9y9cs4pzfg1bwv73k271wp240w8gnpgdbs1532n3mp | 2 + ...tvrqmg8a20yn6zjg040fznngbfzqc6wd8hxqjza3de | 1 + ...bj14d4d6jx6t9dwevjz9qjy9hvkm6yq0zsvhq0traa | Bin 0 -> 13 bytes ...vvbrx1tcewc1h1932qkz4qm9yjdbs7g3072ackqg06 | 1 + ...rh5101zazqjygn9mnf19aa05ybkq9hyh1w1as4pbjc | Bin 0 -> 86 bytes .../tools/genvm-tool/fuzz/src/scheduling.py | 346 +++++ .../tools/genvm-tool/genvm_tool/__init__.py | 4 + .../tools/genvm-tool/genvm_tool/__main__.py | 19 +- .../genvm_tool/cmd_build_manifest.py | 3 +- .../genvm-tool/genvm_tool/cmd_codegen.py | 3 +- .../genvm-tool/genvm_tool/cmd_configure.py | 43 +- .../tools/genvm-tool/genvm_tool/cmd_docs.py | 3 +- .../genvm-tool/genvm_tool/cmd_fuzz_corpus.py | 429 +++++++ .../tools/genvm-tool/genvm_tool/cmd_test.py | 3 +- .../genvm-tool/genvm_tool/codegen/__init__.py | 3 +- .../tools/genvm-tool/genvm_tool/codegen/go.py | 24 +- .../genvm-tool/genvm_tool/codegen/model.py | 39 +- .../genvm-tool/genvm_tool/codegen/python.py | 8 +- .../genvm-tool/genvm_tool/codegen/rst.py | 13 +- .../genvm-tool/genvm_tool/codegen/rust.py | 20 +- support/tools/genvm-tool/genvm_tool/common.py | 25 +- .../tools/genvm-tool/genvm_tool/formatter.py | 8 +- .../genvm_tool/git/check_for_push.py | 12 +- .../genvm_tool/git/create_branches.py | 9 +- .../genvm_tool/git/verify_pushed_executors.py | 6 +- support/tools/genvm-tool/genvm_tool/io.py | 82 ++ .../tools/genvm-tool/genvm_tool/manifest.py | 6 +- support/tools/genvm-tool/genvm_tool/misc.py | 71 + .../genvm-tool/genvm_tool/tests/__init__.py | 25 +- .../tools/genvm-tool/genvm_tool/tests/cli.py | 29 +- .../genvm_tool/tests/exec/command.py | 58 +- .../genvm_tool/tests/exec/process.py | 46 + .../genvm_tool/tests/exec/service.py | 56 +- .../genvm-tool/genvm_tool/tests/exec/step.py | 18 +- .../genvm_tool/tests/stage/collection.py | 74 +- .../genvm_tool/tests/stage/configuration.py | 3 +- .../genvm_tool/tests/stage/execution.py | 23 +- .../genvm_tool/tests/stage/filter.py | 8 +- .../genvm_tool/tests/stage/scheduling.py | 429 ++++--- .../tools/genvm-tool/genvm_tool/tests/tags.py | 68 + .../tools/genvm-tool/genvm_tool/tests/test.py | 3 + .../genvm_tool/tests/util/watchdog.py | 70 +- .../unit_tests/test_codegen_detail_suffix.py | 94 ++ .../genvm-tool/unit_tests/test_fuzz_corpus.py | 150 +++ .../unit_tests/test_fuzz_corpus_layout.py | 27 + .../unit_tests/test_process_teardown.py | 90 ++ .../unit_tests/test_service_semaphores.py | 356 +++++ .../unit_tests/test_service_startup.py | 79 ++ .../unit_tests/test_watchdog_ack.py | 55 + tests/presets/python-fuzz.txt | 1 + tests/presets/python.txt | 2 +- tests/runner/genvm_tool_plugins/afl.py | 594 +++++++++ tests/runner/genvm_tool_plugins/cargo.py | 340 +++-- tests/runner/genvm_tool_plugins/docker.py | 84 +- tests/runner/genvm_tool_plugins/genvm.py | 133 +- .../runner/genvm_tool_plugins/integration.py | 150 ++- tests/runner/genvm_tool_plugins/ninja.py | 45 +- tests/runner/genvm_tool_plugins/pytest.py | 152 ++- tests/runner/genvm_tool_plugins/runners.py | 55 + tests/runner/gvm_extra/case_inputs.py | 17 + tests/runner/origin/base_host.py | 36 +- tests/runner/origin/fees.py | 3 +- tests/runner/origin/host_fns.py | 22 +- tests/runner/origin/log_asserts.py | 12 +- tests/runner/origin/public_abi.py | 88 +- .../assets/v0.2/caller.py | 27 + .../assets/v0.2/chain.py | 15 + .../assets/v0.3/chain.py | 16 + .../assets/v0.3/helper.py | 11 + .../assets/v0.3/observer.py | 60 + .../assets/v0.3/self_recursion.py | 20 + .../assets/v0.3/trap.py | 11 + .../assets/v0.3/user_error.py | 11 + .../system/cross-major-observability/test.py | 642 ++++------ .../cross-major/assets/v0.2/blob_caller.py | 11 + tests/system/cross-major/assets/v0.2/busy.py | 12 + .../system/cross-major/assets/v0.2/callee.py | 11 + .../system/cross-major/assets/v0.2/caller.py | 11 + tests/system/cross-major/assets/v0.2/chain.py | 14 + tests/system/cross-major/assets/v0.2/loop.py | 11 + .../cross-major/assets/v0.2/signer_caller.py | 11 + .../cross-major/assets/v0.2/user_error.py | 11 + tests/system/cross-major/assets/v0.3/blob.py | 11 + .../system/cross-major/assets/v0.3/callee.py | 11 + .../system/cross-major/assets/v0.3/caller.py | 12 + tests/system/cross-major/assets/v0.3/chain.py | 15 + tests/system/cross-major/assets/v0.3/loop.py | 14 + .../system/cross-major/assets/v0.3/signer.py | 11 + .../cross-major/assets/v0.3/state_caller.py | 17 + .../assets/v0.3/structured_error.py | 11 + .../cross-major/assets/v0.3/user_error.py | 11 + .../system/cross-major/cases/routing.jsonnet | 95 ++ ..._null-mismatch-callee_null-mismatch.stdout | 2 + ...er_null-same-callee_null-same-major.stdout | 2 + ...ller_plain-error-callee_plain-error.stdout | 2 + ...-reverse-callee_plain-error-reverse.stdout | 2 + ....signer-caller_signer-callee_signer.stdout | 2 + ...tured-error-callee_structured-error.stdout | 2 + ...caller_v02-to-v03-callee_v02-to-v03.stdout | 2 + ...caller_v03-to-v02-callee_v03-to-v02.stdout | 2 + tests/system/cross-major/test.py | 1141 ++++++----------- tests/system/manager-socket/test.py | 374 +++--- tests/system/parse_version/test.py | 5 +- tests/system/permits/test.py | 75 +- tests/tags.json | 148 +++ .../simple_deploy_then_write.jsonnet | 8 +- webdriver/src/prj/package.json | 4 +- webdriver/src/prj/src/duration.test.ts | 40 + webdriver/src/prj/src/duration.ts | 65 + webdriver/src/prj/src/index.ts | 262 +++- webdriver/src/prj/src/semaphore.test.ts | 270 ++++ webdriver/src/prj/src/semaphore.ts | 156 +++ webdriver/src/prj/ts-node-register.mjs | 6 + 1348 files changed, 13438 insertions(+), 2932 deletions(-) create mode 100644 .claude/settings.local.json create mode 100644 AGENTS.md mode change 100644 => 120000 CLAUDE.md create mode 100644 crates/fuzzing/Cargo.lock create mode 100644 crates/fuzzing/Cargo.toml create mode 100644 crates/fuzzing/preload/Cargo.lock create mode 100644 crates/fuzzing/preload/Cargo.toml create mode 100644 crates/fuzzing/preload/src/lib.rs create mode 100644 crates/fuzzing/src/depth_limit.rs create mode 100644 crates/fuzzing/src/lib.rs create mode 100644 docs/contributing/explanation/fuzz.md create mode 100644 docs/website/src/spec/appendix/internal-constants.rst create mode 100644 docs/website/src/spec/changelog.rst rename implementation/fuzz/{inputs-genvm-modules-complete-json => inputs-genvm-modules-complete-json-curated}/1 (100%) create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json-curated/2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/0/00d3ga150hdc2vahv7sek5vhev60wgxrqmchnxqg3tkgj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/0/00esba677v1ndtj0816kwhjph61a9mtjqrhqp45j4pn8j create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/0/00m6tt8xf34nkv5f4jvcv7t5qnbvq8e6vspmf0we96ydt create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/1/0113bt3yk923gfp1a4cnxp8n9k0nqjsd6003qrspy8ng0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/3/03tgtrmf50h7edgb1jvdpp767qs4j6vjfp33ty9rr9w1t create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/4/045698ck5t9h0fn9dbv9x26q7gxekqbn9chzzbskfp53c create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/5/05r1ay1bw7ngb8zmtkdfkyvrka6qbjs9jwv46mt3cbgde create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/5/05z7425x8bd6nvkk4kgq4f2499n09vpv1paeafe025c6c create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/8/082658bdw9cssdkncjmxvzbhmff4n1j4pwhntw0n9mj2t create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/9/09j7nh5jet076pmv9f8pqe6swkjsqdqc9yxw67105wrnc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/a/0a34bxzvvbkk9zdf1wh22spsbdwbqeqerm0e43pv2ngct create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/a/0a52mzaj1hv1tb2txtrjrs0ejszt3fgn469604sqnqj6w create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/a/0a7d5brepkxdgktr1f7xwgdg5swstym8vsx6fg3ncrmp4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/a/0asfwrht8gf6bz9tf3ag2ah4sdtaexyeeaatfy86cfbse create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/a/0avcwmc836hmvcx4tcsgxjt88gfqgr6crja3s08qjb2em create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/b/0b3zfjthc54aqca5f5q9776emq6rtmc4psze4xt987swm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/d/0dkbwhymbmwe8yfb2af3mdmd6sreg4w60t8km5ctnghr8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/h/0h92aedsc1y7xgr695dmyvyf4zm587ab3yd1acdhrvr9a create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/h/0hfwbfz1w1wys0ckdwxg5y4tvhshzwmq46h9mh79qw1ae create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/j/0j3dp76k6cfjc5zkzec3cn0t5h0t58w96yyzeyhzsm6he create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/j/0j89xg8cfb3xb62hhx33xhhd813c2qrfrwjjgj5ebsw7w create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/m/0m4rse79871djv54arat6a564d9wk6b32et8xfaatccqr rename implementation/fuzz/{inputs-genvm-modules-normalize-whitespace/9a70598e97b57c7a6c6d7d77cc64509b13c0caf72203e8cfbe0c6f2e3446c804 => inputs-genvm-modules-complete-json/0/m/0mddxqyra4jsre5cw5fmk3fg3y4gx74fc32dxwggnkqz6} (50%) create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/n/0nz26d1454cv5768t5j9se7txfecpxxsm9x8s7r91qf1e create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/p/0paa3j6967xv5d1a2074nyqtnbbtv76pvbpzgevzfgy54 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/p/0prjncdjcy75m9m6q0qk6ezw8zj1596rhj36e402ew754 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/q/0qn2kcn21t453s1b2ngz23bwnbzkm23e5ks6x0v2z5td0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/r/0rtkxs54nn6ex33a27wg1ppmthvkknkp3mep8f5b98k50 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/t/0tjjkt9cpff1d660acdtdzdpfv43mfctgbpy3he9beysw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/w/0wqka8ved58jyqtjbr88vpkg80h3sbf3pjyznxq7j1904 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/y/0y24j1rns05r9jsbwe40h08etjq468myc7zyqnr06d3et create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/0/y/0ynj4895jyafkpw0jnvzmxdnhkv2p5jz9p6kc483sgk50 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/2/12qz7rfp162bvpwtqdcsjfcte6gnaqhbn0brtbqmrfeyy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/2/12v1440bpgmpf20twrkek8mv0d8005q3q499gz8acnzmm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/4/149cmt9ms89v020yrryvpa8jvmc20h657s4n8p4ypamy0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/4/14qyfsbfxsjvhq4h4px6vne04dr3tedqcnk65kx1h0x5a create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/5/152sp9r1b3r2ws1hk69wtkfwp9rrxedhcyss8bdcnvaha create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/5/15bp4vcf7xkp37ac1718tt0rxvgts1agh64p5aw1fhxbj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/5/15sf0t7k419d92gz7xhsav1gcmq07n07wydnnwsrgphym create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/7/17hz2hbxc3cj4tw3tje2j8d5ty7kc6kfpsmfte6p2twm2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/8/184jstbv6j02k45pq0cvc2v78est9zdsmbnrffr0r7nv2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/9/19dp9v5s7zg0r44q1q10j4cw9xczdd69pvt8v340a6f8c create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/a/1acaehj72a3q4n0svg1mw6sr73c755f4fs585a33prhzp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/a/1aj0wvbm2cwde34147rf5ha82ry271c5rc0agxjrc47x4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/a/1ajgxbt71nyw23zrd1qy323jtwynep5d2pdaav2tffxp8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/b/1b6evrr1ecfjkt9k5kg0tk3xh25s33wx4ww96573naghw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/c/1cph9wc8w0a8z0w2028vtcx5xs4dgyzf5w1s7jdppr3xy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/f/1f72s7zs5t4wmrbvk0yg71wxveqe55ztfpg8jbsa3bqmg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/f/1fghdv1x7bnfg9pavb755sf0sc40qmhsbcwqf5nrs7ae4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/f/1fjcx4dk7z22dava03ptrv3ymfjycm4m4ffx7j0d98m4p create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/j/1jj15a1rq85qvscnan6she76mdje40y78df623nha4fyj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/k/1k3r491j8kg26xvpnfe3a0yb3ve9wvy43c3n09dgv7ctw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/k/1knejvhs0c6k96dxf9zspqgns0xwvzn3ntmnc3m7hfgbw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/m/1msmyw0naed8mgex7ss57qmqbfwapn427xst8jsqe3ngj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/r/1rmm9pj961n1pq2vsy22xpbxw0nhyq93px4r60hahzjma create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/s/1sf4137gha4gmqm24trscfjqc7jm4479w6qj1mex11fry create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/v/1v0k1nwfyggr3b0wc35azwddz7t89e408jvrrapd5edrw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/v/1vfxfq59pf73na9hbcz0b6vdm97rwqjegsmyfg1vqsm82 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/x/1x74f8x8hn228h57pkdye6wysbhsrrhjw49z4gepbqzvj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/y/1ytqg1fmemq3efa31gttwkc9ks89mdx2dbzc5qhgj92s4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/1/z/1zbxn03hxa23gxe1md3gbn3zv7cngzcerj1j675n9780a create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/0/20n3w7v3kk9wzmhsayk4at70qkrajx55jgnepk7z6hr0r create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/1/210xq1kcqh6mwx1jv8e4m8p45ep59sdmv28pmzy4pw1a4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/1/21ya1p19ay28psnn5f4zhyd2t4kfvda8a4y3dpc14v5f4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/3/23vz35x95rw4mrq1a5fxzy55qjks164pc29znrc45cdtp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/5/25c2p7k1zb2gkvyfdaz725jw76qrm1wncjwqkqc4kk1m8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/6/26wa4awjzxj0n7cxbv03m54mfedmavr2f6m01vv3zvtte create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/9/29tp9v5282spx6x5aagjzrpyypvmtpkq3r0rrfdg4m67c create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/b/2babs58b5a87gfxksxtm649ypqgmkacmejzry836t92k0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/c/2c95ns6xkaakcy132nmxmq4x2zgqr90x0dmsnz627ed66 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/d/2d8qwhcyefn0frp5r1ca0x7c5fx7z73799v9jgh5kznrm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/e/2ej6zv22vbtxd1h5fyy6aqs1709dm2kcner8xgmdjw3gy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/h/2hmtt4mqq71y2pvf4twdsffeyvc71wp3h2hvs5ahme1nr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/j/2jng17dez65x6wswjp25acskmrx7b5tcmq386s35axwnc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/k/2kqfqq0x171fhs9f654mhmhzdam101sx78y1pg4xvzj2e create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/k/2ksxsdkrcj75gxj5bh515daqdr49gxas5gq4w3mne8fxe create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/n/2n3jwfv96hh6722m749ghsxbesbbkgqgajvx8czn183fa create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/n/2n4t3zk62tgnhnhvqgzvfw352g9yy662b1fn2087cqc18 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/p/2p0k398b7qp548psbch15wvnbqehqgkz4pf2gtj1tpb7m create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/p/2pm3p5fxq3fpxt5g0j5tpje93fn9r6c4b4qz0zmfn1df2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/q/2q195hbtgbyx52kbb43mdbrmt6gzsc3693yd49g1j2jga create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/r/2rmtbeedk3mnayqb6z0dj77583dh0arvgz4456d2yp2wy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/s/2s4as110gqppmf984s9600v742ztpwrbf4gkgkrayw2q0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/t/2t0ftjj6197wjb7dqch5ammz2f5esnh0zrw4fh1vzk35e create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/w/2wn6p7whcvzg482hfct6tzax39zggc7bt3qqxj393awqr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/x/2xa502ckstahndqb4bqhxdwq7hzsxbw4a3dh9008n5grr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/y/2ykbambjhke293td0wnyhmqnprz3dr3kckw2t81vdeq32 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/z/2z3p4rpamny067vhq88ke789xdnyt23zn2ywjq7sbxy6p create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/2/z/2zazarnhgndp91dxsf8m775r96x1hb59bpaa1942fe22p create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/0/30d131f7jpbsdzp0t3f3ry9shwecm2mbn3sfxqy4vxqrt create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/0/30hhad75c83y5s8a6z9ftdbnnmatgktgsasr18av2cj36 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/2/325vkc6r7q84h3g63whr2hdc69chys6bafjqyr21vd556 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/2/32wc7343p2qsgg1vr2c8cfxf29rxjte6xaf1j3kqrthp2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/2/32zvz3ffjf0rsaayrf4drj4x6a87162a5dxa9x5gbyy40 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/3/335qkpa6a6a55kg78v14wk3yyesena6v3304gw7mp792t create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/3/33ew3bbq8bsesg4jf189jf9ard8cnp9m4sxsxsb96q3fj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/3/33qz17sfvejgr7dfczk6w4qbt77qwanv1307w4b8ja0ma create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/4/34j4w84w1cnqb7cr41p52saatagrqsxk8wj2ehhbpc7fw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/5/35237jnwf7qj4e3jy7dngv203sb8da6za3tmdtaz8m71y create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/5/35wd5p3vpd27tw2r15btrpq06gt1b708brb74z1z6k5f8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/6/36qhwstm4ezxvnsem3n9rkbwe5971cq5r9eyvt51n1ca4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/7/37223ehxrzsjx4h98n1t8tzxdeez2q54n4ghv7y87h99y create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/7/37epan24avchbwj139h8gwrgrn168hpdn6wctp4w3kvnw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/8/38t9f41n2ynf9n1r6yq9wv9h9zygjpz50ghzy7qzfxb4e create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/9/39jhye51bpxdznqxjc3n7txbqtdxw8tk999evs6pe6pty create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/b/3b5snsywt1yg9608yk9dtkzcsw8j226873xmgrbtx5e2w create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/b/3bc93yvqp1d1zes49sk9vwyf8enqcmkfectpyjg700p5r create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/c/3cv357mm22rrbcdb29bv4883ajrnye3p05wh3p4e9vvde create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/d/3dygjt8z5jp6gss3nfv19ht36jhan7xc4x46dh9wxxb14 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/e/3ejnm2369k6hgrghespqr1pe0qdxrwv8yqrwjpevdvk68 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/g/3gtdrvgpzq462t4wsnd5k20xxfvpwckw3b1gg9077ey4t create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/h/3htw69mppz8dkd8kkysh4gc00j3021v0zv38sy6nhq02p create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/j/3jep0893yw33esbfnsx3vtpn03jw2f2kav5261w8tk8fj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/k/3kbz0gcyv9ydzwdszy7q1c4ktka3rfn4d8pk9e4318etr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/k/3kv8nxj26hfm5ez2vrp38j59q0rpgvxffcvd8x0vme6n4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/m/3mdxxf03629wvddwgvezn1r428tykhd7spzdd5hn2fcmm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/q/3qbv6wqxrtgkh6rbsmf4n7ta1xyndvfaedd6rbk08peap create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/q/3qtfgm5c9jtkw8ae8gwh01s6tkk18my2ag0y7epc1ckd2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/r/3r1fn4qcz970rxcapmbg7axet37yk0c30pden7zfnbrcp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/t/3tx2a7qvwfc8df5hzpjcyhkc65hvjwfk4b9v649x59n46 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/w/3w7w2k51qnmw7z4j79g0dngx0x3xv81fqx11rmktjvd5w create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/3/z/3zrna3xrtgxct2en27tz1pb3v7dvtt5qh2fynhyvmhwew create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/0/4039y0m4gwtzm6ybeecvxq6d297w7h1h3zwfpqeqwejp6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/2/42ckpme1rg6chpv2jg81r2mp6a1pqeb7jnpxkrj1zvvz0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/2/42txhvm8f01c4cdcaymqg3nmjsbc91sxz2xryj3nmng3a create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/4/44nkn4y353ss52zenyq9e8gr7vcarz4y36dtff3nd9af8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/5/454pdwe2qc8f6ck1zfkd4czrtxzbgf92qywfftqgxjhr0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/6/46hzz84st57awtf74kqg6x1ph1nc1b550hxnn8ky5e46p create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/6/46s556f8ke1g4dtjahxs94mzecqzw1n3twh8m9vtxdk5c create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/7/47a21mjw0h89fdx7t27e856cxrbv2ahsh3xybqjfqrq36 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/7/47aenj50bwcb52ts5me0mptej88cabpzew64b22ncw82m create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/7/47zdxfswt8ax6ccwdq71k2wzyr2pv2sd7hcpcb3yes5rm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/8/483rdf9z0bqhr2s4f0s7yw5gawhafpd26csq0xrn78ehe create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/8/488m98q123vvxhqx0aagr7fptytjjm2sesvzstq7vnjd4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/9/49076gsq2b7p3hqv2h0fssazfg0mbppj9hr8yxyhbykwg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/9/49438ym1f018m8ctq0gbb06cgkamh1yb5yhztnt2sbgwm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/e/4e6m73vd7pqnte9f4dmahm7eddc8n3nb78hf0f9d14b9j create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/f/4f82mbvdzrxewmjfyk3g5xg07xn8j49tc92n845861rty rename implementation/fuzz/{inputs-genvm-modules-normalize-whitespace/b82254c422c4a0de4fde9cf66488007a6f787d972f1ff42a8f0d3a07204fdaff => inputs-genvm-modules-complete-json/4/g/4g0fnmrht3baacq1spykfq06esnj3smp0rd5e7jp79eyc} (50%) create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/h/4hn2107rfefkdjabs9rhdsw49zx8y2gx8p2c0qgt21926 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/p/4pr8k38eg2vs9bccsw8mnjcnx5te4y1g11rgme8h3gybg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/p/4pyjs7hxbkmv5bb8nk2ey2d0wjx8k82f81c6768pc92ge create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/q/4qp2afa7b9e3hmb9et592k41sh0f15patxjf2v5y5ax28 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/q/4qqkbm0kf3s0n4adszk893w6w8wnyjvf1e76ye91gg6tw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/r/4rd4fhxdd75yrzwqrt2e1e9wewtthq7qdsxqqdng0b060 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/r/4rshs07vxp9p01tfz7pvd0jraxfs0jee1nw0cwkehxx94 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/4/w/4wey7y6s511635spzptgtg0zhbcsa537xqby99h0nv250 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/0/50sf3sj3zza00020bnq6r03axvz1vksraj1573jebfd6g create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/1/511bbrs4vynrjpt7pmjj4897n9mfpbe50b7rwn7x9pgk2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/1/51dz1xs6nywx9v858m9bnd8ast8y973mrmt6s2kgtp9we create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/2/521ask5rah2rmhtk8w53w5dvfptr9anhetwce58yktk1e create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/3/53nstbc50pvj2vw2nave0q2ry661kggrh2xrzfbnabzeg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/5/5532hjx36v13jedse38grc2h9jcqcrq3panpry2b2cq5p create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/5/55pm4s9k7pjvttjg3vmhhwkvgtp5rt9rren3884mtychm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/5/55y8fgk28sjsw9kc4ct5vaw0nscda5yjqb3wxn81bjdpj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/7/57h0p1x6sm52v6sgcw3k06afpbfxmb9d3xhzjretpzxhy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/7/57q7gt19ynvbezapg0t7ercqeqbyetjdb4h3f7xy7s28y create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/7/57x0e8msvtg6fh2rgj738kh0zrmsnr65xhp8sknvdaf0g create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/8/58s6jqed3mz3m6eaqe529dqf6qrbr9pzx13mer6gwwnvy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/a/5a982thpv82fgbs86s3dtzsz5wnxt0yqz4dvhhwz3r1ye create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/b/5ba7bygx5f8z6r1s2a2519a6c625ytcfwmz4q9nt641qr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/c/5ckz0981gspjax26nkh652wc7tcb54w7fy5csjms0d66e create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/h/5h2g0chm9b3g0gtyv3vwa5125zj6h9wpewa1d9ttasjcc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/h/5h3sncn3nmnesyx8kpmqmvfkvkj44xzebssp7xnczq6hr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/j/5j5yksckw2vp4xrca0xy5xnsa8sy9ytjw2wt1zhhndx36 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/k/5ksca34p8jvyyv4r4t9aq8fqz0wyr6c5w6a5j1cns3wtj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/m/5m13t0nyge0w12tkmwt21zv8gphpckwv79ky7syc8fz04 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/m/5meq1wankjerhv937773xend4eakwq3xfyaescec2yy54 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/n/5nxmsy3nbk3n9x2eezrgbjj21j80xj62n9c8svwt2weva create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/p/5pzkgwrwycj09hfrjtmyfhpgmnerkapbh6xhp55gskj9w create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/q/5q2611whwhv6gmbtrtwm09b0cbpnjr0mcnrvfas0ky1ma create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/r/5rhhmvfczvhj7ba6jaxjqhx7d44drdy8nv5ypw3przvme create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/s/5sjmmjcchvtx07q0s65jd41npa39zadh6pdfavdebrk3a rename implementation/fuzz/{inputs-genvm-modules-normalize-whitespace/b99e1959cf0de1171606c1971933f6b68cfc618b1937fc3117af71e4877ea0f1 => inputs-genvm-modules-complete-json/5/s/5st59vnef87wq5077p90tfrqwq4zwa7seh3erqrztx5xt} (76%) create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/t/5tm51hcwchb3mvj75w58m2grm3dm3n82nvv3c0e6mwv0m create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/t/5tmrg5k6rz6vg0cmfwbrnmbzybvxptypmp4ghactbwkzm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/t/5trdrhkddcaqa06fhrjy51knjj279hx2a87rtc9rwgs7c create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/w/5wqvwve9j7bc3f8x0jb6z5qtff5tqedkwkad3zr0g7y5t create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/y/5y8k3vxza1nxqkpp32q8r5027bbbv4qbfy37ad1knt6w4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/y/5yxxpcxncfjgm9e5bff4v1wbh7pny1gd26hqybg84sabg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/z/5z2n879zp21139g3x4ra4m07sh9s2gn1fwwnn1m1sn1br create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/5/z/5zmgmc6sv8n8tzcz1s8j5cpzq2n7a26ermg60hyz4t1h4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/0/601srznj4t6bk5w9x4pcr0zwxmh6avsnt7gpn0fm7ak3c create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/0/606g3wx92025zvx1dnn197sr2sxja0yvrdy1p97xdxthw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/1/61mta1s9373nq89nvskpew6nssr5b9gvk6dyv1r0jrcz0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/2/620n716s2sn0567k9wwcq1vs380t3ap6m3526mkcgdhtt create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/2/62148mftv5xr6nej0mnpbg4eygjz8mqgfgnt0qsve1pt4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/2/62kak2fjfc2q7p4515s3gt8c42n443gqq58qt9hwcnzs0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/4/64p3kq1c31cejcj9qtn0rz5k7pzevbjyah0t1jsj84cbt create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/5/65jh0f2sd99x7d18esapxv0x0gvqmzzz8r3fw4sg1gvw0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/8/68ka1qexyqvggrsm11r04zrg8bt4ygm1c5jr683y1xvk6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/9/698cfc2vbwxfdptecap1mxfgd5xeprwj203yq0fj9smhp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/c/6c3qj9g5qak95p6mw2p3p7814bgwesxeceqwd97f83464 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/c/6car9rqrptwd0md4bppt1jr9vpf9r4b77a74wzqc1e0pt create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/e/6ebwq1t7yq53h7rpn35n04399zqvqkar42gebmqmbefmc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/h/6h4krjdvvw5pmgfnbbh5tyhw5hfpbtfpk72x35bcvyb0c create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/h/6he21spbt5fm52anbs9a3b7dj3s86f40gg6cz81acrt7t create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/h/6hwdx92zmptj4h2j7zf3r3e42w3zh6bvbrz5z2p2e3h2c create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/k/6kjg78eczceasp09agz77gav04w2cmqttcb1a1z89k7rg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/m/6m6xkpezne5pp3m6z8age604q7cpv1x920qnkvz1bkwyp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/m/6mqgag5enzvbfj1jj3p1h9vnbqe748dq2ppejheajd5ng create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/m/6mrbsr64qxtbfwjkrca2mcwecqydf7daxy28pc0vfe7ga create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/n/6nh78x0s7vpt01c4jm93bcz1b34cy3fr0tqwv7tr549er create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/n/6nndeg4erafb4pzb2901wkjqtdds2c1xdb7fv3hxmfy08 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/p/6pr35dbxwq0p8n3ms3tvtmkqeb60fef4pnkwz0fvagavg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/p/6py5gqqwqynzs9x0hw765emeg89cewjz87h01btpt6hsm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/q/6qywzpqkyc3m2nervjxc7xrff5by8m334by2ehynfa566 rename implementation/fuzz/{inputs-genvm-modules-normalize-whitespace/9e76479946b62a0bcd38c64e6362921ffc3e5c9d88c50c8eb3dd77529793625d => inputs-genvm-modules-complete-json/6/s/6s8c2d0dafx3tczd8ba0d3q08tdben51y533v9nfbp9tt} (85%) create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/s/6saxjzt801waqf7pynga8dtztvf33cxav6gnakf3drksj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/s/6srqet48avcywyfmwdxfve36a9ghbr9wsa51d35cydp2c create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/s/6ss1rznx8wf9tt6fyrps4510fq9zj0d5d4634jyyevnq0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/t/6tx3r8mjwycqk3cc19tk6vz6v0mpx5b1skh4619860kcy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/v/6vkrd7rbzfmpqy99m87rakngp591kxkjb6npwzhyetr0g create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/x/6x04fjc4187d9vgnra9sgq9mms214txwpsp3kvqgd3cvj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/y/6yvt19scjh8kgqscps8x2f1rz3e4jbc9aasct5hsk1s72 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/z/6z0a57zfe11k63pk5mdzqwqh9q4wnhr3rjsqsvpsd56b2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/z/6zkx97mnxq79jxx3p6v1ash40kmtc2sg8rb0pkxga505p create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/6/z/6zm7xgc4drd8e67mde018kypayx07c8vb8vh8j7vpd57r create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/7/0/700hxytcf4491x4ydx46vqpyacj3205hsb3brs7p7n4ty create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/7/3/732e6g98xw74xt2m44tza0kca6t24qsaqm5cmrgw0xf86 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/7/4/740p7skkfw1b68nrs3sq5zxtr9axxaxd01nrkkgbqebw0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/7/6/761bhyqcknm6pyt1f7j8jd61q4yrzhmvhy353v23257tr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/7/7/779swdcbj9e7djcah0pmjvtxsd7m588966stts93xg9yg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/7/a/7aey027n4v93kp4s0qh20fx4gkved3fw15n7r18yq07ha create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/7/b/7bpbt1he8ntbggfw9tse48emwb2kbycj77jgz76ddeyfg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/7/c/7c777qz80hpxtgnynsqmqj74byzc144gtxq76kwyrmad6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/7/c/7cqjbvhqx45fv2n0r972app5mqy1hrq1xdk2bnq3he5qj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/7/f/7f6vedsdq879bn98wspeyrsn6dvzagxmryh2y5r1d1c9w create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/7/g/7g15fmyk9fhwvtzx0qcm8p3hc0z75ys0dtvtpqnvcyw52 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/7/g/7gpcdbfdsm22fw79j8b0h99d158d59af312qf7xembhzr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/7/j/7jhrja2fjxnemgfffhcbwms91t3nct5hha8x28py326y8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/7/m/7mpygmpq420qqgrshs10nenpk20mnzqtqz3mt22jhm9zw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/7/n/7n4tmxbfh43pa7xerzq5gzg15ad9hz007etcbz5fm0g7c create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/7/n/7ncz7fcaqtq179b6m9pjb88yd9ge48fcq98mz0z7z04jm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/7/r/7rm41e9f692tk3awzkp4y3mfm8tz4tzk9mqdrydn4jwh8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/7/s/7s0bar4weepxqm36gjtmngd0s4s87t0zs71gras1azkja create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/7/t/7t6wync6tykyywar2shdyswn9r1re8ta4x7kxc21586p0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/7/y/7y7bc8ad66w2zzn4rpff9ntkjw5r6g7rsqa16hgy3at1g create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/3/83rbwdmzca793m5jvdh96qbx9kmsq4ydvyg3e6yqny8k2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/5/85rhes7r132gs7dr83w6w7q2x33ce0h82vffctfn6eqv0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/6/867rvjnahynn25ac14cwvt9t6jzvggz372ydp8fqswv2a create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/6/86k3v2zfg6c9n6n90t48dxem8619svqp59wxtvej6c5ha create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/7/8772ghfrhxs1ahgdn3fw4m2y492x836wf7k46sr5err0m create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/7/87qbtm14hgyxeyn8ey5dgnxtggr212adw4kwvzbnybdct create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/b/8b7pzscez3h4q8sxq7dmxcqvnfn5pgkdfxrqq1gr9csvt create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/b/8bky8ft3qegkfnscpfrx977aq71fvfkfggktv1q8f7f78 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/b/8bxa62pfbntw5ftd5xs2v8rrcdsmt2s84vc608cfn9efy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/d/8d55edm56x6y688pfpkvrm2m67q4j9xxaw2twbsbkbyec create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/e/8eqck26hk0rmgzpwed603cmmqm6wzhp1e3aarwg34r7xg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/g/8gdah1hcnmr8captbmxmrvjxs1dn8gbn0v7a10jf9msfp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/g/8gezvhamg4x4p2dc22wt60w0stt38wpk0re71drs2dajr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/g/8gt98q0hhqgn55z6vczfxgp42qb5awzyjd131cz51zwbg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/j/8jqj3fy8nbnk194bxprz80a7yfmdhdkqtgtd6s8zk138w create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/m/8m2qdka9j6w1fg7mg0wn0tb355jkbatrnzv6n7nmw4skt create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/n/8n4hrxsbftvpfmavg3smrgjc4hh6ezkawrfcepxk2jmde create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/p/8psw56dbhmxvhk9fhkmk8y0p0gwa88vszgnchgenysxh6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/q/8qk3zk4k8vtbbkpxa5q0sp8fch71gka8tv8bny9kdktm2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/r/8r0hp2xf71j0b3sxjm9mkbwvpyf8jff8n64n6wkjr6368 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/r/8rxmh4hmmgpgm7dxwht1cp1amvsd0qxnc23tdgfdh8k9g create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/r/8rzd98pan04nx6q9q9n5mkqtz86cg7hnkm1mkcq44qjmt create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/s/8s2r3qc3h1anzm3hkwr6j3r6rmad853tc0ds25hrc2fb2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/v/8vdr6yembj5xj2bm2cyg20q57cj4hrf1p8x80ndymj4aw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/w/8wy643cjwk8wfh0004edbbst8wa1b73aywaqfc0mcf0kp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/x/8xbj6pprejy2v5shedeb0xq7dqfchsdcjy9tt523dz5mc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/8/y/8ykr1bp9z55bqng865rp8s6wx7w7hc6n2jk0wanp61062 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/0/900w61hvabmpf0a96abnadvjsnn6q53zwxatx2t7d0tw6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/6/969ard33ab13sqxf820qr4xb9cgscj55spqa0neg7epe4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/6/96samzadf8rnaf6j7g1t39dft2r9tm3b9rkj28d3edhhp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/8/98854yqfez4decm5rhrdrs2bxfdjmcge4tgd9wygtgh10 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/a/9ajc9e1wemy51xq2xpwm52cc7pjda593acq5vtwd1bfd4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/a/9arqrp6srq0pd6vccjfkfymafvrh4qg32cx1br2exnd5a create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/d/9dt8e15aj1a7yp124h139794c8we0wdnmp7jrtepj9zzt create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/f/9f06vx30habsa70mpy6c1mtqscca4q0q70695yqxx3578 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/f/9ftgssx6eqdc4ktnadb6t92gz3g3veep8a5fqkeve8jsy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/m/9m5b5xm7mmt0whe7p2yqrr46d84j7tphrj202tazvzgej create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/p/9pa7me5gr10qg7qmhs49aqy7ymgpef4b6y8j5tp56p6ke create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/p/9pt2pz5srn6gthdq019taegmadr7pfwxv24e5qajd5cbe create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/p/9pyzvf0969q6r8nwnmr7yhwyegx8m8vffgnbjh8darjcj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/r/9rccrh1twhkb756ves35p72ydzvds4v9a58ckxv4ccjhy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/r/9rwcjbaa7kxnvt61ysr5aa9a1htsgsc5akc4w41k3y6ht create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/s/9saeytr2fzvg7ep4x96tzbq20tv1b9mfv6q6q9bbrakrr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/s/9sry4weyyekrmefx9xx4jcsfnf1dj0vy1e5vp1zsyyzny create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/t/9t1jhwp88r17fndf8a6mw93spgxbzcv3bgyvnhv70ca5g create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/t/9tv8bc75k3bzqhjeqpwkyv29kzt7p8bazzx3ty7artsk8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/v/9vhw4120f7nv6dvvhmsyb1khrxmwbqkgs22k838edwedj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/w/9wbbvcxcy4p2925nytewgyq3wh3tjbn6mp8d0cap1n7jw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/w/9wdtbsr7qeshkz69p2kgshe0xsa45ntjw6ypx6a3142by create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/x/9x2e52cvp0d2ebjhvbb9gfcyjss12qtv2kr0cdjkcang4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/x/9xn2apb41f7ev2vzwfh5002wp8jq1t9hgycz9b913znx2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/x/9xnfg7md78205facm1zrbcwazzg87wrxkg6nhhyc7242p create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/x/9xrbx5dcssbk9fgs3250tt06s57txd90ddpdevz64y7kt create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/9/y/9yywvhjaq25kg1r9489qdcrbdp051mxnyexd4r98zcxw8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/a/2/a2cd3q0q8nty2kamzc30yd3yrsca6cv5p1qwzb5jkkh2m create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/a/4/a44jjd8tqccyt151zdc50zv32f9v7e9x39qmxrf50pswy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/a/4/a4r64smhx7gpf3pf0ztfjdp4cqr4fjdcgdwjzgdzxnbf2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/a/6/a61dsw5z4095vy5a9nrzbbmctqj1s60t8a4nx4z5masbw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/a/6/a6sv323xdcfz69fkq3hdepy0014265agv95f8v9685n56 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/a/7/a78f2j2cp06v3pxabfw8a6qfz1gzxpvnzm06d4rt8qtmw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/a/7/a7k16nf5284aa24r0spdgrph37mpb4d7ws7ez4qwqzt3t create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/a/9/a9ygmyzxnswhedm95ey6jmpa2egzn9jceyd74zjj8ep8t create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/a/d/adqgep5rgg42hdagzzcaqcwkq8dnq5xywq41p8yzhjhxr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/a/f/afg3jgfgacqbyp0e0hw5w3bw7ne6fqnsbymaw99qvym9a create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/a/g/ag3rh55v0g8j79j5bb7267tzqgdjrqzhpbvde5qp98sxt create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/a/j/aj2dkkddzftkjddb7ztsdbjz6dmpjjn6x3y295gq39n98 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/a/n/anhr0t9ghya12j6htrh77pjte2jeq23ftqyw4b2qjej52 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/a/p/ap712egc4y89qq05pep6z4f2y6mxw2xrc5yw0q9b25nd4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/a/q/aqpdhzv05hc0sxkg8vgjmvymaqw3f6q26mwmty8vygs48 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/a/r/arfgc8zcqrbh0f5yzpjrqts7ganxrw1b6bpcvm9d3g1wm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/a/t/atmpzxjkayxkqzjsefhdxc96qbm94etg252p41fx214pt create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/a/v/avvknp9mtyb13s8xzb43p22w4g6hasm6s9xn96z93hhh0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/a/x/ax3adfvkr5t4afqhfb6tbtgg4heqcv34z860ftazx8f1e create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/a/x/ax87204a9gvnrwhsfs6gw3wd9dgp53k6wcj5v7t5vt39g create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/5/b5xkhvdfpwcw9t9dhmdggn32aycqwaftsqjc93ph6f9mr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/7/b72dm8vrs55qdq3mbmh9s1rr4x1qyhfb9hz91w0fg6am6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/7/b792ade597qyvp0q44d1pnbj9yrxc2aegmjtzxw2g6cwr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/9/b922m26p9tjmqpcgjmm15a87y3q6ge5vr12vfd5cegjza create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/9/b9zjk64ptxd1rqjsh0g7yg9bwc3vr6jay0rqjnb2cgq3g create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/c/bcnnahc097sf7wfdz84yntp9h8xhb1cyntp5mtfbh0bcr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/c/bcvpdd7znb1h88w52fyf4ss16j6g5x6y1xdrbch3f2498 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/f/bfdm55ahtbz3bstsb7wa1zc5cwe8j0kf1ac6kn2b3c9e0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/g/bgnptbbyxjbtzx5r683vg13k1gv4c428jbfk27m58vwca create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/h/bh5pj4v790fdb76zgnp1h74skr5nv7mcty01stnyj86dc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/h/bhjjkqvqr89xn9f94n91n25rqzs58s7gkq12c4qb19n82 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/h/bhyhcrg11qye6fygr8ve1jrv75z6vxzgwpc10ykare34p create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/j/bjf5jcbq1bh9rmwq2arjsd3nbkfj9cabtkjc6rytb707y create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/j/bjw8y3t1ypcbv2r80jsymm5yqtkbx41kqb7yax0dag4rp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/k/bk7tg4v8q8489zy60xa9kjwfn9dtnf6f5841aw9mbz84j create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/m/bmckydcqpd8k65kkc18gahhkr8ckmc2tfs4fsc3rx54mw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/m/bmwh1asmc9q9qptsthtjgw247pyeasgpcy17gx32ka5kc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/n/bn21bfa4kh47929dmgnee4d1f05hgv6js583hxnzacqat create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/p/bp3te430cppsj8f0n1tr69zgme8zm3zdctwkts89tqkgj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/q/bqtd1xq1cbjw4bv28vrdaptenxn31d03qfycsxd94dztw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/s/bsbp7ykhgax3jbh9pm9v832kxgfpc8yj2wdqnj0dnbshc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/s/bsvnbfz83cjp98eh9qrz4e7baqbcfr8w07c9mr8h8h76r create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/t/btpd8pnyd810hns19dkvp0pm6mbctydr6nxh2h5bj28f2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/v/bv4dcsdt837x02eq88kajab91nq0ctkmc5fja6s14x49g create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/y/by0vf31j6shg87ajmc19gh3f36tc4vr6b7v81n73f21cg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/b/y/by404cjxa879cfr3mkp8j5v99ewqdh1ka3bqptc3r7248 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/0/c00d75zm9sz89vs3pnwfs94sn7rxdxg25tyqgx5jbdbp0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/1/c1xfgsxp69zhyth69xdj5wvrsj2v898bb12r1xvcpg390 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/3/c3t4rfdgtkkcy6efj3fyz1excf7pww2x15239qk3etjpy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/4/c4szvzad8fpgnp25t9ea96c4nbkmts8gxsdkq301t1sbr rename implementation/fuzz/{inputs-genvm-modules-normalize-whitespace/708713afdb215a7fdd1b3246ec662a3d992648dc262ca1d5360be94b6d75313b => inputs-genvm-modules-complete-json/c/4/c4wkbgpf2hrga2ja9gan85nve6vs8ndygv9atc4gvx9zr} (50%) create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/5/c5gqzg4fntq5azg6h5f1n3k89v7c3zkd79a68gvqpa9jy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/b/cb2jgg28j8qmpnrxvgwqwhy9rsa3qzrnqmzj9ppdafjag create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/c/ccn5t75s30qs8f06japgnm7sc9vq1m1qwrqs634edemx6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/d/cdbjcc0akvqmxres0ak235a7j1g5x8af42gvewk0w0ary create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/d/cdswa6f4rx04dgwghpam5zkxp9c4yvnry1a9dm6708hcr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/e/ce6q5vbgw31nc3nvdrve6xhx519nntpfp466y772cd562 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/f/cf6wctsh5htv0fhkw46ab49ws2dqrng17h3panefejg3c create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/f/cfm826zbpsn5r4wex6spd3043c4y5gcnbvyxmfpgj97w2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/h/ch7v9q3a817bjvgqk19qhsrmre8hr82mhrjc2zq2m19gr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/k/ck2mhak8fj2023hsbnd500aknqbzpvx1gghaxdfbmx9mr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/n/cnnd3zk59t022ennk6sne1h1m5jzkv16e7tcqaaeh4ngc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/q/cqg62jc16td8pgmwkmpb887sccg89r05ph3n0k2emj4jw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/q/cqvndvgd652rw5bfgenmkatrxbypkxm658ykfnq29h4g0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/s/csk3f07z6bfh43433v3t4sfrg22ybgsyfy42fqm6x1v3r create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/t/ctj41vh54xd59bpg48hmrjgz890q69jmejh756a0q8nnt create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/t/ctqthskpwwnmrm8g6khj3j8hxs5yfvhxgf086pq30jhtr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/w/cw1cfp9bdvcqkqg5tm08ggrc5bda7zmqz8xq3k3d6ysam create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/w/cw1v9r7a7eysaxd0fpm6d58tbdg981d7z1jdjvcy9xmj6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/w/cwa33vsd7h36xx5pzk5wzyk4hnn9ha7y87eh90vszdtwc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/w/cwmpyftwdby1bddzawz9ee6bavbfagjwem3n3yvsa5936 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/c/z/czsfsvp41g06qv09d387sz4kknemgat7pv72apmrvav5r create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/1/d13vbtddm9r6x9jq3wdgpckfe4xzxgp19bh2x9ncjqwnc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/1/d1q9ctz9pyrpym136n3yra4fhxqvzjks22hjm9y2errxy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/2/d27grm16kjp4rfzwbzk3p7sda804ykfma4wmb53ar4998 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/4/d46ttf0zq9pvmgs3qjpdegznawqw1ndzbtbvs40the3h6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/6/d6dqgr1jgbkmebh826wq0heyv6071h8j84qw4xmjdcrap create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/7/d7hsbgnjd6mtrdw1nsn4p31s2arbkw7gy8manf8vp4tz4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/8/d82hxbrtkmkz7zt2vg3zq107ez9g017egpmcac6w50vbm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/9/d91jv8nn4e18xh44q9kswsggmy91vy11ykx85ttpc6a7g create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/9/d93mqvmwkazrrm0gzftmzw2604x4pkpner8a4g52rgnhc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/c/dctpvb2zt2hrkg19mkfqc9h9sk8yz3rxj95z6y2n6tbee create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/e/de70hek7tx48svhkcmgtr4jp6cp0nmzsgzqdp0qkrbjz0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/e/dewbqrqshc4a4e544gy7bra0cc7ngwb8nk98zwexz4ek2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/h/dhk6b8jk1e8d8gg6n97s15b4h6y9q8n0r5yp0r9wsmzgc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/k/dk9ye8hftb4hf441w1rsnrk9zhps2tfwfm6xdz6v8497a create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/k/dkba0gfw61g6810w4p3njyk0d0wh0xf498g53ntcj4rjt create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/k/dkmhenq6tnsbsncefwrtcxcj2zc3h3jkdmcb7f95skgny create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/m/dm4nvqbr2pm9vaagx1nkz146334pgeaqhwkvdsw3pv9wy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/n/dnw4ywfh2ctkm2tm83xfhj4nv0a6hph0220eznt31rf9t create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/p/dpafw3gwg4st7g6jsby4tqa9b6b8qz8yfsy3wxcqa8m9m create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/q/dqbjhhgnmdp394wyrsrdhhaarc93anpyxdb722st357r0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/v/dv5tqa29astpjxqb9qb9nqy7a9p2yp7jff7ewbyqj4jjt create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/v/dv8djb7j6ykqpqp5xkznbzx0fx4j0fv9eeb86t21ngqc8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/v/dvm11rn82hs4z3c99f5kvs8e08skq9frctwpbtgj6vxzw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/v/dvp6az1bt52tr38crbmgm9ffvsaqm9me6x8w8z62qca6w create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/v/dvpzes6wrn2rt75rrgmvsx54ep3zb3e2psa7fvyghhd28 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/d/z/dzr40rh8bnnba51n7mg5cgxjhd6m83qazmq7w4yp7b13r create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/0/e02vsbkhabpazvdv8bwezwexe2e88n4dn8ve59wy3dkfp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/0/e0c7785fpwp0z6r9he4bbkpk3xqjndx2yanmy2d4qdvcp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/1/e1epvtd5v0g86azye9vbwtdfeq00p1sseg096m3j9cs80 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/1/e1mmg4qtd0ezmtb4bf6beemmaqh9h76hkfx8th8y94mey create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/2/e20857bs4stbmpedvjgn6avmv6weje9x8gk386v9jrspt create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/2/e2qxf7j5hfttj5g4d8e2hzb90pmtfb16brhwm4v6gx11p create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/4/e42jccxftrntwr3se574eq9e7ykcpcapyewr1rsa5kf6g create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/5/e59046tvy72ss2g7vv16ppqtgy8nrq349ajkt5esk7j60 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/5/e5pd5j0jb6rj91rnf8vdfv5mj7frgnh6b3q6ty1nff452 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/6/e6h4svg8jmemyt4177w80xen3bs5fstgc8jbkb6ttcrqg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/6/e6tzw9ba8amkm74msqq0012txz5aqq9q9qe99f8csqr1c create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/7/e7cx24jfe7r8jg011g5j6z871zjjqc0hvtcsf8bksf9rp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/8/e8erj3me5g573cnrzgk30d8350x3e8tdtkqn6banswm2y create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/8/e8g8n6g0e3b9b31ptzy2zdmf8q7xp9txsqhqhkhj78hp8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/9/e9s4tg672179s8epq9vjc1t8xc7p426bjcz5arcz9p9py create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/b/eb127pt6r50fwsjxvtcvtgrqqyjskvzraqnmbz5c4nhs8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/b/ebppt36hmn1raq16m83ywr2v1hfksbc677j05jz3a5cta create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/b/ebt503723z2emxs30rr989mgg7jcw5597bgjzdtbsn43y create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/b/ebv0ny12mz2f64ah46mqt4h1244vn25gtjdh4rcp40yxr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/c/ec6n23yd7cbe5zk7fasp1c8h7h6r9pqx84kf59kkq9t6j create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/c/ecadpx0fdp3t2b9f0dq8tkyjz7bb17wp7qek6c5j2wbpy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/c/ecbfma1cype1bcfa17gp8y8mzvsqb7r09f6trh09sv72y create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/d/edj2jxcnb53f4y97p9a8rgypqezdfap98c3wgneg7k3fg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/d/edpwnq7kzhv187n0eefn36fxjqqkh811hpe5mschmt682 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/e/eegsza8ysntt59aawddf8nrjfz11yr5avv3mfzjpa4cct create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/f/efqfmbd7qgdmfcmx9gnpypcabepgxw28cyk07c90xqzkg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/f/efthb1cez1ecc2v4ft3g9br7hgm9pn19295v93vj7xd98 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/g/egvnv6b036px26c1pfxdyetr2ke0t5k19q9x0697h0620 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/k/ekw1vwn92g566pqhj4psd63yh1t2mmrty1xvfba4v2dmg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/k/ekw8e6jejmqxgs5feynsczrd46hhyhh4w8kr21xx78fs2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/q/eqw32e17fbw05ezyr972xx9kp3yv30jgk5fk31yhwhhye create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/r/er4venxzh25x3nhg28jjsvkz3r9vdwrmn3mp51n9hjscc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/r/er8fpyb5ted5r0ydph71yvwk92w9ad8jc7cwdey5d1wt8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/r/erbzxzy6c0se61kh6fw955s9q7c74r6dqrn29pq7j7nva create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/t/etng0z2n7emt92qnkhvn9e40mre0cm7fj6cavcg3fa8pt create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/x/ex8ebm6z9e8603wab4pna1mf1cdec3wrp32jem3aw64zy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/e/y/ey6frz98yn558h2wzg6a1q9m9mna6h73tfa0bazs7sn8j create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/0/f0kp1rtsrfr2e8b3kkp860q87jekvsmh09s5yh461kebm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/0/f0vkjt3y2enqdjd79k21h1c0knams8se5fehqmjz3ezmj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/0/f0w1wp4f4g2j3eev35nwd693ztg9rywxbf2xz2sw97efc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/2/f2977sr15mekm241hw6307vdxw6jfpvtzcv96e0kpb30t create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/2/f2mw7jkye43zq3m8tcjfavsyxb0ydpfvhecr88cct7qqy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/5/f5mxash0dv9x92eban9n4bja4a9f02re6s0cfdvgxggsg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/7/f722yfy9gpzwpkyd441q5bxa9d6q0znw8cn5c38yakb8j create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/8/f894kk1aszm9zrt7r2rk33emns5jh7mt8v9ma5atbwd3t create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/8/f8f838tn0zrencezbxme6vs2k4ehm2m25vpvaakhz7ger create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/9/f9qj2956qabnb1858sgp1x5fqec9f81j796pe84cd0fnr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/b/fbq5975x2xbt7q49nejc75g2gkgq1sazyfz2g4s7dbza0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/d/fdarbet0j38wtdpacqvcedcp5nskf95r02gek39rmg8qw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/d/fdxw7s5sstzbwkzhcmrd55mrgw5ydy3kwys6cpx1znspy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/e/fe908rz29x6xjyhzyt3cdtz1btr6tgatnyhnc07a2d5vg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/f/ffabam1yxkm107he6rdbwpthe7npazfph718gv3802qy8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/f/ffzbr34j2epdjf3hm6gs0bn44dkv64q71s8vxrwn4ghfy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/k/fkeqwc9ng2a7y42dae5ax8bv7zvms6s4jqb3ms9q1062a create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/m/fmw01nxpr25fjkpb44v57kfxy22jbhre9jk9xmz903st6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/r/frr2tx60pfkvq45nsmz9b71pp579pdqd5g9njtv0bnw90 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/t/ft635tsas864bn4tkwtkbxf623k66fnffb27x07czte6t create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/v/fvgd11vja9g02rct4rgk4sbyz2pq8g6ce8sv4hc7wwbtr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/v/fvn42ng8jwjq002dmsatnmn21as2fd1g5h4srjywym9g2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/v/fvqnwfm2teefsk6cqhaahqvmaeppjcdzgfyph7y64cs06 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/f/x/fxv0dxa6py99hk9vmne6g5w317jh1spjt90vf5pkq904c create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/1/g1fsd04pp0ek735a5d3fzbxnxhpvbafw9hvh99kvbwz8p create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/3/g3htj4zjgtrxfvw4hmnbkzdp6bdh1j0x9rrj0804xz2g6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/3/g3m2wz64dne91ntf7e90dhbf9srktb5p29aq26jzwk0bg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/4/g4eq0tjf2yp04axpjztgdrg2q1m1rvzsvp351nc80dpam create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/5/g5pjkd2759bpn5f461dkws3h2j15yy7keerbyspd857b0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/5/g5v21bx76yg9g3vd6kmxcnkh2dg6q0pctj5bhngfannba create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/6/g6t74w7s5gapgnshxyn15401mxhzm5hh3fve4cdmjwncr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/7/g79z13a134phq13pmsjfmm4a8jzb5n2nbzjaq0bvj78ja create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/7/g7bwdm2hqypr8xfsgwq6cgekw1wqsrzpww5nwscttq46p create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/8/g8w3at38nnnj5pbjqbfs84vekef7cz8w0hppz1egw5dwg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/9/g9qa3ry1jg09wd47m2xwpvgae90wnxtr2rvwf8e146qg6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/9/g9qtzypr7b7x9c00zgpnw90pch381j378ttszp1jfb658 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/b/gb62dbqk4z17473cs581byf9df8452h86tz7r7vjja3er create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/b/gb6q6gtnpe7dtegw8qsney5km59ma0yn4690y7qg2hq04 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/d/gdawmvp49h1dt7259q310ypjasyxkq3fxs1svg1rr3c18 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/d/gdrt3ewgwe2zgrax02f99a2mz17c7mzej0zkhmc5sxz60 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/e/gejprghszwxv6ppp3mrranea2ptkgwenp6h2gpyn03rsm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/m/gm4zy0ph9dzdwvdf02pvmmnb3z71fxqdzmk5tfcd95016 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/m/gmbdhbg2n4jtfvgpzkdrvag402km42qm3cvykssn1f7c2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/m/gmgzrf6rdq7jav2mc6v518jtcs63dr389zfqj1awnmx82 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/m/gmyj4521be0c23ktwdyqs75esqbby40y7tc4ee40mg33e create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/n/gn161457rhjg8q1gtgwrxwmhv7fe4hd36n16x15e3zjmm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/q/gqnz8wygwa45hanm7s90tvaw890psc9tg15712zb3p7j4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/s/gs2391srmekajtdzkg6xvyr4rd6ndvp5279vwc0xn2bcp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/s/gsxfwzkf15t5ab0xfzq7kwvzf9c3ej1vk3sdz9jpnykm8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/t/gtnxy4531pmxv9847jz7perpg0cpz4wnkdkxgtydg3v60 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/v/gvh7p1xkxz9brkee1ea2ywawfgxqn5x8t9svnqt9244ea create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/w/gw0baa8yz1ty6dywpg4xjeawgmehkk287m40ygkx6f6zp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/x/gx98f4rk68hcfbeqdx4pk7bzjz07vg6e7a3cxzx3v9wft create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/x/gxwg8stb3a070a7d4pg61a7rveqv0ccr5bhfpn7a4rstg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/y/gyqgq9ge6v81dz4ah04p7s2wmgpxxvzqwytpzbmwz7b3a create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/g/z/gzj084c49th6y4ryysvh0027yvt77cfmxxn79qcyyhzgg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/1/h1ybayrg290j0f6myh3tt1p63zzjx1mf29k0rwewqqchw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/2/h213vzjvnvfx83c7abfycjh14x57afa1ceyznkx4tg0k8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/2/h2wcbzae9g1dae8mbrgtcph3phzvn6xs0p4hgwcxnzeea create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/4/h4ep3m70qztxm8dd5ftste6jege5zgy5t6j021833j7ej create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/4/h4jhyy4pf9dk9sm960mm91qpnw8draq2q4mwvdngp56d2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/5/h5wxz58hzw7pmvdgyt09dyarfk10n5g1rfxf5nep1531r create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/6/h62x0c4w7p7jsrz1h1ezka109ryjqetjtm9n6bth6ea4e create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/8/h8dk8bqhfqc4qy61zpzberwejg3b5evkeq3dma3js2t0e create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/8/h8eegm2adakfzwk3dh4hwkepwt67gpkyfw5x6ywrrs9jg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/8/h8s754wqsxw871nt24v192x2eck1jz9w9s8bk89m7657m create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/a/ha1k3z20wf9ahpv6ttewhna2m0251hx8tvtsk13pdazb8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/a/haagrvyam74hae6x8wsw3an148qa9caw8cjx2jwxpyznr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/c/hc7wg34atrg7afqky1ajnxprcdzbbdqfg09fb92m063r2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/f/hfh1j3r352wvahzbgnh8t449j3pm9kb4d1ax0ezky2b7j create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/g/hgw6n5jgrsxe3aydj10cvq35ma4wsg7qczhz1r64d7hn0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/h/hhfkz92b2h54dsc8s1vzbhfzenxw9r7hx740z41fexja0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/h/hhkddf8e6nbae84a2vgwbs0dcm847zgw3vctbsjd6j2ag create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/h/hhxkfkn00xvw37f3t551t5tcemzfqe9jegt9wgftas6c2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/j/hjrr8ycqfat197v4k1hxtkt0zcyrvhgx8tmzx326zrd0r create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/n/hn2gy0dcn4srykfn7x9vabhne57j2x7y8dg4mhrjdw7wj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/n/hn9qfpe5y3st6etwykvvb01v697hvpsbzgpq98e44xvpy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/n/hnamj82p5zpjpyzzvxe1ztgte2spnpdqet0gm82frhmda create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/q/hq75ncgkjyx1j6h3h5vw9x9m3nw6f6h5rnkv1e1qx55qp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/q/hqmnjzsw0nb75195g8emmhk4tjw68n44xwvgkz4w8063p create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/r/hrbxm7ybsmr740a6hbpeaavxczg1yq6eza16jvst2ppg0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/s/hsznzbxvyc2zgevg0344280fmx3ahkk1hnjzr1715g3j6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/t/ht4v0zqe12ekgy8jzscfbwprhaj8nwpz70p11k1zwsmzg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/v/hvcgvt6d2g6613m3w203h288dzd2k6d92wn4kfvzbd7je create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/y/hyc888ywyvy5fr83bdyj7dxjeq62mc10s4xshxsqhw7wp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/h/z/hz604cp3v0gt2pjkkzmqd84nx5qfv1d90x6qtre0n9qcg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/0/j00hadzgnrkbdch4ja8rjvc6yc6fdk5canytgzgr7qhs2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/1/j1wvajs26edvpejqkc27syy0dqxttg0epvf1dbzfvce18 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/4/j4nzmgpapfbw9q5gd1r99hzchwqmnc130bv3e102xeekw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/4/j4zgfdkbdfjrbhyctrkkdwzyy6tv0xx7xdjd3syvq9pte create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/5/j5a2m63pssmgd46emw3s4mrk88agm1pr3ykwkpxx5nhna create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/7/j7gc0kzcgk2v3hq0ehgh1fcs2272ryyan83wm7p3gxa78 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/8/j83hfvekz2y5g1jhg1ykyemphdhfyarhmwg7smgvy28w8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/8/j8rb6d6578z22xtepbzrc67xhp4cr6c5azxex2p3m841y create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/8/j8ytdmjfsm33pdkx1vneefqterd9ajy4w4caztg49m49r create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/b/jb8e27vb4h8m64gn1qepw3kgrzm6ygdtgrr03nb685w3y create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/b/jbqnh283dae76dtmhfkvq7nmd6qt8rva7y2hbz51fmdzy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/d/jdats9sxdjzpxdfkb3kape5azt6yde0se4f664h6tefke create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/d/jdqkeac33py9haf2ervq2ggmcwhen40aj4sc291x22xv6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/d/jdshqt7jp74v9e149zrv089cb812zcdqz9nsrvzyn54p4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/e/je6jbergqyrxdm309dnn4x1t085j601kvppjycgfam982 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/k/jk1wdf80q75qrbb8zbzgycmahpcbtyjzgm502764ee8tp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/p/jpqfx60td314ksyxv666k9awxntamx4zcnbxbyw8pvsrc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/r/jr60zpc4dd7hc1cac6jydf05dyf59kv9g86pyygsmq76m create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/s/jsgx8wb9rbc02j98tz450a1xkst7j3v185atgmtsbcvfm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/t/jtd53xadg9jt8grsvsh9a8bkceye8zr1rxx4wn1qh5gwp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/v/jvm7y97hwf2hespz771jydy0mxe1gbgqqj86q67z3bxw8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/w/jw14ta37vnr37zdj46hcvkxg3tzdbvv9hrkcmj98rhhy2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/w/jwtrd5e0gr5evfwqz6n983xmpr1zqcpg53ap1gftvkx3p create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/y/jy2dwkz0s5qa16xke0n9d4zkaefmp349kbwyjpd6nj1ry create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/j/y/jy8tv9rzs0ewfa9c71aqc4t7qym7mjyywwxb0cjkm39tc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/0/k0adjkygzy5vt8e1yhtb9r0dhg19hxzxcdtp5whmpe6a0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/0/k0s9ekbqz6ts2av7eb8n3yjv4wytdaarys3ed9gvnz5b4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/0/k0wkm3rtc76y4amxbq6a3bvj28wt28t9127hf7cverh92 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/1/k1rjtsqeqb0xm894bjt7vy73prmyhyhzpe9hg1nk349n4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/1/k1wz7cgm8ra1sarnn2w689q42sed8xb9ve78mvj85knry create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/4/k4838jmv5xazrbrknbzv2w01bzfh74j3s7pw5wntdgzcg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/6/k6nka9cctyna6x83rethzyb8d7vy6915xmv1xa90snb2c create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/8/k83gwrajz3mzbq960z8vb6sq1mf72n39dbja6a93mfqsy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/a/karq2vdertx5s0530v4cc7hf5932h40dhsz5wbkh6ac38 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/b/kbmxbt4vz15rxtvy75a2c7zrcqq80ywr682e36936shdy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/d/kd1dfh3hfn0b7cn92xd8fyrx6jx96e1sp3pwdq64wvpc8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/d/kdbgas0n2fctkfdx4m1bevmrk333drnreerk4scwtmb0t create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/d/kddc8w3t0sa6bgt4hqfmk0s702fhw3aj2s23vrf113vhj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/d/kdkd1aeh2c5te4wzhqg19vgrt8xay96svegd8190h53fa create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/g/kgaj8p56a7r8jrt40152sd7fcc4c90j1y2890rqat47kw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/g/kgmgxgmb7s36z7t5w0c13v2kz5m7bf4qw7bgcys380f08 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/j/kj25phm9g9r65k34nf2bnbvktjcxarpnshyhss1hgzrcm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/j/kjsqsn694mxs46wv9pxk5wr0v7w32h7yq1am1qxnrq3a8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/k/kk2z2tx173gmjdhbh0tkeg62s8n7kcsv9gktyt864mhnm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/m/km351mdw2h6myk3rettmc5nhmye9h8k67d8rd5s747qx2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/n/kn0szcfjdy98emzg60xkmccxk3qdcsk6ads62zsf4vyqm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/p/kpeapxmj9qkwvszvqsrktmkcrkvss8wq7dfm9p462p064 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/p/kpv7nrbmhdc6556cy33hd5d3fqcw518m68q4gcbsmzpma create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/q/kqkz5qnj4nkj1esk3m2v3tw4hzgcvd4aq2zcv0a0vv90a create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/r/kr3jxhewcm04e4px2m2znvdxjbr686pmewxrstvaxz9he create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/r/krh4hj84agz7txk2hsapr4r7gbpxac5ttbdefme657ysg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/s/ksqdnet3e2y8ztax53q7hddaej4xqjgaz5kveh5eeyxbw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/t/kt8wttecepmpdjfnc0ht0x0gwb6a1jq03s3yj444kqjcy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/t/ktafsc8tmnxj0cxxmr3jes8gz76p54fs8wzfqh7pz9274 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/y/ky0p59y4jd3yq8j6gz8zz668capv25c5ya0s58qydxcst create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/y/ky4mbkfs19k1fmkfhx1ej4jqns8h1v8dyj58eg6j33dmt create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/y/kyst24ensy38wm2t0at68frg52g4g812hm20ws9ne1mde create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/y/kyx60vyjpbs117mf2gz69h6enprvzm0hcwt3z641kf5xe create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/k/z/kz3m9qrp2a5axfa9jy5h8ewtxanwygafwhx4r5fwbztce create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/0/m0wmr0cmdm54pr7gsbxyskvymrvkdyh003phfftngp9dj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/1/m1qhqarrsg7mnv6d49q2ksgb6q2afqe8z16ct7dkxy9aw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/3/m32t8fg331gpkvmxp9mkgyxyk8r1ndbqtfxxh7904mkda create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/3/m3ahpq4mgferty6rhpdp79xvte4cfjmzwtf53kmsxaz4g create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/3/m3mzkfk06j8qbanxvsdd0ctez8e8js8qq86w1n8s85kzj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/4/m493qx6671gfk42fjcpzapxgjv932b4najhcdcvb87vcy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/5/m5972ey1t36ymxs03rc2yz80xavs5dfjfc8gy1zgsm2yc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/6/m68has31kcvzdmf3rmzmc54tja0yk4ebs21kt9v1htm16 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/6/m6abvdrjj88h71m40pamp9x2ty7p1v0h5afjcscnhfjvm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/7/m7dpad9g37xfp5826mapya0j9fjfasbja8fsz721k7hse create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/7/m7k6a08a240xtex9khqvm8zkj6v4ane2yqvajq13a64q8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/9/m9ypnkqd0fd7b89g1r8zw2sn6t1ffhc34chtkb4zt4g6p create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/a/mabk4cpr62tte8fpee0h93ej82ebadtdmzev02ankgxxc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/b/mb6qw3wvss3wv90ty3689ayg9bh3hm1yj1v81d7mmkmrm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/b/mbn6cytj7h2etyzm73q23gzwb3r3zzn46a26147c3ngtt create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/c/mc2g13cjhwvkmnjkzhap1wv65s0d6mrsfnpvgqjd4d43t create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/c/mcvp61x7qvhm54q7venkq2j0rxvcj8pkz54tktsmz696m create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/d/md3nvsew9f6adkessshmv0jp07cs9t1ammp05wfapy95w create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/d/mdzbn1tkad4dcz38gynvv3b9vjjxa753a6smp4w0gq8fw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/f/mfe555xm1czdmsz55emnt639nhve81rb305236qf5cvw2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/f/mfp4jnm2pgnprzney40fatb7pp46t42kb5fk5bwagzksy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/f/mftybwf9g3rm5g31dmygq0ksw3hdxwpmr2msqhz46581g create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/g/mg5f0w63svmgw0k720qpmarnn3b7x1jfd6sxzfjrv0qsj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/h/mh89vhjanjap5bqrg5n0y4awn9ey3b9hv04y0505ycf8m create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/h/mhkkk8x1hczb24rycg0wk93k0n71vrkd129shee2kb770 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/j/mj61caxe8khbx3femfbaeeqyf8rtjxxnvh7peyzvr6nr8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/q/mq2w64nvaq0ek0d3n4trpsnkrx13bh73eexhqy3qz1n50 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/s/msjqvqw6nxfk7ccsbfqbphcbtjm3chag6qdy7t667dvxw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/w/mw17vyjk6cj3yh3k8f0rdzt65b7j6tp7vzhht4e8g3ed6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/w/mw3bwkxt1sgswfqnxb2ksghfs930jn8wt94e4ftsrh84g create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/w/mw95h82x0xmdasfnqp69gzrv0kag7fyytg72g7wsqp1qe create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/w/mwvwy5wqq8a78r9krk8bdrkc6dgy4rfwcjjjm0d6n04zm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/m/x/mxys9rn0bks5a8stzkxj5z2e617qr56dn9r6y4amjf6aw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/1/n1dtcpmdyg4mv2echk5hmx1gw435cy74yzqe63rv3w2xe create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/1/n1r5h883zt39y2k6qb2s6t6aj88pdr0f3vfs1fw18y5gr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/1/n1v7ztryqh0pqzj368wwbxqkvm7qbvs33n66hxx7nrqwm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/2/n2hmwrdvrc4nsc74704jejejj7axdre87g6zpggvrbd3r create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/2/n2j89f9aqmhsv9bnyeqzn91bpdt7b98hfef1h55f3svva create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/3/n3g9vf59rm5hmm5f7jxhc5st3mtygp36p0x9wwj2qtnbw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/5/n5159m6kqnn4x3frndv6zm7acsqtt2abaknc1zk5px8ce create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/7/n7dy1dsabxynmvt3x0c6gehwykk90p57sm0dw4yv30wn2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/8/n83y3d9a13g5dmxd7kahqes3eqy60fcv6v0xd2dhd783j create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/9/n9330495hyfzbhes4m5b24jh013b6wkyrb1nv59takz1e create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/9/n9afwk9mv069s48jzh27mv334kwn483b343g05psgg1h0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/g/ng5dswqsnt0nz180w1njgh84rsevdd04qvzx737tqp4ny create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/g/ng7y0bw3s81dq313y936cngh5v3vbxst6c4s91v444jr2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/g/ngk6cm42qnjr54s0gwv2gehm9t0v2kq8p3fb84fdbq6wm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/j/njm94atgazn4sqp0y06bfer99f5n9d0z47251b0t1nbrc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/j/njx918nmttxgteyaykpskyqswf27byd6dv7v3c6mr9ce8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/m/nmysrgc94jph3xbps9f1zmwdyb5z68rtbqmhx2j43rv54 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/s/nsvc3ayxsqq26r2y7ehk3t0x139cmem9fyjmx7q07yr70 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/t/ntftmawhwhs2ha6c76dxh02gswf2h4vh6vham7m3sfdct create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/t/ntg935cet85vqftahbkvazp0hy57ee73y1gccm9hf8gqc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/t/ntq3r5tp52qea2p58k13t20fp1y8z4y6sctkjf8bhmyec create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/v/nvav67fs6raebm8yy7tnxdrfn4nstrdcc7xtwj7ec4864 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/x/nx9ndd6wvxxe9pztv02yrhqsk0qhkk03hhsb6z4xqpqg6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/x/nxhz15vspeftz6hvkdstfgdnmv7q9bh5v5tpasqshkx74 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/y/nysnaj2py5tjqqj394c5ndb89ycet34x94fw8dygjd4ew create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/n/z/nzf01kbbdv8hwahc86r3tjncbce3gynjtrz5t02p99bqy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/0/p0p3c0xzs6tr5c3y2meepqx344ra5nnwzj5k4p3w197yw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/1/p1kszrpddaqfpf849d2mmygc3pa2w2j7canbcmvbvns8y create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/2/p287mydv35s2xwtnrdnyc3pd56awqzh67157x8y6mpw9e create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/2/p2fx30snm4efr2k1x8mqpej6xdv2hpwc13vv2njapmt3c create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/3/p32zpavsm0j6fx9mbn21b8126993m8mc8fkpmheapshac create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/3/p368t8wtgrt740a0aeyfjjts65pyaw6w3sjpazhpt2h94 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/5/p5b4pv72mn0h9ekhe92x8zhn6r03n7j6fh0w6vz1spe9g create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/5/p5wwkgjqjyja1vak6tv7yxyaygm73g4psv9pexeqr9v1c create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/8/p868kv3f7ap1y7frhkfzjcxs3p4ja3za0e46vj4e245g6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/a/patxxt64rh1qcbhctjpsbnhx1s8h1kt28aejhvs4nt71a create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/b/pb7f6wcyfjdk2c23myaqx4sqbef6wsy8j3dvz3m449fzr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/b/pbejrk8cbm11vcgfv0k9vbc3v6mhntmfevse94ddtx87j create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/e/pek78ck9a0kyxemegbagc2rjfedsha7z80gt6fztyht2w create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/f/pfp74myh8qrgwatp0tvksqb3r6rze4am7zcerdfpbt95g create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/f/pftwz4qs3hsbf428b1mkem5f51drw08afybzybxz4kz24 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/g/pg8h16tn6nzr6s54fqys8twzwvt4nf3r1jnpjz1abaj6y create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/h/phrk1hwdpd06mahek2rzzrfqsmhng70qv6ttv0zfkva50 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/j/pj481h7q6wx5z6s7b4mrma2mj26awddz79ve8mttxh7fg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/j/pj75key1yebs99qhj5qr9paqvy0ck0w2y7ph9e63n4xyc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/m/pm1rsjzm5ffxrb7tjz9g2ttmbsg79bd399fgh3qffaxr0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/r/prdm0t56pfry6xsf9mvc4w1rkrzy7crwff5srqf7zz2a6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/s/psq0xew56vpdtmecqyd965zxgzke9tmb0tgj5nsbr6hke create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/v/pvk1zkyxmscw8gfnprjyjz3s4mq07nb1ndg0bf4ptr5x6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/w/pwps76p2mngwb2g0s36t87nfw9771gnkbh88x64v3b9za create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/w/pwxm2140kkdd3y52kv6da4r8r7vk6bhxk2nhhj2wrrx90 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/p/z/pzdkt9mh86k8rq8ksknbzsvptc3274n2n1zjgswg1ehqm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/0/q0nf8cpayztamyr7evqjfy6wga3zngxhk4kvx0dza4mv8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/0/q0prpmnjbk9d5ymty9jcby1093s57dkm118qcs250k05y create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/2/q2m3epw20qqgp7shh42j9kbbeq79znh82r03bmv9jq832 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/3/q3p690xw3m4yzy85b9vb4t4cq42158d96rfd923m8aa2p create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/4/q45my1w9wtefsgpzdk6nvsz98z23k9wmz63w1ej6xe766 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/5/q5df95x81dj1gn9tpbj8w8r0ht7c3w60hskcn6mgjtrme create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/6/q6gebjxz3vwfj4pd0dc1kerm6gq0egmy1mxr4g82zjg64 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/9/q9a59mn46kmhq246znnmh6wzajqcmngexwn2qhbepg02a create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/9/q9d9n5fkfwsfdery7z1e7gsh5a9qdqmt0vfmkf185rp7p create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/9/q9e1emsm4enja8d8gdxb0173t52zah1pm9rbbatghtg6a create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/b/qb1dg1yxdy9fbywxyn689e3n8s17jqvs8vj3dm4c09f6p create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/c/qcq8fxxg0886x5118vcn9hn9re95kjbm64m1mnv1v2yv8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/d/qd5dzxmff201w13fv07e00kgx7y6xzk80dmf6h0n6e8he create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/d/qdarjc9gm33ymfwkpsw3pdm4bm7e38hyakp6m5rd3hdf6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/d/qdjjdjb5ztvry0ky10ryyx6j3a0v84f4jcfwa8v3swn3j create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/e/qebc2ds26vf511s9ev9e0ymjbmw01an7s43nypap1yd2j create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/g/qg7xyqbzsmnv7z2r12gtre42jtnn0evnz8sghsbzfbvty create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/g/qgqa29n6vmqy1cmsdgn259sa2gear6ansyytb7dsnj380 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/g/qgw5gj9bemrbyaptz86xrsvkgrz43e5fd766v8sptck92 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/m/qmsqzbe79qkxy5zv5daw6m1x7kh2f68gnxz4k8rxr7bet create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/m/qmtws2y6pk25cgmf8fg74p3z1e8tw9g7h72m2x5am92tc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/n/qn0t88k7rhyt3jyq9174j4k059espkf5nnnvt1wn254ea create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/y/qyecheaygp5n2htj123hvsgfyfjdpmwb46v7yv8k9kbsp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/q/z/qz9v320wcgc0ydng7frvmm58x4az6r1w8j5knk9c8ejma create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/0/r005wtb7jsahx35v0fgnd0d5cp3gnas1fv24jsbyt7fet create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/1/r1b4z4m42s02q4ab3gezsvp1ytyfhhmxag9sdxdrsh3cr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/1/r1cdd04qajrp85sczjm8s2y26c7xyns3mwtypkx1n19y8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/2/r254rs232s782j37a38v7f3cbgmxr8gw2450eq26f9732 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/2/r29f3etsn2vgy2342p8ezq2bbbn5mgwqx5mb67eyre9hg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/3/r32mdfagf8w7x7tfzqsgb5k4abcfmk3p1kmggc8ya37dg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/3/r3y803bhd7qf17s9aq8q5rxrh6384f5q48h7e3pbmn94y create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/7/r76wr3jct03x1hcdfyr9zc5de8kjzhqdftatb9p0txjy2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/9/r9gm6axcx8mpe1qp1whakh1y0t0wgfahsvgwth5p7mwy4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/a/ranvb980qjve6cak095mg75awgrd5p14s3bqnccs3d9vp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/a/rar68phs41hzs9gfadgbhm8jp91n9zbyb73cbmvhc8mhy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/d/rd9b48n0xygtvkx3nckbc9p4ky0kphkxj1b0zzpfa9bg4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/f/rfcj6z0sr8yz063zzaxameqvq8kntp05bh1cp3tnefr06 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/g/rg8pj4jk38xv6fhpf1bbn2398bkvcgmkqq1crd55ja9ke create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/g/rg8q6t50jp1c9gst4ek2j8r245e2hw5a7gwvvpgnfhf1t create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/h/rhtmpfv58qes02wt4ktjxrwveypfwns9hne6hvk9mrd44 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/j/rj71xj66vxs4qczheqy8ne3rtf5jsa0e84d787cfeh8xe create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/k/rks8yw6t9nqwhn9ygqqjfn42egqbmz9tvxwjj4wtvvp7j create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/k/rkwm6vptf0pxp94z7dseek6j01pcsaxa669xmnj0gpy68 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/n/rngntzfd0n1t66793erxeqbgbp8etqkyfsg0m56gb19xe create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/n/rnvm0dbv2tezpv8wtgzehd84x35bbqecq4r3pp1ss5s7y create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/p/rphqjmqw0ersskqb60kag18j2xj99gcz1caszeapaxv82 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/p/rpjqfegw5ybpp8qakdfc3k8gwf3jwx1e9jpm8nvyjaa2g create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/q/rq57j344ypcyv8zrwr98g3g5n8h3pr19p8mcmmg6n1avc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/v/rvfj1zs8cr9sxh03r64qr0y9rkmatt2qs2772k49fk6qt create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/v/rvh6nrpbnsfjd33qy67epbwhnvf8rjr75dhcz9w85t8ta create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/v/rvnx9h9xjstjgzmmj18r8g515kwvre8wrb9zr8btxhpyj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/w/rw6hk88m8twgs79ndsypq12yb3ab7ae4n2t3z45gy2ey8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/x/rx7phk58zbbyr4dcgzymj9fvdwpyazrc9f0qkpgb17p5w create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/y/ry06bs5fkzz4rmvkf6p1sv8mhyafa5bgaar290ae37kxc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/z/rzes82sf0h9mheve4rtr7et2yahhaapjhjfajk33b8kbc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/z/rzktdgqz67sfj5ykcwv0fr8e3ssaesj6zxnfbb2pgjczw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/r/z/rzvcecva3rt0z8852gz1f9tgq7a7eebcfbs5dvhbp3hr4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/0/s0z3smqnjfb2way9n0n9praqmjxjz6j87a2t6n04gzxha create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/3/s3as9nevz7ys78r8cyz6jhd7z2e50c8ve5npey393prya create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/5/s5dpj46txknxehtjbtm2mf8xe42m810vdfw9ngf5e2p6j create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/7/s7wz172q8pprzf70wxcd76nvqz816abpercv1m6d0tsje create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/8/s84jvn9nfee3kzs0w03f45814khxz0m70hns9mf3kbhrt create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/a/sab21yexdccy2rhr3w32q832kk62dbwj6rmj7wnnfsyj0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/a/sah5nna4pvs9azyhqsq3rqz5dxsr2m9n1a557zm3ejx1a create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/a/saswj19zc6xv7kmsb087yrcrhdzb4hhvf3w65pxkmbkh8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/b/sbepevrk0tzwspssqan4ycb1pk0scekrjak5y8t6jm9e6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/b/sbj1y9pevygw3shngyczkcfcxbmjv4fmf0tqzcgy9w5wy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/c/sch1bx4mpgstvnv1fns60d9hrzswpt6s8fgmvr6pjtzd6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/e/sepyp22kyv11cm1njcbsxr0d0p9cnyaqjn8cpheqapv4c create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/e/sewpv417w2tcwf9p9n6sj8c5aa14eryvjt55q6m61byf0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/h/shbzkkv7z5sq8ejty3d85npfsypfnrtktm61ce75wm8gm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/k/sk04ga1sjg4xj9mvqfbxq5a8g0rczv1p5hmpjj7m25fw6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/k/skw1n9487pkkys6qjqnwh3dxwnnfwwd3yrgg6cb49jjdc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/m/smed9gvse0wb83r7aqgkstv6gdcck4h94tej49q39tp7m create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/m/smj6k6yx46bcymgfhcmn1hbhej3km6yfr3c9wvh5xe63t create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/n/sn8ydke73da5rnxnmpdn1sywrw0e9qw1z39rm8vw1875p create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/p/spd83sdtasgb2mw9aaaqtd2ag8bd8r8sg02e78e5nrhqr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/p/spj3bsfmd8z424mnm6vnmqxxk2578bkzztxtxbw7td7a2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/s/ssqjmb7kcpmjdfbwtqxt8mmfqwacc1ag8yprymdb8snep create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/s/sssc9q6nt579crjpv174n51wpjn43bn909zaxnaayb4sj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/s/ssw4ytb1yy66twvrgjyfvwhfnkxk2kx2b0tdx3pcbsxae create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/t/sty8pqkhmpd4zqgwev6da6th185z93cx5xdwgvjmwjtr8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/w/swxbs2ndsbvwv69rf6yrma4478m5tbq1rxaew320spk8c create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/x/sxgx73x7d4skxrhkga3978tv1ftdjwa13gf35gxpb4mz6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/y/syemw0n5g8krbh5mfk84gqvbstaw9hxayxjqf9q0zwsra create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/y/symmye7nza29sez2a9029kn3h0g0f51yvm5ertx0cppyr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/s/z/szkkg31h97m32mqp6qrs2p8f41cvr6y7f6qfkr7bcpzke create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/0/t0nc5jyr3pe6v9bs5qeaf4khz36sn00g713mypkjvb7me create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/3/t3gehabpnf1n5b1znxw3tssraag8cb1z8ff0zscdtsgwt create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/4/t4c0kr0xyk4tgzr9xmzgk85mw4abc3f7qw7hjrgyjhv9r create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/7/t7mp7d81dhz89yhk5yk0pxn4jxj751g9yh1kvqwtpd5ww create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/b/tb20b0s3mn5gg6e6jjxn7fs8khj3jh9de89q75yjp2tt2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/b/tbh8ppt850729b51y9nq4wkbkeczhyr1qbxdyekh7ggcr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/b/tbzd4c43m17kehn6f4gbvjv81512b7ma1ffaq1xm5e4vt create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/c/tccnrkkqzmrd17eh91gmtanm2hqs9jva7xed2a54cayd0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/c/tcqdv403zxegm5pgexxxknh3xzd09f9s1zw488xfzab4r create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/e/tewt7a2mr57vzp3k7ydqxm7jdqg2xykadr6zbjkq1qys4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/f/tfjrjfrctqnbnhkwyyjgkcfx3e93q9g42xfx6prq8mqg0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/g/tghvavtjyjphjx3r37e97cpexy5871p899xet1x7m3ht4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/h/thzkrf36h9dg6rwsac79b4k61gw1vqv6kw8n84ambexj4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/j/tjz9ftrgnt21xexwhtaznm62y4d0n39sgcey08s4pqn32 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/k/tkqszdz6rkktpz6712rj3jfh5x4by23nm5tyrkgabbxqr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/m/tm1sxtx5gy8fg6qqxy4fp89bd6j5p43r7k2rd53s0546m create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/q/tq0hzsh2sy3ddcsg40ew1mwzk7t3ndxnx76b7rk8pcbza create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/q/tqqm05gz4tfbkzy9d0x40p1cj1mpvv18yx53kpwk0hajm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/q/tqsgy5jc4ey7xqhd0pqgv9peh363c6rtzpqgzxr2j370j create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/s/tsr9tph355x87s5cafd7358xfetzmna2jaje9tn63hnze create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/v/tvg7yr8tr3r56kpmyh06mgde04kmepy0y78fxwkqbvya2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/v/tvmb6ayrwvh5vxfdq3xv5m2qvx77r48zezsjedz6mmae2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/w/tw670yp56sq147e0zedx9kpbkqgceykbz4v2y6ga8wvjw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/x/txnccemyszf7rt08ae038h1y4j3eangvrjm1f0qgfzw18 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/y/ty27wk4wrch8ce8vdw81g5azp09v462g422pxzsxn13jp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/t/y/tyegkzzk97gb87zw8n0jxt3e1tm0af7ga1s127eg8y6g2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/0/v01hpm7n0mr8w9zvfjj77ja3dds7d3t4eykavvjyb9m18 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/0/v0mpmhw2nvq116a2mq66w5ac0t0n0rh9n803ws906ezt6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/0/v0n4ehya912q5endeyjvppc7xk4a3p4pywpme4e8cm0f2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/1/v1bbhk3wqc0516fwh3znyrpb8ccx98nb67ytedg78vz4w create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/2/v226w6c43jv18cfeb1bnxkjc1dv6yvb16ghhpksdtdqam create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/2/v2ydwb8kqxsbsft3xqrjr6ph3ppj99yhenczadg1b6ate create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/3/v3fny0ttw0wsmmhf0tt3qwz2w8n455h6ty27qjq0pwqxe create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/3/v3rf8grtvs24scm7eht2f38dwpeffbmnxptb81yszkbh4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/4/v4mx2wxpjc3ypdq1rfnjhg8jxg94pnfyzdsmkqq10vgz8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/5/v5j0gwb56jzrre8y93et4mcv9x71s3takyq3bkf8kwagg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/5/v5sxkhpw15t9fyev7w2frdce2kzxtrbmpvrpm77cvz15e create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/6/v6qzwvrh6qzg0q78njxekj5xg587hfb3x88dytjc91tqy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/b/vbtrzd9d9nszedymt6vd4b1nfyv5g3ne00k2cqf1d4zxe create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/c/vc5ww77ga0fk0cdsxtckn180ensm0ns09dyavgvwky8r4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/c/vcxkywx2ywv64776g163kf3cefzwz3694bxebr7svcyw8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/f/vffm0hhkv5f63jcf4j05zb3n78vd0qp63fex6qeq4xkp2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/f/vfy3tt0qcnf44gpzmrtys7c6m0payywz0ebwd84xq28ky create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/g/vgwa3yyr5zkyk7dg3xpn2rzrn42dgytz80he4m10560xy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/h/vh8rwxqf32axt398a08qrrvz9h90qzhjq4x86evknssbc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/m/vm4kkahbvyvb8sffh3rwmf7eq5bydnv3vx5gtap05a9z8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/q/vqn8sf0fpgcf5nth6d4xkhjytxynyqpr8kp2z0nmxc0e6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/q/vqpgxh7cnypmzrfphqxsy7qtxbqtsfnq1ep7ndksgww2e create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/s/vsdj5q9vxs4g30xzwvsbz7hg6nb9dn00tpdc6qk9tyhg2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/s/vsyxzq69qcqef54brey6fwpv7dh8fqmmgmbzq7a6n4j60 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/t/vt2g24hdjy5vwww4x7y5p44azbjrvzjn1717jas35cteg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/w/vwhwypz73cj0fkgaachvc33598qjb92j8ctd4j4ng3ndr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/w/vwtnpjteafpchkcd19tsd63z67d4m1fxbrwy46skjamq0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/v/y/vy8fz3gbm7k0mxgbew3vw5n5bmq6jhakqmttp3r5dbgrm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/0/w0225bd73w9dazbw6jb2pgh84cpw34z4aga4jzn7b82ap create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/0/w07t44ytv2x4cagakbp8vyced6dxaffy35h6t2fsa3nk4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/1/w1229a8rvrkwbhyktew1xb3frek1atfrxzw33kq8ssgh2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/2/w2abwa2c3bmhgjnc1qmt5xrhnr96aarma0tk1n2dz8sft create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/3/w3nar75v78qkx3d928h0he832sqbkctbmcrk5fe9ws8ba create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/8/w8j0vfcsy4ex7923x16y4wrhh0h70kenfhy215j09jf28 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/8/w8rwmgvasgfdha3k13fyf7h2m6mg00kd77waj719nhbfe create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/a/wa556dm9x1mzfj5g2th5wmys862hry0ryn5rde5xg3be8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/a/waf2pz4cpn6fxk22zay0d1g8k7nzbhffyf573ajvg3te6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/a/wan3zs63jsevc9x72va1apz2t0ynsktxdxryvsf8bpt10 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/b/wbn6hd1d29xjz910rz9haaxdj81atz1gpmk6a8910w5jj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/c/wc7166zk28n709g67hkqn9e4vb38t749q18srgb226yhy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/d/wd1dqfbtbahx5wngqwwzjrs59v7p10gfcndybp0d96j6j create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/e/wee7ssenrycdbatem6dtavfcxnyqs4qmaca3cnaxk1bya create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/f/wfr8wqbx83fgq50mww2ect3a8j08189dy7v8663mrregr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/g/wgbw3wrjhp2ywmqdg8cbgedrjy9apfx30bvm0c4h4w9gm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/g/wggdm8g9sepcbgchsj5gjfhqnn15r4xgxzv225hd94dqa create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/g/wgjt61ess9kww0xvgsq35ej5new78w63pzkhfc252tchg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/j/wj34mctxj9r2m4f7mp8cdmg1s776c0feyxn27h206yms6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/j/wjj5qa0n4pp10ejqmt8qrzy6wvwkja36my7rhtc046q14 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/j/wjk3ttywnza76t2k3z4qvrbmyg2b9ptvr7ennmym1n59g create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/k/wkgbj1ak3n7ercyw3x0f3nf884dja04kcbg7wey0kfvxc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/k/wkktvvynb5h7hgm8py35yf9ta0r6psqww75yg99ypm26g create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/k/wkygkggtxf22b7w6d38faw092jf348v67vp78dc7esj1r create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/n/wn5e036b3prr4germa9hy89g82j908yd9tn2pg7vds984 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/p/wp50v8nk3akyvwhn06hwzz1b1ssz04n83wwzc1ex5p0tm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/p/wp8ksqp4rzj5czsyq8ad6dmr0zbw8mwqpzpyt5zgvs638 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/p/wphfn9cmx58aw16edmv25m9p93zvvp2wx3y9fd0e9ktey create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/q/wq79wfbcss4wzg30xfctg28sang4r84taka353p2j7v3w create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/r/wrs5t71dcjjsxgs535bvcjgn24hegspkjfzsdbajznj4c create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/s/wsfags1x4xer51704f72d0ymmk40kabm1eeezg84rf8r6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/v/wv6st7rt4c9n8pqq0t14s83m0akm8cx594yv0fnc5zmg2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/w/wwb5adm1pqs5928hf33j2sedc6j7try738exxnh6hypc0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/x/wx7w4p18yyc3a01apa5qz0w31n0sbgbwj1jxvs3dwh8zc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/x/wxd3t34dgg13219xkkbakdj9wgrshqsg2vqmj82t9hxm8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/w/y/wyjsr0jjm2qa355th3w231761y1s3cwy2bqzd7eam3wbp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/0/x0b9bjk8bhnjw5zvg8bmm9tbvfxjk0vp4ejy7yqn51cat create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/2/x2y2wxzhvb64j5v9y1wsvw25wskfh6r4r41dhcjx9vf84 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/3/x31bt75p0d02masjc7bb36dqz3w478hrp838z7vgnmkfc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/3/x3xn1mgbwk5sm1eksq5rdw36x3qs1s410zsd7fyz8tb7e create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/7/x7z9y3rfa7r2p2as8e6cb9nd4mcze4ez61hrdc59bj774 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/9/x9vhhbw4nq8hp3bnekcxcgkxvmz213h30h866bw592m50 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/b/xbzbem843j8vaevc0551zcb60f8br7ezhwvyzfh8g9wdw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/c/xc68061ezanp6hv7db2605w2r8v3r092yfcs6bnj4fxqy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/c/xcz9d9fqq2p5tbxy7bg0kkye1zhj9dg932bfny8h7j412 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/d/xd1wspeerh2t52fm38ngbcv1a0vy24k6j2hykbtf6g7vw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/f/xf7nec3t7xfrezaacqkt64v40xmbapa90ra07h5kqfj12 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/g/xg1nqjd3axjyy7vswtf683s63g7x4qbtynp1xjtpawrx0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/g/xgzc2sv4nwbamhn2p6es0n4t1r292078dwe5w9mwr1j8t create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/h/xhmre3dg37xp3988dzxnkeaezejnbejvjt93b72g20c5j create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/k/xkbr14gk3a7rr65r5tk7hfat39pevmz8why3gn0tvh57c create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/k/xkmwqaa2w39myhpa309a3b2hdr202f63jfbr343nzhmza create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/m/xmq5ewyq17ta0sadjn489c4dpkgn5bnrmw6be2tmw0dw8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/p/xp8sqt9zk6h6bt0tq2wf62xb1pck71qvn6r8d0g70mmja create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/p/xpvwyb9ad0rfk3yjwtfjha05etx8te3peqbwddheh8fwc create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/q/xq3tjskn8hg3ydkemexpfa75fvm46rasg29y7zjkd7za4 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/q/xqw45r3n70nw3wj6d638e448qf6zbrd0mt87j9698pyj0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/t/xt8jyccjejyze9n80tsqf7xsjpq5nzt1c21g8rmsa1khr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/v/xv4ne8e51c1hch84yxk993218ykvmfp3gq4c66r4x22hw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/x/w/xwhde5sh1dmy64dvf4jjs30x34d291a6v6r2d03nqnpvj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/y/1/y1xw7nq6z3pdayphm1vyc5rq1xsd9fadnp8m3y6ykep1y create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/y/3/y3qj9bnaksy94s17nvg4gef25kr6w1p125bq2ypdwv7ac create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/y/5/y51y1mf9z97wqwnxyrhj1qrt0tydh3cgttqwhpdxyk6by create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/y/5/y584nfccdc4nxyk791qsyfeysmt4w73kr0t1xbffvyv76 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/y/7/y730k36mhsd91yaj4gkennz0hng2992z3wc1d2b7xh1b6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/y/7/y79exx9baft7b1mvwk8w7s45arqjmgph7gepxhyjyzfyp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/y/7/y7jjsfaczgb0t5ef708k00m489v4b8nrkhz4y6nnxcf40 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/y/7/y7sz6nb3rz8wx7y76cymb95zt6z691adqvfnpv80yvsy2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/y/8/y8gk3gmkbgwb9fe497h121av0m23cnd6zk1rr3fyp7hjr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/y/a/ya3d6rzthp5zxm8jg5f6nh6yqs81fefzxdy874fmh6kg8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/y/b/ybt964nbb5yb9ps6jtk72grm9y99dv2q7xc1nbk41h5fj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/y/e/yex06rh07tncp10v3ck21ftg8esb1ez461dsrafy4b1cy create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/y/h/yh3g712vt6x1b3zhcj1s1p8jxfen93gtd42fxtjktwykp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/y/m/ymr2htwvdcpehh55smk7n56fcmz7mmqcpfc2k83q51qkj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/y/p/yp25xrkzh6cbr4afqcawsaredtfg9c5ape7seebsaax4m create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/y/p/ypj8a1df23mmj32g64hykewsqzng41a5zkj006089msq8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/y/q/yqmec8gra9kkb9kp03kfsq32en9qf0xnq8e3628mk4msa create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/y/r/yr76r68778ggn6d8n6npcppzwrkfhzk84jxv5a4ty4rgr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/y/s/yswexssab5tdnfx7511f6tk9p893yhkvfe0kw4scj03dw create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/y/t/yts85j4ftnhe1nvktt9j6dmch9hj2bhwcqzpjxvws2jrg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/y/v/yvkhkdhwqsd9t5eq7ks3wf602jf3bwt8eczx2vybh6zc0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/y/w/ywmhyj7wq34fhptmx4amwpefx3nqsww494c8wyrz37eva create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/y/x/yxfmh1pze8kkvezr7abqjr3tnhpqbbxp48kd2qwv0wk54 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/0/z0fk59m6rrgjabzhxmr32c09fh750e6k03zfa20k2vrxa create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/3/z34jsxa265sxqyb2cwx1thqtexxcar9egnjvnpcvkcrvj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/3/z39kydgt59x46cdhf6vjhy39pe44ge3rvkhvb1nkwb2zr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/3/z3eqckb2scmz4kjf7qt1yztrsfky9qraatwe03x51h7k6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/3/z3yvw1ngyxqxp5wn2km4cd12kbm9cye0pz29wcymqgwgp create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/4/z472bjs2xxz4h1frvp4kewrt6hzem2ksne0k68c6w2478 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/5/z5f8bcx0bhxt4bc16ybcgjxgakyhz6081ej47wwb6yr6g create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/7/z70ryqvfm418005sc8r4bfm6v9ys4bbrmf0x5nnvsn1m0 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/8/z821q1k0181fd425hst88zjpc27fcjs81z16vp3f89rm6 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/9/z9ap3tct6s8eqh3eck88e5aw9sqj3ga4yzznm2m2j0604 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/a/zarvjgwmv5q3vwyd58gkw4gc501v7zkwjx00pkmgkft22 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/e/zer1ffmaw8crmjm9de5g8zqtarpbwr23epvv20t5bs8x8 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/e/zewv083f1apdzf1kg8vbg2jjfnvxgz9z00xa1h4mf65sa create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/f/zfg0xsh5caxhzqb9z8nwpjzsvr0q8g0fjkz3y4y43kdjg create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/g/zgqxey2qy8j4gqm0rd91k8fbx1p23t4nwmc7gabhafhsm create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/n/zn265mn3xv8v3v6zetbedfg88vjcvffa19ebk98pc5t6e create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/n/zntc9yjnew3s8krzbcd9m8b567mmq3d92b7e6henf2nhj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/p/zp2gxjckb10wqsjcp91bmtqq9chq2qq5gpdyym87v6q1j create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/p/zpm8204mejxydjsawbrhn7vje3xjgaar0cpk7zy64ws0r create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/q/zqwvef7cvxgb2tybnypx352v6tdbpmr49vx29z97z5jtr create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/r/zrj953c90pegf5s0v2ehgb286hxrsgzh77cv6mx6zrfa2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/t/zt8jegx974khs3jmwa42r8h98wypp5gsv1ss4s8je0166 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/t/ztkqhjcy7hbng5ndn9f36zaxab33220jxj2d0q7rgt72j create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/v/zvcfa3ehdtsn1djntnwmv4mn2jm17t3t659k2b3mn1ryj create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/w/zwby1chwm64dgy0t105pr72a9se3x4e75xennhgf7fct2 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/x/zx51d2g9vv3w2s6eh0fgy6esppgtmhary97nfcjqgtfza create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/y/zy2w7wxymampccdp97g9rzv76qwxk7vj05z145zenb364 create mode 100644 implementation/fuzz/inputs-genvm-modules-complete-json/z/z/zzn0apphqhr3g24550pxepzcyb5j2gp8px27fdjj1dt0r rename implementation/fuzz/inputs-genvm-modules-normalize-whitespace/{db91d0d947f0f760465149f837c4bc02bf02c988c7eb7824c7e9496a52884908 => 0/e/0ep4zdf4ndsymnwtkeh8j0tztts0y186jq1bcw3wch8pe} (100%) create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/0/p/0pez5en5ybbdkbh9axzqq7c4wgs8rt6mctebe7zf9kzy2 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/03fc8c99262f53a7d60c876faf4876a11a92c2e045c0ad0fcc738399f61fc240 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/06e3c1413644ebd520e20235d3dfa3145613e296cb645884ffe0b885b63bd99b delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/0a150ae9c5d282876a4e896149d6c486e771088809bf02e59aa61ca3d1c3e2e1 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/0abd764f1b303911ca744e429fd729ffc1624caf063177229727e526f3dcbf1c create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/1/4/141ka9q4c2mgw2zqpxgjpmtbrpcx3q4ywn28z3hh4ss9r create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/1/s/1s28fveg5getzbynkzmb3t77fh8g40qsq7xp2ebfm6ye6 rename implementation/fuzz/inputs-genvm-modules-normalize-whitespace/{3caac4d461b724c627cbc28a9e96641f09c2130fb7e1fd0d9433bd63b2c12a20 => 1/t/1tk837vrcb0qn02pw3an43bzssvwsrc1e4t60fq0dknhc} (94%) delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/108efca4997c179e75c9c443def521c0bf14f754fa13984e8f6f4b25e3fe19fe delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/13a6f1b73ba94d5c0ec7097fac90f1bababca6ec0095c6d7dc6fdb4680112804 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/18847d26806d9ac4981dd642d6aca8346cd197d647ed119cee4a6e5e95785183 rename implementation/fuzz/inputs-genvm-modules-normalize-whitespace/{85870cb385a6431e482529b899cc64ac4e3a3f99424bae342e19e1ef8cdc0fb5 => 2/n/2nnyph5gamd1qcg99hg1yc9c37h5ej81ny8m647z61vj0} (100%) delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/2afdb94524a31c4607ade0e66a33a33b94a6e6fc11da8e0ac8dc684550637684 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/2b0698696f26299c279bef4360e307c4f4b41dcf7a8fe4db7b82dde9103e1351 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/2b4985bd1778fbb5f2aec4265651102ad3f0d53bbada124914d102b92f2be068 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/2f2af5cba25cf00d90e48678f7092ae6217152bc42205385d0b5996721c6034b rename implementation/fuzz/inputs-genvm-modules-normalize-whitespace/{a77a0b19ea78584e0ea34252aa4faab2839be31b03d9f27d7cd86f503153c038 => 3/x/3xfr5w22w0a3d2c5tddyy9qwdjg55hj6ve1xmfnpct7dj} (84%) delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/3462c1d0fca3164ff490caa99736fa4eae1ca1a646bf880d8b5894c955033450 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/34e791781a9d100ab2a6d7dbef5b5eb38c4c38d887618ff5e94a8d117d4973df create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/4/2/42xap88t5te2mew2v7b9ekgkdy86ddj7kyg122q62qyrg create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/4/3/4372gqsr02f3mbqpv5sb1arw5zcrvjptra0e18973v30m create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/4/7/4730f4bwrk39hybvx8szvyvqyck9ad0aejq1zz34tgcby create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/4/b/4bnwwcdggzxf2s57jye94rmc46zrnd8551hd6gaaf0t0r create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/4/h/4htd2gzh8zfzp34tyr6eh4jq6nyqev0nbgvtpswcybxrg create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/4/r/4ryz1gbe2d7tkmrb5jab1m391vjpytdx7rgx8bne9ams6 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/45eae75b464a765dc836ffdd8596874c5d0b7fa33c9685fb77ac22738dbe9edf delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/4888b4e22f1132f4617b3470c99715c2701e115f3023b1e7893d335bf807d4c9 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/4a6cf03c7706d26879d5a738f98eed6e39312ebf0b61fa1f053b5cdb3c8869a0 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/4b531e98e5057fd2eb3c96eb7973a5c90df1234758b5ee02c97755227a084e3f create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/5/0/50ae4phj2re52zkjrh1vj0vgh66t73e2870bhrrvey074 create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/5/f/5f0c7bjwbwg1ycpwcfp5dpmmjhvm7jk2smf2eevwcsvjy delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/50ae20ac4f0dd0a0d779ee8b2017b11348cfd8bd0f591c2abc2bbef7b6e95134 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/53a4e4cb235b274fdb21397a1141b4d6b3ee23fdde1151f799df7c3d14c86ca1 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/55443a6927436f5f0fde21ffd5ae2c195565e2e058ec518421272eb952dbd429 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/59d573431e4724864b40110bb3247f783fb8fc33584238baeb1519ab70b426a1 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/5c2c0103f79c00f4ee500842085ffcc424ebab149f1c85bdb6991de0b4ab86f6 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/5ede5b56920816525591723816c93c0d9c830264b24ca58c386075072b388372 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/5f77b630b55a04c392f2caf506e2660aa0352a11c83af4f9e58b01169ecb8ac9 create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/6/n/6nzf697cve2978kqd9jby90x9ekg4m8m5nysp1jngy8jc delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/61c8efd9f69870226747b046f077b5751015cea9dc045849d65509918973b62d delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/620942b003b1bae02a40d38e7b03f3cc4cc9e948192cfd5e7d0cb77b31d069ef create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/7/4/745nee7h4x050p29a485e3t21m37hsa5y7a1wn9amb3wc create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/7/c/7ccqs9fgddtc4r3s7axbxz1hr61n8rtqp6nsqc0cd5me6 create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/7/f/7fd6ksepb7j5k4q8t8e3p230agfvr357se20qa952dn2r delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/70546d5fca6e8da3f4320b2bb5a2789bedcac8a5bd30820c7aac957d3c6e1684 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/7923fd9b7984beaa52f2b5e97ecbf0812db63788b4eb8411bcddc4be7267e428 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/7b2c4f7c87a84c1e2c26e69abf2fe09932db7ef15b4c939c079cf8fb0d275cbc delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/823ded55b18db8759c77a9c684b6d3af75c26871dd228082e3f3171ebda3b5a4 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/85ccfc35f2828100617311f9ebb138147e03034d9acbe149c2c1e93fba076dad delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/891736f80c0acb4550ebf3a53fbde2113736faefe5e5107d3d7da299369df1b0 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/8fde056b9da569485292d132338d9af447d0b4e17345b30d0874b8ecccc88535 create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/9/1/91de5j750xjrn3kyfs8n3vgzt7389p5z7rnpxdw20mfrt create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/9/4/94g4fe2jqv1ktz8h03heqvtybz5zekjr3kzgmg73jyzzr rename implementation/fuzz/inputs-genvm-modules-normalize-whitespace/{931f79f6a9b51bb5822885e25a66a326e2beae862e1f8493d137870f9526abb0 => 9/7/974px1w6qq7hdrmawg8d8m32fccy4ft8jk32h57863qgc} (93%) delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/9cf2c3c978eb136c0bc952d366b028830ebe2391400b3d6658ac26f5dba36868 rename implementation/fuzz/inputs-genvm-modules-normalize-whitespace/{8d56d269122a8bbee7db1f44f0d2bc3a834cb31b8d2538dedc5c0b6ff9a740a0 => a/6/a68wtsxj7hgjqf2j6yrqfqcbqa85px7mms469p8j7n2bw} (60%) create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/a/g/agnftywfhe3yc82jp0f4jad4wad9awev9gbq4px62c0gc create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/a/w/awkr5j8mde696580twqnhkvrkjg1b8b44pf9vvyhbyc7m create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/a/w/awm30caerhxjrabr6nxxp215bmmnzp576ds3n0fnd5qej delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/abfcf8aa5a090baf9be4f429ac9bea30c17dff4b027e19ec303d143d82cc3eb6 create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/b/r/brgcy15k37c4rk914aktt5fxp4z1wdv0sjzp0va05a3s0 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/b84925528f02d3ff5848684e0c537a889e6d301c9de358ab1959ec04e80af57f rename implementation/fuzz/inputs-genvm-modules-normalize-whitespace/{bd2ee8d25a19d78820a021ee98d8dc8de927f858011075464cb3ad4288b7ea0c => c/c/ccn0xhgpacrfh1aq74fkjnkd6qha0rp1z9zr22byttbgm} (100%) create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/c/s/csx0dgbx4j5a96gazak55b9ekgvw4f0cgk2zbmtjjjkve delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/c3bcfe060468c318a0bfea760a116fd4b1e13a3905ae812b4c4434484297ca53 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/c48855b1773d9593d2bfbcd50023edf88c026e39d5a407c1b7b9155704add33d delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/c7df8fdd6edee85308057d4f35c608d9f2d2c8e9320b136bd312cf028400df4c delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/cd40d68396aa759f586d90a3b4887a2672716b4ef446659f26d1c030acedd63d delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/ceb8a0e16a10fb5086e705c9cc73174b55c7a826833b26ab01a78cc5304725ea delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/dbfa4b3440b784d342db858d835171514a94c3b3fee05e4cf9caae20e0d28df0 create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/e/4/e4692ckej8yvykkywjmdmz3y8k7062my5rk753watxfj0 create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/e/7/e7yvwya7erng8g6r1xee9we5cjd7ys97ejb0yc1crfpzr delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/e6237eb52e4a8750685e1fb8741b2c0cbac5e873876430bc8f6e41b5ad0209c8 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/e72d0a509f5966a8861516dd92358725c1c5603183da9733bb90a125f85ab9db delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/e8b6d77f122eb966b7a7cbb6a225ef83020029066c04ad009ec529c273de0fa8 create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f/7/f717g71e7k6bcs5q565ze8z0f8xna7kpmt8j8kcp7t4rg create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f/j/fj28aaza5he7xhhe0pff01yxcft748ycsfxjkz1p1pzw2 rename implementation/fuzz/inputs-genvm-modules-normalize-whitespace/{5df9f5badb887ecd9ffbe572515a25f71356275d18023fb295c80fe8caba5c82 => f/r/fr6sp1b7ghxs3gbj8e6je6nc4bwqra5kpkd4exvremh62} (100%) create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f/v/fvq371s3kcysrjp95yrvxpccg93687d7c8c7ypv3xadvg create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f/w/fwqe7ds6xt6f0mvqxw2gvqmwnsgb15fas67ge0wb0mbe0 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f35d3bec11953f5914c9ca460ef3d4a1d5d7121d0ff0d8d6cdbc374ae9946c80 delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f71d8c3bc20355985702ac0223e06edd28d33945777415f169219fc560a6025b delete mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f7e3e6880c7e27d1a97f3a04f448e90e33f72f377cf4fcc582fa70c9fbeec75a create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/g/e/gecqrc9ajgg1n1dtv2p2v1qjxjgrh535tb5hwqkngyz00 create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/h/0/h013nnr4swa87d0ztyyvvrvqb28vkagw6m9xs5vb9grsm create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/h/8/h8rtrgawv1nqn6hg52g9t04zpspzmdrakrktftpejfg4y rename implementation/fuzz/inputs-genvm-modules-normalize-whitespace/{f9024ec809d2d43073ab044fa702ae963fdba5c841b38a76999eb5ccead5518c => h/x/hxj83xa25drwh4m46gdt9naav2gzf3yg450m3gtd5xhz4} (100%) create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/j/g/jgjsyahmzmj5v16fek5xs8aa88g7nbe8n3mwbkpy4j1ce create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/j/j/jj3w58ycvjfwcfsv728ky0ym67zwq5ghv97tr3gvs709w create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/j/j/jjnrnbpw8tdkz7x7d88ksjpvma82a1eesd5kq3ma7cbma rename implementation/fuzz/inputs-genvm-modules-normalize-whitespace/{0a53edc743484691ae84defc2db71ac98893a8c4afc437239bbf602cadafcf01 => j/m/jmg6zts2m7cnj5v0cwbp2tzeez12bya52tf8ff84vcx2a} (89%) rename implementation/fuzz/inputs-genvm-modules-normalize-whitespace/{07d0413d5429f6ec807e88ee6428490ca8c4e7486981a814b99a1dcd1460be16 => j/r/jrm84mt72pk0x462yncar39r2ztrbqa2hz12d6akabk92} (69%) create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/j/s/jshb3dwrfzdq3w7zdrmsf5e5ed4djp29a0a2khgaff4ky rename implementation/fuzz/inputs-genvm-modules-normalize-whitespace/{24047b08dbc5f81e0d744bee88f975cd94332c54c3887d0305a1b768ed23b1ab => k/j/kjzgqk5d7x3mfk4eh2r3erw2bcjvbb2a4tx5bmyg5h7gm} (67%) rename implementation/fuzz/inputs-genvm-modules-normalize-whitespace/{709af572b2d689c93a58cc6beacccd0e41429338d17234b2a1591ffbf28e0aaf => k/z/kz1hkv3gm079cr4xbqx5r88g7n89246m27dcckhwdrdn4} (65%) rename implementation/fuzz/inputs-genvm-modules-normalize-whitespace/{b39d82c804f3d1d5d8b219aab4aa30e36f7d4e00e1657d89a4dd2cefc2d47c58 => m/k/mkvxxgdq2vw8r2zch1k1m1j8w8s48dtst8d6ckyj2hzg6} (76%) create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/m/z/mzfpjfw6n0r4khj55ptpnx9cayycmwj6rb0hc1q6m8rb4 rename implementation/fuzz/inputs-genvm-modules-normalize-whitespace/{add963d8792a3271636e0d20bb97a73de0ea4220567f4fba49a271018360f15f => n/e/neab4np5n178b82cn37w6wwwew2s3hbz2xgtawd732qm4} (75%) create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/n/r/nr89fnaja49pea92v7ynqbrmtv9fmeqp91kpvb5cxkqj6 create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/p/1/p1zpp6xkygnwpdwe92026bywfvmxgwjmms4xp1p031gne create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/p/8/p8awpn2bs92fdxdgba32kgfqzy20eqysnv60tc2bdtw00 create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/p/e/pe5n6cfvewh2w64bd0za74k56dm5w120w067p8e7s8zqe rename implementation/fuzz/inputs-genvm-modules-normalize-whitespace/{167391bcddba8328537beeeb9c29c8ae7c1f4a23113ce87e30aa365fdec40971 => p/x/pxbseqw4f9cwxkxm8qjv999ydvxydehy9xfrw5x0pynjg} (84%) create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/q/d/qda1v0f123z425e6e676d6jxpx5depn9zy8mrncp32ky2 create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/q/d/qdq0byn41gzhq0wqwfcs77e4kcmftqh4r11237dqpg8j4 create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/q/j/qjrs2n5jd5yenchgmwk4zny08by0d7qtqq6paysg185h6 create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/q/w/qwk9094vv8hx6rmr13g2ncxp0wjj2pbvd73t02498vdq8 create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/r/5/r5jvp155d7b5sa8zbgqzc2x6176bgs69qz9g0hx99r79e create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/r/7/r7bm9nh1znjv0nh4qcy272s9brgsz64pz4dq52sx0ajec create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/r/m/rm7j76kpffjnykfqxcgx0925xen98vn3t09atfgxapbmp create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/r/r/rrg0pbmdjev80ps4d0js812gzqa86q9jpa7rj5dn29rrp create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/r/z/rzpzfk0mrj3zpzt3637hkx9zr4578xrbznyq6e2a7w91g create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/s/j/sjnxj30614zv737b6tjpmtnce0992v52bzadh2rhxzjf0 create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/s/s/ssx9arzd57h63sh653erphygbrm9xnq5t4e4yhs2yq5aj create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/s/w/swzsf6kzdrj1gay4k3mpkhwen689j0z2191zpt6qw1bm0 create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/s/y/sybedhhm3tshmxs05mtw2vsqenrw8wv4cvw7wae800jk0 create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/w/9/w9frp6nrpx9teh9vx8q52bwe8pz3gmzv2320qv3mttqtw create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/w/a/wa80m1ba2zgfd9y9bqvh13wfm83kqbqpsjwhv4mjmqebj create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/x/4/x4gh60rdd803axv8pw9kh27xe1enmx1nhfhmjrags7jy8 create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/y/b/yb68cax2dvjwqrnpxdq5srdezdcfwjfsfx6bsfcf9sk78 create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/y/q/yqzk58tjef594ycch1z76qwvtyms5e4rvj2989her6rey create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/z/9/z941c9vqggbmfxm8shz7vrn24bvpvajg0wpdeym43vbym create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/z/g/zg4trx14yq823m5wamqwvdrz61sh6vkhc4y3fps0m02w6 create mode 100644 implementation/fuzz/inputs-genvm-modules-normalize-whitespace/z/x/zx6bt1mp5mztw0q4nzhjezfq249br5779q1v51s6hk85e create mode 100644 implementation/tests/manager_permits.rs create mode 100644 support/tools/genvm-tool/flake.lock create mode 100644 support/tools/genvm-tool/flake.nix create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/0/a/0a77zeewq0aqkcykz2bb1xwhdr99xh4w8sajwhz3k7t4c create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/1/j/1j7zdpm0keqes0emct1z75fvxqefmg86rabh7f58b9j1t create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/1/m/1m3m9gb15nqrbsf0s0yxnwkxw8bvjchzt3g3292nfh89r create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/1/q/1qak1b713h3b43wtnpxr3k4szgy779kkpt5fmmgk3k7r8 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/1/r/1rm6sfd3ce16mneqnza9a6k44q1q0b630bjyjsr0bay2t create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/2/8/2889c6vjcr10k5mct810px4hwtvkjjmfap9g4v7vqw49m create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/2/z/2z4a5kfma2ck2ptfr4vgf7x93035nc52ysw31vcmwz8kw create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/2/z/2ztshe2mqj9vscyc77m0xhsh0mv1syb797gssvxk2qgrg create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/3/x/3xjn8db9k106dpsxg3p4safeddkwr8vyb46fzb42ycz6m create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/4/e/4ebgh2n7349b26mbas03fnk883hbd8bfxkk3ta9gfzem8 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/4/y/4ysd4fq9jcf95wvg4fpk73h0ftkyg9dy285arxvgqft2j create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/5/n/5n4jjf4c6xgejs3ntw83jbpakfa8y26hrka9d9ykpkt7y create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/5/n/5nmfkg45vmckx2qj1gpm5tbke0cqedmvsgky5pa5fdhdj create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/5/q/5qh9w8qmh1wz818jmnwnrd7aqq6f7y39hx1fqn6gret3a create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/6/d/6dge9wd637rp52z6bazc1ph9jbacfknb3mpkcwff8y8be create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/7/a/7a5y9xan3xzj1vam3946gqbepe41p9471t8f5gw0gfn1a create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/7/d/7dbdpj58bhnvv9zcqaxg1gyf6ty707k25avczqr13n414 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/7/m/7mne39ergtbmmtvn8dwf5rts4c4k5aaac1t6rf7rypn1y create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/8/h/8h406nwh64gfav2jxv96hbmhrb1t03yqf5e61s7jf7tfm create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/8/v/8vfbamrjk4e8cm6nc8qmp2jx8dkqqhfs13wkb1hb5rq90 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/9/v/9vv23ykykwfjgdmnsfxxtrqzfjx5r0b30frarwecm3rd8 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/9/w/9wmhqg28z4ergsgh57jkqfyx2p66pdby1r1zs5wth779p create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/a/0/a03g00cnvfa0gs77n0y1ww0tdn8908qnja4bxw9a7gpmw create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/a/4/a4r7021ggw1rmd6qz9p3spjn266k328eh5vr8pg0pm2gm create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/a/7/a77dmacngtkjb9y93610yv1zh6a9rtd1s6dt3vjz00zcg create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/a/y/ayj9117xzpdr731k488aawap9fa25kbg0yez0yxncp8r6 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/a/z/azat8a0r7d706fa7tnee39qz1rbdc92ekgbxtgejyntrc create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/b/h/bh4wrvwgtw8a0xw2836gdfej6qxws1f66ej3hxtqf480m create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/c/a/ca97ypke6xjfbx2n9jpex04wy2rd0nh950vrteqpx6v4c create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/d/1/d1ftb59xsy5bkg0vacd8wrqrhm8c5s10zd3xcpc7edtn4 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/d/j/djj76h73qn7c9yh8r6xfzehdtvsbn0hkxvz5gz1w8cw6r create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/d/s/ds11mdgj72234c89gzj6k0cvw7vpb5v2n3c9327rmch3a create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/d/t/dtjpxmbt1f6axs8fh7kz3mb4xhstcm3erhpx9nnsmb5c8 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/d/t/dtt19bz3ejma3sk5xyk9bhnz9yna4w7qwc5xvqt12n1nr create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/e/5/e56xem18j5vnd0db4gmheccjjrzp6114yjzv0rwpvkarr create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/e/k/ek756vzwq4xcp9g7ncsqmc1n0bpa2391kkjwa70anx5km create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/e/w/ewzaq332qw2ef9kjhgknt5jgzqvq9959t18a9netpe7n2 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/f/2/f2977sr15mekm241hw6307vdxw6jfpvtzcv96e0kpb30t create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/f/r/frwjgmhyf89bdtnk33sfphqeqh99a7bgnjm672d7491sp create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/f/s/fs19mwm00yyna4dgd0vfdd2xsz9tta24qqnb3a5j2fpb4 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/f/y/fypk3np5dvfnrfhm0mp84qmkpbweyfyqtenpb9tybvv4r create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/g/k/gk362a9qzh27m009584enyxjpcgrydm3gpvh2pfgragvp create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/g/s/gs7tthhttxra0bw9pr03wswx1zca0tasa30ban582d1ry create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/h/0/h0rj8gfaf7y5xn1bd2f55dxj285rfmrv8ja0zypgzdjc2 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/h/2/h2vx2w3me566fak1gsq86nytqw7x2egsgqntxh4m811rp create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/h/8/h8s06mw10v4v4hs3dd98gfqnpszmh7s2bfp3bgstpx1sc create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/h/k/hke62nwahseh6j9eb81qsbggf2k585jf9t01jf5s49cwt create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/j/g/jgvxrb5teh8rxxejpttpqzwhthnpctfrnxma8fzf07zqt create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/j/q/jq7d47bpcygzb55b6jsjwh3xb7nq5p5swwg52dv0je7qt create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/j/t/jt773qwy1mj50y89pkcasgkkm326mykrzx9yvx94ts4kw create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/j/t/jtccnqnb3bh8m1dtcd9wh20qxbyhggqhk559d4xafecb8 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/k/3/k3n2b2f1cvyd4nnep751pzhdh0fn48ga066nn3d2jpgs4 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/k/j/kjy0wbyzj59320tt8pbm99abg80w2v0spd0v1g1q2jxaa create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/k/p/kpwwz2fcjyav4ksb0rcj53w0ansjt4gb9yh1ynhapkz0j create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/k/q/kq8w2s5d2rq6ncbzmryxtzcc62jz09j2vzb1cs24t8mcg create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/k/x/kxhe3xvpb0s9d1f7ffrnkwrg2h61dqqkgrn5sap51xkqm create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/n/v/nv0apj6jkdsnskpkhbnpxhq75zq69msynk5mab9mgv54w create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/p/s/ps065bgt8wk77gp5pacydweetf153h40chbhpb5advvj8 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/q/1/q1ggb0ky8p285276zx7gnbyfd8ygy3t6r7vrv2x9y7rjt create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/q/q/qqkmwgxfve8zjkwyag90ha2k573f1sfja9mcxttfmqkw0 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/q/r/qr29xg001ksft36c10dn085qrsfwqv5q0414rnrpwtzgm create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/r/2/r284nd9vqrwfx5hb6ve95gbakraz1e9xmqse6m6vyme7e create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/r/5/r5zhh7c9j6r51vggk6ab360krd6x252xxgh3tdfp6rksa create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/r/e/rekdzpff11mgb0mtkjc166frrkre6smknejpqcpt7f22p create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/r/t/rt4ykf5cbnv0n2r107km5yh0qqmx2vsjjp1qwybpjgy5t rename implementation/fuzz/inputs-genvm-modules-normalize-whitespace/0c8b1f460e1ccc4f95050847930e5b35a31848eeee570692c202ed78f3fa739e => support/tools/genvm-tool/fuzz/inputs/scheduling/s/k/sk5exxw1y9681n735pv748t072w0qz7s9x23907cdjj68 (50%) create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/t/1/t1hj52m3a64ws7xxvx7qps9xsnhehfay1k6j88tr3ypke create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/t/r/trx1968q1gq2y6dbw2nbykrrendnqp1stprbxvd7mt558 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/t/t/ttdsymeqpec56fp0mrr72150b33memf6nex59dhnbkqfg create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/t/z/tzhred7xrw335kmfkv4px3sppvkjx8kff9ykcv0nfr1gg create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/t/z/tzm8wzrej02f2qhyj478hsx7jzj55ge236qr4hz2zajdt create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/v/9/v9bn5x7sxq15qm7yckys35008w0b0d4mp59gcp0th6hta create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/v/q/vq8mbh2tkh0ce4nq474f49zrg0egdva3bxyhs2m0jhv7m create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/w/9/w9b8068b46gp8ajd9xzv810kws9j84q5eb2rj5pgmn9t2 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/w/9/w9exq2ds6v5amcy0sv3q7s2c8thhpb4tafjsmawb7f132 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/w/b/wbjmbw1dr6vxhxvmavvsa3zq0h4mm209am9qteesgyekg create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/w/h/whza2rpj7esftmqkevjy248v1p0a13rawsz3cz6jg172a create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/w/j/wj4fkpxc9em4mhhhymes72frtqxkjckgjbvwn5cdnzy4e create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/x/2/x25dmm6a6rbny7cwfsbxz7p2ccdjg3r42cfxqjaqj0vea create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/x/3/x36pbrm7ks6yytqpe4eye2n8zbhh15n3fnkng3p5m9a9w create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/x/f/xfnb5rmw43mb4w66amzywjvy5hrdy2zj8s9wy15g2vfsc create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/x/h/xhebxpwxedbn894hgq2x212xe7nc1ky9brgnqpt9emw6y create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/x/x/xxthw0f8kdytdk9ww8p3pb17seayx23p73ye02px68sra create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/x/y/xyechygnfyvjc98mxcqa33pxqdtny51d3avkgy5rqrmbc create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/y/1/y1x97drzaeq8r3a3tsb44s1xhd9rq5w34jceqcf0cnzk2 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/y/3/y3sn7080jpjd06ttd23q11f1gvf7e8x2vksq2987e74x6 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/y/b/yb13jgagqpa7t8wm0p1cm563cqzs3t7bnma3b1c15ks70 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/y/e/yep2zs7xpq5936mtf5cachrha72j0j1512g1c8hbgvmnm create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/y/m/ym3qhn9hdmjz2f11dxm70nzrwmb4akc4rh536xmx8mkvj create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/z/1/z1tpx2ffwwzkhmysrgp72696z3nwm1b9c0w0rjqs21ge0 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/z/a/za6qeb27pkvczyyz2b75c59yaa5c9sghmgrekcr80ea28 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/z/e/zef9y9cs4pzfg1bwv73k271wp240w8gnpgdbs1532n3mp create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/z/j/zj9tvrqmg8a20yn6zjg040fznngbfzqc6wd8hxqjza3de create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/z/m/zm2bj14d4d6jx6t9dwevjz9qjy9hvkm6yq0zsvhq0traa create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/z/t/ztgvvbrx1tcewc1h1932qkz4qm9yjdbs7g3072ackqg06 create mode 100644 support/tools/genvm-tool/fuzz/inputs/scheduling/z/t/ztkrh5101zazqjygn9mnf19aa05ybkq9hyh1w1as4pbjc create mode 100755 support/tools/genvm-tool/fuzz/src/scheduling.py create mode 100644 support/tools/genvm-tool/genvm_tool/cmd_fuzz_corpus.py create mode 100644 support/tools/genvm-tool/genvm_tool/io.py create mode 100644 support/tools/genvm-tool/genvm_tool/misc.py create mode 100644 support/tools/genvm-tool/genvm_tool/tests/exec/process.py create mode 100644 support/tools/genvm-tool/genvm_tool/tests/tags.py create mode 100644 support/tools/genvm-tool/unit_tests/test_codegen_detail_suffix.py create mode 100644 support/tools/genvm-tool/unit_tests/test_fuzz_corpus.py create mode 100644 support/tools/genvm-tool/unit_tests/test_fuzz_corpus_layout.py create mode 100644 support/tools/genvm-tool/unit_tests/test_process_teardown.py create mode 100644 support/tools/genvm-tool/unit_tests/test_service_semaphores.py create mode 100644 support/tools/genvm-tool/unit_tests/test_service_startup.py create mode 100644 support/tools/genvm-tool/unit_tests/test_watchdog_ack.py create mode 100644 tests/presets/python-fuzz.txt create mode 100644 tests/runner/genvm_tool_plugins/afl.py create mode 100644 tests/runner/genvm_tool_plugins/runners.py create mode 100644 tests/runner/gvm_extra/case_inputs.py create mode 100644 tests/system/cross-major-observability/assets/v0.2/caller.py create mode 100644 tests/system/cross-major-observability/assets/v0.2/chain.py create mode 100644 tests/system/cross-major-observability/assets/v0.3/chain.py create mode 100644 tests/system/cross-major-observability/assets/v0.3/helper.py create mode 100644 tests/system/cross-major-observability/assets/v0.3/observer.py create mode 100644 tests/system/cross-major-observability/assets/v0.3/self_recursion.py create mode 100644 tests/system/cross-major-observability/assets/v0.3/trap.py create mode 100644 tests/system/cross-major-observability/assets/v0.3/user_error.py create mode 100644 tests/system/cross-major/assets/v0.2/blob_caller.py create mode 100644 tests/system/cross-major/assets/v0.2/busy.py create mode 100644 tests/system/cross-major/assets/v0.2/callee.py create mode 100644 tests/system/cross-major/assets/v0.2/caller.py create mode 100644 tests/system/cross-major/assets/v0.2/chain.py create mode 100644 tests/system/cross-major/assets/v0.2/loop.py create mode 100644 tests/system/cross-major/assets/v0.2/signer_caller.py create mode 100644 tests/system/cross-major/assets/v0.2/user_error.py create mode 100644 tests/system/cross-major/assets/v0.3/blob.py create mode 100644 tests/system/cross-major/assets/v0.3/callee.py create mode 100644 tests/system/cross-major/assets/v0.3/caller.py create mode 100644 tests/system/cross-major/assets/v0.3/chain.py create mode 100644 tests/system/cross-major/assets/v0.3/loop.py create mode 100644 tests/system/cross-major/assets/v0.3/signer.py create mode 100644 tests/system/cross-major/assets/v0.3/state_caller.py create mode 100644 tests/system/cross-major/assets/v0.3/structured_error.py create mode 100644 tests/system/cross-major/assets/v0.3/user_error.py create mode 100644 tests/system/cross-major/cases/routing.jsonnet create mode 100644 tests/system/cross-major/cases/routing.null-mismatch-caller_null-mismatch-callee_null-mismatch.stdout create mode 100644 tests/system/cross-major/cases/routing.null-same-caller_null-same-callee_null-same-major.stdout create mode 100644 tests/system/cross-major/cases/routing.plain-error-caller_plain-error-callee_plain-error.stdout create mode 100644 tests/system/cross-major/cases/routing.plain-error-reverse-caller_plain-error-reverse-callee_plain-error-reverse.stdout create mode 100644 tests/system/cross-major/cases/routing.signer-caller_signer-callee_signer.stdout create mode 100644 tests/system/cross-major/cases/routing.structured-error-caller_structured-error-callee_structured-error.stdout create mode 100644 tests/system/cross-major/cases/routing.v02-to-v03-caller_v02-to-v03-callee_v02-to-v03.stdout create mode 100644 tests/system/cross-major/cases/routing.v03-to-v02-caller_v03-to-v02-callee_v03-to-v02.stdout create mode 100644 tests/tags.json create mode 100644 webdriver/src/prj/src/duration.test.ts create mode 100644 webdriver/src/prj/src/semaphore.test.ts create mode 100644 webdriver/src/prj/src/semaphore.ts create mode 100644 webdriver/src/prj/ts-node-register.mjs diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 00000000..d61c7860 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,3 @@ +{ + "outputStyle": "Brief Style" +} diff --git a/.claude/skills/agentic-fuzzing/SKILL.md b/.claude/skills/agentic-fuzzing/SKILL.md index 4c03387a..d7b00ca0 100644 --- a/.claude/skills/agentic-fuzzing/SKILL.md +++ b/.claude/skills/agentic-fuzzing/SKILL.md @@ -119,8 +119,8 @@ leader-vs-validator comparison does not catch a load failure either: it is identical in all three modes, so the hashes agree and the case still passes — a probe whose contract never loaded reports `✓` in 50ms. Before believing a pass, open `genvm.log.gz` and check the run reached the contract, and decode the `hash` -artifact — `base64 -d < hash` on a failed load reads `invalid_contract -malformed_runner`. +artifact — `base64 -d < hash` on a failed load reads `invalid_contract runner +malformed`. ## Reviewing a PR for a failing test diff --git a/.claude/skills/commit-style/SKILL.md b/.claude/skills/commit-style/SKILL.md index 6857ba4c..793c27c3 100644 --- a/.claude/skills/commit-style/SKILL.md +++ b/.claude/skills/commit-style/SKILL.md @@ -140,3 +140,6 @@ submodule's linter reformat leak an unrelated file into a commit. Each repo's per-repo pre-commit hook (git-hooks.nix, in its flake) runs on the repo you commit in. Do not `--no-verify` (even for gitlink bumps — let the hooks run). Full workflow (order, pushing, `--force-with-lease` after a rebase): `/submodules`. + +Never include text like "bump the v0.3 gitlink". State the underlying change, +not name the file updated diff --git a/.claude/skills/rust-test-style/SKILL.md b/.claude/skills/rust-test-style/SKILL.md index 8eaa1851..4b6feb9d 100644 --- a/.claude/skills/rust-test-style/SKILL.md +++ b/.claude/skills/rust-test-style/SKILL.md @@ -1,6 +1,6 @@ --- name: rust-test-style -description: GenVM Rust test conventions and style. Use when writing, adding, or modifying Rust tests — inline `#[cfg(test)] mod tests`, integration tests under a crate's `tests/`, helpers, assertions, and how `genvm-tool test` discovers them. +description: Always read before writing, adding, or modifying Rust tests — where to put and how to run them. --- # Writing Rust tests in GenVM diff --git a/.claude/skills/spec/SKILL.md b/.claude/skills/spec/SKILL.md index ad9f83bb..d5eed14e 100644 --- a/.claude/skills/spec/SKILL.md +++ b/.claude/skills/spec/SKILL.md @@ -30,11 +30,13 @@ generated pages stay the single source of truth: - Constants: `:ref:`gvm-def-consts-value--`` / `:ref:`gvm-def-const-`` from `spec/appendix/constants.rst` - (generated from `executor/codegen/data/public-abi.json`) or + (generated from `executor/codegen/data/public-abi.json`), + `internal-constants.rst` (from `internal-constants.json`) or `constants-pending.rst` (from `public-abi-pending.json`). **Never edit these .rst by hand** — edit the JSON and regenerate - ([genvm-tool.md](../../../docs/contributing/howto/genvm-tool.md)). New - not-yet-stabilized constants go to the pending JSON. + ([genvm-tool.md](../../../docs/contributing/howto/genvm-tool.md)). Constants a + contract cannot read go to the internal JSON, not-yet-stabilized ones to the + pending JSON. - Error outcomes: `:ref:`gvm-def-str-trie-value-vm-error-...`` — every "traps with" / "rejected with" must link the exact vm_error entry. - Glossary terms: `:term:`sub-VM`` etc. on first use in a section. diff --git a/.claude/skills/test/SKILL.md b/.claude/skills/test/SKILL.md index a7e23014..eb1206ad 100644 --- a/.claude/skills/test/SKILL.md +++ b/.claude/skills/test/SKILL.md @@ -5,6 +5,17 @@ description: Runs tests for the GenVM project. Use after making code changes to See docs/contributing/howto/testing/README.md. +Invoke the tool as: + +``` +nix run '.?submodules=1#genvm-tool' -- test run --filter-tag '!fuzz' ... +``` + +A bare `genvm-tool` from `PATH` is a nix store copy pinned at dev-shell build +time; it goes stale against the working tree and fails with import errors such +as `ModuleNotFoundError: No module named 'genvm_tool.tests.exec.process'`. +`build/genvm_tool.sh` has the same problem — it bakes the store path in. + After fixing a failure, rerun with `--filter-continue ` (path printed in the failure summary) before any full rerun — see the "Fix–rerun loop" section there. diff --git a/.genvm-monorepo-root b/.genvm-monorepo-root index 08b44276..e11b5104 100644 --- a/.genvm-monorepo-root +++ b/.genvm-monorepo-root @@ -8,6 +8,7 @@ "v0.2" ], "artifacts_dir": "build/test-artifacts", + "tags_registry": "tests/tags.json", "extra_python_paths": [ "tests/runner" ] diff --git a/.genvm-tool.py b/.genvm-tool.py index 35b4bf13..7b4ca8ed 100644 --- a/.genvm-tool.py +++ b/.genvm-tool.py @@ -1,4 +1,5 @@ -"""Manager-root genvm-tool project config. +""" +Manager-root genvm-tool project config. Loaded once by genvm-tool (``common.load_project``) before any subcommand runs; subcommands ask it for what they need: @@ -20,12 +21,14 @@ def tests(ctx): - """Umbrella test suite (was the top-level .ya-test.py). + """ + Umbrella test suite (was the top-level .ya-test.py). ``ctx`` is the runner's configuration ``Context``. Collectors close over the imports below (resolved lazily when collection runs). """ import json + import platform import sys from pathlib import Path @@ -56,32 +59,21 @@ def tests(ctx): + '\n' ) - ctx.run_parser.add_argument( - '--fuzz-timeout', - type=int, - default=30, - help='Timeout for each fuzzing run in seconds', - ) - - ctx.run_parser.add_argument( - '--fuzz-update-corpus', - default=False, - action='store_true', - help='Whether to update the fuzzing corpus', - ) - import genvm_tool_plugins ctx.shared.logger.trace( 'import path', path=sys.path, plugins_path=genvm_tool_plugins.__path__ ) from genvm_tool_plugins import ( + afl, cargo, genvm, integration, pytest, ) + afl.register(ctx) + def collect_rust(ctx: genvm_tool.tests.stage.collection.Context): for t in filter(lambda x: x.name == 'Cargo.toml', ctx.shared.git_files): ctx.shared.logger.debug('discovered Cargo.toml', path=t) @@ -101,54 +93,47 @@ def collect_rust(ctx: genvm_tool.tests.stage.collection.Context): name = f'{name.parent}/{name.stem}' cargo.cargo_fuzz( ctx, - genvm_tool.tests.test.Description( - name, - console_pool=True, - ), + genvm_tool.tests.test.Description(name), rust_root_dir=rust_root_dir, name=fuzz_file.stem, ) def collect_pytest(ctx: genvm_tool.tests.stage.collection.Context): - p = ctx.shared.root_dir.joinpath( - 'executors', 'v0.3.x', 'runners', 'genlayer-py-std' - ) - pytest.pytest( - ctx, - genvm_tool.tests.test.Description( - str(p.relative_to(ctx.shared.root_dir)), - console_pool=True, - tags=frozenset({'unit'}), - ), - project_root_dir=p, - ) - - ci = ctx.shared.root_dir.joinpath('support', 'ci') - pytest.pytest( - ctx, - genvm_tool.tests.test.Description( - str(ci.relative_to(ctx.shared.root_dir)), - console_pool=True, - tags=frozenset({'unit'}), - ), - project_root_dir=ci, - ) - - fuzz_files = list(p.glob('fuzz/src/*.py')) - fuzz_files.sort() - for fuzz_file in fuzz_files: - name = fuzz_file.relative_to(ctx.shared.root_dir) - name = f'{name.parent}/{name.stem}' - continue # for now let's disable it - pytest.py_fuzz( + dirs = [ + ctx.shared.root_dir.joinpath('executors', 'v0.3.x', 'runners', 'genlayer-py-std'), + ctx.shared.root_dir.joinpath('support', 'tools', 'genvm-tool'), + ctx.shared.root_dir.joinpath('support', 'ci'), + ] + for p in dirs: + pytest.pytest( ctx, genvm_tool.tests.test.Description( - name, + str(p.relative_to(ctx.shared.root_dir)), + console_pool=True, + tags=frozenset({'unit'}), ), project_root_dir=p, - name=fuzz_file.stem, ) + # A project's flake carries python-afl and AFL++ on x86_64-linux only, + # so elsewhere the case could not start at all + if (platform.system(), platform.machine()) != ('Linux', 'x86_64'): + continue + + fuzz_files = list(p.glob('fuzz/src/*.py')) + fuzz_files.sort() + for fuzz_file in fuzz_files: + name = fuzz_file.relative_to(ctx.shared.root_dir) + name = f'{name.parent}/{name.stem}' + pytest.py_fuzz( + ctx, + genvm_tool.tests.test.Description( + name, + ), + project_root_dir=p, + name=fuzz_file.stem, + ) + ctx.add_collector(collect_rust) ctx.add_collector(collect_pytest) @@ -196,6 +181,7 @@ def collect_integration(ctx: genvm_tool.tests.stage.collection.Context): ci = ctx.shared.ci manager_port = genvm.get_manager_port(ctx.configuration) + manager_semaphore = ctx.new_semaphore('manager-listener') if no_manager: manager_impl = genvm.ExternalManagerService( @@ -225,6 +211,7 @@ def collect_integration(ctx: genvm_tool.tests.stage.collection.Context): manager_service = ctx.new_service( name='manager', manager=manager_impl, + semaphores=[manager_semaphore], ) manager_service.meta = { 'port': manager_port, @@ -250,11 +237,47 @@ def collect_integration(ctx: genvm_tool.tests.stage.collection.Context): webdriver_service=webdriver_service, ci=ci, ) + integration.integration_test_directory( + ctx, + cases_dir=ctx.shared.root_dir / 'tests' / 'system' / 'cross-major' / 'cases', + reroute_to=build_info['executor_versions']['v0.3'], + save_hashes=False, + manager_service=manager_service, + modules_service=modules_service, + webdriver_service=webdriver_service, + ci=ci, + ) ctx.collect_dir('tests/system/permits', manager_service=manager_service) - ctx.collect_dir('tests/system/manager-socket') - ctx.collect_dir('tests/system/cross-major') - ctx.collect_dir('tests/system/cross-major-observability') + limited_manager_service = None + if not no_manager: + limited_manager_service = ctx.new_service( + name='manager-cross-major-small-message-cap', + manager=genvm.ManagerService( + bin_path=build_dir / 'out' / 'bin' / 'genvm-modules', + log_path=tests_output_root / 'cross-major-small-message-cap.log', + env=ctx.configuration, + ci=ci, + config={'max_message_bytes': 1024 * 1024}, + ), + semaphores=[manager_semaphore], + ) + ctx.collect_dir( + 'tests/system/manager-socket', + manager_semaphore=manager_semaphore, + build_dir=build_dir, + ci=ci, + ) + ctx.collect_dir( + 'tests/system/cross-major', + manager_service=manager_service, + limited_manager_service=limited_manager_service, + managed_manager=not no_manager, + ) + ctx.collect_dir( + 'tests/system/cross-major-observability', + manager_service=manager_service, + ) ctx.add_collector(collect_integration) diff --git a/.github/workflows/incl_release_build_test_cell_build.yaml b/.github/workflows/incl_release_build_test_cell_build.yaml index c39ed002..d79e09bb 100644 --- a/.github/workflows/incl_release_build_test_cell_build.yaml +++ b/.github/workflows/incl_release_build_test_cell_build.yaml @@ -77,6 +77,7 @@ jobs: with: token: ${{ secrets.NIX_CACHE_PUSH_TOKEN }} include: genvm|genlayer|(^lief) + exclude: genvm-cpython-objs - name: Upload artifacts uses: actions/upload-artifact@v4 diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..462fc4a4 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,54 @@ +# GenVM manager + +Before changing this repository, read the matching page in `docs/contributing/`: +a task has a how-to, a design question has an explanation + + + +## Tutorial +- [first-contribution.md](docs/contributing/tutorial/first-contribution.md) — patch an executor, branch, commit, push, open the PR + +## Howto +- [genvm-tool.md](docs/contributing/howto/genvm-tool.md) — the umbrella tool: man page, test and git subcommands, codegen +- [pr.md](docs/contributing/howto/pr.md) — branch model, PR action panel, `ci-safe` / `run-full-tests`, merge gates +- [setup.md](docs/contributing/howto/setup.md) — first-time clone: submodules, vendored trees, nix/direnv dev shell + +## Howto/Building +- [build.md](docs/contributing/howto/building/build.md) — debug build: configure + ninja, targets, outputs, cargo quirks +- [docs.md](docs/contributing/howto/building/docs.md) — building and publishing the website, spec vs impl-spec, ADRs +- [runners.md](docs/contributing/howto/building/runners.md) — where runners come from: build on Linux, download elsewhere + +## Howto/Committing +- [git-third-party.md](docs/contributing/howto/committing/git-third-party.md) — how vendored trees (wasmtime, …) are pinned and patched +- [runners.md](docs/contributing/howto/committing/runners.md) — clearing runner dev-mode and refreshing hashes before a commit +- [submodules.md](docs/contributing/howto/committing/submodules.md) — repo topology, gitlink bumps, pre-commit hooks, push order + +## Howto/Docs +- [style.md](docs/contributing/howto/docs/style.md) — prose conventions for guides, specs, ADRs and commit bodies + +## Howto/Extending +- [add-host-function.md](docs/contributing/howto/extending/add-host-function.md) — new executor↔host protocol method +- [add-llm-provider.md](docs/contributing/howto/extending/add-llm-provider.md) — new LLM backend in the manager +- [add-wasi-function.md](docs/contributing/howto/extending/add-wasi-function.md) — new gl_call method or raw WASI function +- [modify-runner.md](docs/contributing/howto/extending/modify-runner.md) — runner dev-mode and hash refresh +- [modify-wasmtime.md](docs/contributing/howto/extending/modify-wasmtime.md) — patching vendored wasmtime, trap plumbing +- [write-a-script.md](docs/contributing/howto/extending/write-a-script.md) — conventions for helper scripts and pre-commit hooks + +## Howto/Releasing +- [release-build.md](docs/contributing/howto/releasing/release-build.md) — nix packages, platforms, release assets +- [versioning.md](docs/contributing/howto/releasing/versioning.md) — release trains, `.genvm-monorepo-root`, version tools + +## Howto/Testing +- [README.md](docs/contributing/howto/testing/README.md) — `genvm-tool test`: filters, presets, continue files +- [fuzzing.md](docs/contributing/howto/testing/fuzzing.md) — AFL fuzz targets, host sysctl prep +- [integration.md](docs/contributing/howto/testing/integration.md) — jsonnet cases, tags, golden `.stdout`/`.hash` files, services +- [python.md](docs/contributing/howto/testing/python.md) — Python tests, direct pytest for genlayer-py-std +- [rust.md](docs/contributing/howto/testing/rust.md) — Rust tests: where they go, how to run them, coverage + +## Explanation +- [docs-layout.md](docs/contributing/explanation/docs-layout.md) — the 4 kinds of page and where each belongs +- [executor-lines.md](docs/contributing/explanation/executor-lines.md) — why several executor lines ship side by side, and what it costs +- [fuzz.md](docs/contributing/explanation/fuzz.md) — why fuzz targets get fake entropy and no CmpLog +- [merge-model.md](docs/contributing/explanation/merge-model.md) — why merging is a maintainer panel rather than a merge queue +- [shared-submodule-cache.md](docs/contributing/explanation/shared-submodule-cache.md) — why submodules are worktrees of one cache repo, not clones +- [vendored-trees.md](docs/contributing/explanation/vendored-trees.md) — why third-party sources are patch series, not forks diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index b62f2919..00000000 --- a/CLAUDE.md +++ /dev/null @@ -1,53 +0,0 @@ -# GenVM manager - -Before changing this repository, read the matching page in `docs/contributing/`: -a task has a how-to, a design question has an explanation - - - -## Tutorial -- [first-contribution.md](docs/contributing/tutorial/first-contribution.md) — patch an executor, branch, commit, push, open the PR - -## Howto -- [genvm-tool.md](docs/contributing/howto/genvm-tool.md) — the umbrella tool: man page, test and git subcommands, codegen -- [pr.md](docs/contributing/howto/pr.md) — branch model, PR action panel, `ci-safe` / `run-full-tests`, merge gates -- [setup.md](docs/contributing/howto/setup.md) — first-time clone: submodules, vendored trees, nix/direnv dev shell - -## Howto/Building -- [build.md](docs/contributing/howto/building/build.md) — debug build: configure + ninja, targets, outputs, cargo quirks -- [docs.md](docs/contributing/howto/building/docs.md) — building and publishing the website, spec vs impl-spec, ADRs -- [runners.md](docs/contributing/howto/building/runners.md) — where runners come from: build on Linux, download elsewhere - -## Howto/Committing -- [git-third-party.md](docs/contributing/howto/committing/git-third-party.md) — how vendored trees (wasmtime, …) are pinned and patched -- [runners.md](docs/contributing/howto/committing/runners.md) — clearing runner dev-mode and refreshing hashes before a commit -- [submodules.md](docs/contributing/howto/committing/submodules.md) — repo topology, gitlink bumps, pre-commit hooks, push order - -## Howto/Docs -- [style.md](docs/contributing/howto/docs/style.md) — prose conventions for guides, specs, ADRs and commit bodies - -## Howto/Extending -- [add-host-function.md](docs/contributing/howto/extending/add-host-function.md) — new executor↔host protocol method -- [add-llm-provider.md](docs/contributing/howto/extending/add-llm-provider.md) — new LLM backend in the manager -- [add-wasi-function.md](docs/contributing/howto/extending/add-wasi-function.md) — new gl_call method or raw WASI function -- [modify-runner.md](docs/contributing/howto/extending/modify-runner.md) — runner dev-mode and hash refresh -- [modify-wasmtime.md](docs/contributing/howto/extending/modify-wasmtime.md) — patching vendored wasmtime, trap plumbing -- [write-a-script.md](docs/contributing/howto/extending/write-a-script.md) — conventions for helper scripts and pre-commit hooks - -## Howto/Releasing -- [release-build.md](docs/contributing/howto/releasing/release-build.md) — nix packages, platforms, release assets -- [versioning.md](docs/contributing/howto/releasing/versioning.md) — release trains, `.genvm-monorepo-root`, version tools - -## Howto/Testing -- [README.md](docs/contributing/howto/testing/README.md) — `genvm-tool test`: filters, presets, continue files -- [fuzzing.md](docs/contributing/howto/testing/fuzzing.md) — AFL fuzz targets, host sysctl prep -- [integration.md](docs/contributing/howto/testing/integration.md) — jsonnet cases, tags, golden `.stdout`/`.hash` files, services -- [python.md](docs/contributing/howto/testing/python.md) — Python tests, direct pytest for genlayer-py-std -- [rust.md](docs/contributing/howto/testing/rust.md) — Rust tests: where they go, how to run them, coverage - -## Explanation -- [docs-layout.md](docs/contributing/explanation/docs-layout.md) — the 4 kinds of page and where each belongs -- [executor-lines.md](docs/contributing/explanation/executor-lines.md) — why several executor lines ship side by side, and what it costs -- [merge-model.md](docs/contributing/explanation/merge-model.md) — why merging is a maintainer panel rather than a merge queue -- [shared-submodule-cache.md](docs/contributing/explanation/shared-submodule-cache.md) — why submodules are worktrees of one cache repo, not clones -- [vendored-trees.md](docs/contributing/explanation/vendored-trees.md) — why third-party sources are patch series, not forks diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 00000000..47dc3e3d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md index eefc9fc1..d60a8d1b 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -6,8 +6,8 @@ identical and trustworthy across all validators. Please treat security issues ac ## Reporting a vulnerability **Do not open a public issue.** Report privately via GitHub's -[private vulnerability reporting](https://github.com/genlayerlabs/genvm/security/advisories/new), -or email kira@yeager.ai +[private vulnerability reporting](https://github.com/genlayerlabs/genvm-manager/security/advisories/new), +or email kira@genlayerlabs.com Include a description, affected component/version, and a reproduction (a contract, calldata, or test case) where possible. We aim to acknowledge within a few business days. @@ -37,3 +37,12 @@ In scope: the executor, runners/SDK, modules (LLM/web/manager), the install/mani the CI/release supply chain. Out of scope: issues requiring a pre-compromised host or operator machine, and non-default deployments that expose the loopback-only manager to untrusted networks (though we still want to know). + +## Trust boundary + +The following relationships are trusted. Hardening them is welcome, but a report that assumes +one side is hostile is not treated as a vulnerability: + +- host and GenVM +- executor and manager +- the local disk and loopback in general diff --git a/crates/fuzzing/Cargo.lock b/crates/fuzzing/Cargo.lock new file mode 100644 index 00000000..9a86e14f --- /dev/null +++ b/crates/fuzzing/Cargo.lock @@ -0,0 +1,177 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror", +] + +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + +[[package]] +name = "genvm-fuzzing" +version = "0.1.0" +dependencies = [ + "mutatis", + "postcard", + "serde", +] + +[[package]] +name = "mutatis" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "468ca2a8bc8087a0b2c11d21e7dca51d92cc2662a6993d6b56bac2701795f202" +dependencies = [ + "mutatis-derive", + "rand", +] + +[[package]] +name = "mutatis-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5708f6e65277d4a89733aff227b43d0989c5ead03999b6f1f33a8ec7a9978361" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "serde", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" diff --git a/crates/fuzzing/Cargo.toml b/crates/fuzzing/Cargo.toml new file mode 100644 index 00000000..7d5398d6 --- /dev/null +++ b/crates/fuzzing/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "genvm-fuzzing" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +# `default-features = false` keeps heapless, spin and lock_api out of the tree +postcard = { version = "1.1.3", default-features = false, features = [ + "use-std", +] } +serde = { version = "1.0.219", features = ["derive"] } + +[dependencies.mutatis] +default-features = false +features = ["derive", "std"] +version = "0.5.3" diff --git a/crates/fuzzing/preload/Cargo.lock b/crates/fuzzing/preload/Cargo.lock new file mode 100644 index 00000000..bb34fecc --- /dev/null +++ b/crates/fuzzing/preload/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "genvm-fuzz-preload" +version = "0.1.0" diff --git a/crates/fuzzing/preload/Cargo.toml b/crates/fuzzing/preload/Cargo.toml new file mode 100644 index 00000000..38d05633 --- /dev/null +++ b/crates/fuzzing/preload/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "genvm-fuzz-preload" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +crate-type = ["cdylib"] + +[dependencies] diff --git a/crates/fuzzing/preload/src/lib.rs b/crates/fuzzing/preload/src/lib.rs new file mode 100644 index 00000000..56d24168 --- /dev/null +++ b/crates/fuzzing/preload/src/lib.rs @@ -0,0 +1,78 @@ +//! `LD_PRELOAD` shim that makes the OS randomness syscalls deterministic. +//! +//! Loaded into AFL targets only, via `AFL_PRELOAD`. Without it every process +//! seeds its hashers from real entropy, so a saved crash need not replay and +//! coverage differs between runs. + +use core::ffi::{c_int, c_uint, c_void}; +use std::cell::Cell; + +thread_local! { + /// Number of `u64` words handed out by this thread. + static WORDS: Cell = const { Cell::new(0) }; +} + +fn next_word() -> u64 { + // splitmix64 over the call counter + let mut z = WORDS.with(|words| { + let current = words.get(); + words.set(current.wrapping_add(1)); + current.wrapping_add(0x9e37_79b9_7f4a_7c15) + }); + z = (z ^ (z >> 30)).wrapping_mul(0xbf58_476d_1ce4_e5b9); + z = (z ^ (z >> 27)).wrapping_mul(0x94d0_49bb_1331_11eb); + z ^ (z >> 31) +} + +/// # Safety +/// `buffer` must be writable for `length` bytes, or `length` must be zero. +unsafe fn fill(buffer: *mut c_void, length: usize) { + if length == 0 { + return; + } + assert!(!buffer.is_null(), "genvm-fuzz-preload: null buffer"); + + let mut written = 0; + while written < length { + let word = next_word().to_le_bytes(); + let chunk = word.len().min(length - written); + std::ptr::copy_nonoverlapping(word.as_ptr(), (buffer as *mut u8).add(written), chunk); + written += chunk; + } +} + +/// # Safety +/// See [`fill`]. Matches the libc signature, flags are ignored: every flag +/// combination is satisfiable when the entropy is fake. +#[no_mangle] +pub unsafe extern "C" fn getrandom(buffer: *mut c_void, length: usize, _flags: c_uint) -> isize { + fill(buffer, length); + length as isize +} + +/// # Safety +/// See [`fill`]. Unlike libc this accepts any `length`; the 256 byte cap exists +/// to bound how much real entropy one call may drain. +#[no_mangle] +pub unsafe extern "C" fn getentropy(buffer: *mut c_void, length: usize) -> c_int { + fill(buffer, length); + 0 +} + +#[cfg(test)] +mod tests { + use super::next_word; + + #[test] + fn threads_have_the_same_sequence() { + let threads: Vec<_> = (0..4) + .map(|_| std::thread::spawn(|| [next_word(), next_word()])) + .collect(); + let sequences: Vec<_> = threads + .into_iter() + .map(|thread| thread.join().unwrap()) + .collect(); + + assert!(sequences.windows(2).all(|pair| pair[0] == pair[1])); + } +} diff --git a/crates/fuzzing/src/depth_limit.rs b/crates/fuzzing/src/depth_limit.rs new file mode 100644 index 00000000..afc0d6ab --- /dev/null +++ b/crates/fuzzing/src/depth_limit.rs @@ -0,0 +1,408 @@ +use core::fmt; +use serde::de::{self, DeserializeSeed, Visitor}; + +pub(crate) struct Deserializer { + inner: D, + remaining: usize, +} + +impl Deserializer { + pub(crate) fn new(inner: D, remaining: usize) -> Self { + Self { inner, remaining } + } + + fn descend<'de, V>(self, visitor: V) -> Result<(D, LimitVisitor), D::Error> + where + D: de::Deserializer<'de>, + { + let remaining = self + .remaining + .checked_sub(1) + .ok_or_else(|| de::Error::custom("deserialization depth limit exceeded"))?; + Ok(( + self.inner, + LimitVisitor { + inner: visitor, + remaining, + }, + )) + } +} + +macro_rules! delegate { + ($($method:ident $(($($arg:ident: $ty:ty),*))?);+ $(;)?) => { + $( + fn $method(self, $($($arg: $ty,)*)? visitor: V) -> Result + where + V: Visitor<'de>, + { + self.inner.$method($($($arg,)*)? visitor) + } + )+ + }; +} + +impl<'de, D> de::Deserializer<'de> for Deserializer +where + D: de::Deserializer<'de>, +{ + type Error = D::Error; + + delegate! { + deserialize_any(); + deserialize_bool(); + deserialize_i8(); + deserialize_i16(); + deserialize_i32(); + deserialize_i64(); + deserialize_i128(); + deserialize_u8(); + deserialize_u16(); + deserialize_u32(); + deserialize_u64(); + deserialize_u128(); + deserialize_f32(); + deserialize_f64(); + deserialize_char(); + deserialize_str(); + deserialize_string(); + deserialize_bytes(); + deserialize_byte_buf(); + deserialize_unit(); + deserialize_unit_struct(name: &'static str); + deserialize_identifier(); + deserialize_ignored_any(); + } + + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let (inner, visitor) = self.descend(visitor)?; + inner.deserialize_option(visitor) + } + + fn deserialize_newtype_struct( + self, + name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + let (inner, visitor) = self.descend(visitor)?; + inner.deserialize_newtype_struct(name, visitor) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let (inner, visitor) = self.descend(visitor)?; + inner.deserialize_seq(visitor) + } + + fn deserialize_tuple(self, len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + let (inner, visitor) = self.descend(visitor)?; + inner.deserialize_tuple(len, visitor) + } + + fn deserialize_tuple_struct( + self, + name: &'static str, + len: usize, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + let (inner, visitor) = self.descend(visitor)?; + inner.deserialize_tuple_struct(name, len, visitor) + } + + fn deserialize_map(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let (inner, visitor) = self.descend(visitor)?; + inner.deserialize_map(visitor) + } + + fn deserialize_struct( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + let (inner, visitor) = self.descend(visitor)?; + inner.deserialize_struct(name, fields, visitor) + } + + fn deserialize_enum( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + let (inner, visitor) = self.descend(visitor)?; + inner.deserialize_enum(name, variants, visitor) + } + + fn is_human_readable(&self) -> bool { + self.inner.is_human_readable() + } +} + +struct LimitVisitor { + inner: V, + remaining: usize, +} + +impl<'de, V> Visitor<'de> for LimitVisitor +where + V: Visitor<'de>, +{ + type Value = V::Value; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + self.inner.expecting(formatter) + } + + fn visit_none(self) -> Result + where + E: de::Error, + { + self.inner.visit_none() + } + + fn visit_some(self, deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + self.inner + .visit_some(Deserializer::new(deserializer, self.remaining)) + } + + fn visit_newtype_struct(self, deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + self.inner + .visit_newtype_struct(Deserializer::new(deserializer, self.remaining)) + } + + fn visit_seq(self, seq: A) -> Result + where + A: de::SeqAccess<'de>, + { + self.inner.visit_seq(LimitSeqAccess { + inner: seq, + remaining: self.remaining, + }) + } + + fn visit_map(self, map: A) -> Result + where + A: de::MapAccess<'de>, + { + self.inner.visit_map(LimitMapAccess { + inner: map, + remaining: self.remaining, + }) + } + + fn visit_enum(self, data: A) -> Result + where + A: de::EnumAccess<'de>, + { + self.inner.visit_enum(LimitEnumAccess { + inner: data, + remaining: self.remaining, + }) + } +} + +struct LimitSeed { + inner: S, + remaining: usize, +} + +impl<'de, S> DeserializeSeed<'de> for LimitSeed +where + S: DeserializeSeed<'de>, +{ + type Value = S::Value; + + fn deserialize(self, deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + self.inner + .deserialize(Deserializer::new(deserializer, self.remaining)) + } +} + +struct LimitSeqAccess { + inner: A, + remaining: usize, +} + +impl<'de, A> de::SeqAccess<'de> for LimitSeqAccess +where + A: de::SeqAccess<'de>, +{ + type Error = A::Error; + + fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> + where + T: DeserializeSeed<'de>, + { + self.inner.next_element_seed(LimitSeed { + inner: seed, + remaining: self.remaining, + }) + } + + fn size_hint(&self) -> Option { + self.inner.size_hint() + } +} + +struct LimitMapAccess { + inner: A, + remaining: usize, +} + +impl<'de, A> de::MapAccess<'de> for LimitMapAccess +where + A: de::MapAccess<'de>, +{ + type Error = A::Error; + + fn next_key_seed(&mut self, seed: K) -> Result, Self::Error> + where + K: DeserializeSeed<'de>, + { + self.inner.next_key_seed(LimitSeed { + inner: seed, + remaining: self.remaining, + }) + } + + fn next_value_seed(&mut self, seed: V) -> Result + where + V: DeserializeSeed<'de>, + { + self.inner.next_value_seed(LimitSeed { + inner: seed, + remaining: self.remaining, + }) + } + + fn size_hint(&self) -> Option { + self.inner.size_hint() + } +} + +struct LimitEnumAccess { + inner: A, + remaining: usize, +} + +impl<'de, A> de::EnumAccess<'de> for LimitEnumAccess +where + A: de::EnumAccess<'de>, +{ + type Error = A::Error; + type Variant = LimitVariantAccess; + + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> + where + V: DeserializeSeed<'de>, + { + let (value, variant) = self.inner.variant_seed(LimitSeed { + inner: seed, + remaining: self.remaining, + })?; + Ok(( + value, + LimitVariantAccess { + inner: variant, + remaining: self.remaining, + }, + )) + } +} + +struct LimitVariantAccess { + inner: A, + remaining: usize, +} + +impl<'de, A> de::VariantAccess<'de> for LimitVariantAccess +where + A: de::VariantAccess<'de>, +{ + type Error = A::Error; + + fn unit_variant(self) -> Result<(), Self::Error> { + self.inner.unit_variant() + } + + fn newtype_variant_seed(self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + self.inner.newtype_variant_seed(LimitSeed { + inner: seed, + remaining: self.remaining, + }) + } + + fn tuple_variant(self, len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + let remaining = self + .remaining + .checked_sub(1) + .ok_or_else(|| de::Error::custom("deserialization depth limit exceeded"))?; + self.inner.tuple_variant( + len, + LimitVisitor { + inner: visitor, + remaining, + }, + ) + } + + fn struct_variant( + self, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + let remaining = self + .remaining + .checked_sub(1) + .ok_or_else(|| de::Error::custom("deserialization depth limit exceeded"))?; + self.inner.struct_variant( + fields, + LimitVisitor { + inner: visitor, + remaining, + }, + ) + } +} diff --git a/crates/fuzzing/src/lib.rs b/crates/fuzzing/src/lib.rs new file mode 100644 index 00000000..6727a013 --- /dev/null +++ b/crates/fuzzing/src/lib.rs @@ -0,0 +1,177 @@ +pub use mutatis; +pub use postcard; +pub use serde; + +mod depth_limit; + +/// Corpus files above this are refused rather than decoded. +pub const MAX_CORPUS_BYTES: usize = 8 * 1024; + +/// Maximum number of nested containers in a corpus value. +pub const MAX_CORPUS_DEPTH: usize = 128; + +/// Decodes a corpus file into the value a target consumes. A file AFL produced +/// by other means than the custom mutator will not decode, hence the `Option`. +pub fn decode(bytes: &[u8]) -> Option { + if bytes.len() > MAX_CORPUS_BYTES { + return None; + } + let mut deserializer = postcard::Deserializer::from_bytes(bytes); + serde::Deserialize::deserialize(depth_limit::Deserializer::new( + &mut deserializer, + MAX_CORPUS_DEPTH, + )) + .ok() +} + +/// Encodes a value back into the bytes AFL stores. Only fails when `T`'s +/// `Serialize` does, which for a fuzz input is a bug rather than an input error. +pub fn encode(value: &T) -> Vec { + postcard::to_allocvec(value).expect("fuzz input must serialize") +} + +/// Defines the `afl_custom_*` entry points AFL++ dlopens, mutating `$ty` +/// structurally instead of editing its serialized bytes. +/// +/// Expand it in a crate with `crate-type = ["cdylib"]`, next to the `#[path]` +/// module that also defines the target's input type: +/// +/// ```ignore +/// #[path = "../../shared/leader-result-input.rs"] +/// mod input; +/// +/// genvm_fuzzing::mutator!(input::Input); +/// ``` +#[macro_export] +macro_rules! mutator { + ($ty:ty) => { + struct MutatorState { + session: $crate::mutatis::Session, + buf: ::std::vec::Vec, + calls: u64, + } + + /// How many mutations one call stacks. + /// + /// A session applies a single mutation, which on its own explores about + /// as far from a seed as one bit flip does. AFL's own havoc stage owes + /// much of its reach to stacking, and a structural mutator that does + /// not stack loses to it. + const MAX_STACKED: u64 = 8; + + #[no_mangle] + pub extern "C" fn afl_custom_init( + _afl: *mut ::core::ffi::c_void, + seed: u32, + ) -> *mut ::core::ffi::c_void { + let state = ::std::boxed::Box::new(MutatorState { + session: $crate::mutatis::Session::new().seed(seed as u64), + buf: ::std::vec::Vec::new(), + calls: 0, + }); + ::std::boxed::Box::into_raw(state) as *mut ::core::ffi::c_void + } + + /// # Safety + /// `data` is what [`afl_custom_init`] returned. + #[no_mangle] + pub unsafe extern "C" fn afl_custom_deinit(data: *mut ::core::ffi::c_void) { + drop(::std::boxed::Box::from_raw(data as *mut MutatorState)); + } + + /// # Safety + /// `buf` is readable for `buf_size` bytes and `out_buf` is writable, as + /// the AFL++ custom mutator API specifies. The returned buffer stays + /// alive until the next call, which is when AFL is done with it. + #[no_mangle] + pub unsafe extern "C" fn afl_custom_fuzz( + data: *mut ::core::ffi::c_void, + buf: *mut u8, + buf_size: usize, + out_buf: *mut *const u8, + _add_buf: *mut u8, + _add_buf_size: usize, + max_size: usize, + ) -> usize { + use $crate::mutatis::Mutate as _; + + let state = &mut *(data as *mut MutatorState); + let input = ::core::slice::from_raw_parts(buf, buf_size); + + // A seed AFL minimized, spliced or havoc'd is no longer a valid + // encoding; starting over from the default beats emitting garbage. + let mut value: $ty = $crate::decode(input).unwrap_or_default(); + + // splitmix64 over the call counter, so the count varies without a + // second source of randomness to seed and replay + state.calls = state.calls.wrapping_add(1); + let mut z = state.calls.wrapping_mul(0x9e37_79b9_7f4a_7c15); + z = (z ^ (z >> 30)).wrapping_mul(0xbf58_476d_1ce4_e5b9); + for _ in 0..=(z >> 32) % MAX_STACKED { + let _ = state.session.mutate(&mut value); + } + + state.buf = $crate::encode(&value); + + // Truncating would corrupt the encoding, so an oversized mutation + // is dropped in favour of the input it came from. + let max_size = max_size.min($crate::MAX_CORPUS_BYTES); + if state.buf.len() > max_size { + state.buf.clear(); + state + .buf + .extend_from_slice(&input[..input.len().min(max_size)]); + } + + *out_buf = state.buf.as_ptr(); + state.buf.len() + } + }; +} + +#[cfg(test)] +mod tests { + use super::{decode, encode, MAX_CORPUS_DEPTH}; + use serde::{Deserialize, Serialize}; + use std::collections::BTreeMap; + + #[derive(Debug, Deserialize, PartialEq, Serialize)] + struct Mixed { + values: Vec>, + named: BTreeMap, + } + + #[derive(Debug, Deserialize, PartialEq, Serialize)] + enum Nested { + More(Box), + End, + } + + fn nested(depth: usize) -> Nested { + (0..depth).fold(Nested::End, |inner, _| Nested::More(Box::new(inner))) + } + + #[test] + fn decode_preserves_normal_values() { + let value = Mixed { + values: vec![Some(42), None], + named: BTreeMap::from([("answer".to_owned(), true)]), + }; + + assert_eq!(decode(&encode(&value)), Some(value)); + } + + #[test] + fn decode_accepts_bounded_nesting() { + let value = nested(MAX_CORPUS_DEPTH - 1); + + assert_eq!(decode(&encode(&value)), Some(value)); + } + + #[test] + fn decode_rejects_excessive_nesting() { + let bytes = encode(&nested(MAX_CORPUS_DEPTH)); + + assert_eq!(decode::(&bytes), None); + } +} diff --git a/crates/modules-interfaces/Cargo.lock b/crates/modules-interfaces/Cargo.lock index 433aeb5d..d218bf78 100644 --- a/crates/modules-interfaces/Cargo.lock +++ b/crates/modules-interfaces/Cargo.lock @@ -41,12 +41,6 @@ version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" -[[package]] -name = "arbitrary" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" - [[package]] name = "arrayvec" version = "0.7.6" @@ -281,7 +275,6 @@ name = "genvm_modules_interfaces" version = "0.1.0" dependencies = [ "anyhow", - "arbitrary", "bytes", "chrono", "genlayer_calldata", diff --git a/crates/modules-interfaces/Cargo.toml b/crates/modules-interfaces/Cargo.toml index 63a37027..9d5122e5 100644 --- a/crates/modules-interfaces/Cargo.toml +++ b/crates/modules-interfaces/Cargo.toml @@ -4,12 +4,10 @@ version = "0.1.0" edition = "2021" [features] -arbitrary = ["dep:arbitrary"] default = [] [dependencies] anyhow = "1.0.97" -arbitrary = { version = "1.0", optional = true } bytes = { version = "1.11.0", features = ["serde"] } chrono = "0.4.45" genlayer_calldata = { path = "../../executors/v0.3.x/executor/crates/calldata" } diff --git a/crates/modules-interfaces/codegen/data/host-fns.json b/crates/modules-interfaces/codegen/data/host-fns.json index 245044ac..e9d9e0e5 100644 --- a/crates/modules-interfaces/codegen/data/host-fns.json +++ b/crates/modules-interfaces/codegen/data/host-fns.json @@ -15,6 +15,18 @@ "run_nested": 8 } }, + { + "type": "enum", + "repr": "u8", + "name": "result_code", + "values": { + "return": 0, + "user_error": 1, + "vm_error": 2, + "internal_error": 3, + "fatal_vm_error": 4 + } + }, { "type": "enum", "repr": "u8", @@ -25,14 +37,6 @@ "forbidden": 2 } }, - { - "type": "str_trie", - "name": "vm_error_detail", - "values": [ - "internal", - "external" - ] - }, { "type": "const", "name": "current_major", diff --git a/crates/modules-interfaces/src/abi_stub.rs b/crates/modules-interfaces/src/abi_stub.rs index e829c327..c0dd0892 100644 --- a/crates/modules-interfaces/src/abi_stub.rs +++ b/crates/modules-interfaces/src/abi_stub.rs @@ -11,7 +11,6 @@ use genlayer_calldata::Address; Eq, Debug, )] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] pub enum On { #[serde(rename = "finalized")] #[calldata(rename = "finalized")] @@ -94,38 +93,3 @@ fn default_datetime() -> chrono::DateTime { .unwrap() .to_utc() } - -#[cfg(feature = "arbitrary")] -impl<'a> arbitrary::Arbitrary<'a> for MessageData { - fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { - use arbitrary::Arbitrary; - - let ts = u32::arbitrary(u)?; - let Some(datetime) = chrono::DateTime::::from_timestamp_secs(ts as i64) else { - return Err(arbitrary::Error::NotEnoughData); - }; - - let chain_id_bytes: [u8; 32] = Arbitrary::arbitrary(u)?; - let chain_id = primitive_types::U256::from_big_endian(&chain_id_bytes); - - let value_bytes: [u8; 32] = Arbitrary::arbitrary(u)?; - let value = primitive_types::U256::from_big_endian(&value_bytes); - - Ok(Self { - contract_address: Arbitrary::arbitrary(u)?, - sender_address: Arbitrary::arbitrary(u)?, - origin_address: Arbitrary::arbitrary(u)?, - signer_address: Arbitrary::arbitrary(u)?, - chain_id: num_bigint::BigInt::from_bytes_be( - num_bigint::Sign::Plus, - &chain_id.to_big_endian(), - ), - value: num_bigint::BigInt::from_bytes_be( - num_bigint::Sign::Plus, - &value.to_big_endian(), - ), - is_init: bool::arbitrary(u)?, - datetime, - }) - } -} diff --git a/crates/modules-interfaces/src/domain.rs b/crates/modules-interfaces/src/domain.rs index aec09051..a083b58c 100644 --- a/crates/modules-interfaces/src/domain.rs +++ b/crates/modules-interfaces/src/domain.rs @@ -152,6 +152,7 @@ pub enum ResultCode { UserError = 1, VmError = 2, InternalError = 3, + FatalVmError = 4, } #[derive(Debug, Clone, serde::Serialize)] @@ -347,9 +348,12 @@ where enc.push_str(match kind { ResultCode::Return => "Return", ResultCode::UserError => "UserError", - // An internal error is never handed to a caller as a result, so it - // shares the `VMError` label rather than inventing a fourth one. - ResultCode::VmError | ResultCode::InternalError => "VMError", + // Neither an internal error nor fatality is part of the outcome + // itself: the first is never handed to a caller as a result, and the + // second only says the caller may not catch it. The value folded is + // the same `vm_error` either way, so a timeout hashes alike whether + // or not the line that served it can raise fatality. + ResultCode::VmError | ResultCode::InternalError | ResultCode::FatalVmError => "VMError", })?; enc.push_map_k("result")?; diff --git a/crates/modules-interfaces/src/domain/fees/mod.rs b/crates/modules-interfaces/src/domain/fees/mod.rs index 0119dcc9..c0efedde 100644 --- a/crates/modules-interfaces/src/domain/fees/mod.rs +++ b/crates/modules-interfaces/src/domain/fees/mod.rs @@ -14,13 +14,9 @@ use crate::On; genlayer_calldata::Encode, genlayer_calldata::Decode, )] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] pub struct InternalMessageParams { - #[cfg_attr(feature = "arbitrary", arbitrary(with = crate::abi::arb::arb_u256))] pub leader_timeunits_allocation: U256, - #[cfg_attr(feature = "arbitrary", arbitrary(with = crate::abi::arb::arb_u256))] pub validator_timeunits_allocation: U256, - #[cfg_attr(feature = "arbitrary", arbitrary(with = crate::abi::arb::arb_u256))] pub execution_budget_per_round: U256, /// Per-round rotation allocations; `rotations[0]` is the initial round, the /// rest are appeal rounds. Must be non-empty. @@ -31,21 +27,17 @@ pub struct InternalMessageParams { /// so we derive `appeal_rounds = rotations.len() - 1` instead. The ABI /// encoder re-inserts it so the encoded bytes (and their `keccak256` fee-param /// pin) match the chain's field layout. - #[cfg_attr(feature = "arbitrary", arbitrary(with = crate::abi::arb::arb_vec_u256))] pub rotations: Vec, /// Per-time-unit GEN price cap locked at activation (consensus CON-549, /// v0.6-dev). The chain charges at this cap as the funding multiplier and /// cancels the tx if the global price exceeds it; `MessagePayments` requires /// it to be non-zero for internal messages. - #[cfg_attr(feature = "arbitrary", arbitrary(with = crate::abi::arb::arb_u256))] pub max_price_gen_per_time_unit: U256, /// Max gas price applied to the storage-fee component (v0.6-dev). Revert /// guard in `_calculateRoundFees`; must be non-zero for internal messages. - #[cfg_attr(feature = "arbitrary", arbitrary(with = crate::abi::arb::arb_u256))] pub storage_fee_max_gas_price: U256, /// Max gas price applied to the receipt-fee component (v0.6-dev). Revert /// guard in `_calculateRoundFees`; must be non-zero for internal messages. - #[cfg_attr(feature = "arbitrary", arbitrary(with = crate::abi::arb::arb_u256))] pub receipt_fee_max_gas_price: U256, } @@ -110,6 +102,7 @@ impl MessageAllocationNode { abi::encode(roots) } + #[allow(clippy::if_same_then_else)] pub fn matches_internal( &self, on: On, @@ -130,6 +123,7 @@ impl MessageAllocationNode { } } + #[allow(clippy::if_same_then_else)] pub fn matches_external( &self, recipient: genlayer_calldata::Address, diff --git a/crates/modules-interfaces/src/host_fns.rs b/crates/modules-interfaces/src/host_fns.rs index d3cfcbe1..ae6be202 100644 --- a/crates/modules-interfaces/src/host_fns.rs +++ b/crates/modules-interfaces/src/host_fns.rs @@ -1,11 +1,9 @@ // This file is auto-generated. Do not edit! -#![allow(dead_code, clippy::redundant_static_lifetimes)] +#![allow(dead_code, clippy::all)] use serde::{Deserialize, Serialize}; -use std::borrow::Cow; - #[derive( Debug, PartialEq, @@ -88,6 +86,61 @@ impl TryFrom for Methods { ::genlayer_calldata::Decode, )] #[repr(u8)] +pub enum ResultCode { + Return = 0, + UserError = 1, + VmError = 2, + InternalError = 3, + FatalVmError = 4, +} + +impl ResultCode { + pub const SIZE: usize = 5; + pub fn value(self) -> u8 { + match self { + ResultCode::Return => 0, + ResultCode::UserError => 1, + ResultCode::VmError => 2, + ResultCode::InternalError => 3, + ResultCode::FatalVmError => 4, + } + } + pub fn str_snake_case(self) -> &'static str { + match self { + ResultCode::Return => "return", + ResultCode::UserError => "user_error", + ResultCode::VmError => "vm_error", + ResultCode::InternalError => "internal_error", + ResultCode::FatalVmError => "fatal_vm_error", + } + } +} + +impl TryFrom for ResultCode { + type Error = (); + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(ResultCode::Return), + 1 => Ok(ResultCode::UserError), + 2 => Ok(ResultCode::VmError), + 3 => Ok(ResultCode::InternalError), + 4 => Ok(ResultCode::FatalVmError), + _ => Err(()), + } + } +} +#[derive( + Debug, + PartialEq, + Clone, + Copy, + Serialize, + Deserialize, + ::genlayer_calldata::Encode, + ::genlayer_calldata::Decode, +)] +#[repr(u8)] pub enum Errors { Ok = 0, EvmReverted = 1, @@ -124,34 +177,6 @@ impl TryFrom for Errors { } } } -#[derive(Debug, Clone, PartialEq, Eq, Serialize)] -pub struct VmErrorDetail(pub Cow<'static, str>); - -impl From for String { - fn from(val: VmErrorDetail) -> String { - val.0.into() - } -} -#[rustfmt::skip] -impl VmErrorDetail { - pub const fn internal() -> Self { Self(Cow::Borrowed("internal")) } - pub const fn external() -> Self { Self(Cow::Borrowed("external")) } -} - -#[rustfmt::skip] -impl VmErrorDetail { - /// Whether `s` is a well-formed `vm_error_detail` path. - pub fn is_valid_(s: &str) -> bool { - if matches!(s, - "internal" | - "external" - ) { - return true; - } - false - } -} - pub const CURRENT_MAJOR: u8 = 0; pub const CURRENT_MAJOR_STR: &'static str = "v0.0.0"; diff --git a/crates/modules-interfaces/src/manager_api.rs b/crates/modules-interfaces/src/manager_api.rs index 8b46009a..aa87d711 100644 --- a/crates/modules-interfaces/src/manager_api.rs +++ b/crates/modules-interfaces/src/manager_api.rs @@ -1,6 +1,6 @@ // This file is auto-generated. Do not edit! -#![allow(dead_code, clippy::redundant_static_lifetimes)] +#![allow(dead_code, clippy::all)] use serde::{Deserialize, Serialize}; diff --git a/crates/modules-interfaces/src/nested.rs b/crates/modules-interfaces/src/nested.rs index 57021cf8..94577089 100644 --- a/crates/modules-interfaces/src/nested.rs +++ b/crates/modules-interfaces/src/nested.rs @@ -249,9 +249,11 @@ mod tests { assert_ne!(hash(ResultCode::Return), hash(ResultCode::UserError)); assert_ne!(hash(ResultCode::Return), hash(ResultCode::VmError)); - // An internal error is never a caller-visible outcome, so it shares the - // `VMError` label rather than adding a kind a peer line might not know. + // Neither an internal error nor fatality changes the outcome value, so + // both fold as a plain `VMError` rather than adding a kind a peer line + // might not know. assert_eq!(hash(ResultCode::VmError), hash(ResultCode::InternalError)); + assert_eq!(hash(ResultCode::VmError), hash(ResultCode::FatalVmError)); } #[test] diff --git a/docs/adr/012. runner memory accounting.md b/docs/adr/012. runner memory accounting.md index 0571d2aa..db235999 100644 --- a/docs/adr/012. runner memory accounting.md +++ b/docs/adr/012. runner memory accounting.md @@ -221,4 +221,4 @@ surface comes later in a runner release. point. - Spec: gl_call payloads, the permissions note, the runners page (load action, loaded set, custom lifetime), the RAM-limiting page (charge rule), - and `memory_limiter_consts.runner_load_cost` in the public ABI constants. + and `memory_limiter_consts.runner_load_cost` in the internal constants. diff --git a/docs/adr/013. pre-validating untrusted decoded inputs.md b/docs/adr/013. pre-validating untrusted decoded inputs.md index 229d36ef..1317889b 100644 --- a/docs/adr/013. pre-validating untrusted decoded inputs.md +++ b/docs/adr/013. pre-validating untrusted decoded inputs.md @@ -44,27 +44,28 @@ and handle its failure correctly. One total function, `parse_leader_result`, a pure function of the proposed bytes so every honest node derives the same result: -1. **Absent or empty** → `absent_leader_nondet_output`. (Empty must equal +1. **Absent or empty** → `leader_fault nondet_output absent`. (Empty must equal absent: `Supervisor::push_nondet_result` pads gaps with empty `Bytes`.) 2. Result code not in `Return`(0)/`UserError`(1)/`VmError`(2) → - `leader_output malformed`. This includes `InternalError`(3): the enum admits - it but the wire format does not. + `leader_fault nondet_output malformed`. This includes `InternalError`(3): + the enum admits it but the wire format does not. 3. **`Return`/`UserError`**: the payload must satisfy `calldata::decode` - (canonical, depth ≤ 128, no trailing bytes) else `leader_output malformed`. - Accepted bytes are preserved **exactly** — validation never re-encodes, or - validators would hash a value other than the one proposed. + (canonical, depth ≤ 128, no trailing bytes) else + `leader_fault nondet_output malformed`. Accepted bytes are preserved + **exactly** — validation never re-encodes, or validators would hash a value + other than the one proposed. 4. **`VmError`**: the payload must be UTF-8, carry **no ` # ` detail** (Rule 1b: an honest leader never publishes one), then, *in order*: 1. If the code is in the **derived-outcome namespace** (equals or - space-extends `absent_leader_nondet_output` or `leader_output`), it is - replaced by `leader_output uses_this_error `. Checked *before* validity - so proposing the literal `leader_output malformed` cannot echo verbatim. + space-extends `leader_fault nondet_output`), it is replaced by + `leader_fault nondet_output uses_this_error `. Checked *before* + validity so proposing the literal `leader_fault nondet_output malformed` + cannot echo verbatim. 2. Otherwise the code must be a valid `vm_error` trie path, including the canonical spelling of any parameter (`exit_code +7`/`007` are rejected — same `i32`, different bytes, and codes reach the hash). The check is **generated** from the trie data, so it cannot drift. Fail → - `leader_output malformed`. Pending-ABI codes (below) are not trie paths, - hence not proposable. + `leader_fault nondet_output malformed`. The parsed-or-substituted result then flows through the **standard consensus comparison** — handed to the contract's validator function like any proposal. @@ -75,17 +76,19 @@ directly is removed. Fees (`consume_nondet_output`) are charged on the accepted/substituted result's **own** length — rejected bytes never enter the result or the hash. -**Derived-outcome namespace.** Validators derive `absent_leader_nondet_output`, -`leader_output malformed`, `leader_output uses_this_error ` and -`leader_output extra ` themselves. A proposal must never be byte-equal to -what a validator derives from rejecting it, or "leader proposed X" and -"proposal rejected as X" become indistinguishable (namespace hygiene, not +**Derived-outcome namespace.** Validators derive +`leader_fault nondet_output absent`, `leader_fault nondet_output malformed`, +`leader_fault nondet_output uses_this_error ` and +`leader_fault nondet_output extra ` themselves. A proposal must never be +byte-equal to what a validator derives from rejecting it, or "leader proposed X" +and "proposal rejected as X" become indistinguishable (namespace hygiene, not anti-spoofing — a dishonest leader controls its own hash regardless). So an -in-namespace proposal maps to `leader_output uses_this_error `, `` = first -6 chars of `gvm32(sha3_256(proposed code))`. A self-replacing fixed point -(~2³⁰ brute force) maps to the sentinel `…uses_this_error fix_point`, which -can't collide with an `` (9 chars vs always 6). `` collisions are -harmless — the value carries no meaning. +in-namespace proposal maps to +`leader_fault nondet_output uses_this_error `, `` = first 6 chars of +`gvm32(sha3_256(proposed code))`. A self-replacing fixed point (~2³⁰ brute +force) maps to the sentinel `…uses_this_error fix_point`, which can't collide +with an `` (9 chars vs always 6). `` collisions are harmless — the value +carries no meaning. ### Rule 1.5 — surplus leader results (`Validator` and `Sync`) @@ -94,14 +97,15 @@ run reaching a block with no result is Rule 1.1; the complement — a leader publishing **more** results than the run consumed — was silently tolerated, hiding a leader whose execution diverged into extra blocks. Now: if the leader supplied more results than blocks run, the run's result is replaced by -`leader_output extra `, `` = first 6 chars of `gvm32(sha3_256(b))` where -`b` is the **full `[result_code][data]` buffer** the run would otherwise have -returned (`RunOk::as_bytes()`) — fingerprinting the discarded result rather -than losing it. This is **not** a non-deterministic disagreement (it's a -property of the counts, not a re-executed block). No fix-point escape is needed: -a `leader_output` code is never accepted verbatim (Rule 1.4), so this can't be -byte-equal to a proposal. The outcome depends only on the two counts, so *when* -the check runs (after the block count is final) is unspecified. +`leader_fault nondet_output extra `, `` = first 6 chars of +`gvm32(sha3_256(b))` where `b` is the **full `[result_code][data]` buffer** the +run would otherwise have returned (`RunOk::as_bytes()`) — fingerprinting the +discarded result rather than losing it. This is **not** a non-deterministic +disagreement (it's a property of the counts, not a re-executed block). No +fix-point escape is needed: a `leader_fault nondet_output` code is never +accepted verbatim (Rule 1.4), so this can't be byte-equal to a proposal. The +outcome depends only on the two counts, so *when* the check runs (after the +block count is final) is unspecified. ### Rule 1b — publishing the leader's own result (`Leader`) @@ -160,15 +164,12 @@ Rule 1b governs `Leader`. ### Where the constants live -`malformed_entry`, `leader_output malformed`, `leader_output uses_this_error -{str}` and `leader_output extra {str}` go in the **pending** ABI data -(`executor/codegen/data/public-abi-pending.json`), the -[ADR-012](<012. runner memory accounting.md>) mechanism for public-ABI -constants that must not regenerate the runner-hashed `public_abi.py`. Generated -into `common` only → hash-neutral. Cost: the `vm_error` taxonomy temporarily -lives in two shapes; fold the pending codes into the trie at the next -hash-moving release train. Until then the generated validity check rejects them, -which is what makes them unproposable under Rule 1.4. +`malformed_entry`, `leader_fault nondet_output malformed`, +`leader_fault nondet_output uses_this_error {str}` and +`leader_fault nondet_output extra {str}` live in the public ABI trie. The +generated validity check rejects the leader-fault nondet-output subtree for +leader proposals because it is executor-derived, which is what makes those +codes unproposable under Rule 1.4. ## Consequences @@ -182,14 +183,12 @@ leader results collapse into one total parse feeding one comparison path. **Negative.** Consensus-visible behaviour change (results/calls accepted before are now rejected; nondet `VMError` loses its ` # detail`); ships with a version -bump ([ADR-010](<010. versions.md>)), runner hashes unmoved thanks to the -pending mechanism. Rust-SDK contracts relying on `MainCalldata::parse`'s lenient -defaulting (non-Map payload, wrong-typed `args`) now get `malformed_entry`. A -`""` key on a deployment is now an error (was silently ignored on init) — eight -integration fixtures sent one and their goldens move to `malformed_entry`. The -`vm_error` taxonomy is split until the next hash-moving train. Validating -`Return` costs one decode pass over host-bounded leader bytes on the validator -path. +bump ([ADR-010](<010. versions.md>)). Rust-SDK contracts relying on +`MainCalldata::parse`'s lenient defaulting (non-Map payload, wrong-typed `args`) +now get `malformed_entry`. A `""` key on a deployment is now an error (was +silently ignored on init) — eight integration fixtures sent one and their +goldens move to `malformed_entry`. Validating `Return` costs one decode pass +over host-bounded leader bytes on the validator path. **Neutral.** A leader still has an arbitrary-*content* channel via a *well-formed* `Return`/`UserError` (inherent — the rules bound shape, not @@ -250,8 +249,7 @@ calldata, extra keys or observable nondet details. - Spec: proposed-result rules and derived namespace in `subvm-result-encoding`; `03-vm/04-determinism-mode-switching.rst` covers all three modes; Rule 2 on the calling-convention page with its failure surfaces in `03-vm/01-startup.rst` - and under `CallContract`. The rst backend gained `--rst-anchor-ns` so the - pending appendix does not redefine the real `gvm-def-str-trie-vm-error` label. + and under `CallContract`. ### Deferred @@ -260,5 +258,3 @@ calldata, extra keys or observable nondet details. tree and would move hashes. Rule 1 makes the guard defensive, not load-bearing. - **`message.rs` `CallKey::UNNAMED` fallback** on a decode failure — should be an error. -- **Folding the pending codes into the `vm_error` trie** at the next hash-moving - train. diff --git a/docs/adr/015. cross-major contract calls.md b/docs/adr/015. cross-major contract calls.md index eff91c2e..08c75fc1 100644 --- a/docs/adr/015. cross-major contract calls.md +++ b/docs/adr/015. cross-major contract calls.md @@ -141,7 +141,7 @@ computed by the caller and carried on the wire. The table is complete against | `method_hosts` | Constructed by the manager: host 0 by default, `consume_result` and `run_nested` on host 1. | | `host_hello_data` | Copied from the outer request; entry 1 is cleared for the new manager socketpair. | | Effectful and nondeterministic allocations | Cleared: `leader_nondet_results` and `record_actions` are empty because a deterministic child produces neither; `bucket_totals`, `message_fee_allocation` and `initial_time_units_allocation` are empty or zero because the child imports its remaining deterministic budget instead of being granted a fresh one. | -| `remaining_recursion` | Parent budget minus one. Carried as a remainder, not a spent count, so the bound stays the one the chain's root minted even when the lines disagree on `VM_RECURSION` -- but the receiving executor clamps it to its own limit, since a remainder is not an authority to exceed one. Also set, for a chain root, by the `initial_recursion` debug override. | +| `remaining_recursion` | Parent budget minus one. Carried as a remainder, not a spent count, so the bound stays the one the chain's root minted even when the lines disagree on `VM_RECURSION` -- but the receiving executor clamps it to its own limit, since a remainder is not an authority to exceed one. The manager clamps it again, to `CROSS_MAJOR_RECURSION` (6), so a delegated chain is bounded far more tightly than an in-process one: a hop costs a whole executor process, and the manager is the only party that sees the chain as a whole. The clamp also bounds the subtree below a delegated call, which is intended -- a chain that has already crossed a boundary does not get to recurse deeply in-process either. Also set, for a chain root, by the `initial_recursion` debug override. | | `nested.memory_limit` | The derived limiter's remaining memory, made an explicit process-spawn limit. | | `nested.stack` | Caller stack with the caller contract appended. | | `nested.permissions` | `CallContract`-derived permissions. Unknown envelope bits decode as denied. | diff --git a/docs/contributing/explanation/README.md b/docs/contributing/explanation/README.md index 918220f7..a7ab0ac3 100644 --- a/docs/contributing/explanation/README.md +++ b/docs/contributing/explanation/README.md @@ -5,6 +5,7 @@ lives in the spec, and these pages only motivate it and link out - [docs-layout.md](docs-layout.md) — the 4 kinds of page and where each belongs - [executor-lines.md](executor-lines.md) — why several executor lines ship side by side, and what it costs +- [fuzz.md](fuzz.md) — why fuzz targets get fake entropy and no CmpLog - [merge-model.md](merge-model.md) — why merging is a maintainer panel rather than a merge queue - [shared-submodule-cache.md](shared-submodule-cache.md) — why submodules are worktrees of one cache repo, not clones - [vendored-trees.md](vendored-trees.md) — why third-party sources are patch series, not forks diff --git a/docs/contributing/explanation/fuzz.md b/docs/contributing/explanation/fuzz.md new file mode 100644 index 00000000..d9e7015f --- /dev/null +++ b/docs/contributing/explanation/fuzz.md @@ -0,0 +1,39 @@ +# Why Fuzzing Is Set Up This Way + +## Fake Entropy + +A fuzz target is only useful if a saved crash reproduces. Real entropy breaks +that: `std` seeds tokio's scheduler and every `HashMap` from `getrandom`, so two +runs over one input take different task orders and different bucket layouts, and +an input AFL saved as a crash need not crash again + +So fuzz cases — and no other test — run with `crates/fuzzing/preload` in +`AFL_PRELOAD`, a shim whose `getrandom`/`getentropy` hand out a fixed sequence. +AFL turns that into an `LD_PRELOAD` for the target alone, which is why it is a +preload rather than a patch: the seeding happens in `std`, below any code this +repository owns, and interposing the symbol is the only place to stand + +`glibc` seeds its allocator from inside the loader, before a preloaded symbol can +win, so that call stays random — it perturbs heap layout only, and AFL already +disables ASLR. The mechanism also assumes a dynamically linked target: a static +or `musl` build would ignore the preload and say nothing, so the entropy would +come back silently rather than as a failure + +## No CmpLog + +CmpLog logs both operands of every comparison, letting AFL write a magic value +straight into an input instead of guessing it. It is the standard answer for a +parser gated on tags and headers, and it does nothing for us + +Our targets are `arbitrary`-driven: input bytes are *interpreted* to construct a +value, not compared against constants, so there is almost nothing for CmpLog to +log. Measured over 60s per side, `genvm-common-encode` found 1791 edges either +way, and `genvm-common-decode` 1782 against 1785 — noise + +The cost is not noise. CmpLog is a second instrumentation, and AFL wants it as a +separate binary so the fuzzing loop stays fast, which means building the whole +dependency graph twice. For one crate that came to 1.2G + +Worth revisiting for a target that parses raw bytes rather than driving +`arbitrary` — `runners-parse` reads real zip data and was never measured, since +building its second graph pulls in wasmtime diff --git a/docs/contributing/howto/README.md b/docs/contributing/howto/README.md index 7988ef81..7a5349b8 100644 --- a/docs/contributing/howto/README.md +++ b/docs/contributing/howto/README.md @@ -17,7 +17,7 @@ - [rust.md](testing/rust.md) — Rust tests: where they go, how to run them, coverage - [python.md](testing/python.md) — Python tests, direct pytest for genlayer-py-std - [integration.md](testing/integration.md) — jsonnet cases, tags, golden `.stdout`/`.hash` files, services -- [fuzzing.md](testing/fuzzing.md) — AFL fuzz targets, host sysctl prep +- [fuzzing.md](testing/fuzzing.md) — AFL fuzz targets, seeding a corpus from a run, host sysctl prep ## committing/ - [submodules.md](committing/submodules.md) — repo topology, gitlink bumps, pre-commit hooks, push order diff --git a/docs/contributing/howto/genvm-tool.md b/docs/contributing/howto/genvm-tool.md index 3fbd80d6..8df682b6 100644 --- a/docs/contributing/howto/genvm-tool.md +++ b/docs/contributing/howto/genvm-tool.md @@ -13,23 +13,38 @@ has no wrapper | `codegen` | render a data JSON into rust/python/rst/go | | `build-manifest` | write the manager's `data/manifest.yaml` | | `docs` | render the `docs/contributing/` indexes, the source of the list in `CLAUDE.md` | +| `fuzz-corpus` | seed the fuzz corpora from a finished run ([testing/fuzzing.md](testing/fuzzing.md)) | | `git` | `ls`, `list-repo`, `create-branches`, `check-for-push` across the manager and every executor submodule ([submodules.md](committing/submodules.md)) | ## Codegen `ninja -C build codegen` regenerates from data JSON; never edit an output by -hand. Host protocol data is shared, public ABI data comes from the primary line +hand. Host protocol data is shared, per-line data lives in +`executors/.x/executor/codegen/data/` | Data | Generated | |---|---| | `crates/modules-interfaces/codegen/data/host-fns.json` | `…/src/host_fns.rs`, `tests/runner/origin/host_fns.py` | | `crates/modules-interfaces/codegen/data/manager-api.json` | `…/src/manager_api.rs`, `tests/runner/origin/manager_api.py`, `docs/website/src/impl-spec/appendix/manager-socket-consts.rst` | -| `executors/.x/executor/codegen/data/public-abi.json` | `tests/runner/origin/public_abi.py`, `docs/website/src/spec/appendix/constants.rst` | + +Per line, with the manager-global outputs taken from the primary line only: + +| Data | Per-line output | From the primary line only | +|---|---|---| +| `public-abi.json` | `executor/crates/sdk-rs/src/abi/consts.rs`, `runners/genlayer-py-std/src/genlayer/vm/public_abi.py` | `tests/runner/origin/public_abi.py`, `docs/website/src/spec/appendix/constants.rst` | +| `public-abi-pending.json` | `executor/crates/common/src/public_abi_pending.rs` | `docs/website/src/spec/appendix/constants-pending.rst` | +| `internal-constants.json` | `executor/crates/common/src/internal_constants.rs` | `docs/website/src/spec/appendix/internal-constants.rst` | ## Suite Layout The suite is `tests(ctx)` in the root `.genvm-tool.py`, which registers collectors. Plugins in `tests/runner/genvm_tool_plugins/` are plain importable modules, with no runner-specific registry. Per-suite definitions live next to -the tests in `tests/system//test.py`, pulled in with `ctx.collect_dir`. -Each executor line carries its own `.genvm-tool.py` +the tests in `tests/system//test.py`, pulled in with `ctx.collect_dir`, or +reuse `integration_test_directory` for contract-execution Jsonnet. Each +executor line carries its own `.genvm-tool.py` + +Services that bind the same listener declare the same `ctx.new_semaphore` +value. The scheduler finishes a service and its dependent cases before starting +the next service holding that semaphore; `genvm-tool test show plan` displays +the resulting lifetime boundaries diff --git a/docs/contributing/howto/testing/README.md b/docs/contributing/howto/testing/README.md index 0e5886f3..b8429cb0 100644 --- a/docs/contributing/howto/testing/README.md +++ b/docs/contributing/howto/testing/README.md @@ -20,7 +20,8 @@ subcommand Presets in `tests/presets/`: `release.txt` is `integration & stable & !bench`, `rust.txt` is `(rust | integration) & !bench & !fuzz`, `rust-fuzz.txt` is -`rust & fuzz`, `python.txt` is `python`. `genvm-tool test show tags` lists every +`rust & fuzz`, `python.txt` is `python & !needs-fuzz`, `python-fuzz.txt` is +`python & needs-fuzz`. `genvm-tool test show tags` lists every tag, the integration ones are in [integration.md](integration.md) ## Fix–Rerun Loop @@ -37,6 +38,8 @@ genvm-tool test run --filter-continue Rust from every tracked `Cargo.toml` and its `fuzz/*.rs`, python from `executors/v0.3.x/runners/genlayer-py-std`, integration from each line's -`tests/integration/`, system from `tests/system//test.py`. Collection is -wired in the root `.genvm-tool.py`, runner configuration in +`tests/integration/`, and system from `tests/system/`. System suites use the +same Jsonnet collector when they execute contracts; protocol-level assertions +use `test.py`, which must register 1 `genvm-tool` case per assertion. Collection +is wired in the root `.genvm-tool.py`, runner configuration in `.genvm-monorepo-root` ([genvm-tool.md](../genvm-tool.md)) diff --git a/docs/contributing/howto/testing/fuzzing.md b/docs/contributing/howto/testing/fuzzing.md index 5901182f..621697e6 100644 --- a/docs/contributing/howto/testing/fuzzing.md +++ b/docs/contributing/howto/testing/fuzzing.md @@ -1,17 +1,165 @@ # Fuzzing -Rust fuzz targets run under AFL (`cargo-afl`); a target is any `fuzz/*.rs` next -to a tracked `Cargo.toml`: +Rust and Python fuzz targets run under AFL. A Rust target is any `fuzz/*.rs` +next to a tracked `Cargo.toml`; a Python target is any `fuzz/src/*.py` in a +collected Python project: ```bash -genvm-tool test run --filter-tag "$(cat tests/presets/rust-fuzz.txt)" # rust & fuzz +genvm-tool test run --filter-tag "$(cat tests/presets/rust-fuzz.txt)" # rust & fuzz +genvm-tool test run --filter-tag "$(cat tests/presets/python-fuzz.txt)" # python & needs-fuzz ``` -Python fuzz targets exist, but their collection is currently disabled in -`.genvm-tool.py`. Some integration cases carry the `fuzz` tag too +A corpus is committed next to its target: `fuzz/inputs-` for Rust, +`fuzz/inputs/` for Python. Beside it, `-curated` holds seeds +written by hand — see [Curated Seeds](#curated-seeds) -Options: `--fuzz-timeout N` (seconds per run, default 30) and -`--fuzz-update-corpus` (write interesting inputs back) +A generated entry is named `gvm32(sha3_224(input))` and stored under the first +two characters of that name, `///`, so a corpus of +thousands of entries stays a tree of small directories. Reading takes an entry +wherever it sits, so entries an older run left directly in the corpus dir are +still used; a corpus update rewrites the whole dir and shards them + +`needs-fuzz` is the tag to select on: it means the case drives AFL and wants the +host prepared as below, whereas the plain `fuzz` tag some integration cases carry +only says the case is randomized. The CI cell that runs the AFL cases is `other` + +Python targets are collected on x86_64 Linux only — the pinned python-afl and +AFL++ are packaged for that platform alone + +The shared AFL test plugin owns the process fleet for both languages. Options: +`--fuzz-timeout D` (per run, a duration such as `30s` or `5m`, default `30s`), +`--fuzz-concurrent N` (targets side by side, default: cores minus two), +`--fuzz-jobs N` (processes per target, default: the cores `--fuzz-concurrent` +leaves over, so one), and `--fuzz-update-corpus` (write interesting inputs back) + +A fleet is N instances sharing one output dir; they only exchange corpora every +`AFL_SYNC_TIME` (20 minutes, halved for the `-M` instance), so below that it is N +independent searches — still worth it, since every instance's crashes are +collected. That is why the default spends cores across targets rather than within +one: a second instance of a target re-searches what the first one covers, while +another target covers code neither reaches + +AFL's live UI needs the terminal to itself, so it is only shown when a single +target runs at a time (`--fuzz-concurrent 1`). Otherwise every instance writes to +`/.log` and the case reports the closing `afl-whatsup` +summary + +`--fuzz-concurrent` sizes the fleet; what physically bounds overlap is the case +pool, `--max-concurrent` (default: the core count). A fuzz case holds one permit +of it per fuzzer process it starts + +A crash is copied into the target's generated corpus (`fuzz/inputs-`, +named as a corpus entry) as soon as it is reported, so every later run replays +it — the next run wipes the crash dir it was saved in. Commit it along with the +fix; put it in `-curated` instead if a corpus update must never drop it + +Findings of both languages live under `build/test-artifacts/fuzz//`. +Reruns resume from that dir (`AFL_AUTORESUME`) and therefore ignore `-i`: remove +it to pick up a corpus that changed. Corpus updates `cmin` the fleet's queues +and replace the committed corpus with what survives, laid out as above — so the +first update of a corpus moves every file it keeps + +## Curated Seeds + +`cmin` judges an input by the edges it reaches, so a seed written to pin a shape +down — the one input covering a format's corner — is dropped as soon as some +havoc'd blob happens to cover the same edges. Put such an input in +`-curated` instead: `fuzz/inputs--curated` for Rust, +`fuzz/inputs/-curated` for Python + +That dir is read-only to the tooling. Every run stages it together with the +generated corpus into the `-seeds` dir it hands to `-i`, and neither +`--fuzz-update-corpus` nor `fuzz-corpus` ever writes or deletes anything in it. +Name the files for humans — `deeply-nested-object`, not a content hash; the +staging renames them on the way in, and a corpus update drops the copy `cmin` +kept of a curated seed rather than committing it twice. A `README.txt` there is +not a seed, so the dir can say what its inputs are for + +A curated seed still has to buy something: `fuzz-corpus` counts its coverage as +already-covered, so a harvested blob reaching nothing beyond it is not added + +## Seeding a Corpus From a Test Run + +Random bytes are almost never a zip or a calldata frame, so a target with a +committed corpus of a dozen entries spends its budget rediscovering the reject +path. The integration suite produces real calldata, contract code and leader +results on every run; `fuzz-corpus` harvests them from the artifacts dir into +`fuzz/inputs-`, named by content hash: + +```bash +genvm-tool test run --filter-tag integration # produce the artifacts +genvm-tool fuzz-corpus --dry-run # what it would add, and why not +genvm-tool fuzz-corpus +``` + +Each candidate is kept only if `afl-showmap` says it reaches an edge the corpus +does not already cover, so the committed corpus grows by seeds that buy +something. It also drops what a corpus should not carry: a blob above +`--max-size`, or one embedding a path of the machine that produced it. The check +needs the targets built; `--no-verify` skips it + +A harvest only adds; run the targets once with `--fuzz-update-corpus` afterwards +to `cmin` the union back down, and check the repo delta before committing + +Nothing is harvested for a `-structured` target or its op-sequence kin: they take +a serialized value rather than a format, which a run does not produce. Seed those +by driving their mutator, as below + +## Structured Targets + +A target whose input is a value rather than a byte format comes in two halves. +`-raw` takes the bytes verbatim and is what covers the parser. Next to it, +`-structured` takes a [`postcard`] encoding of the value, and a mutator +crate at `fuzz/mutators//` mutates that value structurally — AFL loads it +through `AFL_CUSTOM_MUTATOR_LIBRARY`, which the test plugin sets whenever such a +crate exists + +The input type lives in its own file under `fuzz/shared/`, pulled into both the +target and the mutator crate with `#[path = ...] mod`. Keep that file free of +anything the executor owns: the mutator crate is a small `cdylib` and must not +have to link `genvm` to build + +AFL's own mutations are deliberately left on. Handing every mutation to the +custom mutator (`AFL_CUSTOM_MUTATOR_ONLY`) measures worse — a havoc'd buffer that +fails to decode costs one cheap early return, while the ones that do decode reach +values the structural mutator never proposes. `GENVM_FUZZ_MUTATOR_ONLY=1` turns +it on to compare + +### Seeding One + +A structural mutator only mutates a value it already has, so a `-structured` +target needs a non-empty corpus before it explores anything. Generate one by +driving the built mutator library, which makes every seed valid by construction: + +```python +import ctypes, pathlib +from genvm_tool.misc import fuzz_input_name, fuzz_input_path + +lib = ctypes.CDLL('/debug/libfuzz_mutator_.so') +lib.afl_custom_init.restype = ctypes.c_void_p +lib.afl_custom_init.argtypes = [ctypes.c_void_p, ctypes.c_uint] +lib.afl_custom_fuzz.restype = ctypes.c_size_t +lib.afl_custom_fuzz.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t, + ctypes.POINTER(ctypes.c_char_p), ctypes.c_char_p, ctypes.c_size_t, ctypes.c_size_t] + +state, current = lib.afl_custom_init(None, 0), b'\x00' # the default value +for _ in range(60): + out = ctypes.c_char_p() + n = lib.afl_custom_fuzz(state, current, len(current), ctypes.byref(out), None, 0, 4096) + current = ctypes.string_at(out, n) + path = fuzz_input_path(pathlib.Path('fuzz/inputs-'), fuzz_input_name(current)) + path.parent.mkdir(parents=True, exist_ok=True) + path.write_bytes(current) +``` + +Two things to check in the result. Every variant of the input type should appear +across the seeds — a mutator that cannot construct one leaves that variant's code +unreachable, and seeds generated from it will not cover it either. And the type's +own `serde` impls are not always a corpus codec: `calldata::Value` describes +itself to the format (a null is a unit, a number is an `i64` when it fits), which +`postcard` cannot read back, so it has a separate `Corpus` representation + +[`postcard`]: https://docs.rs/postcard ## Host Preparation diff --git a/docs/contributing/howto/testing/integration.md b/docs/contributing/howto/testing/integration.md index 7593f763..4c8c3b65 100644 --- a/docs/contributing/howto/testing/integration.md +++ b/docs/contributing/howto/testing/integration.md @@ -21,6 +21,14 @@ stays in-process, which is what all other cases do. A routed callee must pin its runner by hash: the nested executor runs with debug mode disabled, where `:test` does not resolve. See `misc/routed_call` on v0.3.x +A multi-line system case may also set `reroute_to` on an individual step, for +example while deploying a fixture with the executor line that owns its public +ABI. Use `${executorV02}` or `${executorV03}` rather than pinning a release +version; the collector unfolds these from `build/info.json` + +Set `expected_executor_route_requests` to assert the exact hook calls. Each +entry has `contract_address`, numeric `state_mode`, and `advisory_major` + A step's declared public-ABI `major` is read from the contract's root slot, so the manager routes it the way a real host would. A step may set `major` explicitly when its subject is what the executor does with a major the manager @@ -37,8 +45,8 @@ would otherwise refuse to route — see `runner/major_mismatch` Stability is the second argument of `util.features(paths, stability)` in the case's jsonnet `tags`; legacy v0.2.x uses a `stable/` top-level directory -instead. `--filter-tag` tokenizes alphabetic words only, so a hyphenated tag — -`semi-stable`, any `feature-*` — is unmatchable there; use `--filter-name` +instead. `--filter-tag` accepts alphanumeric tag names containing `-` and `_`; +matching remains exact ## Running a Subset @@ -76,8 +84,11 @@ exposed. A top-level `debug_mode` in the jsonnet lowers that to `safe`, `safe-unbounded` or raises it to `unsafe-tracing`; `disabled` is rejected, because `reroute_to` — what points a case at its own line's executor — is honored only from `safe` up. Below `unsafe` a contract must name its runner by -hash instead of `:test`, read from -`build/out/executor//data/latest.json` +hash instead of `:test`. Write `@RUNNER_LATEST__@` for that hash, +for example `py-genlayer:@RUNNER_LATEST_v0.3_py-genlayer@`: the harness replaces +it with the uid in `build/out/executor//data/latest.json` before the +code reaches an executor, so a runner change needs no test edit. A literal uid +still works and goes stale ## Services @@ -85,3 +96,6 @@ The manager, the modules and the webdriver start automatically; `--no-manager` and `--no-webdriver` reuse externally running ones (a manual webdriver is `bash webdriver/build-and-run.sh`). After WASM files change, `./build/out/executor//bin/genvm precompile` saves test time + +`--no-manager` omits cases that require a manager with a suite-owned config or +restart lifecycle diff --git a/docs/contributing/howto/testing/rust.md b/docs/contributing/howto/testing/rust.md index 0d5aa57f..5a26cfe3 100644 --- a/docs/contributing/howto/testing/rust.md +++ b/docs/contributing/howto/testing/rust.md @@ -11,6 +11,27 @@ shared `crates/` and executor crates are all picked up 4. Tests for `abc.rs` go into `abc_test.rs`, referenced with `#[path = "abc_test.rs"] mod tests;` +## Extra Tags + +Files in `tests/`, `examples/` and `fuzz/` can add tags to their own case with a +comment anywhere in the file: + +```rust +// genvm-tool-test-tags: feature-web-request-body, needs-web +``` + +They add to `rust` plus `unit`, `example`, or `fuzz` and `needs-fuzz`, depending +on the case kind + +Library and binary cases declare tags in the crate's `.ya-test-config.json`: + +```json +{"tags": {"lib": ["feature-schema-primitive"], "bin/genvm": ["smoke"]}} +``` + +Feature tags expand to their declared dash-prefix ancestors. The complete +vocabulary is in `tests/tags.json`; unknown tags fail collection + ## How To Run ```bash diff --git a/docs/schemas/default-config.json b/docs/schemas/default-config.json index 3f56aa01..692e39fe 100644 --- a/docs/schemas/default-config.json +++ b/docs/schemas/default-config.json @@ -175,10 +175,38 @@ "description": "path to manifest file" }, "permits": { - "type": ["integer", "null"], + "type": ["object", "null"], "default": null, - "minimum": 1, - "description": "concurrency permits; if null will be auto-discovered; full VM takes 2, sync VM takes 1" + "description": "concurrency budget, one permit is one gigabyte of RAM; a total below the most expensive run is raised to it", + "additionalProperties": false, + "properties": { + "total": { + "type": ["integer", "null"], + "default": null, + "minimum": 1, + "description": "total permits; if null, free memory in gibibytes times `per_gib`" + }, + "per_gib": { + "oneOf": [ + { "type": "integer", "minimum": 1 }, + { "type": "string", "pattern": "^\\s*[0-9]+\\s*(/\\s*[0-9]+\\s*)?$" } + ], + "default": 1, + "description": "permits handed out per gigabyte of free memory, an integer or an exact ratio like `1/4`; raise it to overcommit, lower it to undercommit" + }, + "sync": { + "type": "integer", + "default": 4, + "minimum": 1, + "description": "permits a sync run costs" + }, + "nondet": { + "type": "integer", + "default": 8, + "minimum": 1, + "description": "permits a nondet run costs, it also bounds the minimum of `total`" + } + } } }, "required": ["manifest_path"] diff --git a/docs/schemas/runners.json b/docs/schemas/runners.json index 779fe9ed..22a543f0 100644 --- a/docs/schemas/runners.json +++ b/docs/schemas/runners.json @@ -13,12 +13,12 @@ }, "runner-id": { "type": "string", - "description": "Identifier of a runner to load", + "description": "Identifier of a runner to load. Hashes are matched in their canonical GVM32 form; the executor's decoder is additionally lenient about case, the `i`/`l`/`o` aliases and ignored `-`, but ids are not written that way", "anyOf": [ { - "pattern": "^[a-zA-Z0-9_-]+:[a-zA-Z0-9_=-]+$", + "pattern": "^[a-zA-Z0-9_-]+:[0-9abcdefghjkmnpqrstvwxyz]{52}$", "not": { "pattern": "^(contract|chain|custom):" }, - "description": "`name:hash` — packaged runner by human readable name and archive hash (in debug mode hash may be `test`/`latest`). `contract`/`chain`/`custom` are reserved and cannot be used as a name" + "description": "`name:hash` — packaged runner by human readable name and archive hash, the latter 52 GVM32 characters (in dev mode the magic `test0000...` hash, which is itself well-formed GVM32). `contract`/`chain`/`custom` are reserved and cannot be used as a name" }, { "const": "contract", @@ -29,21 +29,22 @@ "description": "`chain:
[:[:]]` — code blob read from a `0x` 20 byte address at a GVM32-encoded 32 byte slot, `a`=accepted / `f`=finalized. `` and `` are optional: `` defaults to `a` and `` to the target contract's root code slot" }, { - "pattern": "^custom:[a-zA-Z0-9_=-]+$", - "description": "`custom:` — runner registered at runtime" + "pattern": "^custom:[0-9abcdefghjkmnpqrstvwxyz]{52}$", + "description": "`custom:` — runner registered at runtime, addressed by 52 GVM32 characters" } ] }, + "NestedInitAction": { + "description": "A rule nested inside another one. `$schema` is only accepted on the top level object.", + "allOf": [ + { "$ref": "#/definitions/InitAction" }, + { "not": { "required": ["$schema"] } } + ] + }, "InitAction": { "description": "A single rule for loading.", "type": "object", "allOf": [ - { - "type": "object", - "properties": { - "$schema": { "type": "string" } - } - }, { "oneOf": [ { @@ -95,9 +96,12 @@ } ], "properties": { + "$schema": { "type": "string" }, "AddEnv": { "description": "Adds environment variable", "type": "object", + "additionalProperties": false, + "required": ["name", "val"], "properties": { "name": { "type": "string", @@ -112,6 +116,8 @@ "MapFile": { "description": "Makes file available at specified path in genvm", "type": "object", + "additionalProperties": false, + "required": ["file", "to"], "properties": { "file": { "type": "string", @@ -146,26 +152,30 @@ "description": "Execute sequence", "type": "array", "items": { - "$ref": "#/definitions/InitAction" + "$ref": "#/definitions/NestedInitAction" } }, "When": { "description": "Conditionally execute action", "type": "object", + "additionalProperties": false, + "required": ["cond", "action"], "properties": { "cond": { "$ref": "#/definitions/WasmMode" }, - "action": { "$ref": "#/definitions/InitAction" } + "action": { "$ref": "#/definitions/NestedInitAction" } } }, "With": { "description": "Makes given runner current without executing it's action. It means that MapFile will fork with files from this archive. Useful for creating lock files", "type": "object", + "additionalProperties": false, + "required": ["runner", "action"], "properties": { "runner": { "description": "runner id to make current", "$ref": "#/definitions/runner-id" }, - "action": { "$ref": "#/definitions/InitAction" } + "action": { "$ref": "#/definitions/NestedInitAction" } } } }, diff --git a/docs/website/generate.py b/docs/website/generate.py index 13d5d6e0..b1bab11e 100755 --- a/docs/website/generate.py +++ b/docs/website/generate.py @@ -23,7 +23,8 @@ def _newest_line() -> str: - """The newest active executor line, e.g. `v0.3`. + """ + The newest active executor line, e.g. `v0.3`. Decided by version order, NOT by position: `active-versions` is hand-ordered and `genvm-tool check-versions bump` APPENDS the new line, so after the next @@ -318,7 +319,8 @@ def version_to_anchor(ver): def build_runner_version_list(rid): - """Build list of (hash, version_range_str) for previous versions of a runner. + """ + Build list of (hash, version_range_str) for previous versions of a runner. Groups consecutive versions sharing the same hash into ranges. Skips the current (latest) hash. diff --git a/docs/website/merge_txts.py b/docs/website/merge_txts.py index a805bc4d..19170776 100644 --- a/docs/website/merge_txts.py +++ b/docs/website/merge_txts.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 -"""Concatenate every ``*.txt`` under a directory into one bundle. +""" +Concatenate every ``*.txt`` under a directory into one bundle. Used to fold a sphinx ``-b text`` build of one section into a single ``_static/ai/
.txt`` file (the "docs for LLMs" bundles). Each entry is diff --git a/docs/website/src/impl-spec/01-core-architecture/01-components.rst b/docs/website/src/impl-spec/01-core-architecture/01-components.rst index d802182e..b8cddb1d 100644 --- a/docs/website/src/impl-spec/01-core-architecture/01-components.rst +++ b/docs/website/src/impl-spec/01-core-architecture/01-components.rst @@ -116,7 +116,7 @@ software floating point implementation for deterministic mode - Curated standard library for deterministic execution - Support for some necessary libraries (NumPy, PIL) -GenVM requires some built-in runners to be accessible by contracts. They are identified by hashes of their ``tar`` contents +GenVM requires some built-in runners to be accessible by contracts. They are identified by hashes of their ``zip`` contents :term:`Host` Interface ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/website/src/impl-spec/02-vm/03-consensus.rst b/docs/website/src/impl-spec/02-vm/03-consensus.rst index e60f75cd..b6cf04b6 100644 --- a/docs/website/src/impl-spec/02-vm/03-consensus.rst +++ b/docs/website/src/impl-spec/02-vm/03-consensus.rst @@ -23,10 +23,10 @@ results: leader's result at ``call_no`` from this vector and feeds it back to the contract as the second argument of the non-det block. If the leader produced fewer entries than the validator demands, the run aborts with - ``VmError::absent_leader_nondet_output``. + ``VmError::leader_fault().nondet_output().absent()``. ``call_no`` is a monotonically increasing counter incremented per ``RunNondet`` -invocation. The hard cap is ``public_abi::top_limits::NONDET_BLOCKS`` (``4096``); +invocation. The hard cap is ``internal_constants::top_limits::NONDET_BLOCKS`` (``4096``); exceeding it produces ``VmError::oom().ram().limit()``. The counter is what binds a leader's i-th non-det result to the validator's i-th non-det check — the ordering of ``RunNondet`` calls in deterministic code MUST match between leader diff --git a/docs/website/src/impl-spec/appendix/manager-api.yaml b/docs/website/src/impl-spec/appendix/manager-api.yaml index 54a52ef2..e2a25f08 100644 --- a/docs/website/src/impl-spec/appendix/manager-api.yaml +++ b/docs/website/src/impl-spec/appendix/manager-api.yaml @@ -57,6 +57,12 @@ paths: max: type: integer description: Maximum number of permits + per_sync_run: + type: integer + description: Permits a sync run costs + per_nondet_run: + type: integer + description: Permits a nondet run costs executions: type: object description: Status of running executions @@ -98,6 +104,8 @@ paths: result: type: string example: module_started + '400': + $ref: '#/components/responses/ErrorResponse' '500': $ref: '#/components/responses/ErrorResponse' @@ -132,6 +140,8 @@ paths: result: type: string enum: [module_stopped, module_not_running] + '400': + $ref: '#/components/responses/ErrorResponse' '500': $ref: '#/components/responses/ErrorResponse' @@ -175,6 +185,8 @@ paths: result: type: string example: module_restarted + '400': + $ref: '#/components/responses/ErrorResponse' '500': $ref: '#/components/responses/ErrorResponse' @@ -278,6 +290,8 @@ paths: type: string format: byte nullable: true + '400': + $ref: '#/components/responses/ErrorResponse' '500': $ref: '#/components/responses/ErrorResponse' delete: @@ -317,6 +331,8 @@ paths: example: timeout during shutdown genvm_id: type: integer + '400': + $ref: '#/components/responses/ErrorResponse' /genvm/{genvm_id}/artifact: get: @@ -373,6 +389,8 @@ paths: data_base64: type: string format: byte + '400': + $ref: '#/components/responses/ErrorResponse' '500': $ref: '#/components/responses/ErrorResponse' @@ -408,6 +426,8 @@ paths: specified_major: type: integer description: Detected major version + '400': + $ref: '#/components/responses/ErrorResponse' '500': $ref: '#/components/responses/ErrorResponse' @@ -444,6 +464,8 @@ paths: example: log_level_set level: type: string + '400': + $ref: '#/components/responses/ErrorResponse' '500': $ref: '#/components/responses/ErrorResponse' @@ -484,7 +506,10 @@ paths: description: Number of available permits post: summary: Set permits - description: Set the number of execution permits. + description: >- + Set the number of execution permits, one permit is one gigabyte of RAM. + A value below the cost of the most expensive run is rejected, and the + response carries the unchanged maximum. operationId: setPermits requestBody: required: true @@ -513,6 +538,8 @@ paths: example: permits_set permits: type: integer + '400': + $ref: '#/components/responses/ErrorResponse' '500': $ref: '#/components/responses/ErrorResponse' @@ -615,6 +642,8 @@ paths: response: type: string nullable: true + '400': + $ref: '#/components/responses/ErrorResponse' '500': $ref: '#/components/responses/ErrorResponse' @@ -642,6 +671,8 @@ paths: type: string nullable: true description: Human-readable error description, or null if unknown + '400': + $ref: '#/components/responses/ErrorResponse' '500': $ref: '#/components/responses/ErrorResponse' diff --git a/docs/website/src/spec/02-execution-environment/01-wasm.rst b/docs/website/src/spec/02-execution-environment/01-wasm.rst index 17839325..0d47f3a4 100644 --- a/docs/website/src/spec/02-execution-environment/01-wasm.rst +++ b/docs/website/src/spec/02-execution-environment/01-wasm.rst @@ -16,15 +16,31 @@ Enabled WASM Features and Proposals :ref:`gvm-def-det-mode` Additional Limitations ---------------------------------------------- -Only following ``f32.*`` and ``f64.*`` operations are allowed: +An operation on a floating point value is allowed *iff* it moves or copies bits +without interpreting them as numbers. The complete allowed set is: - ``f32.store``, ``f64.store`` - ``f32.load``, ``f64.load`` - ``f32.const``, ``f64.const`` - ``f32.reinterpret_i32``, ``f64.reinterpret_i64`` - ``i32.reinterpret_f32``, ``i64.reinterpret_f64`` - -Any other floating point operation is considered non-deterministic and is not allowed in :ref:`gvm-def-det-mode`. +- ``f32x4.splat``, ``f64x2.splat`` +- ``f32x4.extract_lane``, ``f64x2.extract_lane`` +- ``f32x4.replace_lane``, ``f64x2.replace_lane`` + +Every other ``f32.*``, ``f64.*``, ``f32x4.*`` and ``f64x2.*`` operation is +considered non-deterministic — this covers arithmetic, ``min``/``max`` +(including the relaxed and pseudo-min/max forms), ``sqrt``, rounding, +``abs``/``neg``/``copysign``, comparisons, fused multiply-add, and every +conversion between a float and an integer or between float widths. Reaching one +of them in :ref:`gvm-def-det-mode` traps with +:ref:`gvm-def-str-trie-value-vm-error-wasm-trap-nondet-instruction`; a module +merely containing them is not rejected. + +Operations on ``v128`` that do not name a float type (``v128.load``, +``v128.store``, ``v128.const``, ``i8x16.shuffle``, ``v128.bitselect``, the +integer lane operations, …) are not floating point operations and are +unrestricted. :ref:`gvm-def-non-det-mode` does not have these limitations, allowing all floating point operations. diff --git a/docs/website/src/spec/02-execution-environment/02-wasip1.rst b/docs/website/src/spec/02-execution-environment/02-wasip1.rst index beeabe00..51e2bdf4 100644 --- a/docs/website/src/spec/02-execution-environment/02-wasip1.rst +++ b/docs/website/src/spec/02-execution-environment/02-wasip1.rst @@ -128,6 +128,7 @@ Fail with ``Notsup`` error code: - ``proc_raise`` - ``sched_yield`` - ``fd_pwrite`` +- ``fd_renumber`` Functions @@ -155,18 +156,88 @@ caller that wants a graceful fallback must handle that error explicitly. #. ``proc_exit(0)`` is equivalent to :ref:`gvm-def-return` of ``null`` value. #. ``proc_exit(x)`` where :math:`x \neq 0` results in :ref:`gvm-def-vm-error` +.. _gvm-def-vfs-path-resolution: + +Path Resolution +~~~~~~~~~~~~~~~ + +``path_*`` functions take a directory :term:`FD` and a path. Resolution is +purely lexical and identical in both modes: + +#. The directory descriptor's own path and the supplied path are concatenated + and split on ``/``. Empty and ``.`` components are dropped, a ``..`` + component pops the preceding one, and a ``..`` that would escape the root is + dropped. There are no symlinks, so ``dirflags`` never changes the result. +#. The resulting absolute path must lie within a preopened subtree, otherwise + the call fails with ``Notcapable``. +#. The path is then walked through the :ref:`gvm-def-vfs`: a missing component + fails with ``Noent``, and a component that resolves to a file while more + components remain fails with ``Badf``. + +A descriptor that is not a directory fails with ``Badf`` before any of this. + +File Metadata +~~~~~~~~~~~~~ + +The :ref:`gvm-def-vfs` stores no metadata, so every ``Filestat`` reports +``dev``, ``ino``, ``atim``, ``mtim`` and ``ctim`` as ``0``; ``size`` is the +file's length in octets and ``0`` for a directory. Timestamps are **not** +derived from the transaction timestamp — a file has no modification time at +all. + ``path_open`` Function ~~~~~~~~~~~~~~~~~~~~~~ +#. The path is resolved as in `Path Resolution`_. +#. ``oflags``, ``fs_rights_base``, ``fs_rights_inheriting`` and ``fdflags`` are + ignored. The :ref:`gvm-def-vfs` is read-only, so ``creat``, ``excl`` and + ``trunc`` never take effect — opening a non-existent path fails with + ``Noent`` rather than creating it — and ``directory`` does not restrict the + result. +#. On success a fresh descriptor is allocated (see + :ref:`gvm-def-fd-allocation`) that refers to the resolved file or directory. + A file descriptor starts at offset ``0``. +#. The descriptor is released again if the call fails, so a failed open leaks + neither a descriptor nor its :ref:`gvm-def-ram-consumption`. + ``path_filestat_get`` Function ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Resolves the path as in `Path Resolution`_ and returns the ``Filestat`` +described in `File Metadata`_ with ``filetype`` ``regular_file`` or +``directory`` and ``nlink`` ``0``. + ``fd_readdir`` Function ~~~~~~~~~~~~~~~~~~~~~~~ +A descriptor that is not a directory fails with ``Badf``. + +The entry sequence of a directory is fixed and does not depend on how the +:ref:`gvm-def-vfs` was populated: + +#. ``.`` — filetype ``directory`` +#. ``..`` — filetype ``directory``, and refers to the root itself in the root + directory +#. the directory's children in ascending order of their names, compared as raw + octet sequences; a child's filetype is ``directory`` or ``regular_file`` + +``d_ino`` is ``0`` for every entry, ``d_namlen`` is the name's length in +octets, and ``d_next`` is the cookie of the following entry — cookies number +the sequence above from ``1``. The ``cookie`` argument skips that many leading +entries; a cookie past the end yields no entries. + +Entries are written as a ``Dirent`` immediately followed by the name, until the +buffer is exhausted. A truncated entry is not backed out: the last ``Dirent`` +or name may be cut mid-way, and the call then returns ``buf_len`` to signal +that the caller must retry with a larger buffer. Otherwise it returns the +number of octets written. + ``fd_tell`` Function ~~~~~~~~~~~~~~~~~~~~ +Returns the descriptor's current offset. ``stdout``/``stderr`` fail with +``Spipe``, a directory with ``Notsup``. + ``fd_datasync`` Function ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -180,12 +251,22 @@ Does nothing and always returns success. ``fd_seek`` Function ~~~~~~~~~~~~~~~~~~~~ -``fd_renumber`` Function -~~~~~~~~~~~~~~~~~~~~~~~~ +Moves a file descriptor's offset and returns the new value. + +#. ``set`` and ``cur`` clamp the result into :math:`[0, \texttt{size}]` instead + of failing: a negative target becomes ``0`` and a target beyond the end + becomes the file's size. +#. ``end`` is not supported and fails with ``Notsup``. +#. ``stdout``/``stderr`` fail with ``Spipe``, a directory with ``Notsup``. ``fd_prestat_dir_name`` Function ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Writes the preopened directory's name — the last component of its path, or ``/`` +for the root. ``fd_prestat_get`` returns the ``Prestat`` whose ``pr_name_len`` +determines the name's length. A buffer shorter than that name fails with +``Overflow``; any non-directory descriptor fails with ``Badf``. + ``fd_prestat_get`` Function ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -198,21 +279,59 @@ Does nothing and always returns success. ``fd_write`` Function ~~~~~~~~~~~~~~~~~~~~~ -``fd_pread`` Function -~~~~~~~~~~~~~~~~~~~~~ +Only ``stdout`` and ``stderr`` are writable; a file or directory descriptor +fails with ``Rofs``. The written octets are diagnostic output: they are not part +of the :ref:`gvm-def-vm-result` and are not covered by the +:ref:`gvm-def-execution-hash`. + +The call reports every supplied octet as written and never fails on the +underlying stream, so a contract cannot observe whether the :term:`Host` +accepted, buffered or discarded the output. ``fd_read`` Function ~~~~~~~~~~~~~~~~~~~~ +Reads a file descriptor's contents into the ``iovec``\ s in order, starting at +the descriptor's offset and advancing it by the number of octets read. Reading +at or past the end of the file yields ``0`` octets rather than an error. +``stdout``/``stderr`` fail with ``Acces``, a directory with ``Isdir``. + +``fd_pread`` Function +~~~~~~~~~~~~~~~~~~~~~ + +As ``fd_read``, except that it starts at the explicit ``offset`` and leaves the +descriptor's own offset unchanged. + ``fd_filestat_get`` Function ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Returns the ``Filestat`` described in `File Metadata`_ with ``nlink`` ``1`` and +``filetype``: + +- ``regular_file`` for a file descriptor, whose ``size`` is the file's length +- ``directory`` for a directory descriptor +- ``character_device`` for ``stdout``/``stderr`` + ``fd_fdstat_get`` Function ~~~~~~~~~~~~~~~~~~~~~~~~~~ +``fs_flags`` is always empty — no descriptor is appending, non-blocking or +synchronous — and ``fs_rights_inheriting`` always equals ``fs_rights_base``. +The rights are fixed per descriptor kind and never include a mutating right: + +- a file descriptor: ``regular_file`` with the read, seek, tell, advise, sync, + datasync, readdir, readlink, ``path_open`` and filestat-get rights +- a directory descriptor: ``directory`` with the read, ``path_open``, readdir, + readlink and filestat-get rights +- ``stdout``/``stderr``: ``unknown`` filetype with the write right only + ``fd_close`` Function ~~~~~~~~~~~~~~~~~~~~~ +Deallocates the descriptor (see :ref:`gvm-def-fd-allocation`) and releases the +:ref:`gvm-def-ram-consumption` charged for its contents, if any. An unknown +descriptor fails with ``Badf``. + ``fd_advise`` Function ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/website/src/spec/02-execution-environment/03-wasi_genlayer_sdk/02-gl_call.rst b/docs/website/src/spec/02-execution-environment/03-wasi_genlayer_sdk/02-gl_call.rst index 8aafb847..026faa5d 100644 --- a/docs/website/src/spec/02-execution-environment/03-wasi_genlayer_sdk/02-gl_call.rst +++ b/docs/website/src/spec/02-execution-environment/03-wasi_genlayer_sdk/02-gl_call.rst @@ -296,7 +296,9 @@ meta-properties, including the *param* ``runner`` and *param* The caller receives the sandbox result (:ref:`gvm-def-subvm-result-encoding`) and may handle both :ref:`gvm-def-vm-error` and :ref:`gvm-def-user-error`; -storage writes performed by the sandbox are not reverted on error. +storage writes performed by the sandbox are not reverted on error. If the +sandbox terminates with :ref:`gvm-def-fatal-vm-error`, the caller terminates +with the same fatal VM error instead. .. _gvm-def-gl-call-register-runner: @@ -573,6 +575,21 @@ Payload Causes VM to exit with ``ContractReturn``. Encodes return value using :ref:`gvm-def-calldata-encoding` format. +.. _gvm-def-gl-call-observable-discretion: + +Implementation Discretion +------------------------- + +Where a message below says an implementation may ignore it, that discretion +covers only the side effect the message asks for — writing a log line, +recording a timing. The **value returned to the guest** is never at an +implementation's discretion: it is fixed by this specification for the mode the +call is made in, and such a call MUST NOT fail. A message whose result differs +between two conformant implementations would make +:ref:`gvm-def-det-mode` execution diverge across validators; widening or +narrowing what a message returns therefore requires a new +:ref:`GenVM version `. + ``Trace.Message`` Message ------------------------- @@ -595,13 +612,14 @@ Payload .. note:: - Implementations may choose to ignore this message and return an error. + Whether anything is logged is implementation-defined (see + :ref:`gvm-def-gl-call-observable-discretion`); the call returns no value and + always succeeds. Requirements ~~~~~~~~~~~~ #. GenVM version 0.1.10 or higher -#. :term:`GenVM` implementation is allowed ignore this message .. _tracing-runtime-microsec: @@ -622,13 +640,14 @@ Payload .. note:: - Implementations may choose to ignore this message and return an error. + The returned value is not at an implementation's discretion — in + :ref:`gvm-def-det-mode` it is exactly ``0``, and the call never fails (see + :ref:`gvm-def-gl-call-observable-discretion`). Requirements ~~~~~~~~~~~~ #. GenVM version 0.1.10 or higher -#. :term:`GenVM` implementation is allowed ignore this message ``Yield`` Message ----------------- @@ -646,13 +665,14 @@ Payload .. note:: - Implementations may choose to ignore this message. + Whether the implementation actually yields anything is implementation-defined + (see :ref:`gvm-def-gl-call-observable-discretion`); the call returns no value + and always succeeds. Requirements ~~~~~~~~~~~~ #. GenVM version 0.3.0 or higher -#. :term:`GenVM` implementation is allowed ignore this message .. _get-timestamp: diff --git a/docs/website/src/spec/02-execution-environment/03-wasi_genlayer_sdk/03-schemas.rst b/docs/website/src/spec/02-execution-environment/03-wasi_genlayer_sdk/03-schemas.rst index 96074cae..2aeff786 100644 --- a/docs/website/src/spec/02-execution-environment/03-wasi_genlayer_sdk/03-schemas.rst +++ b/docs/website/src/spec/02-execution-environment/03-wasi_genlayer_sdk/03-schemas.rst @@ -43,22 +43,19 @@ stage; it is replaced by a derived :ref:`gvm-def-vm-error` and handed to the comparison as if it had been proposed. #. The buffer is non-empty. An absent or empty proposal yields - :ref:`gvm-def-str-trie-value-vm-error-absent-leader-nondet-output`. + :ref:`gvm-def-str-trie-value-vm-error-leader-fault-nondet-output-absent`. #. ``result_code`` is one of :ref:`gvm-def-enum-value-result-code-return`, :ref:`gvm-def-enum-value-result-code-user-error` or - :ref:`gvm-def-enum-value-result-code-vm-error`. Any other byte — including - :ref:`gvm-def-enum-value-result-code-internal-error`, which the enumeration - admits but the wire format does not — yields - :ref:`gvm-def-pending-str-trie-value-vm-error-leader-output-malformed`. + :ref:`gvm-def-enum-value-result-code-vm-error`; any other byte yields + :ref:`gvm-def-str-trie-value-vm-error-leader-fault-nondet-output-malformed`. #. For **return** and **user_error**, ``data`` is valid :ref:`gvm-def-calldata-encoding` with no trailing bytes; otherwise - :ref:`gvm-def-pending-str-trie-value-vm-error-leader-output-malformed`. + :ref:`gvm-def-str-trie-value-vm-error-leader-fault-nondet-output-malformed`. #. For **vm_error**, ``data`` is UTF-8, carries no ``" # "`` detail, and names a :ref:`gvm-def-str-trie-vm-error` path, including the canonical spelling of - any parameter. Codes outside the trie — among them every - :doc:`pending constant <../../appendix/constants-pending>` — yield - :ref:`gvm-def-pending-str-trie-value-vm-error-leader-output-malformed`. + any parameter. Codes outside the trie yield + :ref:`gvm-def-str-trie-value-vm-error-leader-fault-nondet-output-malformed`. An accepted result is preserved **byte for byte**: validation never re-encodes, so every node hashes the value that was proposed. @@ -71,14 +68,14 @@ Derived-Outcome Namespace Following :ref:`gvm-def-vm-error` codes are derived by the consuming executor rather than proposed: -#. :ref:`gvm-def-str-trie-value-vm-error-absent-leader-nondet-output` -#. :ref:`gvm-def-pending-str-trie-value-vm-error-leader-output-malformed` -#. :ref:`gvm-def-pending-str-trie-value-vm-error-leader-output-uses-this-error` -#. :ref:`gvm-def-pending-str-trie-value-vm-error-leader-output-extra` +#. :ref:`gvm-def-str-trie-value-vm-error-leader-fault-nondet-output-absent` +#. :ref:`gvm-def-str-trie-value-vm-error-leader-fault-nondet-output-malformed` +#. :ref:`gvm-def-str-trie-value-vm-error-leader-fault-nondet-output-uses-this-error` +#. :ref:`gvm-def-str-trie-value-vm-error-leader-fault-nondet-output-extra` -A proposed code that equals, or extends at a space boundary, either -``absent_leader_nondet_output`` or ``leader_output`` is replaced by -:ref:`gvm-def-pending-str-trie-value-vm-error-leader-output-uses-this-error` +A proposed code that equals, or extends at a space boundary, +``leader_fault nondet_output`` is replaced by +:ref:`gvm-def-str-trie-value-vm-error-leader-fault-nondet-output-uses-this-error` whose parameter is the first 6 characters of the :doc:`../../04-contract-interface/06-gvm32` encoding of ``sha3_256`` of the proposed code. A proposal that is its own replacement maps to the parameter diff --git a/docs/website/src/spec/02-execution-environment/04-runners.rst b/docs/website/src/spec/02-execution-environment/04-runners.rst index 6b1cd2d7..b45f1edf 100644 --- a/docs/website/src/spec/02-execution-environment/04-runners.rst +++ b/docs/website/src/spec/02-execution-environment/04-runners.rst @@ -29,26 +29,55 @@ forms (see the ``runner-id`` definition in the runner.json schema): ``contract``, ``chain`` and ``custom`` are reserved prefixes and cannot be used as human-readable ids. +.. _gvm-def-chain-runner-state: + +``chain:`` State Visibility +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A ``chain:`` id is code, but its resolution is an ordinary +:ref:`gvm-def-det-mode` storage read and is subject to the same rules: + +#. The read resolves against the state the executing transaction was fixed to + by consensus, not against whatever a node's chain tip happens to be. Every + validator of the transaction therefore reads the same octets, whichever + :term:`Host` serves them. +#. ``f`` (finalized) reads the state at the last finalized block; ``a`` + (accepted, the default) reads the accepted state — the same view a + read-only :ref:`gvm-def-gl-call-call-contract` child observes by default + (see :ref:`contract-execution-flow`). Neither view includes the executing + transaction's own uncommitted writes, so a contract cannot deploy code and + load it as a runner in the same transaction. +#. The choice between the two is part of the id string and thus part of the + runner graph, never a node-local default. + +A resolution that finds no code, or code that is not a valid :term:`runner`, +fails like any other malformed runner rather than falling back to another view. + Hash Format ~~~~~~~~~~~ -``hash`` is the SHA3 256-bit hash of the runner's contents, encoded with +``hash`` is a 256-bit hash of the runner's contents, encoded with :doc:`../04-contract-interface/06-gvm32` (GVM32, a lowercase Crockford Base32). This keeps it free of filesystem-illegal characters and case-insensitive. +The algorithm differs per id form: + +- ``:`` — SHA-256, matching the hash the runner is + packaged and distributed under. +- ``custom:`` — SHA3-256 of the registered blob. + Runner Layout ------------- -For any of the layouts a file list is constructed. Each file in this name has: - -- a name +For any of the layouts a file list is constructed. Each entry name: - #. it must not start with ``/`` - #. path separator must be ``/`` - #. it must not contain ``.`` or ``..`` path components +- Must not be empty or start with ``/`` +- Must use ``/`` as the path separator; backslashes are forbidden +- Must not contain empty, ``.`` or ``..`` path components +- Must not end with ``/`` unless the entry is a directory -- contents (raw bytes slice) +Each file also has contents as a raw byte slice 1. ZIP Archive ~~~~~~~~~~~~~~ @@ -57,7 +86,17 @@ Used if runner bytes represent a ZIP archive - If successful, extracts the archive contents and processes it as a structured :term:`runner` package - This format supports complex :term:`runners ` with multiple files, dependencies, and configuration -- Only allowed compression is ``stored`` (no compression) +- Only allowed compression is ``stored`` (no compression), declared by both the central directory and the entry's local header +- A stored entry's compressed and uncompressed sizes must be equal +- A stored file's contents must match its declared CRC-32 +- The local header must agree with the central directory on the entry name, and, + unless the entry has a data descriptor (general-purpose flag bit 3), on the + CRC-32 and the sizes. The name is compared as raw bytes and must be valid + UTF-8, so an entry no two readers would decode alike is rejected rather than + silently resolved +- Encrypted entries (general-purpose flag bit 0) are rejected +- An entry ending with ``/`` is a directory; its size and CRC-32 must be 0, and it is omitted from the file list +- If several entries share a name, the file list holds the last of them 2. Raw WASM ~~~~~~~~~~~ @@ -128,11 +167,30 @@ Schema is available in :doc:`../appendix/runner-schema`\. It must be a valid JSON object with described below structure +Each action object accepts exactly the fields shown below. The top-level object may also contain a string ``$schema`` +annotation + +``Seq``, ``When`` and ``With`` nest actions. Nesting deeper than +:ref:`gvm-def-consts-value-runner-limits-init-action-depth`, or a NUL octet in +any action string, is rejected with +:ref:`gvm-def-str-trie-value-vm-error-invalid-contract-runner-malformed`\. + AddEnv ~~~~~~ Adds an environment variable to the GenVM environment with variable interpolation support using ``${}`` syntax. +The name is at most :ref:`gvm-def-consts-value-runner-limits-env-name-len` +octets and consists of ASCII characters other than ``=``, whitespace and control +characters. The value after interpolation is at most +:ref:`gvm-def-consts-value-runner-limits-env-value-len` octets. Violating either +is rejected with +:ref:`gvm-def-str-trie-value-vm-error-invalid-contract-runner-malformed`\. + +The interpolated value's length in octets is charged as +:ref:`gvm-def-ram-consumption`; exceeding the budget results in +:ref:`gvm-def-str-trie-value-vm-error-out-of-memory`\. + Example ^^^^^^^ @@ -298,7 +356,8 @@ Startup ------- Runner actions are executed left-recursively, until :ref:`gvm-def-start-wasm` is reached. -If it was not reached, it will result in a :ref:`gvm-def-vm-error` with ``error_inval`` code. +If it was not reached, it will result in a :ref:`gvm-def-vm-error` with +``invalid_contract runner malformed`` code. Loading a :term:`runner` goes through a single **load action**, defined per :term:`sub-VM`. Each :term:`sub-VM` owns a **loaded-runner set**: the runner diff --git a/docs/website/src/spec/03-vm/01-startup.rst b/docs/website/src/spec/03-vm/01-startup.rst index 97c50836..b580d192 100644 --- a/docs/website/src/spec/03-vm/01-startup.rst +++ b/docs/website/src/spec/03-vm/01-startup.rst @@ -40,7 +40,7 @@ The entry payload is host-supplied and is checked against :ref:`gvm-def-contract-call-conv` before permissions are read and before any runner loads. A payload that violates the convention produces the :ref:`gvm-def-vm-error` -:ref:`gvm-def-pending-str-trie-value-vm-error-malformed-entry` as the execution +:ref:`gvm-def-str-trie-value-vm-error-malformed-entry` as the execution result, like any other failure at this point. Messages emitted by :ref:`gvm-def-post-message` and ``DeployContract`` are @@ -106,8 +106,12 @@ with :ref:`gvm-def-str-trie-value-vm-error-out-of-nondet-blocks`. Creating the :term:`sub-VM` charges :ref:`gvm-def-consts-value-memory-limiter-consts-vm-spawn-cost` octets of -:ref:`gvm-def-ram-consumption` to the new :term:`sub-VM`; the charge is -released when it finishes. +:ref:`gvm-def-ram-consumption` to the new :term:`sub-VM`, plus +:ref:`gvm-def-consts-value-memory-limiter-consts-storage-page-inherited` octets +for every storage region it inherits already written from its caller +(:ref:`gvm-def-gl-call-sandbox` and :ref:`gvm-def-gl-call-run-nondet` inherit +their caller's; the initial entry and :ref:`gvm-def-gl-call-call-contract` +inherit none). Both charges are released when it finishes. After these checks, startup applies the `Custom-Runner Grants`_ for the new :term:`sub-VM`, then performs the runner load action for the entry runner and @@ -202,7 +206,8 @@ inherited permission, never add one. :ref:`gvm-def-gl-call-run-nondet` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The child executes in :ref:`gvm-def-non-det-mode`. +The child executes in :ref:`gvm-def-non-det-mode`, on its own RAM budget seeded +with what the caller had remaining (see :doc:`03-ram-limiting`). - :ref:`gvm_vm_field_permissions` are all false, including :ref:`gvm-perm-deterministic`. diff --git a/docs/website/src/spec/03-vm/03-ram-limiting.rst b/docs/website/src/spec/03-vm/03-ram-limiting.rst index a6c34c3c..2c7db4d2 100644 --- a/docs/website/src/spec/03-vm/03-ram-limiting.rst +++ b/docs/website/src/spec/03-vm/03-ram-limiting.rst @@ -1,9 +1,13 @@ Resource Limiting ================= -:ref:`gvm-def-det-mode` and :ref:`gvm-def-non-det-mode` have two separate RAM budgets. -Each budget starts at 4294967295 octets (4 GiB). -All :term:`sub-VM` instances within the same mode share the same budget. +:ref:`gvm-def-det-mode` and :ref:`gvm-def-non-det-mode` have separate RAM +budgets: what one consumes is never charged to the other. +The deterministic budget starts at 4294967295 octets (4 GiB). +Every :ref:`gvm-def-gl-call-run-nondet` gets its own non-deterministic budget, +starting at what its caller had remaining at the moment of the call, so a +nondet block never gets more RAM than its caller had left. +All :term:`sub-VM` instances within one budget share it. .. _gvm-def-ram-consumption: @@ -42,10 +46,17 @@ The following operations consume RAM: and ``RegisterRunner`` ``gl_call``\ s, and receiving a custom-runner grant at sub-VM creation (see :doc:`../02-execution-environment/04-runners` and :ref:`gvm-meta-property-custom-runners`) +- **Storage writes**: writing to a 32-octet aligned region of a + :term:`Storage Slot` costs + :ref:`gvm-def-consts-value-memory-limiter-consts-new-storage-page` octets the + first time that region is written. Regions the :term:`sub-VM` inherited + already written from its caller, and repeated writes to a region, cost nothing - **Sub-VM creation**: each new :term:`sub-VM` costs - :ref:`gvm-def-consts-value-memory-limiter-consts-vm-spawn-cost` octets, - charged to the new :term:`sub-VM` at creation (see :doc:`01-startup`) and - released when it finishes + :ref:`gvm-def-consts-value-memory-limiter-consts-vm-spawn-cost` octets, plus + :ref:`gvm-def-consts-value-memory-limiter-consts-storage-page-inherited` + octets for every 32-octet region already written in the storage it inherits. + Both are charged to the new :term:`sub-VM` at creation (see :doc:`01-startup`) + and released when it finishes The runner load cost (:ref:`gvm-def-consts-value-memory-limiter-consts-runner-load-cost`) is a fixed per-load overhead @@ -59,6 +70,12 @@ This applies to runner charges as well: memory consumed by loading or registering a runner is released when the registering :term:`sub-VM` finishes, like any other charge. There are no permanent charges. +Storage write charges are the exception: they follow the storage they paid for. +When a :ref:`gvm-def-gl-call-sandbox` child returns and its caller takes over the +child's storage, the charge for the regions the child wrote first is transferred +to the caller rather than released, so a caller cannot use repeated +:ref:`gvm-def-gl-call-sandbox` calls to accumulate storage it never pays for. + Other Limits ------------ diff --git a/docs/website/src/spec/03-vm/05-result.rst b/docs/website/src/spec/03-vm/05-result.rst index 7cd20124..572d30ac 100644 --- a/docs/website/src/spec/03-vm/05-result.rst +++ b/docs/website/src/spec/03-vm/05-result.rst @@ -21,6 +21,16 @@ exceeding resource limits. It uses predefined string error codes. +.. _gvm-def-fatal-vm-error: + +.. rubric:: Fatal VM Error + +Every VM error is either **fatal** or not; both draw their code from the same +set. A non-fatal error of a :term:`sub-VM` is returned to its caller as +:ref:`gvm-def-subvm-result-encoding`. A fatal one is not catchable: the caller +terminates with the same VM error, and propagation continues until the topmost +VM boundary + .. _gvm-def-vm-error-code: VM Error Code Format @@ -37,9 +47,25 @@ VM Error Code Format separated from the public code by ``#`` surrounded by a single space on each side. -The detail MUST be a deterministic function of execution (the full string is -covered by the :ref:`gvm-def-execution-hash`), but its content carries no -compatibility promise — see :ref:`gvm-def-vm-error-compat`. +The full string, detail included, is covered by the +:ref:`gvm-def-execution-hash`, so it must be reproducible octet for octet by +every implementation running the same execution. A detail MUST therefore be +composed only of: + +#. octets the execution itself produced or consumed — a guest-supplied string, + a decoded field of the calldata or of a runner description; +#. values fixed by the WASM module or by this specification — a function or + memory index, a limit, a constant from :doc:`../appendix/constants`; +#. literal text chosen by the code that raises the error. + +Anything the host or the runtime environment supplies MUST NOT appear, even +indirectly. In particular: filesystem paths, operating-system error strings or +numbers, host addresses and pointer values, elapsed times, locale-dependent or +platform-width-dependent formatting, thread or process identifiers, and +implementation build or version strings. + +Beyond that constraint the detail's content carries no compatibility promise — +see :ref:`gvm-def-vm-error-compat`. Consumers MUST compare and match VM error codes only by the public code (the part before the first `` # ``). A consumer matching a known code ``P`` MUST @@ -52,16 +78,24 @@ with further space-separated components. Represents a user-produced error in utf-8 format. +.. rubric:: Effects of a Non-Returning Run + +Only a :ref:`gvm-def-return` carries effects. A topmost run that ends in +:ref:`gvm-def-user-error` or :ref:`gvm-def-vm-error` reports no +``storage_changes`` and no ``emissions``, whatever it wrote or emitted before +failing, and its :ref:`gvm-def-execution-hash` covers those empty fields. + .. _gvm-def-internal-error: InternalError ------------- -It is a special :ref:`gvm-def-vm-result` that represents an internal error in the VM, -such as: :term:`Host` communication failures or :term:`Module` unavailability. +Not a :ref:`gvm-def-vm-result` but the absence of one: the executor could not +run the contract to a verdict at all, because of a :term:`Host` communication +failure or :term:`Module` unavailability. -Internal errors are not visible by the contracts. Most likely :term:`Host` will -vote *timeout* if encounters such an error +Internal errors are not visible by the contracts and are reported only to the +:term:`Host`, which will most likely vote *timeout* if it encounters one Non-Deterministic Block Result Encoding --------------------------------------- @@ -70,6 +104,9 @@ Non-Deterministic Block Result Encoding - :ref:`gvm-def-user-error`\: utf-8 string - :ref:`gvm-def-vm-error`\: utf-8 string +These three are the only codes a leader-proposed non-deterministic block result +may carry; validators treat every other byte as a malformed leader result + Contract Result Encoding ------------------------ @@ -128,7 +165,9 @@ with the following keys (in this order): #. ``backtrace`` #. ``data`` — the contract result value +#. ``data_fees_consumed`` #. ``data_fees_remaining`` +#. ``emissions`` — emitted messages and events, in emission order #. ``kind`` — the :ref:`gvm-def-vm-result` result code #. ``storage_changes`` #. ``subvm_hashes`` — see :ref:`gvm-def-subvm-hash` @@ -137,6 +176,11 @@ with the following keys (in this order): Two runs that agree on the deterministic result produce the same execution hash, so consensus can compare a single 32-byte value instead of the full result. +``emissions`` covers the whole content of every emitted message and event, not +just its metered cost: two emissions can carry different calldata or different +event topics for the same fee, so a fee-only commitment would let nodes agree on +the hash while committing divergent side effects + .. _gvm-def-subvm-hash: Sub-VM Result Hash @@ -149,8 +193,11 @@ into a rolling SHA3-256 accumulator. The finalized accumulator is the For each deterministic sub-VM, its *small hash* is folded into the accumulator. The small hash is a SHA3-256 digest over a :ref:`gvm-def-calldata-encoding` encoded map: -#. ``kind`` — the exact string ``"Return"``, ``"UserError"``, or ``"VMError"`` -#. ``result`` — for ``Return``/``UserError`` the result value in :ref:`gvm-def-calldata-encoding`; for ``VMError`` the error code string +#. ``kind`` — the exact string ``"Return"``, ``"UserError"`` or ``"VMError"``. + Fatality is not an outcome of its own, only a statement about who may catch + it, so a fatal result hashes as ``"VMError"`` +#. ``result`` — for ``Return``/``UserError`` the result value in + :ref:`gvm-def-calldata-encoding`; for ``VMError`` the error code string #. ``subvm_hashes`` — that sub-VM's own finalized accumulator, making the hash recursive over the whole deterministic call tree #. ``wasm_store_hashes`` @@ -171,7 +218,7 @@ A consumer in :ref:`gvm-def-sync-mode` or :ref:`gvm-def-validator-mode` consumes one leader-proposed result per non-deterministic block it runs. If the leader supplied **more** results than the run consumed, the surplus blocks were never reached: the run's result is replaced by -:ref:`gvm-def-pending-str-trie-value-vm-error-leader-output-extra`, whose +:ref:`gvm-def-str-trie-value-vm-error-leader-fault-nondet-output-extra`, whose parameter is the first 6 characters of the :ref:`gvm-def-gvm32` encoding of the ``sha3_256`` digest of the complete ``[result_code][data]`` :ref:`sub-VM result buffer ` the run would diff --git a/docs/website/src/spec/04-contract-interface/02-abi.rst b/docs/website/src/spec/04-contract-interface/02-abi.rst index 6fa33522..83c06ef3 100644 --- a/docs/website/src/spec/04-contract-interface/02-abi.rst +++ b/docs/website/src/spec/04-contract-interface/02-abi.rst @@ -7,6 +7,12 @@ contracts interact with each other. The ABI provides a standardized way to encode method calls, handle parameters, and manage contract schemas while supporting both deterministic and non-deterministic operations. +The public ABI includes the stable values listed in +:doc:`../appendix/constants`. Values listed in +:doc:`../appendix/internal-constants` bound what a run may do, but they are not +part of that surface: a contract cannot read them, and nothing in the ABI is +required to keep them stable + .. _gvm-def-contract-call-conv: Method Calling Convention @@ -45,7 +51,7 @@ set. Element types inside ``args``/``kwargs`` are matched against the method signature by the runner, not here. Violations are reported as -:ref:`gvm-def-pending-str-trie-value-vm-error-malformed-entry`; where that +:ref:`gvm-def-str-trie-value-vm-error-malformed-entry`; where that surfaces depends on the entry point, see :ref:`gvm-vm-startup-entry-validation` and :ref:`gvm-def-gl-call-call-contract`. diff --git a/docs/website/src/spec/appendix/constants-pending.rst b/docs/website/src/spec/appendix/constants-pending.rst index d70b1b90..0b076926 100644 --- a/docs/website/src/spec/appendix/constants-pending.rst +++ b/docs/website/src/spec/appendix/constants-pending.rst @@ -1,33 +1,2 @@ Constants ========= - -.. _gvm-def-pending-str-trie-vm-error: - -vm_error --------- - -Type: str_trie - -.. _gvm-def-pending-str-trie-value-vm-error-malformed-entry: - -``malformed_entry`` -~~~~~~~~~~~~~~~~~~~ - -.. _gvm-def-pending-str-trie-value-vm-error-leader-output-malformed: - -``leader_output malformed`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. _gvm-def-pending-str-trie-value-vm-error-leader-output-uses-this-error: - -``leader_output uses_this_error`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Param: str - -.. _gvm-def-pending-str-trie-value-vm-error-leader-output-extra: - -``leader_output extra`` -~~~~~~~~~~~~~~~~~~~~~~~ - -Param: str diff --git a/docs/website/src/spec/appendix/constants.rst b/docs/website/src/spec/appendix/constants.rst index aa114299..d744f684 100644 --- a/docs/website/src/spec/appendix/constants.rst +++ b/docs/website/src/spec/appendix/constants.rst @@ -29,13 +29,6 @@ vm_error Value: ``2`` -.. _gvm-def-enum-value-result-code-internal-error: - -internal_error -~~~~~~~~~~~~~~ - -Value: ``3`` - .. _gvm-def-enum-storage-type: storage_type @@ -106,48 +99,6 @@ can_use_balance_for_message_fees Value: ``1`` -.. _gvm-def-consts-memory-limiter-consts: - -memory_limiter_consts ---------------------- - -Type: u32 - -.. _gvm-def-consts-value-memory-limiter-consts-table-entry: - -table_entry -~~~~~~~~~~~ - -Value: ``64`` - -.. _gvm-def-consts-value-memory-limiter-consts-file-mapping: - -file_mapping -~~~~~~~~~~~~ - -Value: ``256`` - -.. _gvm-def-consts-value-memory-limiter-consts-fd-allocation: - -fd_allocation -~~~~~~~~~~~~~ - -Value: ``96`` - -.. _gvm-def-consts-value-memory-limiter-consts-runner-load-cost: - -runner_load_cost -~~~~~~~~~~~~~~~~ - -Value: ``4096`` - -.. _gvm-def-consts-value-memory-limiter-consts-vm-spawn-cost: - -vm_spawn_cost -~~~~~~~~~~~~~ - -Value: ``134217728`` - .. _gvm-def-consts-root-offsets: root_offsets @@ -204,76 +155,6 @@ permissions Value: ``37`` -.. _gvm-def-consts-top-limits: - -top_limits ----------- - -Type: u32 - -.. _gvm-def-consts-value-top-limits-nondet-blocks: - -nondet_blocks -~~~~~~~~~~~~~ - -Value: ``4096`` - -.. _gvm-def-consts-value-top-limits-locked-slots: - -locked_slots -~~~~~~~~~~~~ - -Value: ``256`` - -.. _gvm-def-consts-value-top-limits-upgraders: - -upgraders -~~~~~~~~~ - -Value: ``32`` - -.. _gvm-def-consts-value-top-limits-vm-recursion: - -vm_recursion -~~~~~~~~~~~~ - -Value: ``512`` - -.. _gvm-def-consts-value-top-limits-web-request-min-space: - -web_request_min_space -~~~~~~~~~~~~~~~~~~~~~ - -Value: ``65536`` - -.. _gvm-def-consts-value-top-limits-web-render-min-space: - -web_render_min_space -~~~~~~~~~~~~~~~~~~~~ - -Value: ``134217728`` - -.. _gvm-def-consts-value-top-limits-max-fds: - -max_fds -~~~~~~~ - -Value: ``1024`` - -.. _gvm-def-consts-value-top-limits-wasm-call-depth: - -wasm_call_depth -~~~~~~~~~~~~~~~ - -Value: ``1024`` - -.. _gvm-def-consts-value-top-limits-wasm-stack-value-slots: - -wasm_stack_value_slots -~~~~~~~~~~~~~~~~~~~~~~ - -Value: ``65535`` - .. _gvm-def-enum-special-method: special_method @@ -307,10 +188,34 @@ Type: str_trie ``timeout`` ~~~~~~~~~~~ -.. _gvm-def-str-trie-value-vm-error-absent-leader-nondet-output: +.. _gvm-def-str-trie-value-vm-error-malformed-entry: + +``malformed_entry`` +~~~~~~~~~~~~~~~~~~~ + +.. _gvm-def-str-trie-value-vm-error-leader-fault-nondet-output-absent: -``absent_leader_nondet_output`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``leader_fault nondet_output absent`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. _gvm-def-str-trie-value-vm-error-leader-fault-nondet-output-malformed: + +``leader_fault nondet_output malformed`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. _gvm-def-str-trie-value-vm-error-leader-fault-nondet-output-uses-this-error: + +``leader_fault nondet_output uses_this_error`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Param: str + +.. _gvm-def-str-trie-value-vm-error-leader-fault-nondet-output-extra: + +``leader_fault nondet_output extra`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Param: str .. _gvm-def-str-trie-value-vm-error-exit-code: @@ -484,10 +389,10 @@ Param: i32 ``fee too_many_rounds`` ~~~~~~~~~~~~~~~~~~~~~~~ -.. _gvm-def-str-trie-value-vm-error-host-forbidden: +.. _gvm-def-str-trie-value-vm-error-forbidden: -``host_forbidden`` -~~~~~~~~~~~~~~~~~~ +``forbidden`` +~~~~~~~~~~~~~ .. _gvm-def-str-trie-value-vm-error-evm-reverted: @@ -499,21 +404,21 @@ Param: i32 ``invalid_contract`` ~~~~~~~~~~~~~~~~~~~~ -.. _gvm-def-str-trie-value-vm-error-invalid-contract-absent-runner-comment: +.. _gvm-def-str-trie-value-vm-error-invalid-contract-runner-absent: + +``invalid_contract runner absent`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. _gvm-def-str-trie-value-vm-error-invalid-contract-runner-malformed: -``invalid_contract absent_runner_comment`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``invalid_contract runner malformed`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. _gvm-def-str-trie-value-vm-error-invalid-contract-not-utf8-text: ``invalid_contract not_utf8_text`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. _gvm-def-str-trie-value-vm-error-invalid-contract-malformed-runner: - -``invalid_contract malformed_runner`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. _gvm-def-str-trie-value-vm-error-invalid-contract-major-mismatch: ``invalid_contract major_mismatch`` @@ -536,6 +441,16 @@ This error remains terminal for top-level and runner loads. During :ref:`gvm-def ``invalid_contract wasm entrypoint`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. _gvm-def-str-trie-detail-vm-error-internal: + +``# internal`` +~~~~~~~~~~~~~~ + +.. _gvm-def-str-trie-detail-vm-error-external: + +``# external`` +~~~~~~~~~~~~~~ + .. _gvm-def-const-event-max-topics: event_max_topics diff --git a/docs/website/src/spec/appendix/index.rst b/docs/website/src/spec/appendix/index.rst index 9cda9e86..613e7734 100644 --- a/docs/website/src/spec/appendix/index.rst +++ b/docs/website/src/spec/appendix/index.rst @@ -6,4 +6,5 @@ Appendix constants Pending Constants + Internal Constants runner-schema diff --git a/docs/website/src/spec/appendix/internal-constants.rst b/docs/website/src/spec/appendix/internal-constants.rst new file mode 100644 index 00000000..44b72f37 --- /dev/null +++ b/docs/website/src/spec/appendix/internal-constants.rst @@ -0,0 +1,156 @@ +Constants +========= + +.. _gvm-def-consts-memory-limiter-consts: + +memory_limiter_consts +--------------------- + +Type: u32 + +.. _gvm-def-consts-value-memory-limiter-consts-table-entry: + +table_entry +~~~~~~~~~~~ + +Value: ``64`` + +.. _gvm-def-consts-value-memory-limiter-consts-file-mapping: + +file_mapping +~~~~~~~~~~~~ + +Value: ``256`` + +.. _gvm-def-consts-value-memory-limiter-consts-fd-allocation: + +fd_allocation +~~~~~~~~~~~~~ + +Value: ``96`` + +.. _gvm-def-consts-value-memory-limiter-consts-runner-load-cost: + +runner_load_cost +~~~~~~~~~~~~~~~~ + +Value: ``4096`` + +.. _gvm-def-consts-value-memory-limiter-consts-vm-spawn-cost: + +vm_spawn_cost +~~~~~~~~~~~~~ + +Value: ``134217728`` + +.. _gvm-def-consts-value-memory-limiter-consts-new-storage-page: + +new_storage_page +~~~~~~~~~~~~~~~~ + +Value: ``256`` + +.. _gvm-def-consts-value-memory-limiter-consts-storage-page-inherited: + +storage_page_inherited +~~~~~~~~~~~~~~~~~~~~~~ + +Value: ``128`` + +.. _gvm-def-consts-top-limits: + +top_limits +---------- + +Type: u32 + +.. _gvm-def-consts-value-top-limits-nondet-blocks: + +nondet_blocks +~~~~~~~~~~~~~ + +Value: ``4096`` + +.. _gvm-def-consts-value-top-limits-locked-slots: + +locked_slots +~~~~~~~~~~~~ + +Value: ``256`` + +.. _gvm-def-consts-value-top-limits-upgraders: + +upgraders +~~~~~~~~~ + +Value: ``32`` + +.. _gvm-def-consts-value-top-limits-vm-recursion: + +vm_recursion +~~~~~~~~~~~~ + +Value: ``512`` + +.. _gvm-def-consts-value-top-limits-web-request-min-space: + +web_request_min_space +~~~~~~~~~~~~~~~~~~~~~ + +Value: ``65536`` + +.. _gvm-def-consts-value-top-limits-web-render-min-space: + +web_render_min_space +~~~~~~~~~~~~~~~~~~~~ + +Value: ``134217728`` + +.. _gvm-def-consts-value-top-limits-max-fds: + +max_fds +~~~~~~~ + +Value: ``1024`` + +.. _gvm-def-consts-value-top-limits-wasm-call-depth: + +wasm_call_depth +~~~~~~~~~~~~~~~ + +Value: ``1024`` + +.. _gvm-def-consts-value-top-limits-wasm-stack-value-slots: + +wasm_stack_value_slots +~~~~~~~~~~~~~~~~~~~~~~ + +Value: ``65535`` + +.. _gvm-def-consts-runner-limits: + +runner_limits +------------- + +Type: u32 + +.. _gvm-def-consts-value-runner-limits-env-name-len: + +env_name_len +~~~~~~~~~~~~ + +Value: ``128`` + +.. _gvm-def-consts-value-runner-limits-env-value-len: + +env_value_len +~~~~~~~~~~~~~ + +Value: ``1048576`` + +.. _gvm-def-consts-value-runner-limits-init-action-depth: + +init_action_depth +~~~~~~~~~~~~~~~~~ + +Value: ``128`` diff --git a/docs/website/src/spec/changelog.rst b/docs/website/src/spec/changelog.rst new file mode 100644 index 00000000..2751adcb --- /dev/null +++ b/docs/website/src/spec/changelog.rst @@ -0,0 +1,54 @@ +Changelog +========= + +User-observable changes to the specification, grouped by executor line (see +:doc:`01-core-architecture/03-versioning`). Internal refactors are omitted; +see the repository history for those + +.. _gvm-changelog-v0-3: + +v0.3 +---- + +Breaking +~~~~~~~~ + +#. ``runner.json`` rejects unknown top-level and nested fields; a runner that + relied on an extra field being silently ignored fails to load. The single + top-level ``$schema`` string annotation is still accepted. See + :doc:`appendix/runner-schema` and the action definitions in + :doc:`02-execution-environment/04-runners` +#. ZIP-packaged :term:`runners ` are accepted under narrower rules; an + archive that previously loaded despite violating one of them now fails. + See the "ZIP Archive" layout in :doc:`02-execution-environment/04-runners`: + + #. Compression must read ``stored`` in both the central directory and the + entry's local header + #. A stored entry's compressed and uncompressed sizes must be equal + #. Every entry's CRC-32 is validated against its declared value + #. A directory entry must carry no contents; it is skipped rather than + added to the file list + #. Entry names are validated at parse time: no empty name, no leading + ``/``, no backslash, no empty, ``.`` or ``..`` path component, no + trailing ``/`` on a file + #. Entries sharing a name resolve to the last of them + +Changed +~~~~~~~ + +#. A missing or malformed runner archive/comment header is now reported as + :ref:`gvm-def-str-trie-value-vm-error-invalid-contract-runner-absent` or + :ref:`gvm-def-str-trie-value-vm-error-invalid-contract-runner-malformed` + respectively, instead of the former ``invalid_contract absent_runner_comment`` + and ``invalid_contract malformed_runner`` codes. A malformed runner archive + also now reports the precise + :ref:`gvm-def-str-trie-value-vm-error-invalid-contract-runner-malformed` + code where it previously surfaced a bare ``invalid_contract`` +#. A :ref:`gvm-def-gl-call-run-nondet` block starts on a budget seeded with its + caller's remaining RAM instead of a fresh 4 GiB one, so it can no longer use + more RAM than the deterministic caller had left. See + :doc:`03-vm/03-ram-limiting` +#. A resource error raised while a module is being instantiated keeps its own + code — e.g. exhausting the memory budget there reports + :ref:`gvm-def-str-trie-value-vm-error-out-of-memory-wasm-memory` — instead of + being reported as a bare ``invalid_contract`` diff --git a/docs/website/src/spec/index.rst b/docs/website/src/spec/index.rst index f0cfc7b3..5f1b2029 100644 --- a/docs/website/src/spec/index.rst +++ b/docs/website/src/spec/index.rst @@ -13,6 +13,7 @@ The specification has been split into multiple sections for better organization :caption: Contents: glossary + changelog 01-core-architecture/index 02-execution-environment/index 03-vm/index diff --git a/executors/v0.2.x b/executors/v0.2.x index 5b23854c..9da582c9 160000 --- a/executors/v0.2.x +++ b/executors/v0.2.x @@ -1 +1 @@ -Subproject commit 5b23854c49cc978995b5e1d4ac50c64f1c576736 +Subproject commit 9da582c9eb7b8f801cc00a4fd8a20f5dedd33da3 diff --git a/executors/v0.3.x b/executors/v0.3.x index 8a3a80cc..a54b15b7 160000 --- a/executors/v0.3.x +++ b/executors/v0.3.x @@ -1 +1 @@ -Subproject commit 8a3a80cc93c3433c9d34690171d8fbd2e2540738 +Subproject commit a54b15b7f3d4d81e362b80e6d2a678f89ae52b37 diff --git a/flake.nix b/flake.nix index fce2b678..dee0485b 100644 --- a/flake.nix +++ b/flake.nix @@ -150,7 +150,6 @@ mermaid-cli ]; packages-py-test = with pkgs; [ - # aflplusplus # currently we don't run fuzzing on CI python312 poetry # pytest + plugins so `poetry run -- pytest` has the @@ -736,7 +735,10 @@ ''; }; devShells.mock-tests = pkgs.mkShell { - packages = packages-0 ++ packages-rust ++ packages-debug-test; + # `pre-commit` itself, not `enabledPackages`: the push-refs unit test + # drives a `language: system` hook, so it needs no hook tooling. + packages = + packages-0 ++ packages-rust ++ packages-debug-test ++ [ pre-commit-check.config.package ]; shellHook = shell-hook-base; }; devShells.full = pkgs.mkShell { diff --git a/implementation/.ya-test-config.json b/implementation/.ya-test-config.json index e3659a87..bc011a52 100644 --- a/implementation/.ya-test-config.json +++ b/implementation/.ya-test-config.json @@ -14,5 +14,12 @@ "ATOMAKEY", "LSQLITE3_SRC", "LUA_INCLUDE" - ] + ], + "tags": { + "lib": [ + "feature-manager-socket", + "feature-version-routing", + "feature-web-request-signed" + ] + } } diff --git a/implementation/Cargo.lock b/implementation/Cargo.lock index 37e629a6..ee5803e6 100644 --- a/implementation/Cargo.lock +++ b/implementation/Cargo.lock @@ -123,9 +123,6 @@ name = "arbitrary" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" -dependencies = [ - "derive_arbitrary", -] [[package]] name = "archery" @@ -721,17 +718,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "derive_arbitrary" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "digest" version = "0.10.7" @@ -1019,7 +1005,6 @@ dependencies = [ name = "genlayer_calldata" version = "0.0.2" dependencies = [ - "arbitrary", "bytes", "chrono", "genlayer_calldata_derive", @@ -1043,7 +1028,6 @@ dependencies = [ name = "genlayer_sdk" version = "0.0.2" dependencies = [ - "arbitrary", "bytes", "chrono", "genlayer_calldata", @@ -1060,7 +1044,6 @@ name = "genvm-common" version = "0.3.0" dependencies = [ "anyhow", - "arbitrary", "archery", "bytes", "chrono", diff --git a/implementation/default.nix b/implementation/default.nix index 0694077a..ee480581 100644 --- a/implementation/default.nix +++ b/implementation/default.nix @@ -17,9 +17,21 @@ let lib = pkgs.lib; + monorepo = builtins.fromJSON (builtins.readFile (root-src + "/.genvm-monorepo-root")); + release-src = get-root-subtree ( + [ + ".genvm-monorepo-root" + "install" + "libs/unhardcoded-engine/llm_policy" + "libs/unhardcoded-engine/llm_policy.lua" + "support/manifest-base.yaml" + ] + ++ builtins.map (line: "executors/${line}.x/manifest.json") monorepo.active-versions + ); + # The shipped LLM dispatch script requires the `llm_policy` package, which # lives in the unhardcoded-engine submodule instead of under install/. - llm-policy-src = root-src + "/libs/unhardcoded-engine"; + llm-policy-src = release-src + "/libs/unhardcoded-engine"; make-for-target = target: @@ -38,6 +50,8 @@ let "crates/modules-interfaces" "crates/calldata" "crates/calldata-derive" + # a dev-dependency of the executor crates below, but cargo still needs its manifest + "crates/fuzzing" # executor crates come from the v0.3.x submodule mount "executors/v0.3.x/executor/crates" ]; @@ -57,7 +71,7 @@ let srcs = [ exe - ../install + (release-src + "/install") ] ++ compiled-libs.${target}; @@ -103,7 +117,7 @@ let # Assemble data/manifest.yaml from the active executor submodules # (executor-version + available-after) and the static base fields. - genvm-tool -C ${root-src} build-manifest --output "$out/data/manifest.yaml" + genvm-tool -C ${release-src} build-manifest --output "$out/data/manifest.yaml" patch-rpath --codesign --search-dir "$out/lib" --rpath '$ORIGIN/../lib' "$out/bin/genvm-modules" find "$out/lib" -type f -name '*.so' -not -name 'libc.so' | while read lib; do diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1 b/implementation/fuzz/inputs-genvm-modules-complete-json-curated/1 similarity index 100% rename from implementation/fuzz/inputs-genvm-modules-complete-json/1 rename to implementation/fuzz/inputs-genvm-modules-complete-json-curated/1 diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json-curated/2 b/implementation/fuzz/inputs-genvm-modules-complete-json-curated/2 new file mode 100644 index 00000000..490b564b --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json-curated/2 @@ -0,0 +1,3 @@ +{ "fo": [ { "fo": [ ] +} ] +} \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/0/00d3ga150hdc2vahv7sek5vhev60wgxrqmchnxqg3tkgj b/implementation/fuzz/inputs-genvm-modules-complete-json/0/0/00d3ga150hdc2vahv7sek5vhev60wgxrqmchnxqg3tkgj new file mode 100644 index 00000000..ab36f9a2 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/0/00d3ga150hdc2vahv7sek5vhev60wgxrqmchnxqg3tkgj @@ -0,0 +1 @@ +"UUUMbc〻 )rbbbe," diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/0/00esba677v1ndtj0816kwhjph61a9mtjqrhqp45j4pn8j b/implementation/fuzz/inputs-genvm-modules-complete-json/0/0/00esba677v1ndtj0816kwhjph61a9mtjqrhqp45j4pn8j new file mode 100644 index 00000000..97f03a8d --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/0/00esba677v1ndtj0816kwhjph61a9mtjqrhqp45j4pn8j @@ -0,0 +1,54 @@ +{ + + + + + + + + + + "foo": "bar", + + + + + + + "foo": "bar", + + "foo": "bar", + + + + + + + + "foo": "bar" + + + + + + + + + + + + + + +! + + + + + + + + + + + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/0/00m6tt8xf34nkv5f4jvcv7t5qnbvq8e6vspmf0we96ydt b/implementation/fuzz/inputs-genvm-modules-complete-json/0/0/00m6tt8xf34nkv5f4jvcv7t5qnbvq8e6vspmf0we96ydt new file mode 100644 index 00000000..454ce545 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/0/00m6tt8xf34nkv5f4jvcv7t5qnbvq8e6vspmf0we96ydt @@ -0,0 +1,3 @@ +{ + +} \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/1/0113bt3yk923gfp1a4cnxp8n9k0nqjsd6003qrspy8ng0 b/implementation/fuzz/inputs-genvm-modules-complete-json/0/1/0113bt3yk923gfp1a4cnxp8n9k0nqjsd6003qrspy8ng0 new file mode 100644 index 00000000..cf5c6cfd --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/1/0113bt3yk923gfp1a4cnxp8n9k0nqjsd6003qrspy8ng0 @@ -0,0 +1,4 @@ +{ + "foo": [ + [ + [[[[[[[[[[[[[[[[[[[[ [[[[[[[[ [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/3/03tgtrmf50h7edgb1jvdpp767qs4j6vjfp33ty9rr9w1t b/implementation/fuzz/inputs-genvm-modules-complete-json/0/3/03tgtrmf50h7edgb1jvdpp767qs4j6vjfp33ty9rr9w1t new file mode 100644 index 00000000..d98ebe76 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/3/03tgtrmf50h7edgb1jvdpp767qs4j6vjfp33ty9rr9w1t @@ -0,0 +1 @@ +0e555 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/4/045698ck5t9h0fn9dbv9x26q7gxekqbn9chzzbskfp53c b/implementation/fuzz/inputs-genvm-modules-complete-json/0/4/045698ck5t9h0fn9dbv9x26q7gxekqbn9chzzbskfp53c new file mode 100644 index 00000000..cfa49983 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/4/045698ck5t9h0fn9dbv9x26q7gxekqbn9chzzbskfp53c @@ -0,0 +1 @@ +12.1E111 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/5/05r1ay1bw7ngb8zmtkdfkyvrka6qbjs9jwv46mt3cbgde b/implementation/fuzz/inputs-genvm-modules-complete-json/0/5/05r1ay1bw7ngb8zmtkdfkyvrka6qbjs9jwv46mt3cbgde new file mode 100644 index 00000000..93a9ef1c --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/5/05r1ay1bw7ngb8zmtkdfkyvrka6qbjs9jwv46mt3cbgde @@ -0,0 +1 @@ + " \uDbbb\uDDbBu" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/5/05z7425x8bd6nvkk4kgq4f2499n09vpv1paeafe025c6c b/implementation/fuzz/inputs-genvm-modules-complete-json/0/5/05z7425x8bd6nvkk4kgq4f2499n09vpv1paeafe025c6c new file mode 100644 index 00000000..b914e297 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/5/05z7425x8bd6nvkk4kgq4f2499n09vpv1paeafe025c6c @@ -0,0 +1 @@ + [1111111111.1111111111E111, 1111111111.1111111111E111, 2,2, 11.111111111111E111, 2, 111111111111611111111] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/8/082658bdw9cssdkncjmxvzbhmff4n1j4pwhntw0n9mj2t b/implementation/fuzz/inputs-genvm-modules-complete-json/0/8/082658bdw9cssdkncjmxvzbhmff4n1j4pwhntw0n9mj2t new file mode 100644 index 00000000..941c5b4a --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/8/082658bdw9cssdkncjmxvzbhmff4n1j4pwhntw0n9mj2t @@ -0,0 +1,3 @@ +{ + "":{ "":{ +, \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/9/09j7nh5jet076pmv9f8pqe6swkjsqdqc9yxw67105wrnc b/implementation/fuzz/inputs-genvm-modules-complete-json/0/9/09j7nh5jet076pmv9f8pqe6swkjsqdqc9yxw67105wrnc new file mode 100644 index 00000000..1404c1e8 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/9/09j7nh5jet076pmv9f8pqe6swkjsqdqc9yxw67105wrnc @@ -0,0 +1 @@ +"\f \\日112 " \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/a/0a34bxzvvbkk9zdf1wh22spsbdwbqeqerm0e43pv2ngct b/implementation/fuzz/inputs-genvm-modules-complete-json/0/a/0a34bxzvvbkk9zdf1wh22spsbdwbqeqerm0e43pv2ngct new file mode 100644 index 00000000..8a919d7d --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/a/0a34bxzvvbkk9zdf1wh22spsbdwbqeqerm0e43pv2ngct @@ -0,0 +1,2 @@ + { + " \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/a/0a52mzaj1hv1tb2txtrjrs0ejszt3fgn469604sqnqj6w b/implementation/fuzz/inputs-genvm-modules-complete-json/0/a/0a52mzaj1hv1tb2txtrjrs0ejszt3fgn469604sqnqj6w new file mode 100644 index 00000000..5f7e8093 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/a/0a52mzaj1hv1tb2txtrjrs0ejszt3fgn469604sqnqj6w @@ -0,0 +1 @@ +"\f\f\f\ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/a/0a7d5brepkxdgktr1f7xwgdg5swstym8vsx6fg3ncrmp4 b/implementation/fuzz/inputs-genvm-modules-complete-json/0/a/0a7d5brepkxdgktr1f7xwgdg5swstym8vsx6fg3ncrmp4 new file mode 100644 index 00000000..5e0da963 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/a/0a7d5brepkxdgktr1f7xwgdg5swstym8vsx6fg3ncrmp4 @@ -0,0 +1 @@ +22919112111111111111.111111111 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/a/0asfwrht8gf6bz9tf3ag2ah4sdtaexyeeaatfy86cfbse b/implementation/fuzz/inputs-genvm-modules-complete-json/0/a/0asfwrht8gf6bz9tf3ag2ah4sdtaexyeeaatfy86cfbse new file mode 100644 index 00000000..36e83cac --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/a/0asfwrht8gf6bz9tf3ag2ah4sdtaexyeeaatfy86cfbse @@ -0,0 +1,2 @@ + +"р\\uba d r" diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/a/0avcwmc836hmvcx4tcsgxjt88gfqgr6crja3s08qjb2em b/implementation/fuzz/inputs-genvm-modules-complete-json/0/a/0avcwmc836hmvcx4tcsgxjt88gfqgr6crja3s08qjb2em new file mode 100644 index 00000000..7341a61b --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/a/0avcwmc836hmvcx4tcsgxjt88gfqgr6crja3s08qjb2em @@ -0,0 +1,2 @@ +[ + , t \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/b/0b3zfjthc54aqca5f5q9776emq6rtmc4psze4xt987swm b/implementation/fuzz/inputs-genvm-modules-complete-json/0/b/0b3zfjthc54aqca5f5q9776emq6rtmc4psze4xt987swm new file mode 100644 index 00000000..000ffd24 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/b/0b3zfjthc54aqca5f5q9776emq6rtmc4psze4xt987swm @@ -0,0 +1 @@ +00 [ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/d/0dkbwhymbmwe8yfb2af3mdmd6sreg4w60t8km5ctnghr8 b/implementation/fuzz/inputs-genvm-modules-complete-json/0/d/0dkbwhymbmwe8yfb2af3mdmd6sreg4w60t8km5ctnghr8 new file mode 100644 index 00000000..97166e39 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/d/0dkbwhymbmwe8yfb2af3mdmd6sreg4w60t8km5ctnghr8 @@ -0,0 +1,16 @@ +{ + "foo": [ + "bar", + "baz\n\\z", + 123, + -123, + -1e10, + 1e20, false, + [1111111111111111111111111111, 2, 3] + ], + " bar": [ + "русские букв݋ 日本", + "mbbbbbbbbbbbbbbaz\t\uabbbbb", + "кие буквы 日uabbbbb" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/h/0h92aedsc1y7xgr695dmyvyf4zm587ab3yd1acdhrvr9a b/implementation/fuzz/inputs-genvm-modules-complete-json/0/h/0h92aedsc1y7xgr695dmyvyf4zm587ab3yd1acdhrvr9a new file mode 100644 index 00000000..2ce3e2ea --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/h/0h92aedsc1y7xgr695dmyvyf4zm587ab3yd1acdhrvr9a @@ -0,0 +1,2 @@ + +"рbbba===========\ua11E |" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/h/0hfwbfz1w1wys0ckdwxg5y4tvhshzwmq46h9mh79qw1ae b/implementation/fuzz/inputs-genvm-modules-complete-json/0/h/0hfwbfz1w1wys0ckdwxg5y4tvhshzwmq46h9mh79qw1ae new file mode 100644 index 00000000..d5b545fe --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/h/0hfwbfz1w1wys0ckdwxg5y4tvhshzwmq46h9mh79qw1ae @@ -0,0 +1,4 @@ + + + + "bar -123, \\\\\\\\\\\\\\\\bbbbbebbкbbbбуљ\\本\\\\\\кbbbbubbbubbbcе буф\\本\\буфcе буф\\本\\буф\\本\\\\\\квы 旁ba z" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/j/0j3dp76k6cfjc5zkzec3cn0t5h0t58w96yyzeyhzsm6he b/implementation/fuzz/inputs-genvm-modules-complete-json/0/j/0j3dp76k6cfjc5zkzec3cn0t5h0t58w96yyzeyhzsm6he new file mode 100644 index 00000000..b182156f --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/j/0j3dp76k6cfjc5zkzec3cn0t5h0t58w96yyzeyhzsm6he @@ -0,0 +1,3 @@ +{ + "foo": [ + "ba n \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/j/0j89xg8cfb3xb62hhx33xhhd813c2qrfrwjjgj5ebsw7w b/implementation/fuzz/inputs-genvm-modules-complete-json/0/j/0j89xg8cfb3xb62hhx33xhhd813c2qrfrwjjgj5ebsw7w new file mode 100644 index 00000000..4ca669b3 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/j/0j89xg8cfb3xb62hhx33xhhd813c2qrfrwjjgj5ebsw7w @@ -0,0 +1,5 @@ +{ + "foo 222": [ + " " + ] +} \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/m/0m4rse79871djv54arat6a564d9wk6b32et8xfaatccqr b/implementation/fuzz/inputs-genvm-modules-complete-json/0/m/0m4rse79871djv54arat6a564d9wk6b32et8xfaatccqr new file mode 100644 index 00000000..4fee252a --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/m/0m4rse79871djv54arat6a564d9wk6b32et8xfaatccqr @@ -0,0 +1,19 @@ +{ + "f faloo": [ + "bar", + "baz\n\\z", + 123, + -123, + -1e10, + null, + true, + false, + [1, 2, 3] + ], + "bar": [ + "русские букزы 日b", + "bbbb" + ], + "bar": [ + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/9a70598e97b57c7a6c6d7d77cc64509b13c0caf72203e8cfbe0c6f2e3446c804 b/implementation/fuzz/inputs-genvm-modules-complete-json/0/m/0mddxqyra4jsre5cw5fmk3fg3y4gx74fc32dxwggnkqz6 similarity index 50% rename from implementation/fuzz/inputs-genvm-modules-normalize-whitespace/9a70598e97b57c7a6c6d7d77cc64509b13c0caf72203e8cfbe0c6f2e3446c804 rename to implementation/fuzz/inputs-genvm-modules-complete-json/0/m/0mddxqyra4jsre5cw5fmk3fg3y4gx74fc32dxwggnkqz6 index 3834720e..6d03ac6b 100644 --- a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/9a70598e97b57c7a6c6d7d77cc64509b13c0caf72203e8cfbe0c6f2e3446c804 +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/m/0mddxqyra4jsre5cw5fmk3fg3y4gx74fc32dxwggnkqz6 @@ -1,17 +1,16 @@ - + - - - - \ No newline at end of file +" + + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/n/0nz26d1454cv5768t5j9se7txfecpxxsm9x8s7r91qf1e b/implementation/fuzz/inputs-genvm-modules-complete-json/0/n/0nz26d1454cv5768t5j9se7txfecpxxsm9x8s7r91qf1e new file mode 100644 index 00000000..703e58f3 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/n/0nz26d1454cv5768t5j9se7txfecpxxsm9x8s7r91qf1e @@ -0,0 +1 @@ +22222222222222.22222222 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/p/0paa3j6967xv5d1a2074nyqtnbbtv76pvbpzgevzfgy54 b/implementation/fuzz/inputs-genvm-modules-complete-json/0/p/0paa3j6967xv5d1a2074nyqtnbbtv76pvbpzgevzfgy54 new file mode 100644 index 00000000..395a6a3e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/p/0paa3j6967xv5d1a2074nyqtnbbtv76pvbpzgevzfgy54 @@ -0,0 +1 @@ + "󗥗󗥗b󗥗󗥗" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/p/0prjncdjcy75m9m6q0qk6ezw8zj1596rhj36e402ew754 b/implementation/fuzz/inputs-genvm-modules-complete-json/0/p/0prjncdjcy75m9m6q0qk6ezw8zj1596rhj36e402ew754 new file mode 100644 index 00000000..f61a6a1a --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/p/0prjncdjcy75m9m6q0qk6ezw8zj1596rhj36e402ew754 @@ -0,0 +1,2 @@ +[, + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/q/0qn2kcn21t453s1b2ngz23bwnbzkm23e5ks6x0v2z5td0 b/implementation/fuzz/inputs-genvm-modules-complete-json/0/q/0qn2kcn21t453s1b2ngz23bwnbzkm23e5ks6x0v2z5td0 new file mode 100644 index 00000000..2f4081f3 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/q/0qn2kcn21t453s1b2ngz23bwnbzkm23e5ks6x0v2z5td0 @@ -0,0 +1,7 @@ +{"ar + + + + + +", \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/r/0rtkxs54nn6ex33a27wg1ppmthvkknkp3mep8f5b98k50 b/implementation/fuzz/inputs-genvm-modules-complete-json/0/r/0rtkxs54nn6ex33a27wg1ppmthvkknkp3mep8f5b98k50 new file mode 100644 index 00000000..424faaef --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/r/0rtkxs54nn6ex33a27wg1ppmthvkknkp3mep8f5b98k50 @@ -0,0 +1,2 @@ + +"\u0000ы" diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/t/0tjjkt9cpff1d660acdtdzdpfv43mfctgbpy3he9beysw b/implementation/fuzz/inputs-genvm-modules-complete-json/0/t/0tjjkt9cpff1d660acdtdzdpfv43mfctgbpy3he9beysw new file mode 100644 index 00000000..17931f67 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/t/0tjjkt9cpff1d660acdtdzdpfv43mfctgbpy3he9beysw @@ -0,0 +1 @@ +"\fn" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/w/0wqka8ved58jyqtjbr88vpkg80h3sbf3pjyznxq7j1904 b/implementation/fuzz/inputs-genvm-modules-complete-json/0/w/0wqka8ved58jyqtjbr88vpkg80h3sbf3pjyznxq7j1904 new file mode 100644 index 00000000..322876ac --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/w/0wqka8ved58jyqtjbr88vpkg80h3sbf3pjyznxq7j1904 @@ -0,0 +1 @@ +2111111.1121111111111 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/y/0y24j1rns05r9jsbwe40h08etjq468myc7zyqnr06d3et b/implementation/fuzz/inputs-genvm-modules-complete-json/0/y/0y24j1rns05r9jsbwe40h08etjq468myc7zyqnr06d3et new file mode 100644 index 00000000..0eb41820 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/y/0y24j1rns05r9jsbwe40h08etjq468myc7zyqnr06d3et @@ -0,0 +1 @@ +0.11 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/0/y/0ynj4895jyafkpw0jnvzmxdnhkv2p5jz9p6kc483sgk50 b/implementation/fuzz/inputs-genvm-modules-complete-json/0/y/0ynj4895jyafkpw0jnvzmxdnhkv2p5jz9p6kc483sgk50 new file mode 100644 index 00000000..a8e99ef1 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/0/y/0ynj4895jyafkpw0jnvzmxdnhkv2p5jz9p6kc483sgk50 @@ -0,0 +1 @@ +" т\u000000 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/2/12qz7rfp162bvpwtqdcsjfcte6gnaqhbn0brtbqmrfeyy b/implementation/fuzz/inputs-genvm-modules-complete-json/1/2/12qz7rfp162bvpwtqdcsjfcte6gnaqhbn0brtbqmrfeyy new file mode 100644 index 00000000..a36d2a76 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/2/12qz7rfp162bvpwtqdcsjfcte6gnaqhbn0brtbqmrfeyy @@ -0,0 +1,17 @@ + { + "":0, + "": { + "": + { + "":0, + "": { + "": + { +"":0, + "": { + " + + + + + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/2/12v1440bpgmpf20twrkek8mv0d8005q3q499gz8acnzmm b/implementation/fuzz/inputs-genvm-modules-complete-json/1/2/12v1440bpgmpf20twrkek8mv0d8005q3q499gz8acnzmm new file mode 100644 index 00000000..16593f0b --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/2/12v1440bpgmpf20twrkek8mv0d8005q3q499gz8acnzmm @@ -0,0 +1 @@ +-0 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/4/149cmt9ms89v020yrryvpa8jvmc20h657s4n8p4ypamy0 b/implementation/fuzz/inputs-genvm-modules-complete-json/1/4/149cmt9ms89v020yrryvpa8jvmc20h657s4n8p4ypamy0 new file mode 100644 index 00000000..692b8050 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/4/149cmt9ms89v020yrryvpa8jvmc20h657s4n8p4ypamy0 @@ -0,0 +1 @@ +fals \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/4/14qyfsbfxsjvhq4h4px6vne04dr3tedqcnk65kx1h0x5a b/implementation/fuzz/inputs-genvm-modules-complete-json/1/4/14qyfsbfxsjvhq4h4px6vne04dr3tedqcnk65kx1h0x5a new file mode 100644 index 00000000..147a3b66 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/4/14qyfsbfxsjvhq4h4px6vne04dr3tedqcnk65kx1h0x5a @@ -0,0 +1,2 @@ +{ " @fo" : [ 3 ] +} \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/5/152sp9r1b3r2ws1hk69wtkfwp9rrxedhcyss8bdcnvaha b/implementation/fuzz/inputs-genvm-modules-complete-json/1/5/152sp9r1b3r2ws1hk69wtkfwp9rrxedhcyss8bdcnvaha new file mode 100644 index 00000000..cc7ce787 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/5/152sp9r1b3r2ws1hk69wtkfwp9rrxedhcyss8bdcnvaha @@ -0,0 +1,17 @@ +{ + "foo": [ + "baz\n\\z", + 123, + -123, + -1e10, + null, + true, + false, + [1, 2, 3] + ], + "bar": [ + "русские букزы 日本az\t\uabbbbb", + "bbbb" + ] +} + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/5/15bp4vcf7xkp37ac1718tt0rxvgts1agh64p5aw1fhxbj b/implementation/fuzz/inputs-genvm-modules-complete-json/1/5/15bp4vcf7xkp37ac1718tt0rxvgts1agh64p5aw1fhxbj new file mode 100644 index 00000000..0fa37116 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/5/15bp4vcf7xkp37ac1718tt0rxvgts1agh64p5aw1fhxbj @@ -0,0 +1 @@ +2222222222222222222222222E2 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/5/15sf0t7k419d92gz7xhsav1gcmq07n07wydnnwsrgphym b/implementation/fuzz/inputs-genvm-modules-complete-json/1/5/15sf0t7k419d92gz7xhsav1gcmq07n07wydnnwsrgphym new file mode 100644 index 00000000..c4906337 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/5/15sf0t7k419d92gz7xhsav1gcmq07n07wydnnwsrgphym @@ -0,0 +1,20 @@ +{ + "foo": [ + "bar" + ], + "babbbbbbbbbbbbbaz\t\\r": [ + 123, + -123, + -1e10, + 1e20, + null, + true, + false, + [1, 2, 3] + ], + "bar": [ + "русские буквы 日本", + "mbbbbbbbbbbbbbbaz\t\uabbbbb", + "mbbbbbbbbbbbbbbaz\t\\uabbbbb" + ] +} \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/7/17hz2hbxc3cj4tw3tje2j8d5ty7kc6kfpsmfte6p2twm2 b/implementation/fuzz/inputs-genvm-modules-complete-json/1/7/17hz2hbxc3cj4tw3tje2j8d5ty7kc6kfpsmfte6p2twm2 new file mode 100644 index 00000000..512eabc9 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/7/17hz2hbxc3cj4tw3tje2j8d5ty7kc6kfpsmfte6p2twm2 @@ -0,0 +1 @@ + " \uDCb5" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/8/184jstbv6j02k45pq0cvc2v78est9zdsmbnrffr0r7nv2 b/implementation/fuzz/inputs-genvm-modules-complete-json/1/8/184jstbv6j02k45pq0cvc2v78est9zdsmbnrffr0r7nv2 new file mode 100644 index 00000000..6f12b734 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/8/184jstbv6j02k45pq0cvc2v78est9zdsmbnrffr0r7nv2 @@ -0,0 +1,2 @@ + +"рj750 1\uDbbb\uDc11 ! e111@eC@1b11111111111111111;111111.11p" diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/9/19dp9v5s7zg0r44q1q10j4cw9xczdd69pvt8v340a6f8c b/implementation/fuzz/inputs-genvm-modules-complete-json/1/9/19dp9v5s7zg0r44q1q10j4cw9xczdd69pvt8v340a6f8c new file mode 100644 index 00000000..efcbec52 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/9/19dp9v5s7zg0r44q1q10j4cw9xczdd69pvt8v340a6f8c @@ -0,0 +1 @@ +299999999999999999992E+ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/a/1acaehj72a3q4n0svg1mw6sr73c755f4fs585a33prhzp b/implementation/fuzz/inputs-genvm-modules-complete-json/1/a/1acaehj72a3q4n0svg1mw6sr73c755f4fs585a33prhzp new file mode 100644 index 00000000..cd477695 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/a/1acaehj72a3q4n0svg1mw6sr73c755f4fs585a33prhzp @@ -0,0 +1,22 @@ +{ + "foo": [ + "bar", + "baz\n\\{", + 123, +23, + -1e10, + 1e20, + null, + true, + false, + [1, 2, 3] + ], + "": [ ], + "bar":[ ], + "": [ ], + "bar": [ + "русские буквЇ 日本", + "mbbbbbbbbbbbbbbaz\t\uabbbbb", + "mbbbbbbbbbbbbbbaz\t\\tabbbbb" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/a/1aj0wvbm2cwde34147rf5ha82ry271c5rc0agxjrc47x4 b/implementation/fuzz/inputs-genvm-modules-complete-json/1/a/1aj0wvbm2cwde34147rf5ha82ry271c5rc0agxjrc47x4 new file mode 100644 index 00000000..8671c168 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/a/1aj0wvbm2cwde34147rf5ha82ry271c5rc0agxjrc47x4 @@ -0,0 +1 @@ +2e-3333 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/a/1ajgxbt71nyw23zrd1qy323jtwynep5d2pdaav2tffxp8 b/implementation/fuzz/inputs-genvm-modules-complete-json/1/a/1ajgxbt71nyw23zrd1qy323jtwynep5d2pdaav2tffxp8 new file mode 100644 index 00000000..270841da --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/a/1ajgxbt71nyw23zrd1qy323jtwynep5d2pdaav2tffxp8 @@ -0,0 +1 @@ +"f\\.111111,\\\\日1 ', " \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/b/1b6evrr1ecfjkt9k5kg0tk3xh25s33wx4ww96573naghw b/implementation/fuzz/inputs-genvm-modules-complete-json/1/b/1b6evrr1ecfjkt9k5kg0tk3xh25s33wx4ww96573naghw new file mode 100644 index 00000000..1ee1d282 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/b/1b6evrr1ecfjkt9k5kg0tk3xh25s33wx4ww96573naghw @@ -0,0 +1 @@ + "с\\ffffffffffabba\": ffffffffffabba\":fffabba\": [22222222222222222ffffffffffhbba\":f1222bbbb" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/c/1cph9wc8w0a8z0w2028vtcx5xs4dgyzf5w1s7jdppr3xy b/implementation/fuzz/inputs-genvm-modules-complete-json/1/c/1cph9wc8w0a8z0w2028vtcx5xs4dgyzf5w1s7jdppr3xy new file mode 100644 index 00000000..035ff3c1 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/c/1cph9wc8w0a8z0w2028vtcx5xs4dgyzf5w1s7jdppr3xy @@ -0,0 +1 @@ + [1,22, , 21, \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/f/1f72s7zs5t4wmrbvk0yg71wxveqe55ztfpg8jbsa3bqmg b/implementation/fuzz/inputs-genvm-modules-complete-json/1/f/1f72s7zs5t4wmrbvk0yg71wxveqe55ztfpg8jbsa3bqmg new file mode 100644 index 00000000..4672bf57 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/f/1f72s7zs5t4wmrbvk0yg71wxveqe55ztfpg8jbsa3bqmg @@ -0,0 +1,3 @@ + { + "":0, + } diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/f/1fghdv1x7bnfg9pavb755sf0sc40qmhsbcwqf5nrs7ae4 b/implementation/fuzz/inputs-genvm-modules-complete-json/1/f/1fghdv1x7bnfg9pavb755sf0sc40qmhsbcwqf5nrs7ae4 new file mode 100644 index 00000000..6909f8f5 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/f/1fghdv1x7bnfg9pavb755sf0sc40qmhsbcwqf5nrs7ae4 @@ -0,0 +1,15 @@ + [ + + + + + + + + + + + + + +[[[[[[[[[[[[[[[[[[[S \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/f/1fjcx4dk7z22dava03ptrv3ymfjycm4m4ffx7j0d98m4p b/implementation/fuzz/inputs-genvm-modules-complete-json/1/f/1fjcx4dk7z22dava03ptrv3ymfjycm4m4ffx7j0d98m4p new file mode 100644 index 00000000..1ad28cc7 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/f/1fjcx4dk7z22dava03ptrv3ymfjycm4m4ffx7j0d98m4p @@ -0,0 +1 @@ + "Y󗥗11 [," \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/j/1jj15a1rq85qvscnan6she76mdje40y78df623nha4fyj b/implementation/fuzz/inputs-genvm-modules-complete-json/1/j/1jj15a1rq85qvscnan6she76mdje40y78df623nha4fyj new file mode 100644 index 00000000..7430f02c --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/j/1jj15a1rq85qvscnan6she76mdje40y78df623nha4fyj @@ -0,0 +1,3 @@ +{ "o": [ { "o": [ +} ] +} \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/k/1k3r491j8kg26xvpnfe3a0yb3ve9wvy43c3n09dgv7ctw b/implementation/fuzz/inputs-genvm-modules-complete-json/1/k/1k3r491j8kg26xvpnfe3a0yb3ve9wvy43c3n09dgv7ctw new file mode 100644 index 00000000..9a13412d --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/k/1k3r491j8kg26xvpnfe3a0yb3ve9wvy43c3n09dgv7ctw @@ -0,0 +1 @@ +1011111111111111111111111111 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/k/1knejvhs0c6k96dxf9zspqgns0xwvzn3ntmnc3m7hfgbw b/implementation/fuzz/inputs-genvm-modules-complete-json/1/k/1knejvhs0c6k96dxf9zspqgns0xwvzn3ntmnc3m7hfgbw new file mode 100644 index 00000000..06249e40 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/k/1knejvhs0c6k96dxf9zspqgns0xwvzn3ntmnc3m7hfgbw @@ -0,0 +1 @@ +3e-922 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/m/1msmyw0naed8mgex7ss57qmqbfwapn427xst8jsqe3ngj b/implementation/fuzz/inputs-genvm-modules-complete-json/1/m/1msmyw0naed8mgex7ss57qmqbfwapn427xst8jsqe3ngj new file mode 100644 index 00000000..4df6ce0c --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/m/1msmyw0naed8mgex7ss57qmqbfwapn427xst8jsqe3ngj @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/r/1rmm9pj961n1pq2vsy22xpbxw0nhyq93px4r60hahzjma b/implementation/fuzz/inputs-genvm-modules-complete-json/1/r/1rmm9pj961n1pq2vsy22xpbxw0nhyq93px4r60hahzjma new file mode 100644 index 00000000..44620ac5 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/r/1rmm9pj961n1pq2vsy22xpbxw0nhyq93px4r60hahzjma @@ -0,0 +1,2 @@ +[ + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/s/1sf4137gha4gmqm24trscfjqc7jm4479w6qj1mex11fry b/implementation/fuzz/inputs-genvm-modules-complete-json/1/s/1sf4137gha4gmqm24trscfjqc7jm4479w6qj1mex11fry new file mode 100644 index 00000000..5adc2b29 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/s/1sf4137gha4gmqm24trscfjqc7jm4479w6qj1mex11fry @@ -0,0 +1 @@ +21111111111111111111111111.1 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/v/1v0k1nwfyggr3b0wc35azwddz7t89e408jvrrapd5edrw b/implementation/fuzz/inputs-genvm-modules-complete-json/1/v/1v0k1nwfyggr3b0wc35azwddz7t89e408jvrrapd5edrw new file mode 100644 index 00000000..8ffaa9d0 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/v/1v0k1nwfyggr3b0wc35azwddz7t89e408jvrrapd5edrw @@ -0,0 +1,12 @@ +{ + + + + + + + + + + "foo": "bar", +  \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/v/1vfxfq59pf73na9hbcz0b6vdm97rwqjegsmyfg1vqsm82 b/implementation/fuzz/inputs-genvm-modules-complete-json/1/v/1vfxfq59pf73na9hbcz0b6vdm97rwqjegsmyfg1vqsm82 new file mode 100644 index 00000000..4acc4aea --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/v/1vfxfq59pf73na9hbcz0b6vdm97rwqjegsmyfg1vqsm82 @@ -0,0 +1,17 @@ +{ + "foo": [ + "bar", + "baz\n\\zt\uabbbbb", + "mbbbbbbb", + 123, + -123, + -1e10, + 1e20, + false, + [1,3] + ], + "bar": [ + "русские z\n\\zt\uabbbbb", + "mbmbbbbbbbbbbbbbbaz\t\bbbbaz\t\\uabbbbb" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/x/1x74f8x8hn228h57pkdye6wysbhsrrhjw49z4gepbqzvj b/implementation/fuzz/inputs-genvm-modules-complete-json/1/x/1x74f8x8hn228h57pkdye6wysbhsrrhjw49z4gepbqzvj new file mode 100644 index 00000000..5b4c53e5 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/x/1x74f8x8hn228h57pkdye6wysbhsrrhjw49z4gepbqzvj @@ -0,0 +1 @@ + [[ [[1, ,,,,, \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/y/1ytqg1fmemq3efa31gttwkc9ks89mdx2dbzc5qhgj92s4 b/implementation/fuzz/inputs-genvm-modules-complete-json/1/y/1ytqg1fmemq3efa31gttwkc9ks89mdx2dbzc5qhgj92s4 new file mode 100644 index 00000000..b43d02d4 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/y/1ytqg1fmemq3efa31gttwkc9ks89mdx2dbzc5qhgj92s4 @@ -0,0 +1 @@ + [1111111111111111111111111, 2, 3] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/1/z/1zbxn03hxa23gxe1md3gbn3zv7cngzcerj1j675n9780a b/implementation/fuzz/inputs-genvm-modules-complete-json/1/z/1zbxn03hxa23gxe1md3gbn3zv7cngzcerj1j675n9780a new file mode 100644 index 00000000..3cc762b5 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/1/z/1zbxn03hxa23gxe1md3gbn3zv7cngzcerj1j675n9780a @@ -0,0 +1 @@ +"" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/0/20n3w7v3kk9wzmhsayk4at70qkrajx55jgnepk7z6hr0r b/implementation/fuzz/inputs-genvm-modules-complete-json/2/0/20n3w7v3kk9wzmhsayk4at70qkrajx55jgnepk7z6hr0r new file mode 100644 index 00000000..8eaee9c6 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/0/20n3w7v3kk9wzmhsayk4at70qkrajx55jgnepk7z6hr0r @@ -0,0 +1 @@ + [1111111111116111111161e-111111112, 311, 11E1] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/1/210xq1kcqh6mwx1jv8e4m8p45ep59sdmv28pmzy4pw1a4 b/implementation/fuzz/inputs-genvm-modules-complete-json/2/1/210xq1kcqh6mwx1jv8e4m8p45ep59sdmv28pmzy4pw1a4 new file mode 100644 index 00000000..bafe7a35 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/1/210xq1kcqh6mwx1jv8e4m8p45ep59sdmv28pmzy4pw1a4 @@ -0,0 +1,2 @@ + [ [{ + "emo": 1, 2, 3nul \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/1/21ya1p19ay28psnn5f4zhyd2t4kfvda8a4y3dpc14v5f4 b/implementation/fuzz/inputs-genvm-modules-complete-json/2/1/21ya1p19ay28psnn5f4zhyd2t4kfvda8a4y3dpc14v5f4 new file mode 100644 index 00000000..5e955612 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/1/21ya1p19ay28psnn5f4zhyd2t4kfvda8a4y3dpc14v5f4 @@ -0,0 +1,5 @@ +{ "o": [ { "o": [ { "o": [ { "o": [ +} ] +} +} ] +} \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/3/23vz35x95rw4mrq1a5fxzy55qjks164pc29znrc45cdtp b/implementation/fuzz/inputs-genvm-modules-complete-json/2/3/23vz35x95rw4mrq1a5fxzy55qjks164pc29znrc45cdtp new file mode 100644 index 00000000..8fa7afe5 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/3/23vz35x95rw4mrq1a5fxzy55qjks164pc29znrc45cdtp @@ -0,0 +1 @@ +11111111111111111111111e-522 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/5/25c2p7k1zb2gkvyfdaz725jw76qrm1wncjwqkqc4kk1m8 b/implementation/fuzz/inputs-genvm-modules-complete-json/2/5/25c2p7k1zb2gkvyfdaz725jw76qrm1wncjwqkqc4kk1m8 new file mode 100644 index 00000000..5d20f5fc --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/5/25c2p7k1zb2gkvyfdaz725jw76qrm1wncjwqkqc4kk1m8 @@ -0,0 +1,2 @@ + +"р\\ub` d [[1, B\bõ r" diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/6/26wa4awjzxj0n7cxbv03m54mfedmavr2f6m01vv3zvtte b/implementation/fuzz/inputs-genvm-modules-complete-json/2/6/26wa4awjzxj0n7cxbv03m54mfedmavr2f6m01vv3zvtte new file mode 100644 index 00000000..8d2f53d0 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/6/26wa4awjzxj0n7cxbv03m54mfedmavr2f6m01vv3zvtte @@ -0,0 +1 @@ + [[ [[ [[[[[[[[[[[[[[[[[[[1, \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/9/29tp9v5282spx6x5aagjzrpyypvmtpkq3r0rrfdg4m67c b/implementation/fuzz/inputs-genvm-modules-complete-json/2/9/29tp9v5282spx6x5aagjzrpyypvmtpkq3r0rrfdg4m67c new file mode 100644 index 00000000..476f449f --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/9/29tp9v5282spx6x5aagjzrpyypvmtpkq3r0rrfdg4m67c @@ -0,0 +1,3 @@ + + +"\r" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/b/2babs58b5a87gfxksxtm649ypqgmkacmejzry836t92k0 b/implementation/fuzz/inputs-genvm-modules-complete-json/2/b/2babs58b5a87gfxksxtm649ypqgmkacmejzry836t92k0 new file mode 100644 index 00000000..00a55f04 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/b/2babs58b5a87gfxksxtm649ypqgmkacmejzry836t92k0 @@ -0,0 +1 @@ +[[]] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/c/2c95ns6xkaakcy132nmxmq4x2zgqr90x0dmsnz627ed66 b/implementation/fuzz/inputs-genvm-modules-complete-json/2/c/2c95ns6xkaakcy132nmxmq4x2zgqr90x0dmsnz627ed66 new file mode 100644 index 00000000..c17c703a --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/c/2c95ns6xkaakcy132nmxmq4x2zgqr90x0dmsnz627ed66 @@ -0,0 +1,2 @@ +2E+2 + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/d/2d8qwhcyefn0frp5r1ca0x7c5fx7z73799v9jgh5kznrm b/implementation/fuzz/inputs-genvm-modules-complete-json/2/d/2d8qwhcyefn0frp5r1ca0x7c5fx7z73799v9jgh5kznrm new file mode 100644 index 00000000..d96f13d8 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/d/2d8qwhcyefn0frp5r1ca0x7c5fx7z73799v9jgh5kznrm @@ -0,0 +1 @@ + 1 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/e/2ej6zv22vbtxd1h5fyy6aqs1709dm2kcner8xgmdjw3gy b/implementation/fuzz/inputs-genvm-modules-complete-json/2/e/2ej6zv22vbtxd1h5fyy6aqs1709dm2kcner8xgmdjw3gy new file mode 100644 index 00000000..24752035 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/e/2ej6zv22vbtxd1h5fyy6aqs1709dm2kcner8xgmdjw3gy @@ -0,0 +1,10 @@ + { + "":0, + "" + + + "": + " +: { + + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/h/2hmtt4mqq71y2pvf4twdsffeyvc71wp3h2hvs5ahme1nr b/implementation/fuzz/inputs-genvm-modules-complete-json/2/h/2hmtt4mqq71y2pvf4twdsffeyvc71wp3h2hvs5ahme1nr new file mode 100644 index 00000000..d9779a6d --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/h/2hmtt4mqq71y2pvf4twdsffeyvc71wp3h2hvs5ahme1nr @@ -0,0 +1 @@ +"\ri" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/j/2jng17dez65x6wswjp25acskmrx7b5tcmq386s35axwnc b/implementation/fuzz/inputs-genvm-modules-complete-json/2/j/2jng17dez65x6wswjp25acskmrx7b5tcmq386s35axwnc new file mode 100644 index 00000000..3d72cb7a --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/j/2jng17dez65x6wswjp25acskmrx7b5tcmq386s35axwnc @@ -0,0 +1 @@ +{ "р\ \u \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/k/2kqfqq0x171fhs9f654mhmhzdam101sx78y1pg4xvzj2e b/implementation/fuzz/inputs-genvm-modules-complete-json/2/k/2kqfqq0x171fhs9f654mhmhzdam101sx78y1pg4xvzj2e new file mode 100644 index 00000000..8669055f --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/k/2kqfqq0x171fhs9f654mhmhzdam101sx78y1pg4xvzj2e @@ -0,0 +1 @@ + " \uDAbb" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/k/2ksxsdkrcj75gxj5bh515daqdr49gxas5gq4w3mne8fxe b/implementation/fuzz/inputs-genvm-modules-complete-json/2/k/2ksxsdkrcj75gxj5bh515daqdr49gxas5gq4w3mne8fxe new file mode 100644 index 00000000..5b06994e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/k/2ksxsdkrcj75gxj5bh515daqdr49gxas5gq4w3mne8fxe @@ -0,0 +1,2 @@ + +"р\\uba5R [[1, B\bõ r" diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/n/2n3jwfv96hh6722m749ghsxbesbbkgqgajvx8czn183fa b/implementation/fuzz/inputs-genvm-modules-complete-json/2/n/2n3jwfv96hh6722m749ghsxbesbbkgqgajvx8czn183fa new file mode 100644 index 00000000..3f33343f --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/n/2n3jwfv96hh6722m749ghsxbesbbkgqgajvx8czn183fa @@ -0,0 +1 @@ + "򀻃 сскڸʵ6букbbcbbbbb:bbb A A Bxbz" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/n/2n4t3zk62tgnhnhvqgzvfw352g9yy662b1fn2087cqc18 b/implementation/fuzz/inputs-genvm-modules-complete-json/2/n/2n4t3zk62tgnhnhvqgzvfw352g9yy662b1fn2087cqc18 new file mode 100644 index 00000000..0598260e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/n/2n4t3zk62tgnhnhvqgzvfw352g9yy662b1fn2087cqc18 @@ -0,0 +1 @@ + "Y󗥗111 у\u01bb: у\uabbb [," \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/p/2p0k398b7qp548psbch15wvnbqehqgkz4pf2gtj1tpb7m b/implementation/fuzz/inputs-genvm-modules-complete-json/2/p/2p0k398b7qp548psbch15wvnbqehqgkz4pf2gtj1tpb7m new file mode 100644 index 00000000..c43ac613 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/p/2p0k398b7qp548psbch15wvnbqehqgkz4pf2gtj1tpb7m @@ -0,0 +1 @@ +2222222222222222222222222 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/p/2pm3p5fxq3fpxt5g0j5tpje93fn9r6c4b4qz0zmfn1df2 b/implementation/fuzz/inputs-genvm-modules-complete-json/2/p/2pm3p5fxq3fpxt5g0j5tpje93fn9r6c4b4qz0zmfn1df2 new file mode 100644 index 00000000..20dcc940 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/p/2pm3p5fxq3fpxt5g0j5tpje93fn9r6c4b4qz0zmfn1df2 @@ -0,0 +1 @@ + [1, 2, 3] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/q/2q195hbtgbyx52kbb43mdbrmt6gzsc3693yd49g1j2jga b/implementation/fuzz/inputs-genvm-modules-complete-json/2/q/2q195hbtgbyx52kbb43mdbrmt6gzsc3693yd49g1j2jga new file mode 100644 index 00000000..d5ccd0ac --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/q/2q195hbtgbyx52kbb43mdbrmt6gzsc3693yd49g1j2jga @@ -0,0 +1 @@ + "р B\b" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/r/2rmtbeedk3mnayqb6z0dj77583dh0arvgz4456d2yp2wy b/implementation/fuzz/inputs-genvm-modules-complete-json/2/r/2rmtbeedk3mnayqb6z0dj77583dh0arvgz4456d2yp2wy new file mode 100644 index 00000000..632808b1 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/r/2rmtbeedk3mnayqb6z0dj77583dh0arvgz4456d2yp2wy @@ -0,0 +1 @@ +"UUUTmbbbbb00\\\\\\\\\\\\\\u0bbb\u0bbbb\\\\\\\\\\\\u0bbb\u0bbbbbb," diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/s/2s4as110gqppmf984s9600v742ztpwrbf4gkgkrayw2q0 b/implementation/fuzz/inputs-genvm-modules-complete-json/2/s/2s4as110gqppmf984s9600v742ztpwrbf4gkgkrayw2q0 new file mode 100644 index 00000000..f4976c44 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/s/2s4as110gqppmf984s9600v742ztpwrbf4gkgkrayw2q0 @@ -0,0 +1,3 @@ +{ + "1" : [ {} ] +} \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/t/2t0ftjj6197wjb7dqch5ammz2f5esnh0zrw4fh1vzk35e b/implementation/fuzz/inputs-genvm-modules-complete-json/2/t/2t0ftjj6197wjb7dqch5ammz2f5esnh0zrw4fh1vzk35e new file mode 100644 index 00000000..f32a5804 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/t/2t0ftjj6197wjb7dqch5ammz2f5esnh0zrw4fh1vzk35e @@ -0,0 +1 @@ +true \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/w/2wn6p7whcvzg482hfct6tzax39zggc7bt3qqxj393awqr b/implementation/fuzz/inputs-genvm-modules-complete-json/2/w/2wn6p7whcvzg482hfct6tzax39zggc7bt3qqxj393awqr new file mode 100644 index 00000000..07815a83 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/w/2wn6p7whcvzg482hfct6tzax39zggc7bt3qqxj393awqr @@ -0,0 +1,2 @@ + [0, null, + 1, 2, 3] diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/x/2xa502ckstahndqb4bqhxdwq7hzsxbw4a3dh9008n5grr b/implementation/fuzz/inputs-genvm-modules-complete-json/2/x/2xa502ckstahndqb4bqhxdwq7hzsxbw4a3dh9008n5grr new file mode 100644 index 00000000..7cbf9175 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/x/2xa502ckstahndqb4bqhxdwq7hzsxbw4a3dh9008n5grr @@ -0,0 +1,2 @@ + +"рb r" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/y/2ykbambjhke293td0wnyhmqnprz3dr3kckw2t81vdeq32 b/implementation/fuzz/inputs-genvm-modules-complete-json/2/y/2ykbambjhke293td0wnyhmqnprz3dr3kckw2t81vdeq32 new file mode 100644 index 0000000000000000000000000000000000000000..18bc64aafc080e266dd5ab7a93ead1199c776ad1 GIT binary patch literal 129 wcmb>CQUC&_wETP}D}`wM0IU>Q2}r9BcAyZe!v&KAvVj0i1ZWt8f`Xy~0I*ga-T(jq literal 0 HcmV?d00001 diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/z/2z3p4rpamny067vhq88ke789xdnyt23zn2ywjq7sbxy6p b/implementation/fuzz/inputs-genvm-modules-complete-json/2/z/2z3p4rpamny067vhq88ke789xdnyt23zn2ywjq7sbxy6p new file mode 100644 index 00000000..831ce971 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/z/2z3p4rpamny067vhq88ke789xdnyt23zn2ywjq7sbxy6p @@ -0,0 +1 @@ +111111111111111101111115 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/2/z/2zazarnhgndp91dxsf8m775r96x1hb59bpaa1942fe22p b/implementation/fuzz/inputs-genvm-modules-complete-json/2/z/2zazarnhgndp91dxsf8m775r96x1hb59bpaa1942fe22p new file mode 100644 index 00000000..82ce1f87 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/2/z/2zazarnhgndp91dxsf8m775r96x1hb59bpaa1942fe22p @@ -0,0 +1 @@ + " , B\r󗥗000 00000 , B\r󗥗000 000000\u0000 00000 , B\r󗥗000 00000000\u00000" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/0/30d131f7jpbsdzp0t3f3ry9shwecm2mbn3sfxqy4vxqrt b/implementation/fuzz/inputs-genvm-modules-complete-json/3/0/30d131f7jpbsdzp0t3f3ry9shwecm2mbn3sfxqy4vxqrt new file mode 100644 index 00000000..e84a8d7c --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/0/30d131f7jpbsdzp0t3f3ry9shwecm2mbn3sfxqy4vxqrt @@ -0,0 +1 @@ + "b750 " \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/0/30hhad75c83y5s8a6z9ftdbnnmatgktgsasr18av2cj36 b/implementation/fuzz/inputs-genvm-modules-complete-json/3/0/30hhad75c83y5s8a6z9ftdbnnmatgktgsasr18av2cj36 new file mode 100644 index 00000000..ecdbee94 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/0/30hhad75c83y5s8a6z9ftdbnnmatgktgsasr18av2cj36 @@ -0,0 +1,6 @@ + "р\\u ? 12" + + + + + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/2/325vkc6r7q84h3g63whr2hdc69chys6bafjqyr21vd556 b/implementation/fuzz/inputs-genvm-modules-complete-json/3/2/325vkc6r7q84h3g63whr2hdc69chys6bafjqyr21vd556 new file mode 100644 index 00000000..68163bd9 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/2/325vkc6r7q84h3g63whr2hdc69chys6bafjqyr21vd556 @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/2/32wc7343p2qsgg1vr2c8cfxf29rxjte6xaf1j3kqrthp2 b/implementation/fuzz/inputs-genvm-modules-complete-json/3/2/32wc7343p2qsgg1vr2c8cfxf29rxjte6xaf1j3kqrthp2 new file mode 100644 index 00000000..775c4a0f --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/2/32wc7343p2qsgg1vr2c8cfxf29rxjte6xaf1j3kqrthp2 @@ -0,0 +1,2 @@ +111111111111111111111e-777071111 + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/2/32zvz3ffjf0rsaayrf4drj4x6a87162a5dxa9x5gbyy40 b/implementation/fuzz/inputs-genvm-modules-complete-json/3/2/32zvz3ffjf0rsaayrf4drj4x6a87162a5dxa9x5gbyy40 new file mode 100644 index 00000000..297ee259 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/2/32zvz3ffjf0rsaayrf4drj4x6a87162a5dxa9x5gbyy40 @@ -0,0 +1,4 @@ +"f\\\\]\\\\@\\\\" + + + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/3/335qkpa6a6a55kg78v14wk3yyesena6v3304gw7mp792t b/implementation/fuzz/inputs-genvm-modules-complete-json/3/3/335qkpa6a6a55kg78v14wk3yyesena6v3304gw7mp792t new file mode 100644 index 00000000..4beeea30 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/3/335qkpa6a6a55kg78v14wk3yyesena6v3304gw7mp792t @@ -0,0 +1,7 @@ +1e-515 + + + + + + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/3/33ew3bbq8bsesg4jf189jf9ard8cnp9m4sxsxsb96q3fj b/implementation/fuzz/inputs-genvm-modules-complete-json/3/3/33ew3bbq8bsesg4jf189jf9ard8cnp9m4sxsxsb96q3fj new file mode 100644 index 00000000..9e071003 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/3/33ew3bbq8bsesg4jf189jf9ard8cnp9m4sxsxsb96q3fj @@ -0,0 +1,21 @@ +{ + "foo": [ + "bar", + "baz\n\\{", + 123, + -123, + -1e10, + 1e20, + null, + true, + false, + [1, 2, 3] + ], + "": [ ], + "mbb -barar": [ ], + "": [ ], + "bar": [ + "русские null,bbbbbbbbbbb", + "mbbbbbbbbbbbbbbaz\t\\uabbbbb" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/3/33qz17sfvejgr7dfczk6w4qbt77qwanv1307w4b8ja0ma b/implementation/fuzz/inputs-genvm-modules-complete-json/3/3/33qz17sfvejgr7dfczk6w4qbt77qwanv1307w4b8ja0ma new file mode 100644 index 00000000..05dce3c8 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/3/33qz17sfvejgr7dfczk6w4qbt77qwanv1307w4b8ja0ma @@ -0,0 +1 @@ +"\\泛" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/4/34j4w84w1cnqb7cr41p52saatagrqsxk8wj2ehhbpc7fw b/implementation/fuzz/inputs-genvm-modules-complete-json/3/4/34j4w84w1cnqb7cr41p52saatagrqsxk8wj2ehhbpc7fw new file mode 100644 index 0000000000000000000000000000000000000000..e2800224b0651e9e28ebf1ac1074b9948df0c1f3 GIT binary patch literal 127 wcmb>CQUC&_wETP}D}`wM0IU>Q2}r9B8c>MU;erW**idP7VFd*S1qDR~0C0L8WB>pF literal 0 HcmV?d00001 diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/5/35237jnwf7qj4e3jy7dngv203sb8da6za3tmdtaz8m71y b/implementation/fuzz/inputs-genvm-modules-complete-json/3/5/35237jnwf7qj4e3jy7dngv203sb8da6za3tmdtaz8m71y new file mode 100644 index 00000000..5d2b9651 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/5/35237jnwf7qj4e3jy7dngv203sb8da6za3tmdtaz8m71y @@ -0,0 +1,5 @@ +{ + "foo" + + + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/5/35wd5p3vpd27tw2r15btrpq06gt1b708brb74z1z6k5f8 b/implementation/fuzz/inputs-genvm-modules-complete-json/3/5/35wd5p3vpd27tw2r15btrpq06gt1b708brb74z1z6k5f8 new file mode 100644 index 00000000..b1514891 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/5/35wd5p3vpd27tw2r15btrpq06gt1b708brb74z1z6k5f8 @@ -0,0 +1 @@ +"]" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/6/36qhwstm4ezxvnsem3n9rkbwe5971cq5r9eyvt51n1ca4 b/implementation/fuzz/inputs-genvm-modules-complete-json/3/6/36qhwstm4ezxvnsem3n9rkbwe5971cq5r9eyvt51n1ca4 new file mode 100644 index 00000000..39e6a263 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/6/36qhwstm4ezxvnsem3n9rkbwe5971cq5r9eyvt51n1ca4 @@ -0,0 +1,2 @@ + [[ + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/7/37223ehxrzsjx4h98n1t8tzxdeez2q54n4ghv7y87h99y b/implementation/fuzz/inputs-genvm-modules-complete-json/3/7/37223ehxrzsjx4h98n1t8tzxdeez2q54n4ghv7y87h99y new file mode 100644 index 00000000..d1ae23d0 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/7/37223ehxrzsjx4h98n1t8tzxdeez2q54n4ghv7y87h99y @@ -0,0 +1,3 @@ +[[[[[[[[[[[[[[[[[ + + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/7/37epan24avchbwj139h8gwrgrn168hpdn6wctp4w3kvnw b/implementation/fuzz/inputs-genvm-modules-complete-json/3/7/37epan24avchbwj139h8gwrgrn168hpdn6wctp4w3kvnw new file mode 100644 index 00000000..bcdb0d9e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/7/37epan24avchbwj139h8gwrgrn168hpdn6wctp4w3kvnw @@ -0,0 +1,2 @@ + +"рbbbbQbb
 r" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/8/38t9f41n2ynf9n1r6yq9wv9h9zygjpz50ghzy7qzfxb4e b/implementation/fuzz/inputs-genvm-modules-complete-json/3/8/38t9f41n2ynf9n1r6yq9wv9h9zygjpz50ghzy7qzfxb4e new file mode 100644 index 00000000..0332bd79 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/8/38t9f41n2ynf9n1r6yq9wv9h9zygjpz50ghzy7qzfxb4e @@ -0,0 +1 @@ +"󗥺ubb [1" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/9/39jhye51bpxdznqxjc3n7txbqtdxw8tk999evs6pe6pty b/implementation/fuzz/inputs-genvm-modules-complete-json/3/9/39jhye51bpxdznqxjc3n7txbqtdxw8tk999evs6pe6pty new file mode 100644 index 00000000..8622d77c --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/9/39jhye51bpxdznqxjc3n7txbqtdxw8tk999evs6pe6pty @@ -0,0 +1,13 @@ +{ + "foo": [ + "bar", + "baz\n\\z", 1e20, + null, + true, [1, 2, 3] + ], + "ba\\uabbbbbr": [ + "русскиеCбуквы 日本", + "mbbbbbbbbbbbbbbaz\t\uabbbbb", + "mbbbbbbbbbbbbbbaz\t\\uabbbbb" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/b/3b5snsywt1yg9608yk9dtkzcsw8j226873xmgrbtx5e2w b/implementation/fuzz/inputs-genvm-modules-complete-json/3/b/3b5snsywt1yg9608yk9dtkzcsw8j226873xmgrbtx5e2w new file mode 100644 index 00000000..365702a1 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/b/3b5snsywt1yg9608yk9dtkzcsw8j226873xmgrbtx5e2w @@ -0,0 +1,7 @@ + "р750 UwUoU󗥣󗥹2" + + + + + + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/b/3bc93yvqp1d1zes49sk9vwyf8enqcmkfectpyjg700p5r b/implementation/fuzz/inputs-genvm-modules-complete-json/3/b/3bc93yvqp1d1zes49sk9vwyf8enqcmkfectpyjg700p5r new file mode 100644 index 00000000..a5804c8d --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/b/3bc93yvqp1d1zes49sk9vwyf8enqcmkfectpyjg700p5r @@ -0,0 +1 @@ + "с  ! e111@eC@1bz" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/c/3cv357mm22rrbcdb29bv4883ajrnye3p05wh3p4e9vvde b/implementation/fuzz/inputs-genvm-modules-complete-json/3/c/3cv357mm22rrbcdb29bv4883ajrnye3p05wh3p4e9vvde new file mode 100644 index 00000000..883359d0 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/c/3cv357mm22rrbcdb29bv4883ajrnye3p05wh3p4e9vvde @@ -0,0 +1,29 @@ +222222222922222222222E+2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/d/3dygjt8z5jp6gss3nfv19ht36jhan7xc4x46dh9wxxb14 b/implementation/fuzz/inputs-genvm-modules-complete-json/3/d/3dygjt8z5jp6gss3nfv19ht36jhan7xc4x46dh9wxxb14 new file mode 100644 index 00000000..7006372f --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/d/3dygjt8z5jp6gss3nfv19ht36jhan7xc4x46dh9wxxb14 @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + " \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/e/3ejnm2369k6hgrghespqr1pe0qdxrwv8yqrwjpevdvk68 b/implementation/fuzz/inputs-genvm-modules-complete-json/3/e/3ejnm2369k6hgrghespqr1pe0qdxrwv8yqrwjpevdvk68 new file mode 100644 index 00000000..671d029f --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/e/3ejnm2369k6hgrghespqr1pe0qdxrwv8yqrwjpevdvk68 @@ -0,0 +1,16 @@ +{ + "foo": [ + "bar", + "baz\n\\{", + -1e10, + 1e20, + null, + true, + [1, 2, 3] + ], "barrrrrrrrrr": [ ], + "brrrr": [ ], + "bar": [ + "русские mbbbbbbbbb", + "mbbbbbbbbbbbbbbaz\t\\uabbbbb" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/g/3gtdrvgpzq462t4wsnd5k20xxfvpwckw3b1gg9077ey4t b/implementation/fuzz/inputs-genvm-modules-complete-json/3/g/3gtdrvgpzq462t4wsnd5k20xxfvpwckw3b1gg9077ey4t new file mode 100644 index 00000000..7ae10e20 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/g/3gtdrvgpzq462t4wsnd5k20xxfvpwckw3b1gg9077ey4t @@ -0,0 +1,2 @@ +{ + "foo": [[[[[[[[[[[[[[[[[[ "bar", [[[[[[ "bar", 333333333333333333333333333333.3 [ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/h/3htw69mppz8dkd8kkysh4gc00j3021v0zv38sy6nhq02p b/implementation/fuzz/inputs-genvm-modules-complete-json/3/h/3htw69mppz8dkd8kkysh4gc00j3021v0zv38sy6nhq02p new file mode 100644 index 00000000..cfb918ef --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/h/3htw69mppz8dkd8kkysh4gc00j3021v0zv38sy6nhq02p @@ -0,0 +1,3 @@ +"f\\t\\uabbf\\t\\uabbbb" + + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/j/3jep0893yw33esbfnsx3vtpn03jw2f2kav5261w8tk8fj b/implementation/fuzz/inputs-genvm-modules-complete-json/3/j/3jep0893yw33esbfnsx3vtpn03jw2f2kav5261w8tk8fj new file mode 100644 index 00000000..83df38e6 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/j/3jep0893yw33esbfnsx3vtpn03jw2f2kav5261w8tk8fj @@ -0,0 +1 @@ +2522222222222111111111e \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/k/3kbz0gcyv9ydzwdszy7q1c4ktka3rfn4d8pk9e4318etr b/implementation/fuzz/inputs-genvm-modules-complete-json/3/k/3kbz0gcyv9ydzwdszy7q1c4ktka3rfn4d8pk9e4318etr new file mode 100644 index 00000000..e36060f1 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/k/3kbz0gcyv9ydzwdszy7q1c4ktka3rfn4d8pk9e4318etr @@ -0,0 +1,10 @@ +[[[[[[[[ + + +3, [[[[[[[[[[[[[[[[[ + + +3, [[[[[[[[ + + +3, ]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]][[ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/k/3kv8nxj26hfm5ez2vrp38j59q0rpgvxffcvd8x0vme6n4 b/implementation/fuzz/inputs-genvm-modules-complete-json/3/k/3kv8nxj26hfm5ez2vrp38j59q0rpgvxffcvd8x0vme6n4 new file mode 100644 index 00000000..d1543335 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/k/3kv8nxj26hfm5ez2vrp38j59q0rpgvxffcvd8x0vme6n4 @@ -0,0 +1,4 @@ + [111, +true, + false, + 111] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/m/3mdxxf03629wvddwgvezn1r428tykhd7spzdd5hn2fcmm b/implementation/fuzz/inputs-genvm-modules-complete-json/3/m/3mdxxf03629wvddwgvezn1r428tykhd7spzdd5hn2fcmm new file mode 100644 index 00000000..303e55ee --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/m/3mdxxf03629wvddwgvezn1r428tykhd7spzdd5hn2fcmm @@ -0,0 +1,22 @@ +{ + "foo": [ + "bar", + "baz\n\\z", + 123, + -123, + -1e10, + 1e20, + null, + true, + false, + [1, 2, 3] + ], + "bar": [ + "русские буквы 日本", + "mbbbbbbbb}bbbbbaz\t\uabbbbb", + "mbbbbbbbbbbbbbbaz\t\\uabbbbb" + + ], + "bar": [ + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/q/3qbv6wqxrtgkh6rbsmf4n7ta1xyndvfaedd6rbk08peap b/implementation/fuzz/inputs-genvm-modules-complete-json/3/q/3qbv6wqxrtgkh6rbsmf4n7ta1xyndvfaedd6rbk08peap new file mode 100644 index 00000000..385b2caa --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/q/3qbv6wqxrtgkh6rbsmf4n7ta1xyndvfaedd6rbk08peap @@ -0,0 +1 @@ + "򀻃 B Bxbz" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/q/3qtfgm5c9jtkw8ae8gwh01s6tkk18my2ag0y7epc1ckd2 b/implementation/fuzz/inputs-genvm-modules-complete-json/3/q/3qtfgm5c9jtkw8ae8gwh01s6tkk18my2ag0y7epc1ckd2 new file mode 100644 index 00000000..2974771b --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/q/3qtfgm5c9jtkw8ae8gwh01s6tkk18my2ag0y7epc1ckd2 @@ -0,0 +1 @@ +"bbbbbIbbbڲы 日1 qo" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/r/3r1fn4qcz970rxcapmbg7axet37yk0c30pden7zfnbrcp b/implementation/fuzz/inputs-genvm-modules-complete-json/3/r/3r1fn4qcz970rxcapmbg7axet37yk0c30pden7zfnbrcp new file mode 100644 index 00000000..7f922eb6 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/r/3r1fn4qcz970rxcapmbg7axet37yk0c30pden7zfnbrcp @@ -0,0 +1 @@ + "\b󗥬" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/t/3tx2a7qvwfc8df5hzpjcyhkc65hvjwfk4b9v649x59n46 b/implementation/fuzz/inputs-genvm-modules-complete-json/3/t/3tx2a7qvwfc8df5hzpjcyhkc65hvjwfk4b9v649x59n46 new file mode 100644 index 00000000..ebc2c46d --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/t/3tx2a7qvwfc8df5hzpjcyhkc65hvjwfk4b9v649x59n46 @@ -0,0 +1 @@ + "\b󗥗Z󗥗1 " \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/w/3w7w2k51qnmw7z4j79g0dngx0x3xv81fqx11rmktjvd5w b/implementation/fuzz/inputs-genvm-modules-complete-json/3/w/3w7w2k51qnmw7z4j79g0dngx0x3xv81fqx11rmktjvd5w new file mode 100644 index 00000000..309d3e2a --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/w/3w7w2k51qnmw7z4j79g0dngx0x3xv81fqx11rmktjvd5w @@ -0,0 +1 @@ +nu \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/3/z/3zrna3xrtgxct2en27tz1pb3v7dvtt5qh2fynhyvmhwew b/implementation/fuzz/inputs-genvm-modules-complete-json/3/z/3zrna3xrtgxct2en27tz1pb3v7dvtt5qh2fynhyvmhwew new file mode 100644 index 00000000..371cab64 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/3/z/3zrna3xrtgxct2en27tz1pb3v7dvtt5qh2fynhyvmhwew @@ -0,0 +1,4 @@ +{ + "foo": [ + [[[[[[[[": [ +111111 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/0/4039y0m4gwtzm6ybeecvxq6d297w7h1h3zwfpqeqwejp6 b/implementation/fuzz/inputs-genvm-modules-complete-json/4/0/4039y0m4gwtzm6ybeecvxq6d297w7h1h3zwfpqeqwejp6 new file mode 100644 index 00000000..a3d2a4fd --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/0/4039y0m4gwtzm6ybeecvxq6d297w7h1h3zwfpqeqwejp6 @@ -0,0 +1 @@ +[[[[[,,,, \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/2/42ckpme1rg6chpv2jg81r2mp6a1pqeb7jnpxkrj1zvvz0 b/implementation/fuzz/inputs-genvm-modules-complete-json/4/2/42ckpme1rg6chpv2jg81r2mp6a1pqeb7jnpxkrj1zvvz0 new file mode 100644 index 00000000..c98d8a65 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/2/42ckpme1rg6chpv2jg81r2mp6a1pqeb7jnpxkrj1zvvz0 @@ -0,0 +1,18 @@ +{ + "foo": [ + "bar", + "baz\n\\{", + 123, + -123, + -1e10, + 1e20, + null, + true, + false,2222222222222222222.2 ], + "bar": [ ], + "bar": [ + "русские b UUUUUUUUUU\n\\zUбуквЇ 日本", + "mbbbbbbbbbbbbbbaz\t\uabbbbb", + "mbbbbbbbbbbbbbbaz\t\\uabbbbb" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/2/42txhvm8f01c4cdcaymqg3nmjsbc91sxz2xryj3nmng3a b/implementation/fuzz/inputs-genvm-modules-complete-json/4/2/42txhvm8f01c4cdcaymqg3nmjsbc91sxz2xryj3nmng3a new file mode 100644 index 00000000..ec882fff --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/2/42txhvm8f01c4cdcaymqg3nmjsbc91sxz2xryj3nmng3a @@ -0,0 +1 @@ + "bbbbaz\tс\\fffffffffffffffZffffffffffffffffffffffffffffffffffffffffffffaTba\/:fffffffffffffffffffabba\/:fffffffabba\/: [bb [b333" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/4/44nkn4y353ss52zenyq9e8gr7vcarz4y36dtff3nd9af8 b/implementation/fuzz/inputs-genvm-modules-complete-json/4/4/44nkn4y353ss52zenyq9e8gr7vcarz4y36dtff3nd9af8 new file mode 100644 index 00000000..f04a39a3 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/4/44nkn4y353ss52zenyq9e8gr7vcarz4y36dtff3nd9af8 @@ -0,0 +1,9 @@ +{ + "foo":{ + "fTo":{ "foL":{ + "foo":{ + "foo":{ + "foo":{ "foL":{ + "fo "fo{ + "foo":{ "foL":{ + " "fo \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/5/454pdwe2qc8f6ck1zfkd4czrtxzbgf92qywfftqgxjhr0 b/implementation/fuzz/inputs-genvm-modules-complete-json/4/5/454pdwe2qc8f6ck1zfkd4czrtxzbgf92qywfftqgxjhr0 new file mode 100644 index 00000000..8a2b2f0f --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/5/454pdwe2qc8f6ck1zfkd4czrtxzbgf92qywfftqgxjhr0 @@ -0,0 +1 @@ +true \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/6/46hzz84st57awtf74kqg6x1ph1nc1b550hxnn8ky5e46p b/implementation/fuzz/inputs-genvm-modules-complete-json/4/6/46hzz84st57awtf74kqg6x1ph1nc1b550hxnn8ky5e46p new file mode 100644 index 00000000..7efeed6c --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/6/46hzz84st57awtf74kqg6x1ph1nc1b550hxnn8ky5e46p @@ -0,0 +1,3 @@ +{ "o, + +} \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/6/46s556f8ke1g4dtjahxs94mzecqzw1n3twh8m9vtxdk5c b/implementation/fuzz/inputs-genvm-modules-complete-json/4/6/46s556f8ke1g4dtjahxs94mzecqzw1n3twh8m9vtxdk5c new file mode 100644 index 00000000..d8898001 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/6/46s556f8ke1g4dtjahxs94mzecqzw1n3twh8m9vtxdk5c @@ -0,0 +1 @@ + [[1, $ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/7/47a21mjw0h89fdx7t27e856cxrbv2ahsh3xybqjfqrq36 b/implementation/fuzz/inputs-genvm-modules-complete-json/4/7/47a21mjw0h89fdx7t27e856cxrbv2ahsh3xybqjfqrq36 new file mode 100644 index 00000000..a082b719 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/7/47a21mjw0h89fdx7t27e856cxrbv2ahsh3xybqjfqrq36 @@ -0,0 +1,2 @@ + +"рjᛨ -1e 6 1111p" diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/7/47aenj50bwcb52ts5me0mptej88cabpzew64b22ncw82m b/implementation/fuzz/inputs-genvm-modules-complete-json/4/7/47aenj50bwcb52ts5me0mptej88cabpzew64b22ncw82m new file mode 100644 index 00000000..0f9c7bb4 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/7/47aenj50bwcb52ts5me0mptej88cabpzew64b22ncw82m @@ -0,0 +1 @@ +"u`b\nH" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/7/47zdxfswt8ax6ccwdq71k2wzyr2pv2sd7hcpcb3yes5rm b/implementation/fuzz/inputs-genvm-modules-complete-json/4/7/47zdxfswt8ax6ccwdq71k2wzyr2pv2sd7hcpcb3yes5rm new file mode 100644 index 00000000..37490b57 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/7/47zdxfswt8ax6ccwdq71k2wzyr2pv2sd7hcpcb3yes5rm @@ -0,0 +1,2 @@ +"\r" + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/8/483rdf9z0bqhr2s4f0s7yw5gawhafpd26csq0xrn78ehe b/implementation/fuzz/inputs-genvm-modules-complete-json/4/8/483rdf9z0bqhr2s4f0s7yw5gawhafpd26csq0xrn78ehe new file mode 100644 index 00000000..696462c1 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/8/483rdf9z0bqhr2s4f0s7yw5gawhafpd26csq0xrn78ehe @@ -0,0 +1,2 @@ +55555555555555555555555552 + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/8/488m98q123vvxhqx0aagr7fptytjjm2sesvzstq7vnjd4 b/implementation/fuzz/inputs-genvm-modules-complete-json/4/8/488m98q123vvxhqx0aagr7fptytjjm2sesvzstq7vnjd4 new file mode 100644 index 00000000..ab205500 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/8/488m98q123vvxhqx0aagr7fptytjjm2sesvzstq7vnjd4 @@ -0,0 +1,2 @@ + +"фjᛨ7рjᛨ750 1\uDbbb\uDc12.50 1=uDbbb^uDc12.1111111111pрjᛨ750 1\uDbbb\uDc12.11" diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/9/49076gsq2b7p3hqv2h0fssazfg0mbppj9hr8yxyhbykwg b/implementation/fuzz/inputs-genvm-modules-complete-json/4/9/49076gsq2b7p3hqv2h0fssazfg0mbppj9hr8yxyhbykwg new file mode 100644 index 00000000..f3629c7a --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/9/49076gsq2b7p3hqv2h0fssazfg0mbppj9hr8yxyhbykwg @@ -0,0 +1,8 @@ +{ + "foo": [ + "bar", + "bazdn\\z", + 123, + + null, + -123, "222 -1e [[[[[[[[ [[[[ v ]]\]]]]]]]]] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/9/49438ym1f018m8ctq0gbb06cgkamh1yb5yhztnt2sbgwm b/implementation/fuzz/inputs-genvm-modules-complete-json/4/9/49438ym1f018m8ctq0gbb06cgkamh1yb5yhztnt2sbgwm new file mode 100644 index 00000000..9ceb43ce --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/9/49438ym1f018m8ctq0gbb06cgkamh1yb5yhztnt2sbgwm @@ -0,0 +1,2 @@ + +"р\\uba5R [1,[ B\bõ r" diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/e/4e6m73vd7pqnte9f4dmahm7eddc8n3nb78hf0f9d14b9j b/implementation/fuzz/inputs-genvm-modules-complete-json/4/e/4e6m73vd7pqnte9f4dmahm7eddc8n3nb78hf0f9d14b9j new file mode 100644 index 00000000..79722980 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/e/4e6m73vd7pqnte9f4dmahm7eddc8n3nb78hf0f9d14b9j @@ -0,0 +1 @@ +" \uDbbb\uD \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/f/4f82mbvdzrxewmjfyk3g5xg07xn8j49tc92n845861rty b/implementation/fuzz/inputs-genvm-modules-complete-json/4/f/4f82mbvdzrxewmjfyk3g5xg07xn8j49tc92n845861rty new file mode 100644 index 00000000..2117d3df --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/f/4f82mbvdzrxewmjfyk3g5xg07xn8j49tc92n845861rty @@ -0,0 +1 @@ +1111555555555111111111111111e-522222 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/b82254c422c4a0de4fde9cf66488007a6f787d972f1ff42a8f0d3a07204fdaff b/implementation/fuzz/inputs-genvm-modules-complete-json/4/g/4g0fnmrht3baacq1spykfq06esnj3smp0rd5e7jp79eyc similarity index 50% rename from implementation/fuzz/inputs-genvm-modules-normalize-whitespace/b82254c422c4a0de4fde9cf66488007a6f787d972f1ff42a8f0d3a07204fdaff rename to implementation/fuzz/inputs-genvm-modules-complete-json/4/g/4g0fnmrht3baacq1spykfq06esnj3smp0rd5e7jp79eyc index e45ec267dfee16f0f6e2acde04fdb36ea6e01978..7149a86e786efbe357d3136d69e0982d78051b67 100644 GIT binary patch literal 35 McmY#V;vxVP03S^Or2qf` literal 48 icmZQzU|`@<;erE2MP4xAQBX($3n~D)JiI)DP!#|`e*(w= diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/h/4hn2107rfefkdjabs9rhdsw49zx8y2gx8p2c0qgt21926 b/implementation/fuzz/inputs-genvm-modules-complete-json/4/h/4hn2107rfefkdjabs9rhdsw49zx8y2gx8p2c0qgt21926 new file mode 100644 index 00000000..c93ce603 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/h/4hn2107rfefkdjabs9rhdsw49zx8y2gx8p2c0qgt21926 @@ -0,0 +1 @@ +"ркa [1," \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/p/4pr8k38eg2vs9bccsw8mnjcnx5te4y1g11rgme8h3gybg b/implementation/fuzz/inputs-genvm-modules-complete-json/4/p/4pr8k38eg2vs9bccsw8mnjcnx5te4y1g11rgme8h3gybg new file mode 100644 index 00000000..1b4bb28e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/p/4pr8k38eg2vs9bccsw8mnjcnx5te4y1g11rgme8h3gybg @@ -0,0 +1,4 @@ +{ + "foo": [ + ], + "bar" a \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/p/4pyjs7hxbkmv5bb8nk2ey2d0wjx8k82f81c6768pc92ge b/implementation/fuzz/inputs-genvm-modules-complete-json/4/p/4pyjs7hxbkmv5bb8nk2ey2d0wjx8k82f81c6768pc92ge new file mode 100644 index 00000000..ab3e6631 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/p/4pyjs7hxbkmv5bb8nk2ey2d0wjx8k82f81c6768pc92ge @@ -0,0 +1 @@ + "b󗸗50 UwIoU󗭣" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/q/4qp2afa7b9e3hmb9et592k41sh0f15patxjf2v5y5ax28 b/implementation/fuzz/inputs-genvm-modules-complete-json/4/q/4qp2afa7b9e3hmb9et592k41sh0f15patxjf2v5y5ax28 new file mode 100644 index 00000000..666e9d2b --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/q/4qp2afa7b9e3hmb9et592k41sh0f15patxjf2v5y5ax28 @@ -0,0 +1 @@ + [1, , \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/q/4qqkbm0kf3s0n4adszk893w6w8wnyjvf1e76ye91gg6tw b/implementation/fuzz/inputs-genvm-modules-complete-json/4/q/4qqkbm0kf3s0n4adszk893w6w8wnyjvf1e76ye91gg6tw new file mode 100644 index 00000000..03e19810 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/q/4qqkbm0kf3s0n4adszk893w6w8wnyjvf1e76ye91gg6tw @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[[[[[ [[[[[[[[[[[[[ [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[w[ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/r/4rd4fhxdd75yrzwqrt2e1e9wewtthq7qdsxqqdng0b060 b/implementation/fuzz/inputs-genvm-modules-complete-json/4/r/4rd4fhxdd75yrzwqrt2e1e9wewtthq7qdsxqqdng0b060 new file mode 100644 index 00000000..52d8cd2f --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/r/4rd4fhxdd75yrzwqrt2e1e9wewtthq7qdsxqqdng0b060 @@ -0,0 +1,2 @@ + + "\"\"n" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/r/4rshs07vxp9p01tfz7pvd0jraxfs0jee1nw0cwkehxx94 b/implementation/fuzz/inputs-genvm-modules-complete-json/4/r/4rshs07vxp9p01tfz7pvd0jraxfs0jee1nw0cwkehxx94 new file mode 100644 index 00000000..207fbfb3 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/r/4rshs07vxp9p01tfz7pvd0jraxfs0jee1nw0cwkehxx94 @@ -0,0 +1,2 @@ +22222223222222222222222222.22222222E+2 + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/4/w/4wey7y6s511635spzptgtg0zhbcsa537xqby99h0nv250 b/implementation/fuzz/inputs-genvm-modules-complete-json/4/w/4wey7y6s511635spzptgtg0zhbcsa537xqby99h0nv250 new file mode 100644 index 00000000..a7f9700d --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/4/w/4wey7y6s511635spzptgtg0zhbcsa537xqby99h0nv250 @@ -0,0 +1 @@ +222222333333333333333333332E+21 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/0/50sf3sj3zza00020bnq6r03axvz1vksraj1573jebfd6g b/implementation/fuzz/inputs-genvm-modules-complete-json/5/0/50sf3sj3zza00020bnq6r03axvz1vksraj1573jebfd6g new file mode 100644 index 00000000..083012d3 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/0/50sf3sj3zza00020bnq6r03axvz1vksraj1573jebfd6g @@ -0,0 +1,17 @@ +{ + "foo": [ + "bar", + "baz\n\\{", + -1e10, + 1e20, + null, + true, + [1, 2, 3] + ], + "barrrrrrrrrr": [ ], + "brrrr": [ ], + "bar": [ + "Հусские mbbbbZZZZZZZZZZZZZZZZZZZZZZZZZZbbbbb", + "bbbw" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/1/511bbrs4vynrjpt7pmjj4897n9mfpbe50b7rwn7x9pgk2 b/implementation/fuzz/inputs-genvm-modules-complete-json/5/1/511bbrs4vynrjpt7pmjj4897n9mfpbe50b7rwn7x9pgk2 new file mode 100644 index 00000000..2a49e5ee --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/1/511bbrs4vynrjpt7pmjj4897n9mfpbe50b7rwn7x9pgk2 @@ -0,0 +1,2 @@ + + "\/'''3''''H'''''''" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/1/51dz1xs6nywx9v858m9bnd8ast8y973mrmt6s2kgtp9we b/implementation/fuzz/inputs-genvm-modules-complete-json/5/1/51dz1xs6nywx9v858m9bnd8ast8y973mrmt6s2kgtp9we new file mode 100644 index 00000000..e16ae2da --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/1/51dz1xs6nywx9v858m9bnd8ast8y973mrmt6s2kgtp9we @@ -0,0 +1 @@ +611e-5221111511 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/2/521ask5rah2rmhtk8w53w5dvfptr9anhetwce58yktk1e b/implementation/fuzz/inputs-genvm-modules-complete-json/5/2/521ask5rah2rmhtk8w53w5dvfptr9anhetwce58yktk1e new file mode 100644 index 00000000..b0f2f550 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/2/521ask5rah2rmhtk8w53w5dvfptr9anhetwce58yktk1e @@ -0,0 +1 @@ + [[1, 21, 2, "ркu[1\\\\буф\f\\\\\\\\\\\\\\с Aqbz\\\\\\\\\\\\\\\\\\\\\\\\\\\bbbе бурbbbbIbb※ 4/[\/[rф\\\\\\\\\\\\\\\\с Bqbz" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/3/53nstbc50pvj2vw2nave0q2ry661kggrh2xrzfbnabzeg b/implementation/fuzz/inputs-genvm-modules-complete-json/5/3/53nstbc50pvj2vw2nave0q2ry661kggrh2xrzfbnabzeg new file mode 100644 index 00000000..ec3b7ad8 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/3/53nstbc50pvj2vw2nave0q2ry661kggrh2xrzfbnabzeg @@ -0,0 +1,2 @@ +{ + "foo": [[[[[[[[[[[[[[[[[123, [[[[[[[[[[[[[[[[[123, [[[[[[[[[[[[[[[[[[[[[[123, "ba23, [[[[[[[[[[r ------[ 1911111111 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/5/5532hjx36v13jedse38grc2h9jcqcrq3panpry2b2cq5p b/implementation/fuzz/inputs-genvm-modules-complete-json/5/5/5532hjx36v13jedse38grc2h9jcqcrq3panpry2b2cq5p new file mode 100644 index 00000000..0b07b320 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/5/5532hjx36v13jedse38grc2h9jcqcrq3panpry2b2cq5p @@ -0,0 +1 @@ +0e5555555515 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/5/55pm4s9k7pjvttjg3vmhhwkvgtp5rt9rren3884mtychm b/implementation/fuzz/inputs-genvm-modules-complete-json/5/5/55pm4s9k7pjvttjg3vmhhwkvgtp5rt9rren3884mtychm new file mode 100644 index 00000000..7628e8ca --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/5/55pm4s9k7pjvttjg3vmhhwkvgtp5rt9rren3884mtychm @@ -0,0 +1 @@ + "Y󗥗[," \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/5/55y8fgk28sjsw9kc4ct5vaw0nscda5yjqb3wxn81bjdpj b/implementation/fuzz/inputs-genvm-modules-complete-json/5/5/55y8fgk28sjsw9kc4ct5vaw0nscda5yjqb3wxn81bjdpj new file mode 100644 index 00000000..9c3306ba --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/5/55y8fgk28sjsw9kc4ct5vaw0nscda5yjqb3wxn81bjdpj @@ -0,0 +1 @@ +33333333333331111111111e-11133331133333 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/7/57h0p1x6sm52v6sgcw3k06afpbfxmb9d3xhzjretpzxhy b/implementation/fuzz/inputs-genvm-modules-complete-json/5/7/57h0p1x6sm52v6sgcw3k06afpbfxmb9d3xhzjretpzxhy new file mode 100644 index 00000000..2339d8b0 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/7/57h0p1x6sm52v6sgcw3k06afpbfxmb9d3xhzjretpzxhy @@ -0,0 +1 @@ + ",旤bb `B\b󗥗" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/7/57q7gt19ynvbezapg0t7ercqeqbyetjdb4h3f7xy7s28y b/implementation/fuzz/inputs-genvm-modules-complete-json/5/7/57q7gt19ynvbezapg0t7ercqeqbyetjdb4h3f7xy7s28y new file mode 100644 index 00000000..f10725b2 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/7/57q7gt19ynvbezapg0t7ercqeqbyetjdb4h3f7xy7s28y @@ -0,0 +1 @@ + [1.11111111111111111111111111111111111111111111111111] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/7/57x0e8msvtg6fh2rgj738kh0zrmsnr65xhp8sknvdaf0g b/implementation/fuzz/inputs-genvm-modules-complete-json/5/7/57x0e8msvtg6fh2rgj738kh0zrmsnr65xhp8sknvdaf0g new file mode 100644 index 00000000..d8a5a36d --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/7/57x0e8msvtg6fh2rgj738kh0zrmsnr65xhp8sknvdaf0g @@ -0,0 +1,20 @@ +{ + "foo": [ + "bar" + ], + "babbbbbbbbbbb\b󗥗[8bbaz\t\\r": [ + 123, + -123, + -1e10, + 1e20, + null, + true, + false, + [1, 2, 3] + ], + "bar": [ + "русские буквы 日本", + "mbbbbbbbbbbbbbbaz\t\uabbbbb", + "mbbbbbbbbbbbbbbaz\t\\uabbbbb" + ] +} \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/8/58s6jqed3mz3m6eaqe529dqf6qrbr9pzx13mer6gwwnvy b/implementation/fuzz/inputs-genvm-modules-complete-json/5/8/58s6jqed3mz3m6eaqe529dqf6qrbr9pzx13mer6gwwnvy new file mode 100644 index 00000000..20fc751c --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/8/58s6jqed3mz3m6eaqe529dqf6qrbr9pzx13mer6gwwnvy @@ -0,0 +1 @@ +[ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/a/5a982thpv82fgbs86s3dtzsz5wnxt0yqz4dvhhwz3r1ye b/implementation/fuzz/inputs-genvm-modules-complete-json/5/a/5a982thpv82fgbs86s3dtzsz5wnxt0yqz4dvhhwz3r1ye new file mode 100644 index 00000000..ee5d6290 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/a/5a982thpv82fgbs86s3dtzsz5wnxt0yqz4dvhhwz3r1ye @@ -0,0 +1 @@ +"󗥺ubb" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/b/5ba7bygx5f8z6r1s2a2519a6c625ytcfwmz4q9nt641qr b/implementation/fuzz/inputs-genvm-modules-complete-json/5/b/5ba7bygx5f8z6r1s2a2519a6c625ytcfwmz4q9nt641qr new file mode 100644 index 00000000..665f3214 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/b/5ba7bygx5f8z6r1s2a2519a6c625ytcfwmz4q9nt641qr @@ -0,0 +1,3 @@ +222229222222222222222222222 + + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/c/5ckz0981gspjax26nkh652wc7tcb54w7fy5csjms0d66e b/implementation/fuzz/inputs-genvm-modules-complete-json/5/c/5ckz0981gspjax26nkh652wc7tcb54w7fy5csjms0d66e new file mode 100644 index 00000000..d9d40020 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/c/5ckz0981gspjax26nkh652wc7tcb54w7fy5csjms0d66e @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/h/5h2g0chm9b3g0gtyv3vwa5125zj6h9wpewa1d9ttasjcc b/implementation/fuzz/inputs-genvm-modules-complete-json/5/h/5h2g0chm9b3g0gtyv3vwa5125zj6h9wpewa1d9ttasjcc new file mode 100644 index 00000000..f7d38d12 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/h/5h2g0chm9b3g0gtyv3vwa5125zj6h9wpewa1d9ttasjcc @@ -0,0 +1,3 @@ +{ + "foo": + true, [[е Х本 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/h/5h3sncn3nmnesyx8kpmqmvfkvkj44xzebssp7xnczq6hr b/implementation/fuzz/inputs-genvm-modules-complete-json/5/h/5h3sncn3nmnesyx8kpmqmvfkvkj44xzebssp7xnczq6hr new file mode 100644 index 00000000..f06f2512 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/h/5h3sncn3nmnesyx8kpmqmvfkvkj44xzebssp7xnczq6hr @@ -0,0 +1 @@ +6611e-5221111511 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/j/5j5yksckw2vp4xrca0xy5xnsa8sy9ytjw2wt1zhhndx36 b/implementation/fuzz/inputs-genvm-modules-complete-json/5/j/5j5yksckw2vp4xrca0xy5xnsa8sy9ytjw2wt1zhhndx36 new file mode 100644 index 0000000000000000000000000000000000000000..e17ee0bfba3707ccd41e91f3ab85c2e42eaf9c03 GIT binary patch literal 32 Xcmb>CQUC%aB`bw$5DS$dz@PvCTEzub literal 0 HcmV?d00001 diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/k/5ksca34p8jvyyv4r4t9aq8fqz0wyr6c5w6a5j1cns3wtj b/implementation/fuzz/inputs-genvm-modules-complete-json/5/k/5ksca34p8jvyyv4r4t9aq8fqz0wyr6c5w6a5j1cns3wtj new file mode 100644 index 00000000..06695d27 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/k/5ksca34p8jvyyv4r4t9aq8fqz0wyr6c5w6a5j1cns3wtj @@ -0,0 +1,5 @@ +{ + "foo": 1e20, + "\\uabb@bb" + + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/m/5m13t0nyge0w12tkmwt21zv8gphpckwv79ky7syc8fz04 b/implementation/fuzz/inputs-genvm-modules-complete-json/5/m/5m13t0nyge0w12tkmwt21zv8gphpckwv79ky7syc8fz04 new file mode 100644 index 00000000..2eaa299e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/m/5m13t0nyge0w12tkmwt21zv8gphpckwv79ky7syc8fz04 @@ -0,0 +1 @@ +191111.111111111111111E-1111 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/m/5meq1wankjerhv937773xend4eakwq3xfyaescec2yy54 b/implementation/fuzz/inputs-genvm-modules-complete-json/5/m/5meq1wankjerhv937773xend4eakwq3xfyaescec2yy54 new file mode 100644 index 00000000..9536b4fc --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/m/5meq1wankjerhv937773xend4eakwq3xfyaescec2yy54 @@ -0,0 +1 @@ +"]no" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/n/5nxmsy3nbk3n9x2eezrgbjj21j80xj62n9c8svwt2weva b/implementation/fuzz/inputs-genvm-modules-complete-json/5/n/5nxmsy3nbk3n9x2eezrgbjj21j80xj62n9c8svwt2weva new file mode 100644 index 00000000..6c2406e8 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/n/5nxmsy3nbk3n9x2eezrgbjj21j80xj62n9c8svwt2weva @@ -0,0 +1 @@ +222222222222222222222222212.2 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/p/5pzkgwrwycj09hfrjtmyfhpgmnerkapbh6xhp55gskj9w b/implementation/fuzz/inputs-genvm-modules-complete-json/5/p/5pzkgwrwycj09hfrjtmyfhpgmnerkapbh6xhp55gskj9w new file mode 100644 index 00000000..961ee90c --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/p/5pzkgwrwycj09hfrjtmyfhpgmnerkapbh6xhp55gskj9w @@ -0,0 +1 @@ +2222222222.222222222222 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/q/5q2611whwhv6gmbtrtwm09b0cbpnjr0mcnrvfas0ky1ma b/implementation/fuzz/inputs-genvm-modules-complete-json/5/q/5q2611whwhv6gmbtrtwm09b0cbpnjr0mcnrvfas0ky1ma new file mode 100644 index 00000000..6250e8d0 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/q/5q2611whwhv6gmbtrtwm09b0cbpnjr0mcnrvfas0ky1ma @@ -0,0 +1 @@ +"bQzbQz\t\\\\" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/r/5rhhmvfczvhj7ba6jaxjqhx7d44drdy8nv5ypw3przvme b/implementation/fuzz/inputs-genvm-modules-complete-json/5/r/5rhhmvfczvhj7ba6jaxjqhx7d44drdy8nv5ypw3przvme new file mode 100644 index 00000000..35fb2f40 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/r/5rhhmvfczvhj7ba6jaxjqhx7d44drdy8nv5ypw3przvme @@ -0,0 +1,2 @@ + +"\u0400ы\u00000р\\wba r" diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/5/s/5sjmmjcchvtx07q0s65jd41npa39zadh6pdfavdebrk3a b/implementation/fuzz/inputs-genvm-modules-complete-json/5/s/5sjmmjcchvtx07q0s65jd41npa39zadh6pdfavdebrk3a new file mode 100644 index 00000000..b08a37ef --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/5/s/5sjmmjcchvtx07q0s65jd41npa39zadh6pdfavdebrk3a @@ -0,0 +1 @@ +411.111666666666666666661E11 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/b99e1959cf0de1171606c1971933f6b68cfc618b1937fc3117af71e4877ea0f1 b/implementation/fuzz/inputs-genvm-modules-complete-json/5/s/5st59vnef87wq5077p90tfrqwq4zwa7seh3erqrztx5xt similarity index 76% rename from implementation/fuzz/inputs-genvm-modules-normalize-whitespace/b99e1959cf0de1171606c1971933f6b68cfc618b1937fc3117af71e4877ea0f1 rename to implementation/fuzz/inputs-genvm-modules-complete-json/5/s/5st59vnef87wq5077p90tfrqwq4zwa7seh3erqrztx5xt index 492619e57d29cb0927cf9acbc7ce06651e2d130f..d121d3fbcef0e0a5153dc087c2a80df3afdcbcc0 100644 GIT binary patch literal 42 Vcmb>CQs7chP~t)Z3TS*F7XU=w0)_wp literal 47 Wcmd<$;^JapU{C;3FdzkEV4(plg8| B\bz" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/1/c1xfgsxp69zhyth69xdj5wvrsj2v898bb12r1xvcpg390 b/implementation/fuzz/inputs-genvm-modules-complete-json/c/1/c1xfgsxp69zhyth69xdj5wvrsj2v898bb12r1xvcpg390 new file mode 100644 index 00000000..998384b2 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/1/c1xfgsxp69zhyth69xdj5wvrsj2v898bb12r1xvcpg390 @@ -0,0 +1,2 @@ +{ + "foo" " \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/3/c3t4rfdgtkkcy6efj3fyz1excf7pww2x15239qk3etjpy b/implementation/fuzz/inputs-genvm-modules-complete-json/c/3/c3t4rfdgtkkcy6efj3fyz1excf7pww2x15239qk3etjpy new file mode 100644 index 00000000..8878e547 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/3/c3t4rfdgtkkcy6efj3fyz1excf7pww2x15239qk3etjpy @@ -0,0 +1 @@ +[ ] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/4/c4szvzad8fpgnp25t9ea96c4nbkmts8gxsdkq301t1sbr b/implementation/fuzz/inputs-genvm-modules-complete-json/c/4/c4szvzad8fpgnp25t9ea96c4nbkmts8gxsdkq301t1sbr new file mode 100644 index 00000000..c61f7f7e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/4/c4szvzad8fpgnp25t9ea96c4nbkmts8gxsdkq301t1sbr @@ -0,0 +1 @@ +"\t" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/708713afdb215a7fdd1b3246ec662a3d992648dc262ca1d5360be94b6d75313b b/implementation/fuzz/inputs-genvm-modules-complete-json/c/4/c4wkbgpf2hrga2ja9gan85nve6vs8ndygv9atc4gvx9zr similarity index 50% rename from implementation/fuzz/inputs-genvm-modules-normalize-whitespace/708713afdb215a7fdd1b3246ec662a3d992648dc262ca1d5360be94b6d75313b rename to implementation/fuzz/inputs-genvm-modules-complete-json/c/4/c4wkbgpf2hrga2ja9gan85nve6vs8ndygv9atc4gvx9zr index 59f144ee093d5bcf17b6de64d11c2ba0b53eacec..139597f9cb07c5d48bed18984ec4747f4b4f3438 100644 GIT binary patch literal 2 Jcmd<$0ssIY02KfL literal 2 Jcmd;L0000M01E&B diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/5/c5gqzg4fntq5azg6h5f1n3k89v7c3zkd79a68gvqpa9jy b/implementation/fuzz/inputs-genvm-modules-complete-json/c/5/c5gqzg4fntq5azg6h5f1n3k89v7c3zkd79a68gvqpa9jy new file mode 100644 index 00000000..ebbfecc7 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/5/c5gqzg4fntq5azg6h5f1n3k89v7c3zkd79a68gvqpa9jy @@ -0,0 +1 @@ +22202222222222222222E22222222222 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/b/cb2jgg28j8qmpnrxvgwqwhy9rsa3qzrnqmzj9ppdafjag b/implementation/fuzz/inputs-genvm-modules-complete-json/c/b/cb2jgg28j8qmpnrxvgwqwhy9rsa3qzrnqmzj9ppdafjag new file mode 100644 index 00000000..f4c9f6c9 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/b/cb2jgg28j8qmpnrxvgwqwhy9rsa3qzrnqmzj9ppdafjag @@ -0,0 +1 @@ + " \uDAAb\ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/c/ccn5t75s30qs8f06japgnm7sc9vq1m1qwrqs634edemx6 b/implementation/fuzz/inputs-genvm-modules-complete-json/c/c/ccn5t75s30qs8f06japgnm7sc9vq1m1qwrqs634edemx6 new file mode 100644 index 00000000..bbfb7ba0 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/c/ccn5t75s30qs8f06japgnm7sc9vq1m1qwrqs634edemx6 @@ -0,0 +1,3 @@ + [0, + + 1111111111111] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/d/cdbjcc0akvqmxres0ak235a7j1g5x8af42gvewk0w0ary b/implementation/fuzz/inputs-genvm-modules-complete-json/c/d/cdbjcc0akvqmxres0ak235a7j1g5x8af42gvewk0w0ary new file mode 100644 index 00000000..2e15497b --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/d/cdbjcc0akvqmxres0ak235a7j1g5x8af42gvewk0w0ary @@ -0,0 +1,5 @@ + { + "":0, + + + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/d/cdswa6f4rx04dgwghpam5zkxp9c4yvnry1a9dm6708hcr b/implementation/fuzz/inputs-genvm-modules-complete-json/c/d/cdswa6f4rx04dgwghpam5zkxp9c4yvnry1a9dm6708hcr new file mode 100644 index 00000000..9db2ae42 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/d/cdswa6f4rx04dgwghpam5zkxp9c4yvnry1a9dm6708hcr @@ -0,0 +1,16 @@ + [1, 2, + + + + + + "рус + + + + + + + + + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/e/ce6q5vbgw31nc3nvdrve6xhx519nntpfp466y772cd562 b/implementation/fuzz/inputs-genvm-modules-complete-json/c/e/ce6q5vbgw31nc3nvdrve6xhx519nntpfp466y772cd562 new file mode 100644 index 00000000..67efaf23 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/e/ce6q5vbgw31nc3nvdrve6xhx519nntpfp466y772cd562 @@ -0,0 +1 @@ +"{" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/f/cf6wctsh5htv0fhkw46ab49ws2dqrng17h3panefejg3c b/implementation/fuzz/inputs-genvm-modules-complete-json/c/f/cf6wctsh5htv0fhkw46ab49ws2dqrng17h3panefejg3c new file mode 100644 index 00000000..a4053c5c --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/f/cf6wctsh5htv0fhkw46ab49ws2dqrng17h3panefejg3c @@ -0,0 +1,15 @@ +{ + "mb": [ + "bar", + "baz\n\\{", + 123, + 1e20, + null, + true, + false, + [1, 2, 3] + ], + "mbb -barar": [ ], + "": [ ], + "bar": 11112, 3е Х本", + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/f/cfm826zbpsn5r4wex6spd3043c4y5gcnbvyxmfpgj97w2 b/implementation/fuzz/inputs-genvm-modules-complete-json/c/f/cfm826zbpsn5r4wex6spd3043c4y5gcnbvyxmfpgj97w2 new file mode 100644 index 00000000..670e0c14 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/f/cfm826zbpsn5r4wex6spd3043c4y5gcnbvyxmfpgj97w2 @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/h/ch7v9q3a817bjvgqk19qhsrmre8hr82mhrjc2zq2m19gr b/implementation/fuzz/inputs-genvm-modules-complete-json/c/h/ch7v9q3a817bjvgqk19qhsrmre8hr82mhrjc2zq2m19gr new file mode 100644 index 00000000..69294512 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/h/ch7v9q3a817bjvgqk19qhsrmre8hr82mhrjc2zq2m19gr @@ -0,0 +1,7 @@ + "р\\u < 12CabbbMb" + + + + + + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/k/ck2mhak8fj2023hsbnd500aknqbzpvx1gghaxdfbmx9mr b/implementation/fuzz/inputs-genvm-modules-complete-json/c/k/ck2mhak8fj2023hsbnd500aknqbzpvx1gghaxdfbmx9mr new file mode 100644 index 00000000..b5020ebf --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/k/ck2mhak8fj2023hsbnd500aknqbzpvx1gghaxdfbmx9mr @@ -0,0 +1,14 @@ +{ + "foo": [ + "bar", + "baz\n\\z", + 123, + -123, + [[[[[[[[[[[[[[[[[[[[[{ + + + + + + + -1 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/n/cnnd3zk59t022ennk6sne1h1m5jzkv16e7tcqaaeh4ngc b/implementation/fuzz/inputs-genvm-modules-complete-json/c/n/cnnd3zk59t022ennk6sne1h1m5jzkv16e7tcqaaeh4ngc new file mode 100644 index 00000000..74d31ceb --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/n/cnnd3zk59t022ennk6sne1h1m5jzkv16e7tcqaaeh4ngc @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/q/cqg62jc16td8pgmwkmpb887sccg89r05ph3n0k2emj4jw b/implementation/fuzz/inputs-genvm-modules-complete-json/c/q/cqg62jc16td8pgmwkmpb887sccg89r05ph3n0k2emj4jw new file mode 100644 index 00000000..0337474c --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/q/cqg62jc16td8pgmwkmpb887sccg89r05ph3n0k2emj4jw @@ -0,0 +1 @@ +111e-5111111111111111111 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/q/cqvndvgd652rw5bfgenmkatrxbypkxm658ykfnq29h4g0 b/implementation/fuzz/inputs-genvm-modules-complete-json/c/q/cqvndvgd652rw5bfgenmkatrxbypkxm658ykfnq29h4g0 new file mode 100644 index 00000000..1b6cd4f4 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/q/cqvndvgd652rw5bfgenmkatrxbypkxm658ykfnq29h4g0 @@ -0,0 +1 @@ +"bAz\n\/b" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/s/csk3f07z6bfh43433v3t4sfrg22ybgsyfy42fqm6x1v3r b/implementation/fuzz/inputs-genvm-modules-complete-json/c/s/csk3f07z6bfh43433v3t4sfrg22ybgsyfy42fqm6x1v3r new file mode 100644 index 00000000..5b9ecb8a --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/s/csk3f07z6bfh43433v3t4sfrg22ybgsyfy42fqm6x1v3r @@ -0,0 +1,18 @@ +{ + "foo": [ + "bar", + "baz\n\\{", + 123, + 111111111911111111111.11111e-1120, + null, + true, + false, + [1, 2, 3] + ], + "mbb b -barar": [ ], + "": [ ], + "bar": [ + "рۃсские буквЇ 日本", + "mbbbbbbbbmbbbbbbbbbbb bbaz\t\\uabbbb1b" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/t/ctj41vh54xd59bpg48hmrjgz890q69jmejh756a0q8nnt b/implementation/fuzz/inputs-genvm-modules-complete-json/c/t/ctj41vh54xd59bpg48hmrjgz890q69jmejh756a0q8nnt new file mode 100644 index 00000000..91042ef7 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/t/ctj41vh54xd59bpg48hmrjgz890q69jmejh756a0q8nnt @@ -0,0 +1 @@ +[ , , \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/t/ctqthskpwwnmrm8g6khj3j8hxs5yfvhxgf086pq30jhtr b/implementation/fuzz/inputs-genvm-modules-complete-json/c/t/ctqthskpwwnmrm8g6khj3j8hxs5yfvhxgf086pq30jhtr new file mode 100644 index 00000000..e12fc7f5 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/t/ctqthskpwwnmrm8g6khj3j8hxs5yfvhxgf086pq30jhtr @@ -0,0 +1 @@ +"UUUIbc  rbbbb," diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/w/cw1cfp9bdvcqkqg5tm08ggrc5bda7zmqz8xq3k3d6ysam b/implementation/fuzz/inputs-genvm-modules-complete-json/c/w/cw1cfp9bdvcqkqg5tm08ggrc5bda7zmqz8xq3k3d6ysam new file mode 100644 index 00000000..351a0eee --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/w/cw1cfp9bdvcqkqg5tm08ggrc5bda7zmqz8xq3k3d6ysam @@ -0,0 +1,2 @@ + +"р[ bв҇ 󗥺u b r" diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/w/cw1v9r7a7eysaxd0fpm6d58tbdg981d7z1jdjvcy9xmj6 b/implementation/fuzz/inputs-genvm-modules-complete-json/c/w/cw1v9r7a7eysaxd0fpm6d58tbdg981d7z1jdjvcy9xmj6 new file mode 100644 index 00000000..5d5bb8dc --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/w/cw1v9r7a7eysaxd0fpm6d58tbdg981d7z1jdjvcy9xmj6 @@ -0,0 +1 @@ +"UUUTmb  $ \u8bbbbbb," diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/w/cwa33vsd7h36xx5pzk5wzyk4hnn9ha7y87eh90vszdtwc b/implementation/fuzz/inputs-genvm-modules-complete-json/c/w/cwa33vsd7h36xx5pzk5wzyk4hnn9ha7y87eh90vszdtwc new file mode 100644 index 00000000..85ee7d2d --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/w/cwa33vsd7h36xx5pzk5wzyk4hnn9ha7y87eh90vszdtwc @@ -0,0 +1 @@ + " у0000000000000/000\u0000" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/w/cwmpyftwdby1bddzawz9ee6bavbfagjwem3n3yvsa5936 b/implementation/fuzz/inputs-genvm-modules-complete-json/c/w/cwmpyftwdby1bddzawz9ee6bavbfagjwem3n3yvsa5936 new file mode 100644 index 00000000..d3d13c72 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/w/cwmpyftwdby1bddzawz9ee6bavbfagjwem3n3yvsa5936 @@ -0,0 +1 @@ +"бук12C \f\\ " \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/c/z/czsfsvp41g06qv09d387sz4kknemgat7pv72apmrvav5r b/implementation/fuzz/inputs-genvm-modules-complete-json/c/z/czsfsvp41g06qv09d387sz4kknemgat7pv72apmrvav5r new file mode 100644 index 00000000..319c9aab --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/c/z/czsfsvp41g06qv09d387sz4kknemgat7pv72apmrvav5r @@ -0,0 +1,2 @@ + [ + 1111.61e-111111111111] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/d/1/d13vbtddm9r6x9jq3wdgpckfe4xzxgp19bh2x9ncjqwnc b/implementation/fuzz/inputs-genvm-modules-complete-json/d/1/d13vbtddm9r6x9jq3wdgpckfe4xzxgp19bh2x9ncjqwnc new file mode 100644 index 00000000..0a9e1344 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/d/1/d13vbtddm9r6x9jq3wdgpckfe4xzxgp19bh2x9ncjqwnc @@ -0,0 +1,2 @@ + +"\u0000ы\u0000њ\u0000a1 r" diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/d/1/d1q9ctz9pyrpym136n3yra4fhxqvzjks22hjm9y2errxy b/implementation/fuzz/inputs-genvm-modules-complete-json/d/1/d1q9ctz9pyrpym136n3yra4fhxqvzjks22hjm9y2errxy new file mode 100644 index 00000000..44591c85 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/d/1/d1q9ctz9pyrpym136n3yra4fhxqvzjks22hjm9y2errxy @@ -0,0 +1,16 @@ +{ + "foo": [ + "bar", + "baz\n\\{", + -1e10, + 1e20, + null, + true, + [1, 2, 3] + ], + "bar": [ ], + "bar" : [ + "русские mbbbbbbbbbbbbbbaz\t\uabbbbb", + "mbbbbbbbbbbbbbaz\t\\uabbaz\t\\uabbbbb" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/d/2/d27grm16kjp4rfzwbzk3p7sda804ykfma4wmb53ar4998 b/implementation/fuzz/inputs-genvm-modules-complete-json/d/2/d27grm16kjp4rfzwbzk3p7sda804ykfma4wmb53ar4998 new file mode 100644 index 00000000..029a8e72 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/d/2/d27grm16kjp4rfzwbzk3p7sda804ykfma4wmb53ar4998 @@ -0,0 +1,3 @@ + [ [{ + "emo": true, + m \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/d/4/d46ttf0zq9pvmgs3qjpdegznawqw1ndzbtbvs40the3h6 b/implementation/fuzz/inputs-genvm-modules-complete-json/d/4/d46ttf0zq9pvmgs3qjpdegznawqw1ndzbtbvs40the3h6 new file mode 100644 index 00000000..a47fffd2 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/d/4/d46ttf0zq9pvmgs3qjpdegznawqw1ndzbtbvs40the3h6 @@ -0,0 +1 @@ + 111111111111111111111111 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/d/6/d6dqgr1jgbkmebh826wq0heyv6071h8j84qw4xmjdcrap b/implementation/fuzz/inputs-genvm-modules-complete-json/d/6/d6dqgr1jgbkmebh826wq0heyv6071h8j84qw4xmjdcrap new file mode 100644 index 00000000..e18bd45f --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/d/6/d6dqgr1jgbkmebh826wq0heyv6071h8j84qw4xmjdcrap @@ -0,0 +1,4 @@ + [ + +[ [[[[[[[[[[[[[ 123, + ]]]]]]]]]] u \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/d/7/d7hsbgnjd6mtrdw1nsn4p31s2arbkw7gy8manf8vp4tz4 b/implementation/fuzz/inputs-genvm-modules-complete-json/d/7/d7hsbgnjd6mtrdw1nsn4p31s2arbkw7gy8manf8vp4tz4 new file mode 100644 index 00000000..d3a91180 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/d/7/d7hsbgnjd6mtrdw1nsn4p31s2arbkw7gy8manf8vp4tz4 @@ -0,0 +1,2 @@ + [, +  \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/d/8/d82hxbrtkmkz7zt2vg3zq107ez9g017egpmcac6w50vbm b/implementation/fuzz/inputs-genvm-modules-complete-json/d/8/d82hxbrtkmkz7zt2vg3zq107ez9g017egpmcac6w50vbm new file mode 100644 index 00000000..ea9684a3 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/d/8/d82hxbrtkmkz7zt2vg3zq107ez9g017egpmcac6w50vbm @@ -0,0 +1,2 @@ +tr + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/d/9/d91jv8nn4e18xh44q9kswsggmy91vy11ykx85ttpc6a7g b/implementation/fuzz/inputs-genvm-modules-complete-json/d/9/d91jv8nn4e18xh44q9kswsggmy91vy11ykx85ttpc6a7g new file mode 100644 index 00000000..4b98a45d --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/d/9/d91jv8nn4e18xh44q9kswsggmy91vy11ykx85ttpc6a7g @@ -0,0 +1 @@ +"w\ubba6,\ubba6" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/d/9/d93mqvmwkazrrm0gzftmzw2604x4pkpner8a4g52rgnhc b/implementation/fuzz/inputs-genvm-modules-complete-json/d/9/d93mqvmwkazrrm0gzftmzw2604x4pkpner8a4g52rgnhc new file mode 100644 index 00000000..6ce08bd2 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/d/9/d93mqvmwkazrrm0gzftmzw2604x4pkpner8a4g52rgnhc @@ -0,0 +1,53 @@ +{ + + + + + + + + + + "foo": "bIr", + + + + + + + + + + + + + + + + + + + + + + + + + "р\\uuuuuuuuuuu + + + + + + + + + + + + + + + + +  \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/d/c/dctpvb2zt2hrkg19mkfqc9h9sk8yz3rxj95z6y2n6tbee b/implementation/fuzz/inputs-genvm-modules-complete-json/d/c/dctpvb2zt2hrkg19mkfqc9h9sk8yz3rxj95z6y2n6tbee new file mode 100644 index 00000000..5ebb4767 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/d/c/dctpvb2zt2hrkg19mkfqc9h9sk8yz3rxj95z6y2n6tbee @@ -0,0 +1 @@ +0e-5555555515 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/d/e/de70hek7tx48svhkcmgtr4jp6cp0nmzsgzqdp0qkrbjz0 b/implementation/fuzz/inputs-genvm-modules-complete-json/d/e/de70hek7tx48svhkcmgtr4jp6cp0nmzsgzqdp0qkrbjz0 new file mode 100644 index 00000000..593257e4 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/d/e/de70hek7tx48svhkcmgtr4jp6cp0nmzsgzqdp0qkrbjz0 @@ -0,0 +1,3 @@ +{ + "foo": -123, + [[[ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/d/e/dewbqrqshc4a4e544gy7bra0cc7ngwb8nk98zwexz4ek2 b/implementation/fuzz/inputs-genvm-modules-complete-json/d/e/dewbqrqshc4a4e544gy7bra0cc7ngwb8nk98zwexz4ek2 new file mode 100644 index 00000000..7dd46edb --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/d/e/dewbqrqshc4a4e544gy7bra0cc7ngwb8nk98zwexz4ek2 @@ -0,0 +1 @@ + "\f" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/d/h/dhk6b8jk1e8d8gg6n97s15b4h6y9q8n0r5yp0r9wsmzgc b/implementation/fuzz/inputs-genvm-modules-complete-json/d/h/dhk6b8jk1e8d8gg6n97s15b4h6y9q8n0r5yp0r9wsmzgc new file mode 100644 index 00000000..afcf0476 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/d/h/dhk6b8jk1e8d8gg6n97s15b4h6y9q8n0r5yp0r9wsmzgc @@ -0,0 +1 @@ +11.11 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/d/k/dk9ye8hftb4hf441w1rsnrk9zhps2tfwfm6xdz6v8497a b/implementation/fuzz/inputs-genvm-modules-complete-json/d/k/dk9ye8hftb4hf441w1rsnrk9zhps2tfwfm6xdz6v8497a new file mode 100644 index 00000000..18bf327e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/d/k/dk9ye8hftb4hf441w1rsnrk9zhps2tfwfm6xdz6v8497a @@ -0,0 +1 @@ +3. \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/d/k/dkba0gfw61g6810w4p3njyk0d0wh0xf498g53ntcj4rjt b/implementation/fuzz/inputs-genvm-modules-complete-json/d/k/dkba0gfw61g6810w4p3njyk0d0wh0xf498g53ntcj4rjt new file mode 100644 index 00000000..9af238c1 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/d/k/dkba0gfw61g6810w4p3njyk0d0wh0xf498g53ntcj4rjt @@ -0,0 +1 @@ +"р\\㗥11bb r" diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/d/k/dkmhenq6tnsbsncefwrtcxcj2zc3h3jkdmcb7f95skgny b/implementation/fuzz/inputs-genvm-modules-complete-json/d/k/dkmhenq6tnsbsncefwrtcxcj2zc3h3jkdmcb7f95skgny new file mode 100644 index 0000000000000000000000000000000000000000..2bcb16779a7f9ae2592d89c6bac8274d4c7a3f8e GIT binary patch literal 47 kcmY%3tX5D^P|8=bQiujJPCQUC&_wETP}D}`t<2P}}3Sfr$b%&khvi;1a15;HV1)``Xq;CeyE;Z}w$qhOe7 xWPq?VuQVq|2c#P-P%<(y0!ru`rec-GCkV4sK_MwA5ynBHp?b?06hNNP1pu1zL3;oI literal 0 HcmV?d00001 diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/e/y/ey6frz98yn558h2wzg6a1q9m9mna6h73tfa0bazs7sn8j b/implementation/fuzz/inputs-genvm-modules-complete-json/e/y/ey6frz98yn558h2wzg6a1q9m9mna6h73tfa0bazs7sn8j new file mode 100644 index 00000000..413d7be8 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/e/y/ey6frz98yn558h2wzg6a1q9m9mna6h73tfa0bazs7sn8j @@ -0,0 +1,2 @@ +{ + "foo" a \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/0/f0kp1rtsrfr2e8b3kkp860q87jekvsmh09s5yh461kebm b/implementation/fuzz/inputs-genvm-modules-complete-json/f/0/f0kp1rtsrfr2e8b3kkp860q87jekvsmh09s5yh461kebm new file mode 100644 index 00000000..b2f0eea2 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/0/f0kp1rtsrfr2e8b3kkp860q87jekvsmh09s5yh461kebm @@ -0,0 +1,2 @@ + +"\u0000\b󗥗[8本ыb󗥗\u0000ы\u00ba1 r" diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/0/f0vkjt3y2enqdjd79k21h1c0knams8se5fehqmjz3ezmj b/implementation/fuzz/inputs-genvm-modules-complete-json/f/0/f0vkjt3y2enqdjd79k21h1c0knams8se5fehqmjz3ezmj new file mode 100644 index 00000000..def511f4 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/0/f0vkjt3y2enqdjd79k21h1c0knams8se5fehqmjz3ezmj @@ -0,0 +1,12 @@ +{ + "fz\t\uabbbbboo": [ + "bar", + "baz\n\\z", + 123, + -123, + -1e10, + 1e20, + null, + true, + f[ + "bar \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/0/f0w1wp4f4g2j3eev35nwd693ztg9rywxbf2xz2sw97efc b/implementation/fuzz/inputs-genvm-modules-complete-json/f/0/f0w1wp4f4g2j3eev35nwd693ztg9rywxbf2xz2sw97efc new file mode 100644 index 00000000..b370520a --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/0/f0w1wp4f4g2j3eev35nwd693ztg9rywxbf2xz2sw97efc @@ -0,0 +1,2 @@ +{ "fooo":": [ + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/2/f2977sr15mekm241hw6307vdxw6jfpvtzcv96e0kpb30t b/implementation/fuzz/inputs-genvm-modules-complete-json/f/2/f2977sr15mekm241hw6307vdxw6jfpvtzcv96e0kpb30t new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/2/f2977sr15mekm241hw6307vdxw6jfpvtzcv96e0kpb30t @@ -0,0 +1 @@ + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/2/f2mw7jkye43zq3m8tcjfavsyxb0ydpfvhecr88cct7qqy b/implementation/fuzz/inputs-genvm-modules-complete-json/f/2/f2mw7jkye43zq3m8tcjfavsyxb0ydpfvhecr88cct7qqy new file mode 100644 index 00000000..18653291 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/2/f2mw7jkye43zq3m8tcjfavsyxb0ydpfvhecr88cct7qqy @@ -0,0 +1 @@ +3. \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/5/f5mxash0dv9x92eban9n4bja4a9f02re6s0cfdvgxggsg b/implementation/fuzz/inputs-genvm-modules-complete-json/f/5/f5mxash0dv9x92eban9n4bja4a9f02re6s0cfdvgxggsg new file mode 100644 index 00000000..adccbbe2 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/5/f5mxash0dv9x92eban9n4bja4a9f02re6s0cfdvgxggsg @@ -0,0 +1 @@ +3E2 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/7/f722yfy9gpzwpkyd441q5bxa9d6q0znw8cn5c38yakb8j b/implementation/fuzz/inputs-genvm-modules-complete-json/f/7/f722yfy9gpzwpkyd441q5bxa9d6q0znw8cn5c38yakb8j new file mode 100644 index 00000000..75a0687b --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/7/f722yfy9gpzwpkyd441q5bxa9d6q0znw8cn5c38yakb8j @@ -0,0 +1,2 @@ + +":" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/8/f894kk1aszm9zrt7r2rk33emns5jh7mt8v9ma5atbwd3t b/implementation/fuzz/inputs-genvm-modules-complete-json/f/8/f894kk1aszm9zrt7r2rk33emns5jh7mt8v9ma5atbwd3t new file mode 100644 index 00000000..fdd178b4 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/8/f894kk1aszm9zrt7r2rk33emns5jh7mt8v9ma5atbwd3t @@ -0,0 +1 @@ +{ "foo" [[[ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/8/f8f838tn0zrencezbxme6vs2k4ehm2m25vpvaakhz7ger b/implementation/fuzz/inputs-genvm-modules-complete-json/f/8/f8f838tn0zrencezbxme6vs2k4ehm2m25vpvaakhz7ger new file mode 100644 index 00000000..f2f7eee3 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/8/f8f838tn0zrencezbxme6vs2k4ehm2m25vpvaakhz7ger @@ -0,0 +1 @@ + [[ [[1, , \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/9/f9qj2956qabnb1858sgp1x5fqec9f81j796pe84cd0fnr b/implementation/fuzz/inputs-genvm-modules-complete-json/f/9/f9qj2956qabnb1858sgp1x5fqec9f81j796pe84cd0fnr new file mode 100644 index 00000000..f47a7fa7 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/9/f9qj2956qabnb1858sgp1x5fqec9f81j796pe84cd0fnr @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "рbb\\b" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/b/fbq5975x2xbt7q49nejc75g2gkgq1sazyfz2g4s7dbza0 b/implementation/fuzz/inputs-genvm-modules-complete-json/f/b/fbq5975x2xbt7q49nejc75g2gkgq1sazyfz2g4s7dbza0 new file mode 100644 index 00000000..5e1dc0b4 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/b/fbq5975x2xbt7q49nejc75g2gkgq1sazyfz2g4s7dbza0 @@ -0,0 +1 @@ + "}k" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/d/fdarbet0j38wtdpacqvcedcp5nskf95r02gek39rmg8qw b/implementation/fuzz/inputs-genvm-modules-complete-json/f/d/fdarbet0j38wtdpacqvcedcp5nskf95r02gek39rmg8qw new file mode 100644 index 00000000..604b5cc9 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/d/fdarbet0j38wtdpacqvcedcp5nskf95r02gek39rmg8qw @@ -0,0 +1 @@ +22222222222235222121e+22 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/d/fdxw7s5sstzbwkzhcmrd55mrgw5ydy3kwys6cpx1znspy b/implementation/fuzz/inputs-genvm-modules-complete-json/f/d/fdxw7s5sstzbwkzhcmrd55mrgw5ydy3kwys6cpx1znspy new file mode 100644 index 00000000..7acd0cfd --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/d/fdxw7s5sstzbwkzhcmrd55mrgw5ydy3kwys6cpx1znspy @@ -0,0 +1,34 @@ + [1.6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/e/fe908rz29x6xjyhzyt3cdtz1btr6tgatnyhnc07a2d5vg b/implementation/fuzz/inputs-genvm-modules-complete-json/f/e/fe908rz29x6xjyhzyt3cdtz1btr6tgatnyhnc07a2d5vg new file mode 100644 index 00000000..e1039c28 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/e/fe908rz29x6xjyhzyt3cdtz1btr6tgatnyhnc07a2d5vg @@ -0,0 +1 @@ +22222222222222222222 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/f/ffabam1yxkm107he6rdbwpthe7npazfph718gv3802qy8 b/implementation/fuzz/inputs-genvm-modules-complete-json/f/f/ffabam1yxkm107he6rdbwpthe7npazfph718gv3802qy8 new file mode 100644 index 00000000..4265151e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/f/ffabam1yxkm107he6rdbwpthe7npazfph718gv3802qy8 @@ -0,0 +1,2 @@ +{" ] fo": [ 5] +} \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/f/ffzbr34j2epdjf3hm6gs0bn44dkv64q71s8vxrwn4ghfy b/implementation/fuzz/inputs-genvm-modules-complete-json/f/f/ffzbr34j2epdjf3hm6gs0bn44dkv64q71s8vxrwn4ghfy new file mode 100644 index 00000000..1a242859 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/f/ffzbr34j2epdjf3hm6gs0bn44dkv64q71s8vxrwn4ghfy @@ -0,0 +1,17 @@ +{ + "foo": [ + "bar", + "baz\n\\z" ], + "bar": [ + -123, + -1e10, + null, + true, + false, + [1, 2, 3] + ], + "bar": [ + "руѬaz\t\uabbbbb", + "mbbbbbbbbbbbbbbaz\t\\uabbbbb" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/k/fkeqwc9ng2a7y42dae5ax8bv7zvms6s4jqb3ms9q1062a b/implementation/fuzz/inputs-genvm-modules-complete-json/f/k/fkeqwc9ng2a7y42dae5ax8bv7zvms6s4jqb3ms9q1062a new file mode 100644 index 00000000..dba95bcc --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/k/fkeqwc9ng2a7y42dae5ax8bv7zvms6s4jqb3ms9q1062a @@ -0,0 +1 @@ + [11111111,1111311111111111111.11e-51111,111131111111111111E111, 2, 3] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/m/fmw01nxpr25fjkpb44v57kfxy22jbhre9jk9xmz903st6 b/implementation/fuzz/inputs-genvm-modules-complete-json/f/m/fmw01nxpr25fjkpb44v57kfxy22jbhre9jk9xmz903st6 new file mode 100644 index 00000000..b77cf959 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/m/fmw01nxpr25fjkpb44v57kfxy22jbhre9jk9xmz903st6 @@ -0,0 +1 @@ +1e-3333333333333333333333333333333333333333333 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/r/frr2tx60pfkvq45nsmz9b71pp579pdqd5g9njtv0bnw90 b/implementation/fuzz/inputs-genvm-modules-complete-json/f/r/frr2tx60pfkvq45nsmz9b71pp579pdqd5g9njtv0bnw90 new file mode 100644 index 00000000..65b0a109 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/r/frr2tx60pfkvq45nsmz9b71pp579pdqd5g9njtv0bnw90 @@ -0,0 +1,3 @@ + [[ [ + [[[[[ [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ [ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/t/ft635tsas864bn4tkwtkbxf623k66fnffb27x07czte6t b/implementation/fuzz/inputs-genvm-modules-complete-json/f/t/ft635tsas864bn4tkwtkbxf623k66fnffb27x07czte6t new file mode 100644 index 00000000..89d6ff21 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/t/ft635tsas864bn4tkwtkbxf623k66fnffb27x07czte6t @@ -0,0 +1,2 @@ + + "\"\/" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/v/fvgd11vja9g02rct4rgk4sbyz2pq8g6ce8sv4hc7wwbtr b/implementation/fuzz/inputs-genvm-modules-complete-json/f/v/fvgd11vja9g02rct4rgk4sbyz2pq8g6ce8sv4hc7wwbtr new file mode 100644 index 00000000..6a864745 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/v/fvgd11vja9g02rct4rgk4sbyz2pq8g6ce8sv4hc7wwbtr @@ -0,0 +1,19 @@ +{ + "foo": [ + "bar", + "baz\n\\z", + 123, + -123, + -1e10, + 1e20, + null, + true, + false, + [1, 2, 3] + ], + "bar": [ + "русские буквы 日本", + "mbbbbbbbbbbbbbbaz\t\uabbbbb", + "mbbbb + ] +} \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/v/fvn42ng8jwjq002dmsatnmn21as2fd1g5h4srjywym9g2 b/implementation/fuzz/inputs-genvm-modules-complete-json/f/v/fvn42ng8jwjq002dmsatnmn21as2fd1g5h4srjywym9g2 new file mode 100644 index 00000000..5a373848 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/v/fvn42ng8jwjq002dmsatnmn21as2fd1g5h4srjywym9g2 @@ -0,0 +1 @@ +"\n" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/v/fvqnwfm2teefsk6cqhaahqvmaeppjcdzgfyph7y64cs06 b/implementation/fuzz/inputs-genvm-modules-complete-json/f/v/fvqnwfm2teefsk6cqhaahqvmaeppjcdzgfyph7y64cs06 new file mode 100644 index 00000000..446e291f --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/v/fvqnwfm2teefsk6cqhaahqvmaeppjcdzgfyph7y64cs06 @@ -0,0 +1,6 @@ +[[[[[[[[ + + +3,[[[[[[[[[[[[[[[[[[[[[[[[[[ [[[[[[[[[[[[[ [[[[[[[[[[[[[[[[[[[[[[[[[[111123, + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[{ + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/f/x/fxv0dxa6py99hk9vmne6g5w317jh1spjt90vf5pkq904c b/implementation/fuzz/inputs-genvm-modules-complete-json/f/x/fxv0dxa6py99hk9vmne6g5w317jh1spjt90vf5pkq904c new file mode 100644 index 00000000..3f5a8068 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/f/x/fxv0dxa6py99hk9vmne6g5w317jh1spjt90vf5pkq904c @@ -0,0 +1,2 @@ + +"р\\uвы [[1, 1 日本B\bõ " diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/1/g1fsd04pp0ek735a5d3fzbxnxhpvbafw9hvh99kvbwz8p b/implementation/fuzz/inputs-genvm-modules-complete-json/g/1/g1fsd04pp0ek735a5d3fzbxnxhpvbafw9hvh99kvbwz8p new file mode 100644 index 00000000..32e219e8 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/1/g1fsd04pp0ek735a5d3fzbxnxhpvbafw9hvh99kvbwz8p @@ -0,0 +1,2 @@ + + "р\\uabbb ] " \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/3/g3htj4zjgtrxfvw4hmnbkzdp6bdh1j0x9rrj0804xz2g6 b/implementation/fuzz/inputs-genvm-modules-complete-json/g/3/g3htj4zjgtrxfvw4hmnbkzdp6bdh1j0x9rrj0804xz2g6 new file mode 100644 index 00000000..31d070e7 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/3/g3htj4zjgtrxfvw4hmnbkzdp6bdh1j0x9rrj0804xz2g6 @@ -0,0 +1 @@ + "\"\ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/3/g3m2wz64dne91ntf7e90dhbf9srktb5p29aq26jzwk0bg b/implementation/fuzz/inputs-genvm-modules-complete-json/g/3/g3m2wz64dne91ntf7e90dhbf9srktb5p29aq26jzwk0bg new file mode 100644 index 0000000000000000000000000000000000000000..6ac837047360d438ec3a43bf2ae7a9e96f5baf10 GIT binary patch literal 76 zcmb>CQUC%aLqo%0Acg`ZD+L9^R3if&kff5KalH~R2yj9Hm;)g|n!$iUfn5Or#H|U) literal 0 HcmV?d00001 diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/4/g4eq0tjf2yp04axpjztgdrg2q1m1rvzsvp351nc80dpam b/implementation/fuzz/inputs-genvm-modules-complete-json/g/4/g4eq0tjf2yp04axpjztgdrg2q1m1rvzsvp351nc80dpam new file mode 100644 index 00000000..3626f409 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/4/g4eq0tjf2yp04axpjztgdrg2q1m1rvzsvp351nc80dpam @@ -0,0 +1,19 @@ +{ "fo" + + + + + + + + + + + + + + + + +: [ ] +} \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/5/g5pjkd2759bpn5f461dkws3h2j15yy7keerbyspd857b0 b/implementation/fuzz/inputs-genvm-modules-complete-json/g/5/g5pjkd2759bpn5f461dkws3h2j15yy7keerbyspd857b0 new file mode 100644 index 00000000..a53da60b --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/5/g5pjkd2759bpn5f461dkws3h2j15yy7keerbyspd857b0 @@ -0,0 +1 @@ +"ркU[ ; с11 111111," \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/5/g5v21bx76yg9g3vd6kmxcnkh2dg6q0pctj5bhngfannba b/implementation/fuzz/inputs-genvm-modules-complete-json/g/5/g5v21bx76yg9g3vd6kmxcnkh2dg6q0pctj5bhngfannba new file mode 100644 index 00000000..749e1e20 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/5/g5v21bx76yg9g3vd6kmxcnkh2dg6q0pctj5bhngfannba @@ -0,0 +1 @@ +{ + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/6/g6t74w7s5gapgnshxyn15401mxhzm5hh3fve4cdmjwncr b/implementation/fuzz/inputs-genvm-modules-complete-json/g/6/g6t74w7s5gapgnshxyn15401mxhzm5hh3fve4cdmjwncr new file mode 100644 index 00000000..f535e2ab --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/6/g6t74w7s5gapgnshxyn15401mxhzm5hh3fve4cdmjwncr @@ -0,0 +1,16 @@ +{ + "foo": [ + "bar", + "baz\n\\z", + 1.3, + -123, + -1e10, + 1e20, + null, + true, + false, + [ "русские буквы 殥本", + "mbbbbbbbbbbbbbbaz\t\uabbbbb", + "mbbbbbbbbbbbbb бу\\uabbbbb" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/7/g79z13a134phq13pmsjfmm4a8jzb5n2nbzjaq0bvj78ja b/implementation/fuzz/inputs-genvm-modules-complete-json/g/7/g79z13a134phq13pmsjfmm4a8jzb5n2nbzjaq0bvj78ja new file mode 100644 index 00000000..9ff98df1 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/7/g79z13a134phq13pmsjfmm4a8jzb5n2nbzjaq0bvj78ja @@ -0,0 +1 @@ +{ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/7/g7bwdm2hqypr8xfsgwq6cgekw1wqsrzpww5nwscttq46p b/implementation/fuzz/inputs-genvm-modules-complete-json/g/7/g7bwdm2hqypr8xfsgwq6cgekw1wqsrzpww5nwscttq46p new file mode 100644 index 00000000..4c741acc --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/7/g7bwdm2hqypr8xfsgwq6cgekw1wqsrzpww5nwscttq46p @@ -0,0 +1 @@ + "\"((((((((((((((((" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/8/g8w3at38nnnj5pbjqbfs84vekef7cz8w0hppz1egw5dwg b/implementation/fuzz/inputs-genvm-modules-complete-json/g/8/g8w3at38nnnj5pbjqbfs84vekef7cz8w0hppz1egw5dwg new file mode 100644 index 00000000..20db39d1 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/8/g8w3at38nnnj5pbjqbfs84vekef7cz8w0hppz1egw5dwg @@ -0,0 +1 @@ + fal2 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/9/g9qa3ry1jg09wd47m2xwpvgae90wnxtr2rvwf8e146qg6 b/implementation/fuzz/inputs-genvm-modules-complete-json/g/9/g9qa3ry1jg09wd47m2xwpvgae90wnxtr2rvwf8e146qg6 new file mode 100644 index 00000000..97c1aec3 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/9/g9qa3ry1jg09wd47m2xwpvgae90wnxtr2rvwf8e146qg6 @@ -0,0 +1 @@ +1111111111111111111111111 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/9/g9qtzypr7b7x9c00zgpnw90pch381j378ttszp1jfb658 b/implementation/fuzz/inputs-genvm-modules-complete-json/g/9/g9qtzypr7b7x9c00zgpnw90pch381j378ttszp1jfb658 new file mode 100644 index 00000000..f0cf5d4e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/9/g9qtzypr7b7x9c00zgpnw90pch381j378ttszp1jfb658 @@ -0,0 +1,3 @@ +{ + "111E11111111111111111.11111111353331111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1111111.111111111133.3foo 4 -12222": 44444444444444444444444444 +} \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/b/gb62dbqk4z17473cs581byf9df8452h86tz7r7vjja3er b/implementation/fuzz/inputs-genvm-modules-complete-json/g/b/gb62dbqk4z17473cs581byf9df8452h86tz7r7vjja3er new file mode 100644 index 00000000..27b88173 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/b/gb62dbqk4z17473cs581byf9df8452h86tz7r7vjja3er @@ -0,0 +1,9 @@ +{ + "": { + "":{ + "": { + "": { + "": { + "":{ + "": { +, \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/b/gb6q6gtnpe7dtegw8qsney5km59ma0yn4690y7qg2hq04 b/implementation/fuzz/inputs-genvm-modules-complete-json/g/b/gb6q6gtnpe7dtegw8qsney5km59ma0yn4690y7qg2hq04 new file mode 100644 index 00000000..e971cb03 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/b/gb6q6gtnpe7dtegw8qsney5km59ma0yn4690y7qg2hq04 @@ -0,0 +1 @@ +22222222222222222222 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/d/gdawmvp49h1dt7259q310ypjasyxkq3fxs1svg1rr3c18 b/implementation/fuzz/inputs-genvm-modules-complete-json/g/d/gdawmvp49h1dt7259q310ypjasyxkq3fxs1svg1rr3c18 new file mode 100644 index 00000000..6e24c9c1 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/d/gdawmvp49h1dt7259q310ypjasyxkq3fxs1svg1rr3c18 @@ -0,0 +1 @@ + [11111,111111E 111, \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/d/gdrt3ewgwe2zgrax02f99a2mz17c7mzej0zkhmc5sxz60 b/implementation/fuzz/inputs-genvm-modules-complete-json/g/d/gdrt3ewgwe2zgrax02f99a2mz17c7mzej0zkhmc5sxz60 new file mode 100644 index 00000000..68a26cbe --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/d/gdrt3ewgwe2zgrax02f99a2mz17c7mzej0zkhmc5sxz60 @@ -0,0 +1 @@ + "ру2C _qbz" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/e/gejprghszwxv6ppp3mrranea2ptkgwenp6h2gpyn03rsm b/implementation/fuzz/inputs-genvm-modules-complete-json/g/e/gejprghszwxv6ppp3mrranea2ptkgwenp6h2gpyn03rsm new file mode 100644 index 00000000..0aa7ade6 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/e/gejprghszwxv6ppp3mrranea2ptkgwenp6h2gpyn03rsm @@ -0,0 +1 @@ +111111311111111111111111111E111 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/m/gm4zy0ph9dzdwvdf02pvmmnb3z71fxqdzmk5tfcd95016 b/implementation/fuzz/inputs-genvm-modules-complete-json/g/m/gm4zy0ph9dzdwvdf02pvmmnb3z71fxqdzmk5tfcd95016 new file mode 100644 index 00000000..3f3eefe6 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/m/gm4zy0ph9dzdwvdf02pvmmnb3z71fxqdzmk5tfcd95016 @@ -0,0 +1 @@ +0E5555555515 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/m/gmbdhbg2n4jtfvgpzkdrvag402km42qm3cvykssn1f7c2 b/implementation/fuzz/inputs-genvm-modules-complete-json/g/m/gmbdhbg2n4jtfvgpzkdrvag402km42qm3cvykssn1f7c2 new file mode 100644 index 00000000..78c1311a --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/m/gmbdhbg2n4jtfvgpzkdrvag402km42qm3cvykssn1f7c2 @@ -0,0 +1 @@ +333333333.33333333333333333333333333 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/m/gmgzrf6rdq7jav2mc6v518jtcs63dr389zfqj1awnmx82 b/implementation/fuzz/inputs-genvm-modules-complete-json/g/m/gmgzrf6rdq7jav2mc6v518jtcs63dr389zfqj1awnmx82 new file mode 100644 index 00000000..7d4677b9 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/m/gmgzrf6rdq7jav2mc6v518jtcs63dr389zfqj1awnmx82 @@ -0,0 +1 @@ +111112222222222222222222222 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/m/gmyj4521be0c23ktwdyqs75esqbby40y7tc4ee40mg33e b/implementation/fuzz/inputs-genvm-modules-complete-json/g/m/gmyj4521be0c23ktwdyqs75esqbby40y7tc4ee40mg33e new file mode 100644 index 00000000..4fa45610 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/m/gmyj4521be0c23ktwdyqs75esqbby40y7tc4ee40mg33e @@ -0,0 +1,5 @@ +{ + "foo": [ + 0 , + 123, + -1e * nu \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/n/gn161457rhjg8q1gtgwrxwmhv7fe4hd36n16x15e3zjmm b/implementation/fuzz/inputs-genvm-modules-complete-json/g/n/gn161457rhjg8q1gtgwrxwmhv7fe4hd36n16x15e3zjmm new file mode 100644 index 00000000..98015413 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/n/gn161457rhjg8q1gtgwrxwmhv7fe4hd36n16x15e3zjmm @@ -0,0 +1,4 @@ + [ + [ + [[[ [ + [[[ ,,,,] ,,,,] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/q/gqnz8wygwa45hanm7s90tvaw890psc9tg15712zb3p7j4 b/implementation/fuzz/inputs-genvm-modules-complete-json/g/q/gqnz8wygwa45hanm7s90tvaw890psc9tg15712zb3p7j4 new file mode 100644 index 00000000..583b66ad --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/q/gqnz8wygwa45hanm7s90tvaw890psc9tg15712zb3p7j4 @@ -0,0 +1 @@ + [1111111111111111111111111111111111.1111111111E111,11111111111111111111111111.1111111111E111, 2,11111111E111,11111111111111111111111E111, 2, 3] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/s/gs2391srmekajtdzkg6xvyr4rd6ndvp5279vwc0xn2bcp b/implementation/fuzz/inputs-genvm-modules-complete-json/g/s/gs2391srmekajtdzkg6xvyr4rd6ndvp5279vwc0xn2bcp new file mode 100644 index 00000000..21e4fc78 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/s/gs2391srmekajtdzkg6xvyr4rd6ndvp5279vwc0xn2bcp @@ -0,0 +1 @@ +[[[[[[[[,,,,,,,,,, \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/s/gsxfwzkf15t5ab0xfzq7kwvzf9c3ej1vk3sdz9jpnykm8 b/implementation/fuzz/inputs-genvm-modules-complete-json/g/s/gsxfwzkf15t5ab0xfzq7kwvzf9c3ej1vk3sdz9jpnykm8 new file mode 100644 index 00000000..aa9643b4 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/s/gsxfwzkf15t5ab0xfzq7kwvzf9c3ej1vk3sdz9jpnykm8 @@ -0,0 +1,2 @@ +{ + "foo" & \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/t/gtnxy4531pmxv9847jz7perpg0cpz4wnkdkxgtydg3v60 b/implementation/fuzz/inputs-genvm-modules-complete-json/g/t/gtnxy4531pmxv9847jz7perpg0cpz4wnkdkxgtydg3v60 new file mode 100644 index 00000000..ba544124 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/t/gtnxy4531pmxv9847jz7perpg0cpz4wnkdkxgtydg3v60 @@ -0,0 +1,17 @@ +{ + "foo": [ + "bar", + "baz\n\\{", + -0, + 1e20, + null, + true, + [1, 2, 3] + ], + "barrrrrrrrrr": [ ], + "brrrr": [ ], + "bar": [ + "русские mbbbbbbbbb", + "mbbbbbbbbbbbbbbaz\t\\uabbbbb" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/v/gvh7p1xkxz9brkee1ea2ywawfgxqn5x8t9svnqt9244ea b/implementation/fuzz/inputs-genvm-modules-complete-json/g/v/gvh7p1xkxz9brkee1ea2ywawfgxqn5x8t9svnqt9244ea new file mode 100644 index 00000000..edb52046 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/v/gvh7p1xkxz9brkee1ea2ywawfgxqn5x8t9svnqt9244ea @@ -0,0 +1 @@ + "b󗥗1111󗥗111本" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/w/gw0baa8yz1ty6dywpg4xjeawgmehkk287m40ygkx6f6zp b/implementation/fuzz/inputs-genvm-modules-complete-json/g/w/gw0baa8yz1ty6dywpg4xjeawgmehkk287m40ygkx6f6zp new file mode 100644 index 00000000..b04a28ed --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/w/gw0baa8yz1ty6dywpg4xjeawgmehkk287m40ygkx6f6zp @@ -0,0 +1,3 @@ +{ + "": { + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/x/gx98f4rk68hcfbeqdx4pk7bzjz07vg6e7a3cxzx3v9wft b/implementation/fuzz/inputs-genvm-modules-complete-json/g/x/gx98f4rk68hcfbeqdx4pk7bzjz07vg6e7a3cxzx3v9wft new file mode 100644 index 00000000..a03bdb9d --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/x/gx98f4rk68hcfbeqdx4pk7bzjz07vg6e7a3cxzx3v9wft @@ -0,0 +1,2 @@ +[, + ] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/x/gxwg8stb3a070a7d4pg61a7rveqv0ccr5bhfpn7a4rstg b/implementation/fuzz/inputs-genvm-modules-complete-json/g/x/gxwg8stb3a070a7d4pg61a7rveqv0ccr5bhfpn7a4rstg new file mode 100644 index 00000000..6b787f72 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/x/gxwg8stb3a070a7d4pg61a7rveqv0ccr5bhfpn7a4rstg @@ -0,0 +1 @@ +1.1111 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/y/gyqgq9ge6v81dz4ah04p7s2wmgpxxvzqwytpzbmwz7b3a b/implementation/fuzz/inputs-genvm-modules-complete-json/g/y/gyqgq9ge6v81dz4ah04p7s2wmgpxxvzqwytpzbmwz7b3a new file mode 100644 index 00000000..baaa5311 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/y/gyqgq9ge6v81dz4ah04p7s2wmgpxxvzqwytpzbmwz7b3a @@ -0,0 +1,4 @@ +{ + "foo" + + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/g/z/gzj084c49th6y4ryysvh0027yvt77cfmxxn79qcyyhzgg b/implementation/fuzz/inputs-genvm-modules-complete-json/g/z/gzj084c49th6y4ryysvh0027yvt77cfmxxn79qcyyhzgg new file mode 100644 index 00000000..86a3e43d --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/g/z/gzj084c49th6y4ryysvh0027yvt77cfmxxn79qcyyhzgg @@ -0,0 +1 @@ + 1 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/1/h1ybayrg290j0f6myh3tt1p63zzjx1mf29k0rwewqqchw b/implementation/fuzz/inputs-genvm-modules-complete-json/h/1/h1ybayrg290j0f6myh3tt1p63zzjx1mf29k0rwewqqchw new file mode 100644 index 00000000..e0e1ad41 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/h/1/h1ybayrg290j0f6myh3tt1p63zzjx1mf29k0rwewqqchw @@ -0,0 +1,3 @@ + + +"р\r" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/2/h213vzjvnvfx83c7abfycjh14x57afa1ceyznkx4tg0k8 b/implementation/fuzz/inputs-genvm-modules-complete-json/h/2/h213vzjvnvfx83c7abfycjh14x57afa1ceyznkx4tg0k8 new file mode 100644 index 00000000..bc430114 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/h/2/h213vzjvnvfx83c7abfycjh14x57afa1ceyznkx4tg0k8 @@ -0,0 +1,2 @@ +"\r -1" + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/2/h2wcbzae9g1dae8mbrgtcph3phzvn6xs0p4hgwcxnzeea b/implementation/fuzz/inputs-genvm-modules-complete-json/h/2/h2wcbzae9g1dae8mbrgtcph3phzvn6xs0p4hgwcxnzeea new file mode 100644 index 00000000..e4b6bad7 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/h/2/h2wcbzae9g1dae8mbrgtcph3phzvn6xs0p4hgwcxnzeea @@ -0,0 +1,20 @@ +{ + "foo": [ + "bar", + "baz\n\\z", + 1.3, + 1.3, + -123, + -1e10, + 1e20, + null, + true, + false, + [1, 2, 3] + ], + "bar": [ + "русские буквы 殥本", + { "foo": [ + "b]r", + ", + " \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/4/h4ep3m70qztxm8dd5ftste6jege5zgy5t6j021833j7ej b/implementation/fuzz/inputs-genvm-modules-complete-json/h/4/h4ep3m70qztxm8dd5ftste6jege5zgy5t6j021833j7ej new file mode 100644 index 00000000..19626109 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/h/4/h4ep3m70qztxm8dd5ftste6jege5zgy5t6j021833j7ej @@ -0,0 +1 @@ +222222222222222222222222222 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/4/h4jhyy4pf9dk9sm960mm91qpnw8draq2q4mwvdngp56d2 b/implementation/fuzz/inputs-genvm-modules-complete-json/h/4/h4jhyy4pf9dk9sm960mm91qpnw8draq2q4mwvdngp56d2 new file mode 100644 index 00000000..048c40e1 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/h/4/h4jhyy4pf9dk9sm960mm91qpnw8draq2q4mwvdngp56d2 @@ -0,0 +1 @@ +1.611e00 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/5/h5wxz58hzw7pmvdgyt09dyarfk10n5g1rfxf5nep1531r b/implementation/fuzz/inputs-genvm-modules-complete-json/h/5/h5wxz58hzw7pmvdgyt09dyarfk10n5g1rfxf5nep1531r new file mode 100644 index 0000000000000000000000000000000000000000..d98443ff77e7fe101a4f5fbc24c79cc98a298e80 GIT binary patch literal 260 zcmb>CQUC&_wETP}D}`t<2P}}3Sfr!_kxNRfO390fse4G#sR3b;u5HM83Q&2sA93PvAF(I literal 0 HcmV?d00001 diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/6/h62x0c4w7p7jsrz1h1ezka109ryjqetjtm9n6bth6ea4e b/implementation/fuzz/inputs-genvm-modules-complete-json/h/6/h62x0c4w7p7jsrz1h1ezka109ryjqetjtm9n6bth6ea4e new file mode 100644 index 00000000..bbeba644 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/h/6/h62x0c4w7p7jsrz1h1ezka109ryjqetjtm9n6bth6ea4e @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/8/h8dk8bqhfqc4qy61zpzberwejg3b5evkeq3dma3js2t0e b/implementation/fuzz/inputs-genvm-modules-complete-json/h/8/h8dk8bqhfqc4qy61zpzberwejg3b5evkeq3dma3js2t0e new file mode 100644 index 00000000..7dfe9512 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/h/8/h8dk8bqhfqc4qy61zpzberwejg3b5evkeq3dma3js2t0e @@ -0,0 +1 @@ +" \uDbbb\uDDbBVuu" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/8/h8eegm2adakfzwk3dh4hwkepwt67gpkyfw5x6ywrrs9jg b/implementation/fuzz/inputs-genvm-modules-complete-json/h/8/h8eegm2adakfzwk3dh4hwkepwt67gpkyfw5x6ywrrs9jg new file mode 100644 index 00000000..538f7bf9 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/h/8/h8eegm2adakfzwk3dh4hwkepwt67gpkyfw5x6ywrrs9jg @@ -0,0 +1 @@ + [1, [1, [1, [1, [1, [1, [1, [1, \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/8/h8s754wqsxw871nt24v192x2eck1jz9w9s8bk89m7657m b/implementation/fuzz/inputs-genvm-modules-complete-json/h/8/h8s754wqsxw871nt24v192x2eck1jz9w9s8bk89m7657m new file mode 100644 index 00000000..249a78ec --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/h/8/h8s754wqsxw871nt24v192x2eck1jz9w9s8bk89m7657m @@ -0,0 +1,20 @@ +{ + "bar": [ + "рус", + true, + 123, + -123, + -1e10, + 1e20, + null, + "baz\n\\{", + false, + [1, 2, 3] + ], + "bar": [ ], + "bar": [ + " русские буквЇ 日本", + "mbbbbbbbbbbbbbbaz\t\uabbbbb", + "mbbbbbbbbbbbbbbaz\t\\uabbbbb" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/a/ha1k3z20wf9ahpv6ttewhna2m0251hx8tvtsk13pdazb8 b/implementation/fuzz/inputs-genvm-modules-complete-json/h/a/ha1k3z20wf9ahpv6ttewhna2m0251hx8tvtsk13pdazb8 new file mode 100644 index 00000000..c2520b29 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/h/a/ha1k3z20wf9ahpv6ttewhna2m0251hx8tvtsk13pdazb8 @@ -0,0 +1 @@ +111111111111111111111111111 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/a/haagrvyam74hae6x8wsw3an148qa9caw8cjx2jwxpyznr b/implementation/fuzz/inputs-genvm-modules-complete-json/h/a/haagrvyam74hae6x8wsw3an148qa9caw8cjx2jwxpyznr new file mode 100644 index 00000000..382a60ca --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/h/a/haagrvyam74hae6x8wsw3an148qa9caw8cjx2jwxpyznr @@ -0,0 +1 @@ + 3333333333333333333333333 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/c/hc7wg34atrg7afqky1ajnxprcdzbbdqfg09fb92m063r2 b/implementation/fuzz/inputs-genvm-modules-complete-json/h/c/hc7wg34atrg7afqky1ajnxprcdzbbdqfg09fb92m063r2 new file mode 100644 index 00000000..226d9e67 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/h/c/hc7wg34atrg7afqky1ajnxprcdzbbdqfg09fb92m063r2 @@ -0,0 +1,2 @@ + +"рbbbb\\ua1$, r" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/f/hfh1j3r352wvahzbgnh8t449j3pm9kb4d1ax0ezky2b7j b/implementation/fuzz/inputs-genvm-modules-complete-json/h/f/hfh1j3r352wvahzbgnh8t449j3pm9kb4d1ax0ezky2b7j new file mode 100644 index 00000000..1cbaef2f --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/h/f/hfh1j3r352wvahzbgnh8t449j3pm9kb4d1ax0ezky2b7j @@ -0,0 +1 @@ + [1111111111.1110111111, 2, 1111.11, 2, 1111.111, 1111.11, 2, 1111.11111111111e+2, 1111, 2, 1111.11, 2, 1111.11111116112, 1111.1111111611111111] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/g/hgw6n5jgrsxe3aydj10cvq35ma4wsg7qczhz1r64d7hn0 b/implementation/fuzz/inputs-genvm-modules-complete-json/h/g/hgw6n5jgrsxe3aydj10cvq35ma4wsg7qczhz1r64d7hn0 new file mode 100644 index 00000000..9d012302 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/h/g/hgw6n5jgrsxe3aydj10cvq35ma4wsg7qczhz1r64d7hn0 @@ -0,0 +1 @@ +1111.11111111111111111E311, \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/h/hhfkz92b2h54dsc8s1vzbhfzenxw9r7hx740z41fexja0 b/implementation/fuzz/inputs-genvm-modules-complete-json/h/h/hhfkz92b2h54dsc8s1vzbhfzenxw9r7hx740z41fexja0 new file mode 100644 index 00000000..24abda44 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/h/h/hhfkz92b2h54dsc8s1vzbhfzenxw9r7hx740z41fexja0 @@ -0,0 +1 @@ + [1111111111111111111111E111, 2,11111111111111111111111111111111111111E111,1111E111, 2,1111111111111111E111, 1, 3] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/h/hhkddf8e6nbae84a2vgwbs0dcm847zgw3vctbsjd6j2ag b/implementation/fuzz/inputs-genvm-modules-complete-json/h/h/hhkddf8e6nbae84a2vgwbs0dcm847zgw3vctbsjd6j2ag new file mode 100644 index 00000000..dd34e663 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/h/h/hhkddf8e6nbae84a2vgwbs0dcm847zgw3vctbsjd6j2ag @@ -0,0 +1,2 @@ + [[ [[{ + "fz1T1111111111F1111111111111111111111111111111111111111111111115q1111111111A1111111111111111.11111111E111.111111,o": "bar", , \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/h/hhxkfkn00xvw37f3t551t5tcemzfqe9jegt9wgftas6c2 b/implementation/fuzz/inputs-genvm-modules-complete-json/h/h/hhxkfkn00xvw37f3t551t5tcemzfqe9jegt9wgftas6c2 new file mode 100644 index 00000000..31a1eccb --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/h/h/hhxkfkn00xvw37f3t551t5tcemzfqe9jegt9wgftas6c2 @@ -0,0 +1,16 @@ +{ + "foo": [ + + 123, + -123, + -1e10, + null, + true, + false, + [1, 2, 3] + ], + "bar": [ + "русские бڃкزы 日本az\t\uabbb\b", + "bbbb" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/j/hjrr8ycqfat197v4k1hxtkt0zcyrvhgx8tmzx326zrd0r b/implementation/fuzz/inputs-genvm-modules-complete-json/h/j/hjrr8ycqfat197v4k1hxtkt0zcyrvhgx8tmzx326zrd0r new file mode 100644 index 00000000..9b97d2c1 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/h/j/hjrr8ycqfat197v4k1hxtkt0zcyrvhgx8tmzx326zrd0r @@ -0,0 +1,2 @@ + +"р[ rв҇ 󗥺ub" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/n/hn2gy0dcn4srykfn7x9vabhne57j2x7y8dg4mhrjdw7wj b/implementation/fuzz/inputs-genvm-modules-complete-json/h/n/hn2gy0dcn4srykfn7x9vabhne57j2x7y8dg4mhrjdw7wj new file mode 100644 index 00000000..218b1dbb --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/h/n/hn2gy0dcn4srykfn7x9vabhne57j2x7y8dg4mhrjdw7wj @@ -0,0 +1 @@ +"р\\󗥺r" diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/n/hn9qfpe5y3st6etwykvvb01v697hvpsbzgpq98e44xvpy b/implementation/fuzz/inputs-genvm-modules-complete-json/h/n/hn9qfpe5y3st6etwykvvb01v697hvpsbzgpq98e44xvpy new file mode 100644 index 00000000..81750b96 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/h/n/hn9qfpe5y3st6etwykvvb01v697hvpsbzgpq98e44xvpy @@ -0,0 +1 @@ +{ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/n/hnamj82p5zpjpyzzvxe1ztgte2spnpdqet0gm82frhmda b/implementation/fuzz/inputs-genvm-modules-complete-json/h/n/hnamj82p5zpjpyzzvxe1ztgte2spnpdqet0gm82frhmda new file mode 100644 index 00000000..96741794 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/h/n/hnamj82p5zpjpyzzvxe1ztgte2spnpdqet0gm82frhmda @@ -0,0 +1,5 @@ +{ + "foo" + +% + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/q/hq75ncgkjyx1j6h3h5vw9x9m3nw6f6h5rnkv1e1qx55qp b/implementation/fuzz/inputs-genvm-modules-complete-json/h/q/hq75ncgkjyx1j6h3h5vw9x9m3nw6f6h5rnkv1e1qx55qp new file mode 100644 index 00000000..02a2488e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/h/q/hq75ncgkjyx1j6h3h5vw9x9m3nw6f6h5rnkv1e1qx55qp @@ -0,0 +1,2 @@ +"\"\t" + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/h/q/hqmnjzsw0nb75195g8emmhk4tjw68n44xwvgkz4w8063p b/implementation/fuzz/inputs-genvm-modules-complete-json/h/q/hqmnjzsw0nb75195g8emmhk4tjw68n44xwvgkz4w8063p new file mode 100644 index 0000000000000000000000000000000000000000..98a6f3466a1cefd839b33502b511eec8eb39259c GIT binary patch literal 74 scmb>CQczG*vZ_{q(O@1IL<}SWWr78u{IqCQUC&_wETP}D}`t<2P}}3Sfr$b%&qdti;1a15;HV3)B|E{z{nV?H5xwv+N8_C M$iTp*AOd6p0Qe>zGXMYp literal 0 HcmV?d00001 diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/k/r/krh4hj84agz7txk2hsapr4r7gbpxac5ttbdefme657ysg b/implementation/fuzz/inputs-genvm-modules-complete-json/k/r/krh4hj84agz7txk2hsapr4r7gbpxac5ttbdefme657ysg new file mode 100644 index 00000000..48d77787 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/k/r/krh4hj84agz7txk2hsapr4r7gbpxac5ttbdefme657ysg @@ -0,0 +1 @@ + [ { } ] diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/k/s/ksqdnet3e2y8ztax53q7hddaej4xqjgaz5kveh5eeyxbw b/implementation/fuzz/inputs-genvm-modules-complete-json/k/s/ksqdnet3e2y8ztax53q7hddaej4xqjgaz5kveh5eeyxbw new file mode 100644 index 00000000..c27ee231 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/k/s/ksqdnet3e2y8ztax53q7hddaej4xqjgaz5kveh5eeyxbw @@ -0,0 +1 @@ +111.1115 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/k/t/kt8wttecepmpdjfnc0ht0x0gwb6a1jq03s3yj444kqjcy b/implementation/fuzz/inputs-genvm-modules-complete-json/k/t/kt8wttecepmpdjfnc0ht0x0gwb6a1jq03s3yj444kqjcy new file mode 100644 index 00000000..cd15dfcb --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/k/t/kt8wttecepmpdjfnc0ht0x0gwb6a1jq03s3yj444kqjcy @@ -0,0 +1,15 @@ +{ + "fo + + + + + + + + + + + + +[[ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/k/t/ktafsc8tmnxj0cxxmr3jes8gz76p54fs8wzfqh7pz9274 b/implementation/fuzz/inputs-genvm-modules-complete-json/k/t/ktafsc8tmnxj0cxxmr3jes8gz76p54fs8wzfqh7pz9274 new file mode 100644 index 00000000..dd013145 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/k/t/ktafsc8tmnxj0cxxmr3jes8gz76p54fs8wzfqh7pz9274 @@ -0,0 +1 @@ + "с\fffffffffffffffffff\fffffffffvabba\f/////////////////ffffff@ffffffffffffffffffabba\//////fffffffffffffffffffffffabba\//////////////////////-/111111111111111/////bbbb" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/k/y/ky0p59y4jd3yq8j6gz8zz668capv25c5ya0s58qydxcst b/implementation/fuzz/inputs-genvm-modules-complete-json/k/y/ky0p59y4jd3yq8j6gz8zz668capv25c5ya0s58qydxcst new file mode 100644 index 00000000..a0aeede1 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/k/y/ky0p59y4jd3yq8j6gz8zz668capv25c5ya0s58qydxcst @@ -0,0 +1 @@ +fa \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/k/y/ky4mbkfs19k1fmkfhx1ej4jqns8h1v8dyj58eg6j33dmt b/implementation/fuzz/inputs-genvm-modules-complete-json/k/y/ky4mbkfs19k1fmkfhx1ej4jqns8h1v8dyj58eg6j33dmt new file mode 100644 index 00000000..cd67668e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/k/y/ky4mbkfs19k1fmkfhx1ej4jqns8h1v8dyj58eg6j33dmt @@ -0,0 +1 @@ +1111111111121105111111e-625 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/k/y/kyst24ensy38wm2t0at68frg52g4g812hm20ws9ne1mde b/implementation/fuzz/inputs-genvm-modules-complete-json/k/y/kyst24ensy38wm2t0at68frg52g4g812hm20ws9ne1mde new file mode 100644 index 00000000..1fbf0d2d --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/k/y/kyst24ensy38wm2t0at68frg52g4g812hm20ws9ne1mde @@ -0,0 +1,19 @@ +{ + + "barrrrrrrrrr": [ ], + "foo": [ + "bar", + "baz\n\\{", + -1e10, + 1e20, + null, + true, + [1, 2, 3] + ], + "barrrrrrrrrr": [ ], + "brrrr": [ ], + "bar": [ + "русские mbbbbbbbbb", + "mbbbbbbbbbbbbbbaz\t\\uabbbbb" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/k/y/kyx60vyjpbs117mf2gz69h6enprvzm0hcwt3z641kf5xe b/implementation/fuzz/inputs-genvm-modules-complete-json/k/y/kyx60vyjpbs117mf2gz69h6enprvzm0hcwt3z641kf5xe new file mode 100644 index 00000000..c8eddce8 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/k/y/kyx60vyjpbs117mf2gz69h6enprvzm0hcwt3z641kf5xe @@ -0,0 +1 @@ +[1,22,, ' \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/k/z/kz3m9qrp2a5axfa9jy5h8ewtxanwygafwhx4r5fwbztce b/implementation/fuzz/inputs-genvm-modules-complete-json/k/z/kz3m9qrp2a5axfa9jy5h8ewtxanwygafwhx4r5fwbztce new file mode 100644 index 00000000..03c502e6 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/k/z/kz3m9qrp2a5axfa9jy5h8ewtxanwygafwhx4r5fwbztce @@ -0,0 +1,5 @@ +{"a + + + +, \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/m/0/m0wmr0cmdm54pr7gsbxyskvymrvkdyh003phfftngp9dj b/implementation/fuzz/inputs-genvm-modules-complete-json/m/0/m0wmr0cmdm54pr7gsbxyskvymrvkdyh003phfftngp9dj new file mode 100644 index 00000000..54eb83c6 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/m/0/m0wmr0cmdm54pr7gsbxyskvymrvkdyh003phfftngp9dj @@ -0,0 +1,3 @@ + [1111111111.1111111111111e+2, 1111, 2, 1111.111111E111, -1e10, + 1e+2, 111E111, 2, 111111111111e+2, 1111, 2, 1111.11, 2, 1111.11111116112, -1e10, + 1111] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/m/1/m1qhqarrsg7mnv6d49q2ksgb6q2afqe8z16ct7dkxy9aw b/implementation/fuzz/inputs-genvm-modules-complete-json/m/1/m1qhqarrsg7mnv6d49q2ksgb6q2afqe8z16ct7dkxy9aw new file mode 100644 index 00000000..7f2a262e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/m/1/m1qhqarrsg7mnv6d49q2ksgb6q2afqe8z16ct7dkxy9aw @@ -0,0 +1 @@ + "bIbb򀻃z\n\/222222сс򀻃U2222222222сскиʵ6букbbcbbbbbIbb򀻃z\n\/222222сскиʵ6бbڲы 日12 & Bxbz" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/m/3/m32t8fg331gpkvmxp9mkgyxyk8r1ndbqtfxxh7904mkda b/implementation/fuzz/inputs-genvm-modules-complete-json/m/3/m32t8fg331gpkvmxp9mkgyxyk8r1ndbqtfxxh7904mkda new file mode 100644 index 00000000..d51fe04c --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/m/3/m32t8fg331gpkvmxp9mkgyxyk8r1ndbqtfxxh7904mkda @@ -0,0 +1,21 @@ +{ + "foo": [ + "bar", + "baz\n\\z", + 123, + -123, + -1e10, + 1e20, + null, + true, + false, + [1, 2, 3] + +], + "bar" + : [ + "руссºие буквы 日本\uabbbbb", + "m1111111111111111111111111bbbbbbaz\t", + "mbbвы 日本\uabbbbbbaz\t\\uabbbbb" + ] +} \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/m/3/m3ahpq4mgferty6rhpdp79xvte4cfjmzwtf53kmsxaz4g b/implementation/fuzz/inputs-genvm-modules-complete-json/m/3/m3ahpq4mgferty6rhpdp79xvte4cfjmzwtf53kmsxaz4g new file mode 100644 index 00000000..1dcd97c3 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/m/3/m3ahpq4mgferty6rhpdp79xvte4cfjmzwtf53kmsxaz4g @@ -0,0 +1,3 @@ +{ + "f[ + " \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/m/3/m3mzkfk06j8qbanxvsdd0ctez8e8js8qq86w1n8s85kzj b/implementation/fuzz/inputs-genvm-modules-complete-json/m/3/m3mzkfk06j8qbanxvsdd0ctez8e8js8qq86w1n8s85kzj new file mode 100644 index 00000000..5f075631 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/m/3/m3mzkfk06j8qbanxvsdd0ctez8e8js8qq86w1n8s85kzj @@ -0,0 +1 @@ + [1, 2, 3] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/m/4/m493qx6671gfk42fjcpzapxgjv932b4najhcdcvb87vcy b/implementation/fuzz/inputs-genvm-modules-complete-json/m/4/m493qx6671gfk42fjcpzapxgjv932b4najhcdcvb87vcy new file mode 100644 index 00000000..8ed2b59c --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/m/4/m493qx6671gfk42fjcpzapxgjv932b4najhcdcvb87vcy @@ -0,0 +1,5 @@ +[[[[[[[[ + + +3,[[[[[[[[[[[[[[[[[[[[[[[[[[ [[[[[[[[[[[[[ [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[ null,[ 11111111111E1 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/m/5/m5972ey1t36ymxs03rc2yz80xavs5dfjfc8gy1zgsm2yc b/implementation/fuzz/inputs-genvm-modules-complete-json/m/5/m5972ey1t36ymxs03rc2yz80xavs5dfjfc8gy1zgsm2yc new file mode 100644 index 00000000..5c281734 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/m/5/m5972ey1t36ymxs03rc2yz80xavs5dfjfc8gy1zgsm2yc @@ -0,0 +1 @@ + 22222222222222222222.Q \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/m/6/m68has31kcvzdmf3rmzmc54tja0yk4ebs21kt9v1htm16 b/implementation/fuzz/inputs-genvm-modules-complete-json/m/6/m68has31kcvzdmf3rmzmc54tja0yk4ebs21kt9v1htm16 new file mode 100644 index 0000000000000000000000000000000000000000..2cf4ff3d4da5ac78b2190d90fcbc9d8de017b425 GIT binary patch literal 20 Vcma!!=2GD0CQUC&_wETP}D}`t<2P}}3Sfr$b%&khvi;1a15;HV1hAD`~1PX?!Mg}l>1%fVGPyhf2t^pJP literal 0 HcmV?d00001 diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/r/g/rg8pj4jk38xv6fhpf1bbn2398bkvcgmkqq1crd55ja9ke b/implementation/fuzz/inputs-genvm-modules-complete-json/r/g/rg8pj4jk38xv6fhpf1bbn2398bkvcgmkqq1crd55ja9ke new file mode 100644 index 00000000..fffe9153 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/r/g/rg8pj4jk38xv6fhpf1bbn2398bkvcgmkqq1crd55ja9ke @@ -0,0 +1 @@ +11111111111111111111111111e-11111111111111 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/r/g/rg8q6t50jp1c9gst4ek2j8r245e2hw5a7gwvvpgnfhf1t b/implementation/fuzz/inputs-genvm-modules-complete-json/r/g/rg8q6t50jp1c9gst4ek2j8r245e2hw5a7gwvvpgnfhf1t new file mode 100644 index 00000000..009a4498 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/r/g/rg8q6t50jp1c9gst4ek2j8r245e2hw5a7gwvvpgnfhf1t @@ -0,0 +1 @@ +"р}}}}}}" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/r/h/rhtmpfv58qes02wt4ktjxrwveypfwns9hne6hvk9mrd44 b/implementation/fuzz/inputs-genvm-modules-complete-json/r/h/rhtmpfv58qes02wt4ktjxrwveypfwns9hne6hvk9mrd44 new file mode 100644 index 00000000..374405ff --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/r/h/rhtmpfv58qes02wt4ktjxrwveypfwns9hne6hvk9mrd44 @@ -0,0 +1 @@ +"рº\\\\bba[1a[1рºрºa[1!" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/r/j/rj71xj66vxs4qczheqy8ne3rtf5jsa0e84d787cfeh8xe b/implementation/fuzz/inputs-genvm-modules-complete-json/r/j/rj71xj66vxs4qczheqy8ne3rtf5jsa0e84d787cfeh8xe new file mode 100644 index 00000000..6ba0e99d --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/r/j/rj71xj66vxs4qczheqy8ne3rtf5jsa0e84d787cfeh8xe @@ -0,0 +1,2 @@ + + 525 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/r/k/rks8yw6t9nqwhn9ygqqjfn42egqbmz9tvxwjj4wtvvp7j b/implementation/fuzz/inputs-genvm-modules-complete-json/r/k/rks8yw6t9nqwhn9ygqqjfn42egqbmz9tvxwjj4wtvvp7j new file mode 100644 index 0000000000000000000000000000000000000000..6f99806f7df2c6effa5cde54dfdc79522a9b01d8 GIT binary patch literal 278 zcmb>CQUC&_wETP}D}`t<2P}}3Sfr!_=YoU~AetBeQ=V6vlLIzL*U-pV2PO)mm5hvx gfNWjERG0{CQUC%aLlmH7rJ!J#YGj}Tl2kG@&R61v0Z!aN0jdUMAPB&;@M71ZzyMSO0KV4? AwEzGB literal 0 HcmV?d00001 diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/s/n/sn8ydke73da5rnxnmpdn1sywrw0e9qw1z39rm8vw1875p b/implementation/fuzz/inputs-genvm-modules-complete-json/s/n/sn8ydke73da5rnxnmpdn1sywrw0e9qw1z39rm8vw1875p new file mode 100644 index 00000000..d9dd6a1c --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/s/n/sn8ydke73da5rnxnmpdn1sywrw0e9qw1z39rm8vw1875p @@ -0,0 +1,15 @@ +{ "foo": [ + "bar", + "baz\n\\{", + -1e10, + 1e20, + null, + true, + [1, 2, 3] + ], + "bapppppppppppppppppppppppppr": [ ], + "bar": [ + "русские mbbbbbbbbbbbbbbaz\t\uabbbbb", + "mbbbEbbbbbbbbbbaz\t\\uabbbbb" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/s/p/spd83sdtasgb2mw9aaaqtd2ag8bd8r8sg02e78e5nrhqr b/implementation/fuzz/inputs-genvm-modules-complete-json/s/p/spd83sdtasgb2mw9aaaqtd2ag8bd8r8sg02e78e5nrhqr new file mode 100644 index 00000000..4ab5509d --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/s/p/spd83sdtasgb2mw9aaaqtd2ag8bd8r8sg02e78e5nrhqr @@ -0,0 +1,4 @@ +[[[[[[[[ +3,[[[[[[[[[[[[[[ + +3,[[[[[[[[[[[[[[[[ [[[[[[[[[[[[[ [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[S \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/s/p/spj3bsfmd8z424mnm6vnmqxxk2578bkzztxtxbw7td7a2 b/implementation/fuzz/inputs-genvm-modules-complete-json/s/p/spj3bsfmd8z424mnm6vnmqxxk2578bkzztxtxbw7td7a2 new file mode 100644 index 00000000..457022db --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/s/p/spj3bsfmd8z424mnm6vnmqxxk2578bkzztxtxbw7td7a2 @@ -0,0 +1,21 @@ +{ + "foo": [ + "bar", + "baz\n\\{", + 123, + -123, + -1e10, + 1e20, + null, + true, + false, + [1, 2, 3] + ], + "mbb -barar": [ ], + "": [ ], + " bar": [ + "русские буквЇ 日本", + "mbbbbbbbbbbbbbbaz\t\uabbbbb", + "mbbbbbbbbbbbbbbaz\t\\uabbbbb" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/s/s/ssqjmb7kcpmjdfbwtqxt8mmfqwacc1ag8yprymdb8snep b/implementation/fuzz/inputs-genvm-modules-complete-json/s/s/ssqjmb7kcpmjdfbwtqxt8mmfqwacc1ag8yprymdb8snep new file mode 100644 index 00000000..6e49eb1e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/s/s/ssqjmb7kcpmjdfbwtqxt8mmfqwacc1ag8yprymdb8snep @@ -0,0 +1 @@ +"[[1, B\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ [\\\\\\\\\\\\\\\\@\\\\\\\\\\\\\\\\\\\\\\\\\\\\" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/s/s/sssc9q6nt579crjpv174n51wpjn43bn909zaxnaayb4sj b/implementation/fuzz/inputs-genvm-modules-complete-json/s/s/sssc9q6nt579crjpv174n51wpjn43bn909zaxnaayb4sj new file mode 100644 index 00000000..7c6f8311 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/s/s/sssc9q6nt579crjpv174n51wpjn43bn909zaxnaayb4sj @@ -0,0 +1,17 @@ +{ + "fon": [ + + "baz\n\\z", + 123, + -123, + -1e10, + true, + false, + [1, 2, 3] + ], + "bar": [ + "русские буквы 日本", + "mbbbbbbbb}bbbbbaz\t\uabbbbb", + "mbbbbbbbbbbbbbbaz\tквbbbbb" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/s/s/ssw4ytb1yy66twvrgjyfvwhfnkxk2kx2b0tdx3pcbsxae b/implementation/fuzz/inputs-genvm-modules-complete-json/s/s/ssw4ytb1yy66twvrgjyfvwhfnkxk2kx2b0tdx3pcbsxae new file mode 100644 index 00000000..a327b3f2 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/s/s/ssw4ytb1yy66twvrgjyfvwhfnkxk2kx2b0tdx3pcbsxae @@ -0,0 +1,2 @@ + "р\\u + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/s/t/sty8pqkhmpd4zqgwev6da6th185z93cx5xdwgvjmwjtr8 b/implementation/fuzz/inputs-genvm-modules-complete-json/s/t/sty8pqkhmpd4zqgwev6da6th185z93cx5xdwgvjmwjtr8 new file mode 100644 index 00000000..e32dde2c --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/s/t/sty8pqkhmpd4zqgwev6da6th185z93cx5xdwgvjmwjtr8 @@ -0,0 +1 @@ +112201111111111111111e-12 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/s/w/swxbs2ndsbvwv69rf6yrma4478m5tbq1rxaew320spk8c b/implementation/fuzz/inputs-genvm-modules-complete-json/s/w/swxbs2ndsbvwv69rf6yrma4478m5tbq1rxaew320spk8c new file mode 100644 index 00000000..609b81eb --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/s/w/swxbs2ndsbvwv69rf6yrma4478m5tbq1rxaew320spk8c @@ -0,0 +1 @@ + [1, 2, ) b \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/s/x/sxgx73x7d4skxrhkga3978tv1ftdjwa13gf35gxpb4mz6 b/implementation/fuzz/inputs-genvm-modules-complete-json/s/x/sxgx73x7d4skxrhkga3978tv1ftdjwa13gf35gxpb4mz6 new file mode 100644 index 00000000..5bc6d8d9 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/s/x/sxgx73x7d4skxrhkga3978tv1ftdjwa13gf35gxpb4mz6 @@ -0,0 +1 @@ +"р\\󗥺Fbb r" diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/s/y/syemw0n5g8krbh5mfk84gqvbstaw9hxayxjqf9q0zwsra b/implementation/fuzz/inputs-genvm-modules-complete-json/s/y/syemw0n5g8krbh5mfk84gqvbstaw9hxayxjqf9q0zwsra new file mode 100644 index 00000000..e18cd933 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/s/y/syemw0n5g8krbh5mfk84gqvbstaw9hxayxjqf9q0zwsra @@ -0,0 +1,4 @@ +"" + + + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/s/y/symmye7nza29sez2a9029kn3h0g0f51yvm5ertx0cppyr b/implementation/fuzz/inputs-genvm-modules-complete-json/s/y/symmye7nza29sez2a9029kn3h0g0f51yvm5ertx0cppyr new file mode 100644 index 00000000..158bf204 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/s/y/symmye7nza29sez2a9029kn3h0g0f51yvm5ertx0cppyr @@ -0,0 +1,16 @@ +[ + + + + + + + + + + + + + + +[[b[ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/s/z/szkkg31h97m32mqp6qrs2p8f41cvr6y7f6qfkr7bcpzke b/implementation/fuzz/inputs-genvm-modules-complete-json/s/z/szkkg31h97m32mqp6qrs2p8f41cvr6y7f6qfkr7bcpzke new file mode 100644 index 00000000..c12c8ae6 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/s/z/szkkg31h97m32mqp6qrs2p8f41cvr6y7f6qfkr7bcpzke @@ -0,0 +1 @@ +"\\\\泒a" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/t/0/t0nc5jyr3pe6v9bs5qeaf4khz36sn00g713mypkjvb7me b/implementation/fuzz/inputs-genvm-modules-complete-json/t/0/t0nc5jyr3pe6v9bs5qeaf4khz36sn00g713mypkjvb7me new file mode 100644 index 00000000..5ed6c9d1 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/t/0/t0nc5jyr3pe6v9bs5qeaf4khz36sn00g713mypkjvb7me @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/t/3/t3gehabpnf1n5b1znxw3tssraag8cb1z8ff0zscdtsgwt b/implementation/fuzz/inputs-genvm-modules-complete-json/t/3/t3gehabpnf1n5b1znxw3tssraag8cb1z8ff0zscdtsgwt new file mode 100644 index 00000000..287f0e3b --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/t/3/t3gehabpnf1n5b1znxw3tssraag8cb1z8ff0zscdtsgwt @@ -0,0 +1 @@ +"р" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/t/4/t4c0kr0xyk4tgzr9xmzgk85mw4abc3f7qw7hjrgyjhv9r b/implementation/fuzz/inputs-genvm-modules-complete-json/t/4/t4c0kr0xyk4tgzr9xmzgk85mw4abc3f7qw7hjrgyjhv9r new file mode 100644 index 0000000000000000000000000000000000000000..f1a10f5e23b375eae340a55432a16b6cd6065ccf GIT binary patch literal 284 zcmb>CQUC&_wETP}D}`t<2P}}3Sfr$b%&khvi;1a15;HV1MkoO3iG~0L!&D;!giKy( tP7au-3(^2mhYXYyOpv*_*k+g#P}`z0WgsqrikC59Q-DJ(77SpLc>q4;FpvNM literal 0 HcmV?d00001 diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/t/7/t7mp7d81dhz89yhk5yk0pxn4jxj751g9yh1kvqwtpd5ww b/implementation/fuzz/inputs-genvm-modules-complete-json/t/7/t7mp7d81dhz89yhk5yk0pxn4jxj751g9yh1kvqwtpd5ww new file mode 100644 index 0000000000000000000000000000000000000000..1a348de3e2da6ccb628986062ba7158010dd5f5e GIT binary patch literal 32 Wcmb>CQUC&_wETQ748Xv^$N&IJK?5NG literal 0 HcmV?d00001 diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/t/b/tb20b0s3mn5gg6e6jjxn7fs8khj3jh9de89q75yjp2tt2 b/implementation/fuzz/inputs-genvm-modules-complete-json/t/b/tb20b0s3mn5gg6e6jjxn7fs8khj3jh9de89q75yjp2tt2 new file mode 100644 index 00000000..90d65a66 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/t/b/tb20b0s3mn5gg6e6jjxn7fs8khj3jh9de89q75yjp2tt2 @@ -0,0 +1 @@ +2222222222222222222222 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/t/b/tbh8ppt850729b51y9nq4wkbkeczhyr1qbxdyekh7ggcr b/implementation/fuzz/inputs-genvm-modules-complete-json/t/b/tbh8ppt850729b51y9nq4wkbkeczhyr1qbxdyekh7ggcr new file mode 100644 index 00000000..b581a106 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/t/b/tbh8ppt850729b51y9nq4wkbkeczhyr1qbxdyekh7ggcr @@ -0,0 +1,3 @@ +"f\\u\\\\\\\\\\\\" + + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/t/b/tbzd4c43m17kehn6f4gbvjv81512b7ma1ffaq1xm5e4vt b/implementation/fuzz/inputs-genvm-modules-complete-json/t/b/tbzd4c43m17kehn6f4gbvjv81512b7ma1ffaq1xm5e4vt new file mode 100644 index 00000000..ac81defc --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/t/b/tbzd4c43m17kehn6f4gbvjv81512b7ma1ffaq1xm5e4vt @@ -0,0 +1,33 @@ +111 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/t/c/tccnrkkqzmrd17eh91gmtanm2hqs9jva7xed2a54cayd0 b/implementation/fuzz/inputs-genvm-modules-complete-json/t/c/tccnrkkqzmrd17eh91gmtanm2hqs9jva7xed2a54cayd0 new file mode 100644 index 00000000..5f0fcdef --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/t/c/tccnrkkqzmrd17eh91gmtanm2hqs9jva7xed2a54cayd0 @@ -0,0 +1 @@ +111111111111111111111e-515151611111 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/t/c/tcqdv403zxegm5pgexxxknh3xzd09f9s1zw488xfzab4r b/implementation/fuzz/inputs-genvm-modules-complete-json/t/c/tcqdv403zxegm5pgexxxknh3xzd09f9s1zw488xfzab4r new file mode 100644 index 00000000..5370b604 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/t/c/tcqdv403zxegm5pgexxxknh3xzd09f9s1zw488xfzab4r @@ -0,0 +1,18 @@ +22222222222222222222 + + + + + + + + + + + + + + + + + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/t/e/tewt7a2mr57vzp3k7ydqxm7jdqg2xykadr6zbjkq1qys4 b/implementation/fuzz/inputs-genvm-modules-complete-json/t/e/tewt7a2mr57vzp3k7ydqxm7jdqg2xykadr6zbjkq1qys4 new file mode 100644 index 00000000..39a81d2e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/t/e/tewt7a2mr57vzp3k7ydqxm7jdqg2xykadr6zbjkq1qys4 @@ -0,0 +1 @@ +2e+1722 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/t/f/tfjrjfrctqnbnhkwyyjgkcfx3e93q9g42xfx6prq8mqg0 b/implementation/fuzz/inputs-genvm-modules-complete-json/t/f/tfjrjfrctqnbnhkwyyjgkcfx3e93q9g42xfx6prq8mqg0 new file mode 100644 index 00000000..5b056ada --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/t/f/tfjrjfrctqnbnhkwyyjgkcfx3e93q9g42xfx6prq8mqg0 @@ -0,0 +1,6 @@ +{ + + + + + "Ca \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/t/g/tghvavtjyjphjx3r37e97cpexy5871p899xet1x7m3ht4 b/implementation/fuzz/inputs-genvm-modules-complete-json/t/g/tghvavtjyjphjx3r37e97cpexy5871p899xet1x7m3ht4 new file mode 100644 index 00000000..e5b653fd --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/t/g/tghvavtjyjphjx3r37e97cpexy5871p899xet1x7m3ht4 @@ -0,0 +1,2 @@ + +"р\\uba5R [[1, B\bõ\\u|a5R r" diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/t/h/thzkrf36h9dg6rwsac79b4k61gw1vqv6kw8n84ambexj4 b/implementation/fuzz/inputs-genvm-modules-complete-json/t/h/thzkrf36h9dg6rwsac79b4k61gw1vqv6kw8n84ambexj4 new file mode 100644 index 00000000..a7ec67ea --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/t/h/thzkrf36h9dg6rwsac79b4k61gw1vqv6kw8n84ambexj4 @@ -0,0 +1 @@ +222222222222222222222222122222 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/t/j/tjz9ftrgnt21xexwhtaznm62y4d0n39sgcey08s4pqn32 b/implementation/fuzz/inputs-genvm-modules-complete-json/t/j/tjz9ftrgnt21xexwhtaznm62y4d0n39sgcey08s4pqn32 new file mode 100644 index 0000000000000000000000000000000000000000..58cf8c06d0807e9e1a90f96e028da05daa269edd GIT binary patch literal 3 KcmZRO{0{&DGyxd^ literal 0 HcmV?d00001 diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/t/k/tkqszdz6rkktpz6712rj3jfh5x4by23nm5tyrkgabbxqr b/implementation/fuzz/inputs-genvm-modules-complete-json/t/k/tkqszdz6rkktpz6712rj3jfh5x4by23nm5tyrkgabbxqr new file mode 100644 index 00000000..a3e4771e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/t/k/tkqszdz6rkktpz6712rj3jfh5x4by23nm5tyrkgabbxqr @@ -0,0 +1,2 @@ +99999999999999999999999999999 + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/t/m/tm1sxtx5gy8fg6qqxy4fp89bd6j5p43r7k2rd53s0546m b/implementation/fuzz/inputs-genvm-modules-complete-json/t/m/tm1sxtx5gy8fg6qqxy4fp89bd6j5p43r7k2rd53s0546m new file mode 100644 index 00000000..24996f96 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/t/m/tm1sxtx5gy8fg6qqxy4fp89bd6j5p43r7k2rd53s0546m @@ -0,0 +1 @@ +{ "1": \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/t/q/tq0hzsh2sy3ddcsg40ew1mwzk7t3ndxnx76b7rk8pcbza b/implementation/fuzz/inputs-genvm-modules-complete-json/t/q/tq0hzsh2sy3ddcsg40ew1mwzk7t3ndxnx76b7rk8pcbza new file mode 100644 index 00000000..22eaddbf --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/t/q/tq0hzsh2sy3ddcsg40ew1mwzk7t3ndxnx76b7rk8pcbza @@ -0,0 +1,4 @@ +"\u0000ы\u00001115111\u00001115111111111111111ы\u00000000000000000000000000Ѻаы 嗥Sabbbb)))))))}00ы\u000011151111111111111 + + + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/t/q/tqqm05gz4tfbkzy9d0x40p1cj1mpvv18yx53kpwk0hajm b/implementation/fuzz/inputs-genvm-modules-complete-json/t/q/tqqm05gz4tfbkzy9d0x40p1cj1mpvv18yx53kpwk0hajm new file mode 100644 index 00000000..cd6f68d9 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/t/q/tqqm05gz4tfbkzy9d0x40p1cj1mpvv18yx53kpwk0hajm @@ -0,0 +1 @@ + " у00 0\u00000" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/t/q/tqsgy5jc4ey7xqhd0pqgv9peh363c6rtzpqgzxr2j370j b/implementation/fuzz/inputs-genvm-modules-complete-json/t/q/tqsgy5jc4ey7xqhd0pqgv9peh363c6rtzpqgzxr2j370j new file mode 100644 index 00000000..9d0a21e2 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/t/q/tqsgy5jc4ey7xqhd0pqgv9peh363c6rtzpqgzxr2j370j @@ -0,0 +1,9 @@ + { + "":0, + "mmmXmmmbd" + " + + + + + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/t/s/tsr9tph355x87s5cafd7358xfetzmna2jaje9tn63hnze b/implementation/fuzz/inputs-genvm-modules-complete-json/t/s/tsr9tph355x87s5cafd7358xfetzmna2jaje9tn63hnze new file mode 100644 index 00000000..f6c2f2fb --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/t/s/tsr9tph355x87s5cafd7358xfetzmna2jaje9tn63hnze @@ -0,0 +1 @@ +"р\\ub " \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/t/v/tvg7yr8tr3r56kpmyh06mgde04kmepy0y78fxwkqbvya2 b/implementation/fuzz/inputs-genvm-modules-complete-json/t/v/tvg7yr8tr3r56kpmyh06mgde04kmepy0y78fxwkqbvya2 new file mode 100644 index 0000000000000000000000000000000000000000..f9b078d60ec7f2729dfe211df7d0dacf969b6ae6 GIT binary patch literal 13 Ucmb \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/0/v0n4ehya912q5endeyjvppc7xk4a3p4pywpme4e8cm0f2 b/implementation/fuzz/inputs-genvm-modules-complete-json/v/0/v0n4ehya912q5endeyjvppc7xk4a3p4pywpme4e8cm0f2 new file mode 100644 index 00000000..7c363989 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/0/v0n4ehya912q5endeyjvppc7xk4a3p4pywpme4e8cm0f2 @@ -0,0 +1,3 @@ + + +"р[\bв҇ 󗥺5 b r" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/1/v1bbhk3wqc0516fwh3znyrpb8ccx98nb67ytedg78vz4w b/implementation/fuzz/inputs-genvm-modules-complete-json/v/1/v1bbhk3wqc0516fwh3znyrpb8ccx98nb67ytedg78vz4w new file mode 100644 index 00000000..6e2b4bef --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/1/v1bbhk3wqc0516fwh3znyrpb8ccx98nb67ytedg78vz4w @@ -0,0 +1,18 @@ +{ + "fz\t\uabbbbboo": [ + "bar", + "baz\n\\z", + 123, + -123, + + 1e20, + null, + true, + false, + [1, 2, 3] + ], + "bar": [ + "русские буквы 日本", + "mbbbbbbbbbbbbbbabbbbbbbbbbb\\uabbbbb" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/2/v226w6c43jv18cfeb1bnxkjc1dv6yvb16ghhpksdtdqam b/implementation/fuzz/inputs-genvm-modules-complete-json/v/2/v226w6c43jv18cfeb1bnxkjc1dv6yvb16ghhpksdtdqam new file mode 100644 index 00000000..1cfbc51b --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/2/v226w6c43jv18cfeb1bnxkjc1dv6yvb16ghhpksdtdqam @@ -0,0 +1 @@ +"\"\fo\" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/2/v2ydwb8kqxsbsft3xqrjr6ph3ppj99yhenczadg1b6ate b/implementation/fuzz/inputs-genvm-modules-complete-json/v/2/v2ydwb8kqxsbsft3xqrjr6ph3ppj99yhenczadg1b6ate new file mode 100644 index 00000000..80ed29c8 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/2/v2ydwb8kqxsbsft3xqrjr6ph3ppj99yhenczadg1b6ate @@ -0,0 +1,8 @@ +{ + "foo": [ + "bar", +[[[[[[[[[[[[[[[[[[[[[[[[[[ 123, + -123, + -1e10, + 1e20, + null,,,,,,,,,,,,,,,,,,,,,,,,,a \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/3/v3fny0ttw0wsmmhf0tt3qwz2w8n455h6ty27qjq0pwqxe b/implementation/fuzz/inputs-genvm-modules-complete-json/v/3/v3fny0ttw0wsmmhf0tt3qwz2w8n455h6ty27qjq0pwqxe new file mode 100644 index 00000000..b7147fc5 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/3/v3fny0ttw0wsmmhf0tt3qwz2w8n455h6ty27qjq0pwqxe @@ -0,0 +1,20 @@ +[" + + + + + + + + + + + + + + + + + + + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/3/v3rf8grtvs24scm7eht2f38dwpeffbmnxptb81yszkbh4 b/implementation/fuzz/inputs-genvm-modules-complete-json/v/3/v3rf8grtvs24scm7eht2f38dwpeffbmnxptb81yszkbh4 new file mode 100644 index 00000000..4c723b2a --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/3/v3rf8grtvs24scm7eht2f38dwpeffbmnxptb81yszkbh4 @@ -0,0 +1 @@ +1.61e6 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/4/v4mx2wxpjc3ypdq1rfnjhg8jxg94pnfyzdsmkqq10vgz8 b/implementation/fuzz/inputs-genvm-modules-complete-json/v/4/v4mx2wxpjc3ypdq1rfnjhg8jxg94pnfyzdsmkqq10vgz8 new file mode 100644 index 00000000..62d5d70d --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/4/v4mx2wxpjc3ypdq1rfnjhg8jxg94pnfyzdsmkqq10vgz8 @@ -0,0 +1 @@ +1.111111211 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/5/v5j0gwb56jzrre8y93et4mcv9x71s3takyq3bkf8kwagg b/implementation/fuzz/inputs-genvm-modules-complete-json/v/5/v5j0gwb56jzrre8y93et4mcv9x71s3takyq3bkf8kwagg new file mode 100644 index 00000000..7ee11f64 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/5/v5j0gwb56jzrre8y93et4mcv9x71s3takyq3bkf8kwagg @@ -0,0 +1 @@ +"UUUVbc〻 rIbc〻 rbbbbbb," diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/5/v5sxkhpw15t9fyev7w2frdce2kzxtrbmpvrpm77cvz15e b/implementation/fuzz/inputs-genvm-modules-complete-json/v/5/v5sxkhpw15t9fyev7w2frdce2kzxtrbmpvrpm77cvz15e new file mode 100644 index 00000000..917e19ca --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/5/v5sxkhpw15t9fyev7w2frdce2kzxtrbmpvrpm77cvz15e @@ -0,0 +1,5 @@ +{ "р\\u 4 $$$$ 1111@1110": [ ] +} + + + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/6/v6qzwvrh6qzg0q78njxekj5xg587hfb3x88dytjc91tqy b/implementation/fuzz/inputs-genvm-modules-complete-json/v/6/v6qzwvrh6qzg0q78njxekj5xg587hfb3x88dytjc91tqy new file mode 100644 index 00000000..57a13fac --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/6/v6qzwvrh6qzg0q78njxekj5xg587hfb3x88dytjc91tqy @@ -0,0 +1,2 @@ + { + "":0, \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/b/vbtrzd9d9nszedymt6vd4b1nfyv5g3ne00k2cqf1d4zxe b/implementation/fuzz/inputs-genvm-modules-complete-json/v/b/vbtrzd9d9nszedymt6vd4b1nfyv5g3ne00k2cqf1d4zxe new file mode 100644 index 00000000..331141e5 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/b/vbtrzd9d9nszedymt6vd4b1nfyv5g3ne00k2cqf1d4zxe @@ -0,0 +1 @@ +{ "br" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/c/vc5ww77ga0fk0cdsxtckn180ensm0ns09dyavgvwky8r4 b/implementation/fuzz/inputs-genvm-modules-complete-json/v/c/vc5ww77ga0fk0cdsxtckn180ensm0ns09dyavgvwky8r4 new file mode 100644 index 00000000..3dda308b --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/c/vc5ww77ga0fk0cdsxtckn180ensm0ns09dyavgvwky8r4 @@ -0,0 +1,4 @@ +"f0(00bAz\"\"VnG\"rzDкԸʱ Țуúo00\ro 1a+\ro 1 ( (000 bbaa+O0D07р\\uabb{bb" + + + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/c/vcxkywx2ywv64776g163kf3cefzwz3694bxebr7svcyw8 b/implementation/fuzz/inputs-genvm-modules-complete-json/v/c/vcxkywx2ywv64776g163kf3cefzwz3694bxebr7svcyw8 new file mode 100644 index 00000000..bcf64b9d --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/c/vcxkywx2ywv64776g163kf3cefzwz3694bxebr7svcyw8 @@ -0,0 +1 @@ +2222222222222222222222 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/f/vffm0hhkv5f63jcf4j05zb3n78vd0qp63fex6qeq4xkp2 b/implementation/fuzz/inputs-genvm-modules-complete-json/v/f/vffm0hhkv5f63jcf4j05zb3n78vd0qp63fex6qeq4xkp2 new file mode 100644 index 00000000..9351e598 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/f/vffm0hhkv5f63jcf4j05zb3n78vd0qp63fex6qeq4xkp2 @@ -0,0 +1 @@ + "русскиʵ6букbbcbbbbbIbbbڲы 日1 Bxbz" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/f/vfy3tt0qcnf44gpzmrtys7c6m0payywz0ebwd84xq28ky b/implementation/fuzz/inputs-genvm-modules-complete-json/v/f/vfy3tt0qcnf44gpzmrtys7c6m0payywz0ebwd84xq28ky new file mode 100644 index 00000000..e4eb59f0 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/f/vfy3tt0qcnf44gpzmrtys7c6m0payywz0ebwd84xq28ky @@ -0,0 +1 @@ +1.111 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/g/vgwa3yyr5zkyk7dg3xpn2rzrn42dgytz80he4m10560xy b/implementation/fuzz/inputs-genvm-modules-complete-json/v/g/vgwa3yyr5zkyk7dg3xpn2rzrn42dgytz80he4m10560xy new file mode 100644 index 00000000..0d707f26 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/g/vgwa3yyr5zkyk7dg3xpn2rzrn42dgytz80he4m10560xy @@ -0,0 +1,2 @@ +[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ [[[[[[[[[[[[[ [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/h/vh8rwxqf32axt398a08qrrvz9h90qzhjq4x86evknssbc b/implementation/fuzz/inputs-genvm-modules-complete-json/v/h/vh8rwxqf32axt398a08qrrvz9h90qzhjq4x86evknssbc new file mode 100644 index 00000000..c0988a9a --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/h/vh8rwxqf32axt398a08qrrvz9h90qzhjq4x86evknssbc @@ -0,0 +1,8 @@ + { + "":0, + " + + + + + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/m/vm4kkahbvyvb8sffh3rwmf7eq5bydnv3vx5gtap05a9z8 b/implementation/fuzz/inputs-genvm-modules-complete-json/v/m/vm4kkahbvyvb8sffh3rwmf7eq5bydnv3vx5gtap05a9z8 new file mode 100644 index 00000000..4d2c6902 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/m/vm4kkahbvyvb8sffh3rwmf7eq5bydnv3vx5gtap05a9z8 @@ -0,0 +1 @@ +2E+22 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/q/vqn8sf0fpgcf5nth6d4xkhjytxynyqpr8kp2z0nmxc0e6 b/implementation/fuzz/inputs-genvm-modules-complete-json/v/q/vqn8sf0fpgcf5nth6d4xkhjytxynyqpr8kp2z0nmxc0e6 new file mode 100644 index 00000000..8f92d76e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/q/vqn8sf0fpgcf5nth6d4xkhjytxynyqpr8kp2z0nmxc0e6 @@ -0,0 +1 @@ +22222222222222222222222222222 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/q/vqpgxh7cnypmzrfphqxsy7qtxbqtsfnq1ep7ndksgww2e b/implementation/fuzz/inputs-genvm-modules-complete-json/v/q/vqpgxh7cnypmzrfphqxsy7qtxbqtsfnq1ep7ndksgww2e new file mode 100644 index 00000000..2ce695d2 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/q/vqpgxh7cnypmzrfphqxsy7qtxbqtsfnq1ep7ndksgww2e @@ -0,0 +1,2 @@ + +"р\\ub|5R [[1, B\bõ r" diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/s/vsdj5q9vxs4g30xzwvsbz7hg6nb9dn00tpdc6qk9tyhg2 b/implementation/fuzz/inputs-genvm-modules-complete-json/v/s/vsdj5q9vxs4g30xzwvsbz7hg6nb9dn00tpdc6qk9tyhg2 new file mode 100644 index 00000000..a63cf904 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/s/vsdj5q9vxs4g30xzwvsbz7hg6nb9dn00tpdc6qk9tyhg2 @@ -0,0 +1,4 @@ +{ + "11111111111111": 1e20, + +  \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/s/vsyxzq69qcqef54brey6fwpv7dh8fqmmgmbzq7a6n4j60 b/implementation/fuzz/inputs-genvm-modules-complete-json/v/s/vsyxzq69qcqef54brey6fwpv7dh8fqmmgmbzq7a6n4j60 new file mode 100644 index 00000000..a84fe555 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/s/vsyxzq69qcqef54brey6fwpv7dh8fqmmgmbzq7a6n4j60 @@ -0,0 +1,2 @@ +{ + " " \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/t/vt2g24hdjy5vwww4x7y5p44azbjrvzjn1717jas35cteg b/implementation/fuzz/inputs-genvm-modules-complete-json/v/t/vt2g24hdjy5vwww4x7y5p44azbjrvzjn1717jas35cteg new file mode 100644 index 0000000000000000000000000000000000000000..f5d7432810b7fa657fadc9538f7e6dcfa64c0ddf GIT binary patch literal 256 zcmb>CQUC&_wETP}PF_wlkgaQ&3KJokhFPPakd%}N;~>#cgUT2Po0tax D$A>Wk literal 0 HcmV?d00001 diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/w/vwhwypz73cj0fkgaachvc33598qjb92j8ctd4j4ng3ndr b/implementation/fuzz/inputs-genvm-modules-complete-json/v/w/vwhwypz73cj0fkgaachvc33598qjb92j8ctd4j4ng3ndr new file mode 100644 index 00000000..ab0ba5fb --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/w/vwhwypz73cj0fkgaachvc33598qjb92j8ctd4j4ng3ndr @@ -0,0 +1,16 @@ +{ + "foo": [ + "bar", + "baz\n\\z", + 123, + -123, + -1e10, + 1e20, + null, +true, + false, + [1, 2, 3] + ], "baaz\n\\r": [ + ], "руе \\": "barбуквы 日本", + "mbbbbbbbbbbbbbbaz\t\uabbbbb", + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/w/vwtnpjteafpchkcd19tsd63z67d4m1fxbrwy46skjamq0 b/implementation/fuzz/inputs-genvm-modules-complete-json/v/w/vwtnpjteafpchkcd19tsd63z67d4m1fxbrwy46skjamq0 new file mode 100644 index 00000000..3f0ecf11 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/w/vwtnpjteafpchkcd19tsd63z67d4m1fxbrwy46skjamq0 @@ -0,0 +1 @@ +22919112161111111111111 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/v/y/vy8fz3gbm7k0mxgbew3vw5n5bmq6jhakqmttp3r5dbgrm b/implementation/fuzz/inputs-genvm-modules-complete-json/v/y/vy8fz3gbm7k0mxgbew3vw5n5bmq6jhakqmttp3r5dbgrm new file mode 100644 index 00000000..62e7d951 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/v/y/vy8fz3gbm7k0mxgbew3vw5n5bmq6jhakqmttp3r5dbgrm @@ -0,0 +1,4 @@ + [0, + "bar" + + ] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/0/w0225bd73w9dazbw6jb2pgh84cpw34z4aga4jzn7b82ap b/implementation/fuzz/inputs-genvm-modules-complete-json/w/0/w0225bd73w9dazbw6jb2pgh84cpw34z4aga4jzn7b82ap new file mode 100644 index 00000000..92f3a950 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/0/w0225bd73w9dazbw6jb2pgh84cpw34z4aga4jzn7b82ap @@ -0,0 +1 @@ + [11  \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/0/w07t44ytv2x4cagakbp8vyced6dxaffy35h6t2fsa3nk4 b/implementation/fuzz/inputs-genvm-modules-complete-json/w/0/w07t44ytv2x4cagakbp8vyced6dxaffy35h6t2fsa3nk4 new file mode 100644 index 0000000000000000000000000000000000000000..46bd69a4d3be5729be335102a9393dc7c8f7f086 GIT binary patch literal 76 jcmb>CQUC%aLlmH7rJ!J#YGj}Tl2kG@&R60k3>bI;w%`cs literal 0 HcmV?d00001 diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/1/w1229a8rvrkwbhyktew1xb3frek1atfrxzw33kq8ssgh2 b/implementation/fuzz/inputs-genvm-modules-complete-json/w/1/w1229a8rvrkwbhyktew1xb3frek1atfrxzw33kq8ssgh2 new file mode 100644 index 00000000..ef4eb2e4 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/1/w1229a8rvrkwbhyktew1xb3frek1atfrxzw33kq8ssgh2 @@ -0,0 +1 @@ + "\/r" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/2/w2abwa2c3bmhgjnc1qmt5xrhnr96aarma0tk1n2dz8sft b/implementation/fuzz/inputs-genvm-modules-complete-json/w/2/w2abwa2c3bmhgjnc1qmt5xrhnr96aarma0tk1n2dz8sft new file mode 100644 index 00000000..9c8371a2 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/2/w2abwa2c3bmhgjnc1qmt5xrhnr96aarma0tk1n2dz8sft @@ -0,0 +1 @@ + "b750 4 :UwUoU󗥣" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/3/w3nar75v78qkx3d928h0he832sqbkctbmcrk5fe9ws8ba b/implementation/fuzz/inputs-genvm-modules-complete-json/w/3/w3nar75v78qkx3d928h0he832sqbkctbmcrk5fe9ws8ba new file mode 100644 index 00000000..6cc3083a --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/3/w3nar75v78qkx3d928h0he832sqbkctbmcrk5fe9ws8ba @@ -0,0 +1 @@ +222222222222222222222222222 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/8/w8j0vfcsy4ex7923x16y4wrhh0h70kenfhy215j09jf28 b/implementation/fuzz/inputs-genvm-modules-complete-json/w/8/w8j0vfcsy4ex7923x16y4wrhh0h70kenfhy215j09jf28 new file mode 100644 index 00000000..79132d73 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/8/w8j0vfcsy4ex7923x16y4wrhh0h70kenfhy215j09jf28 @@ -0,0 +1 @@ +2222222222222222222222E+2 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/8/w8rwmgvasgfdha3k13fyf7h2m6mg00kd77waj719nhbfe b/implementation/fuzz/inputs-genvm-modules-complete-json/w/8/w8rwmgvasgfdha3k13fyf7h2m6mg00kd77waj719nhbfe new file mode 100644 index 00000000..7894427f --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/8/w8rwmgvasgfdha3k13fyf7h2m6mg00kd77waj719nhbfe @@ -0,0 +1 @@ +111115111111111111111E-522122 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/a/wa556dm9x1mzfj5g2th5wmys862hry0ryn5rde5xg3be8 b/implementation/fuzz/inputs-genvm-modules-complete-json/w/a/wa556dm9x1mzfj5g2th5wmys862hry0ryn5rde5xg3be8 new file mode 100644 index 00000000..2f46758e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/a/wa556dm9x1mzfj5g2th5wmys862hry0ryn5rde5xg3be8 @@ -0,0 +1,2 @@ + [ + 1111.61e-11111111111] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/a/waf2pz4cpn6fxk22zay0d1g8k7nzbhffyf573ajvg3te6 b/implementation/fuzz/inputs-genvm-modules-complete-json/w/a/waf2pz4cpn6fxk22zay0d1g8k7nzbhffyf573ajvg3te6 new file mode 100644 index 00000000..8b6c64fc --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/a/waf2pz4cpn6fxk22zay0d1g8k7nzbhffyf573ajvg3te6 @@ -0,0 +1,6 @@ +{ + + + + + } \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/a/wan3zs63jsevc9x72va1apz2t0ynsktxdxryvsf8bpt10 b/implementation/fuzz/inputs-genvm-modules-complete-json/w/a/wan3zs63jsevc9x72va1apz2t0ynsktxdxryvsf8bpt10 new file mode 100644 index 00000000..3b334923 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/a/wan3zs63jsevc9x72va1apz2t0ynsktxdxryvsf8bpt10 @@ -0,0 +1 @@ +"UUU\bк" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/b/wbn6hd1d29xjz910rz9haaxdj81atz1gpmk6a8910w5jj b/implementation/fuzz/inputs-genvm-modules-complete-json/w/b/wbn6hd1d29xjz910rz9haaxdj81atz1gpmk6a8910w5jj new file mode 100644 index 00000000..efcb29dd --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/b/wbn6hd1d29xjz910rz9haaxdj81atz1gpmk6a8910w5jj @@ -0,0 +1 @@ +91111111141111111111.11 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/c/wc7166zk28n709g67hkqn9e4vb38t749q18srgb226yhy b/implementation/fuzz/inputs-genvm-modules-complete-json/w/c/wc7166zk28n709g67hkqn9e4vb38t749q18srgb226yhy new file mode 100644 index 00000000..16980aa4 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/c/wc7166zk28n709g67hkqn9e4vb38t749q18srgb226yhy @@ -0,0 +1 @@ +661e-811 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/d/wd1dqfbtbahx5wngqwwzjrs59v7p10gfcndybp0d96j6j b/implementation/fuzz/inputs-genvm-modules-complete-json/w/d/wd1dqfbtbahx5wngqwwzjrs59v7p10gfcndybp0d96j6j new file mode 100644 index 00000000..4f96352b --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/d/wd1dqfbtbahx5wngqwwzjrs59v7p10gfcndybp0d96j6j @@ -0,0 +1,2 @@ + +"\u0000ыbbbbbbbbbbbbbOu0000ы\u00000р\u00000р\\wbbbbbbbbbbbbOu0000ы\u00000р\u00200р\\wba1 r" diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/e/wee7ssenrycdbatem6dtavfcxnyqs4qmaca3cnaxk1bya b/implementation/fuzz/inputs-genvm-modules-complete-json/w/e/wee7ssenrycdbatem6dtavfcxnyqs4qmaca3cnaxk1bya new file mode 100644 index 00000000..b5a8efca --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/e/wee7ssenrycdbatem6dtavfcxnyqs4qmaca3cnaxk1bya @@ -0,0 +1,2 @@ +222222222222222222222E+2 + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/f/wfr8wqbx83fgq50mww2ect3a8j08189dy7v8663mrregr b/implementation/fuzz/inputs-genvm-modules-complete-json/w/f/wfr8wqbx83fgq50mww2ect3a8j08189dy7v8663mrregr new file mode 100644 index 00000000..6916632d --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/f/wfr8wqbx83fgq50mww2ect3a8j08189dy7v8663mrregr @@ -0,0 +1,4 @@ +"f0000000\ro 1a+\ro 1 ( (000кԸʱ Țуúo00\ro 1a+0 bbaa+000000000000000000р\\uabbubb" + + + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/g/wgbw3wrjhp2ywmqdg8cbgedrjy9apfx30bvm0c4h4w9gm b/implementation/fuzz/inputs-genvm-modules-complete-json/w/g/wgbw3wrjhp2ywmqdg8cbgedrjy9apfx30bvm0c4h4w9gm new file mode 100644 index 00000000..8f7f7fe6 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/g/wgbw3wrjhp2ywmqdg8cbgedrjy9apfx30bvm0c4h4w9gm @@ -0,0 +1,9 @@ + + + + +[ [[[[[[[[[[[[ +[[[[[ + + +[[[[[[[[[[[[[[[[[[[[[[[[=, , \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/g/wggdm8g9sepcbgchsj5gjfhqnn15r4xgxzv225hd94dqa b/implementation/fuzz/inputs-genvm-modules-complete-json/w/g/wggdm8g9sepcbgchsj5gjfhqnn15r4xgxzv225hd94dqa new file mode 100644 index 00000000..a3210e9f --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/g/wggdm8g9sepcbgchsj5gjfhqnn15r4xgxzv225hd94dqa @@ -0,0 +1,2 @@ +99999999999999999999999999 + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/g/wgjt61ess9kww0xvgsq35ej5new78w63pzkhfc252tchg b/implementation/fuzz/inputs-genvm-modules-complete-json/w/g/wgjt61ess9kww0xvgsq35ej5new78w63pzkhfc252tchg new file mode 100644 index 00000000..17efdd1c --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/g/wgjt61ess9kww0xvgsq35ej5new78w63pzkhfc252tchg @@ -0,0 +1,3 @@ +[[[[[[[[[ + +3,[[[[[[[ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/j/wj34mctxj9r2m4f7mp8cdmg1s776c0feyxn27h206yms6 b/implementation/fuzz/inputs-genvm-modules-complete-json/w/j/wj34mctxj9r2m4f7mp8cdmg1s776c0feyxn27h206yms6 new file mode 100644 index 00000000..71eaca19 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/j/wj34mctxj9r2m4f7mp8cdmg1s776c0feyxn27h206yms6 @@ -0,0 +1,5 @@ +{ + "foo": [ + + ], + "bar" "baе Х本 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/j/wjj5qa0n4pp10ejqmt8qrzy6wvwkja36my7rhtc046q14 b/implementation/fuzz/inputs-genvm-modules-complete-json/w/j/wjj5qa0n4pp10ejqmt8qrzy6wvwkja36my7rhtc046q14 new file mode 100644 index 00000000..3b4f25ec --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/j/wjj5qa0n4pp10ejqmt8qrzy6wvwkja36my7rhtc046q14 @@ -0,0 +1,5 @@ +{ "р\\u 111111111": [ ], + + + + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/j/wjk3ttywnza76t2k3z4qvrbmyg2b9ptvr7ennmym1n59g b/implementation/fuzz/inputs-genvm-modules-complete-json/w/j/wjk3ttywnza76t2k3z4qvrbmyg2b9ptvr7ennmym1n59g new file mode 100644 index 00000000..495c4718 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/j/wjk3ttywnza76t2k3z4qvrbmyg2b9ptvr7ennmym1n59g @@ -0,0 +1 @@ +"UUUUwUoUUUUUUUUUUU\n]I" diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/k/wkgbj1ak3n7ercyw3x0f3nf884dja04kcbg7wey0kfvxc b/implementation/fuzz/inputs-genvm-modules-complete-json/w/k/wkgbj1ak3n7ercyw3x0f3nf884dja04kcbg7wey0kfvxc new file mode 100644 index 00000000..34da7763 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/k/wkgbj1ak3n7ercyw3x0f3nf884dja04kcbg7wey0kfvxc @@ -0,0 +1,31 @@ +3e-922 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/k/wkktvvynb5h7hgm8py35yf9ta0r6psqww75yg99ypm26g b/implementation/fuzz/inputs-genvm-modules-complete-json/w/k/wkktvvynb5h7hgm8py35yf9ta0r6psqww75yg99ypm26g new file mode 100644 index 00000000..0e8f8e06 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/k/wkktvvynb5h7hgm8py35yf9ta0r6psqww75yg99ypm26g @@ -0,0 +1,2 @@ + +"euu0000ы\u00D0ы\u00ba1 0000ы\u00D0ы\u00ba1 0D0ы\u00ba1r" diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/k/wkygkggtxf22b7w6d38faw092jf348v67vp78dc7esj1r b/implementation/fuzz/inputs-genvm-modules-complete-json/w/k/wkygkggtxf22b7w6d38faw092jf348v67vp78dc7esj1r new file mode 100644 index 00000000..bb40953f --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/k/wkygkggtxf22b7w6d38faw092jf348v67vp78dc7esj1r @@ -0,0 +1 @@ +"\nH" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/n/wn5e036b3prr4germa9hy89g82j908yd9tn2pg7vds984 b/implementation/fuzz/inputs-genvm-modules-complete-json/w/n/wn5e036b3prr4germa9hy89g82j908yd9tn2pg7vds984 new file mode 100644 index 00000000..32150a87 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/n/wn5e036b3prr4germa9hy89g82j908yd9tn2pg7vds984 @@ -0,0 +1 @@ + [1, ,  \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/p/wp50v8nk3akyvwhn06hwzz1b1ssz04n83wwzc1ex5p0tm b/implementation/fuzz/inputs-genvm-modules-complete-json/w/p/wp50v8nk3akyvwhn06hwzz1b1ssz04n83wwzc1ex5p0tm new file mode 100644 index 00000000..4a2bacb2 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/p/wp50v8nk3akyvwhn06hwzz1b1ssz04n83wwzc1ex5p0tm @@ -0,0 +1 @@ +"\f{obj 日ubb[" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/p/wp8ksqp4rzj5czsyq8ad6dmr0zbw8mwqpzpyt5zgvs638 b/implementation/fuzz/inputs-genvm-modules-complete-json/w/p/wp8ksqp4rzj5czsyq8ad6dmr0zbw8mwqpzpyt5zgvs638 new file mode 100644 index 00000000..7dd701ef --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/p/wp8ksqp4rzj5czsyq8ad6dmr0zbw8mwqpzpyt5zgvs638 @@ -0,0 +1 @@ +1e-7333 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/p/wphfn9cmx58aw16edmv25m9p93zvvp2wx3y9fd0e9ktey b/implementation/fuzz/inputs-genvm-modules-complete-json/w/p/wphfn9cmx58aw16edmv25m9p93zvvp2wx3y9fd0e9ktey new file mode 100644 index 00000000..44de08a7 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/p/wphfn9cmx58aw16edmv25m9p93zvvp2wx3y9fd0e9ktey @@ -0,0 +1,4 @@ + [ [{ + "foo" + : null , + nul \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/q/wq79wfbcss4wzg30xfctg28sang4r84taka353p2j7v3w b/implementation/fuzz/inputs-genvm-modules-complete-json/w/q/wq79wfbcss4wzg30xfctg28sang4r84taka353p2j7v3w new file mode 100644 index 00000000..3da4b957 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/q/wq79wfbcss4wzg30xfctg28sang4r84taka353p2j7v3w @@ -0,0 +1,2 @@ + +"рbbbbIbb※ n\/2#\\ubGqz\r" diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/r/wrs5t71dcjjsxgs535bvcjgn24hegspkjfzsdbajznj4c b/implementation/fuzz/inputs-genvm-modules-complete-json/w/r/wrs5t71dcjjsxgs535bvcjgn24hegspkjfzsdbajznj4c new file mode 100644 index 00000000..7b5d59f7 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/r/wrs5t71dcjjsxgs535bvcjgn24hegspkjfzsdbajznj4c @@ -0,0 +1 @@ +"\f\\ 日u " \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/s/wsfags1x4xer51704f72d0ymmk40kabm1eeezg84rf8r6 b/implementation/fuzz/inputs-genvm-modules-complete-json/w/s/wsfags1x4xer51704f72d0ymmk40kabm1eeezg84rf8r6 new file mode 100644 index 00000000..01a28d43 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/s/wsfags1x4xer51704f72d0ymmk40kabm1eeezg84rf8r6 @@ -0,0 +1 @@ + [1, , ] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/v/wv6st7rt4c9n8pqq0t14s83m0akm8cx594yv0fnc5zmg2 b/implementation/fuzz/inputs-genvm-modules-complete-json/w/v/wv6st7rt4c9n8pqq0t14s83m0akm8cx594yv0fnc5zmg2 new file mode 100644 index 00000000..b9cf704e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/v/wv6st7rt4c9n8pqq0t14s83m0akm8cx594yv0fnc5zmg2 @@ -0,0 +1,2 @@ +[, + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/w/wwb5adm1pqs5928hf33j2sedc6j7try738exxnh6hypc0 b/implementation/fuzz/inputs-genvm-modules-complete-json/w/w/wwb5adm1pqs5928hf33j2sedc6j7try738exxnh6hypc0 new file mode 100644 index 00000000..729e63f2 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/w/wwb5adm1pqs5928hf33j2sedc6j7try738exxnh6hypc0 @@ -0,0 +1,2 @@ +22222222222222222222E+2 + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/x/wx7w4p18yyc3a01apa5qz0w31n0sbgbwj1jxvs3dwh8zc b/implementation/fuzz/inputs-genvm-modules-complete-json/w/x/wx7w4p18yyc3a01apa5qz0w31n0sbgbwj1jxvs3dwh8zc new file mode 100644 index 00000000..a8ff260e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/x/wx7w4p18yyc3a01apa5qz0w31n0sbgbwj1jxvs3dwh8zc @@ -0,0 +1 @@ +"\\uрUwUoUUUUUUUUUb\\\\\b\\\ba ,a ,\\\\b\\\ba\bar\\b\\\ba ,a ,\\\\b\\\ba , ,a " \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/x/wxd3t34dgg13219xkkbakdj9wgrshqsg2vqmj82t9hxm8 b/implementation/fuzz/inputs-genvm-modules-complete-json/w/x/wxd3t34dgg13219xkkbakdj9wgrshqsg2vqmj82t9hxm8 new file mode 100644 index 00000000..8749cde7 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/x/wxd3t34dgg13219xkkbakdj9wgrshqsg2vqmj82t9hxm8 @@ -0,0 +1,2 @@ +{ "o" : 9 +} \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/w/y/wyjsr0jjm2qa355th3w231761y1s3cwy2bqzd7eam3wbp b/implementation/fuzz/inputs-genvm-modules-complete-json/w/y/wyjsr0jjm2qa355th3w231761y1s3cwy2bqzd7eam3wbp new file mode 100644 index 00000000..2e1db173 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/w/y/wyjsr0jjm2qa355th3w231761y1s3cwy2bqzd7eam3wbp @@ -0,0 +1,2 @@ + +"рbbbbQbb
 T r" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/0/x0b9bjk8bhnjw5zvg8bmm9tbvfxjk0vp4ejy7yqn51cat b/implementation/fuzz/inputs-genvm-modules-complete-json/x/0/x0b9bjk8bhnjw5zvg8bmm9tbvfxjk0vp4ejy7yqn51cat new file mode 100644 index 00000000..d0de4b02 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/x/0/x0b9bjk8bhnjw5zvg8bmm9tbvfxjk0vp4ejy7yqn51cat @@ -0,0 +1,17 @@ +{ + "foo": [ + + 123, + -123, + -1e10, + null, + true, + false, + [1, 2, 3] + ], + "bar": [ + "Ӏусские букزы 日本az\t\uabbb\b", + "bbbb" + + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/2/x2y2wxzhvb64j5v9y1wsvw25wskfh6r4r41dhcjx9vf84 b/implementation/fuzz/inputs-genvm-modules-complete-json/x/2/x2y2wxzhvb64j5v9y1wsvw25wskfh6r4r41dhcjx9vf84 new file mode 100644 index 00000000..2ab62f6f --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/x/2/x2y2wxzhvb64j5v9y1wsvw25wskfh6r4r41dhcjx9vf84 @@ -0,0 +1 @@ + false \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/3/x31bt75p0d02masjc7bb36dqz3w478hrp838z7vgnmkfc b/implementation/fuzz/inputs-genvm-modules-complete-json/x/3/x31bt75p0d02masjc7bb36dqz3w478hrp838z7vgnmkfc new file mode 100644 index 00000000..5763e7c7 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/x/3/x31bt75p0d02masjc7bb36dqz3w478hrp838z7vgnmkfc @@ -0,0 +1,2 @@ +{ + "" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/3/x3xn1mgbwk5sm1eksq5rdw36x3qs1s410zsd7fyz8tb7e b/implementation/fuzz/inputs-genvm-modules-complete-json/x/3/x3xn1mgbwk5sm1eksq5rdw36x3qs1s410zsd7fyz8tb7e new file mode 100644 index 00000000..169844fb --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/x/3/x3xn1mgbwk5sm1eksq5rdw36x3qs1s410zsd7fyz8tb7e @@ -0,0 +1 @@ +222222222222222222222222.22 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/7/x7z9y3rfa7r2p2as8e6cb9nd4mcze4ez61hrdc59bj774 b/implementation/fuzz/inputs-genvm-modules-complete-json/x/7/x7z9y3rfa7r2p2as8e6cb9nd4mcze4ez61hrdc59bj774 new file mode 100644 index 00000000..bede5bdc --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/x/7/x7z9y3rfa7r2p2as8e6cb9nd4mcze4ez61hrdc59bj774 @@ -0,0 +1,17 @@ +{ + "bbbbbbbbaz\tfoo": [ + "bar", + "baz\n\\z", + 123, + -123, + -1e10, + null, + true, + false, + [1, 2, 3] + ], + "bar": [ + "русск116111111111111111e-111111\uabbbbb", + "mbbrbbbbbbbbbbbaz\t\\uabbbbb" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/9/x9vhhbw4nq8hp3bnekcxcgkxvmz213h30h866bw592m50 b/implementation/fuzz/inputs-genvm-modules-complete-json/x/9/x9vhhbw4nq8hp3bnekcxcgkxvmz213h30h866bw592m50 new file mode 100644 index 00000000..e835a30c --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/x/9/x9vhhbw4nq8hp3bnekcxcgkxvmz213h30h866bw592m50 @@ -0,0 +1,7 @@ + [ + , + + + + + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/b/xbzbem843j8vaevc0551zcb60f8br7ezhwvyzfh8g9wdw b/implementation/fuzz/inputs-genvm-modules-complete-json/x/b/xbzbem843j8vaevc0551zcb60f8br7ezhwvyzfh8g9wdw new file mode 100644 index 00000000..2eda6594 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/x/b/xbzbem843j8vaevc0551zcb60f8br7ezhwvyzfh8g9wdw @@ -0,0 +1 @@ + [1,3] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/c/xc68061ezanp6hv7db2605w2r8v3r092yfcs6bnj4fxqy b/implementation/fuzz/inputs-genvm-modules-complete-json/x/c/xc68061ezanp6hv7db2605w2r8v3r092yfcs6bnj4fxqy new file mode 100644 index 00000000..a8ed145d --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/x/c/xc68061ezanp6hv7db2605w2r8v3r092yfcs6bnj4fxqy @@ -0,0 +1 @@ +1111111111111115111111e-6 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/c/xcz9d9fqq2p5tbxy7bg0kkye1zhj9dg932bfny8h7j412 b/implementation/fuzz/inputs-genvm-modules-complete-json/x/c/xcz9d9fqq2p5tbxy7bg0kkye1zhj9dg932bfny8h7j412 new file mode 100644 index 00000000..3026df79 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/x/c/xcz9d9fqq2p5tbxy7bg0kkye1zhj9dg932bfny8h7j412 @@ -0,0 +1,4 @@ + [1111111111111.1111111111E111, -1e10, + 1e+2, 111E111, 2, 111111111111e+2, 10,1e10, + 1e+2, 111E111, 2, + 1e+2, 111E111, 11111] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/d/xd1wspeerh2t52fm38ngbcv1a0vy24k6j2hykbtf6g7vw b/implementation/fuzz/inputs-genvm-modules-complete-json/x/d/xd1wspeerh2t52fm38ngbcv1a0vy24k6j2hykbtf6g7vw new file mode 100644 index 00000000..e7157567 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/x/d/xd1wspeerh2t52fm38ngbcv1a0vy24k6j2hykbtf6g7vw @@ -0,0 +1 @@ +t^ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/f/xf7nec3t7xfrezaacqkt64v40xmbapa90ra07h5kqfj12 b/implementation/fuzz/inputs-genvm-modules-complete-json/x/f/xf7nec3t7xfrezaacqkt64v40xmbapa90ra07h5kqfj12 new file mode 100644 index 00000000..4ac4f679 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/x/f/xf7nec3t7xfrezaacqkt64v40xmbapa90ra07h5kqfj12 @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/g/xg1nqjd3axjyy7vswtf683s63g7x4qbtynp1xjtpawrx0 b/implementation/fuzz/inputs-genvm-modules-complete-json/x/g/xg1nqjd3axjyy7vswtf683s63g7x4qbtynp1xjtpawrx0 new file mode 100644 index 0000000000000000000000000000000000000000..c2072a8bba5e9d0994416cb3ed8053a0c922e902 GIT binary patch literal 266 zcmb>CQUC&_wETP}D}`t<2P}}3Sfr$b%&khvi;1a15;HV1MkoO3$t%st0gLE@q(CCb jK*`9+2*}qpOhpzYhaC+C*z|&=pyFi=*c70O#UcR!1@JA@ literal 0 HcmV?d00001 diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/g/xgzc2sv4nwbamhn2p6es0n4t1r292078dwe5w9mwr1j8t b/implementation/fuzz/inputs-genvm-modules-complete-json/x/g/xgzc2sv4nwbamhn2p6es0n4t1r292078dwe5w9mwr1j8t new file mode 100644 index 00000000..3ac4a367 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/x/g/xgzc2sv4nwbamhn2p6es0n4t1r292078dwe5w9mwr1j8t @@ -0,0 +1,35 @@ + [, + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + / \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/h/xhmre3dg37xp3988dzxnkeaezejnbejvjt93b72g20c5j b/implementation/fuzz/inputs-genvm-modules-complete-json/x/h/xhmre3dg37xp3988dzxnkeaezejnbejvjt93b72g20c5j new file mode 100644 index 00000000..66cee0dc --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/x/h/xhmre3dg37xp3988dzxnkeaezejnbejvjt93b72g20c5j @@ -0,0 +1 @@ +{ " -@fo":22222212.2} \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/k/xkbr14gk3a7rr65r5tk7hfat39pevmz8why3gn0tvh57c b/implementation/fuzz/inputs-genvm-modules-complete-json/x/k/xkbr14gk3a7rr65r5tk7hfat39pevmz8why3gn0tvh57c new file mode 100644 index 00000000..d9222859 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/x/k/xkbr14gk3a7rr65r5tk7hfat39pevmz8why3gn0tvh57c @@ -0,0 +1,15 @@ +"" + + + + + + + + + + + + + + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/k/xkmwqaa2w39myhpa309a3b2hdr202f63jfbr343nzhmza b/implementation/fuzz/inputs-genvm-modules-complete-json/x/k/xkmwqaa2w39myhpa309a3b2hdr202f63jfbr343nzhmza new file mode 100644 index 00000000..1a87ea35 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/x/k/xkmwqaa2w39myhpa309a3b2hdr202f63jfbr343nzhmza @@ -0,0 +1 @@ +1.111e1 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/m/xmq5ewyq17ta0sadjn489c4dpkgn5bnrmw6be2tmw0dw8 b/implementation/fuzz/inputs-genvm-modules-complete-json/x/m/xmq5ewyq17ta0sadjn489c4dpkgn5bnrmw6be2tmw0dw8 new file mode 100644 index 00000000..0637a088 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/x/m/xmq5ewyq17ta0sadjn489c4dpkgn5bnrmw6be2tmw0dw8 @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/p/xp8sqt9zk6h6bt0tq2wf62xb1pck71qvn6r8d0g70mmja b/implementation/fuzz/inputs-genvm-modules-complete-json/x/p/xp8sqt9zk6h6bt0tq2wf62xb1pck71qvn6r8d0g70mmja new file mode 100644 index 00000000..d0a04647 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/x/p/xp8sqt9zk6h6bt0tq2wf62xb1pck71qvn6r8d0g70mmja @@ -0,0 +1,11 @@ + { + "":0, + "":0, + "": "": { + "": + " + + + + + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/p/xpvwyb9ad0rfk3yjwtfjha05etx8te3peqbwddheh8fwc b/implementation/fuzz/inputs-genvm-modules-complete-json/x/p/xpvwyb9ad0rfk3yjwtfjha05etx8te3peqbwddheh8fwc new file mode 100644 index 00000000..61f2f826 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/x/p/xpvwyb9ad0rfk3yjwtfjha05etx8te3peqbwddheh8fwc @@ -0,0 +1 @@ + [11111111111111111111111E11] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/q/xq3tjskn8hg3ydkemexpfa75fvm46rasg29y7zjkd7za4 b/implementation/fuzz/inputs-genvm-modules-complete-json/x/q/xq3tjskn8hg3ydkemexpfa75fvm46rasg29y7zjkd7za4 new file mode 100644 index 00000000..e5846012 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/x/q/xq3tjskn8hg3ydkemexpfa75fvm46rasg29y7zjkd7za4 @@ -0,0 +1,2 @@ +{ + "foo" 1 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/q/xqw45r3n70nw3wj6d638e448qf6zbrd0mt87j9698pyj0 b/implementation/fuzz/inputs-genvm-modules-complete-json/x/q/xqw45r3n70nw3wj6d638e448qf6zbrd0mt87j9698pyj0 new file mode 100644 index 00000000..ad1b70f1 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/x/q/xqw45r3n70nw3wj6d638e448qf6zbrd0mt87j9698pyj0 @@ -0,0 +1 @@ + " \fz" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/t/xt8jyccjejyze9n80tsqf7xsjpq5nzt1c21g8rmsa1khr b/implementation/fuzz/inputs-genvm-modules-complete-json/x/t/xt8jyccjejyze9n80tsqf7xsjpq5nzt1c21g8rmsa1khr new file mode 100644 index 00000000..90a76629 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/x/t/xt8jyccjejyze9n80tsqf7xsjpq5nzt1c21g8rmsa1khr @@ -0,0 +1 @@ +"]UUIbc ," diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/v/xv4ne8e51c1hch84yxk993218ykvmfp3gq4c66r4x22hw b/implementation/fuzz/inputs-genvm-modules-complete-json/x/v/xv4ne8e51c1hch84yxk993218ykvmfp3gq4c66r4x22hw new file mode 100644 index 00000000..53b5d131 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/x/v/xv4ne8e51c1hch84yxk993218ykvmfp3gq4c66r4x22hw @@ -0,0 +1 @@ +"р\\ub " \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/x/w/xwhde5sh1dmy64dvf4jjs30x34d291a6v6r2d03nqnpvj b/implementation/fuzz/inputs-genvm-modules-complete-json/x/w/xwhde5sh1dmy64dvf4jjs30x34d291a6v6r2d03nqnpvj new file mode 100644 index 00000000..7c52b808 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/x/w/xwhde5sh1dmy64dvf4jjs30x34d291a6v6r2d03nqnpvj @@ -0,0 +1 @@ + " у000 у0000000000000000" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/y/1/y1xw7nq6z3pdayphm1vyc5rq1xsd9fadnp8m3y6ykep1y b/implementation/fuzz/inputs-genvm-modules-complete-json/y/1/y1xw7nq6z3pdayphm1vyc5rq1xsd9fadnp8m3y6ykep1y new file mode 100644 index 00000000..33405e10 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/y/1/y1xw7nq6z3pdayphm1vyc5rq1xsd9fadnp8m3y6ykep1y @@ -0,0 +1,2 @@ +true + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/y/3/y3qj9bnaksy94s17nvg4gef25kr6w1p125bq2ypdwv7ac b/implementation/fuzz/inputs-genvm-modules-complete-json/y/3/y3qj9bnaksy94s17nvg4gef25kr6w1p125bq2ypdwv7ac new file mode 100644 index 00000000..8ad6052c --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/y/3/y3qj9bnaksy94s17nvg4gef25kr6w1p125bq2ypdwv7ac @@ -0,0 +1 @@ + ": " \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/y/5/y51y1mf9z97wqwnxyrhj1qrt0tydh3cgttqwhpdxyk6by b/implementation/fuzz/inputs-genvm-modules-complete-json/y/5/y51y1mf9z97wqwnxyrhj1qrt0tydh3cgttqwhpdxyk6by new file mode 100644 index 00000000..1ffaa875 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/y/5/y51y1mf9z97wqwnxyrhj1qrt0tydh3cgttqwhpdxyk6by @@ -0,0 +1,2 @@ +{ "" : [ 3 ] +} \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/y/5/y584nfccdc4nxyk791qsyfeysmt4w73kr0t1xbffvyv76 b/implementation/fuzz/inputs-genvm-modules-complete-json/y/5/y584nfccdc4nxyk791qsyfeysmt4w73kr0t1xbffvyv76 new file mode 100644 index 00000000..899893dc --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/y/5/y584nfccdc4nxyk791qsyfeysmt4w73kr0t1xbffvyv76 @@ -0,0 +1 @@ +1.11 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/y/7/y730k36mhsd91yaj4gkennz0hng2992z3wc1d2b7xh1b6 b/implementation/fuzz/inputs-genvm-modules-complete-json/y/7/y730k36mhsd91yaj4gkennz0hng2992z3wc1d2b7xh1b6 new file mode 100644 index 00000000..da966960 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/y/7/y730k36mhsd91yaj4gkennz0hng2992z3wc1d2b7xh1b6 @@ -0,0 +1,19 @@ +{ + "foo": [ + "bar", + "baz\n\\z", + 123, + -123, + -1e10, + null, 1e20, + null, + true, + false, + [1, 2, 3] + ], + "bar": [ + "русские буквы 日本", + "mbbbbbbbbbbbbbbaz\t\uabbbbb", + "mbbbbbbbbbbbbbbaz\t\\uabbbbb" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/y/7/y79exx9baft7b1mvwk8w7s45arqjmgph7gepxhyjyzfyp b/implementation/fuzz/inputs-genvm-modules-complete-json/y/7/y79exx9baft7b1mvwk8w7s45arqjmgph7gepxhyjyzfyp new file mode 100644 index 00000000..e57c376f --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/y/7/y79exx9baft7b1mvwk8w7s45arqjmgph7gepxhyjyzfyp @@ -0,0 +1 @@ + "Kf\f\f:o|" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/y/7/y7jjsfaczgb0t5ef708k00m489v4b8nrkhz4y6nnxcf40 b/implementation/fuzz/inputs-genvm-modules-complete-json/y/7/y7jjsfaczgb0t5ef708k00m489v4b8nrkhz4y6nnxcf40 new file mode 100644 index 00000000..d9bc6b7e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/y/7/y7jjsfaczgb0t5ef708k00m489v4b8nrkhz4y6nnxcf40 @@ -0,0 +1 @@ +0e555455551 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/y/7/y7sz6nb3rz8wx7y76cymb95zt6z691adqvfnpv80yvsy2 b/implementation/fuzz/inputs-genvm-modules-complete-json/y/7/y7sz6nb3rz8wx7y76cymb95zt6z691adqvfnpv80yvsy2 new file mode 100644 index 00000000..6c2bbfe6 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/y/7/y7sz6nb3rz8wx7y76cymb95zt6z691adqvfnpv80yvsy2 @@ -0,0 +1,5 @@ + [[[[[[n[ + + + + "fo \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/y/8/y8gk3gmkbgwb9fe497h121av0m23cnd6zk1rr3fyp7hjr b/implementation/fuzz/inputs-genvm-modules-complete-json/y/8/y8gk3gmkbgwb9fe497h121av0m23cnd6zk1rr3fyp7hjr new file mode 100644 index 00000000..4d9ee20c --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/y/8/y8gk3gmkbgwb9fe497h121av0m23cnd6zk1rr3fyp7hjr @@ -0,0 +1,2 @@ +{ + "foo": [[ [ "bar", [[[[[[ "bar", 33333333333333333333333333333333 [ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/y/a/ya3d6rzthp5zxm8jg5f6nh6yqs81fefzxdy874fmh6kg8 b/implementation/fuzz/inputs-genvm-modules-complete-json/y/a/ya3d6rzthp5zxm8jg5f6nh6yqs81fefzxdy874fmh6kg8 new file mode 100644 index 00000000..b48ef2f1 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/y/a/ya3d6rzthp5zxm8jg5f6nh6yqs81fefzxdy874fmh6kg8 @@ -0,0 +1,6 @@ + [{ "":{ + "o":{ "":{ "":{ + "o": [{ "":{ + "oooooooooooooooooooo":{ "":[{ "":{ + "o":{ "":{ "":{{ "":{ + "o":{{ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/y/b/ybt964nbb5yb9ps6jtk72grm9y99dv2q7xc1nbk41h5fj b/implementation/fuzz/inputs-genvm-modules-complete-json/y/b/ybt964nbb5yb9ps6jtk72grm9y99dv2q7xc1nbk41h5fj new file mode 100644 index 00000000..0011aa2e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/y/b/ybt964nbb5yb9ps6jtk72grm9y99dv2q7xc1nbk41h5fj @@ -0,0 +1 @@ + [ { } ] diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/y/e/yex06rh07tncp10v3ck21ftg8esb1ez461dsrafy4b1cy b/implementation/fuzz/inputs-genvm-modules-complete-json/y/e/yex06rh07tncp10v3ck21ftg8esb1ez461dsrafy4b1cy new file mode 100644 index 00000000..f4578e81 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/y/e/yex06rh07tncp10v3ck21ftg8esb1ez461dsrafy4b1cy @@ -0,0 +1,2 @@ + + 22222222222222222222E-2222222222222222222222222222222222222222 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/y/h/yh3g712vt6x1b3zhcj1s1p8jxfen93gtd42fxtjktwykp b/implementation/fuzz/inputs-genvm-modules-complete-json/y/h/yh3g712vt6x1b3zhcj1s1p8jxfen93gtd42fxtjktwykp new file mode 100644 index 00000000..4df51cc9 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/y/h/yh3g712vt6x1b3zhcj1s1p8jxfen93gtd42fxtjktwykp @@ -0,0 +1 @@ + "р\thabb bb" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/y/m/ymr2htwvdcpehh55smk7n56fcmz7mmqcpfc2k83q51qkj b/implementation/fuzz/inputs-genvm-modules-complete-json/y/m/ymr2htwvdcpehh55smk7n56fcmz7mmqcpfc2k83q51qkj new file mode 100644 index 00000000..6aea5698 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/y/m/ymr2htwvdcpehh55smk7n56fcmz7mmqcpfc2k83q51qkj @@ -0,0 +1,4 @@ +[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ [[[[[[ + +3,[[[[[[[[ [[[[[[[[[[[[[[[[[[[[[[[ [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ [[[[[111E1 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/y/p/yp25xrkzh6cbr4afqcawsaredtfg9c5ape7seebsaax4m b/implementation/fuzz/inputs-genvm-modules-complete-json/y/p/yp25xrkzh6cbr4afqcawsaredtfg9c5ape7seebsaax4m new file mode 100644 index 00000000..26178bf1 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/y/p/yp25xrkzh6cbr4afqcawsaredtfg9c5ape7seebsaax4m @@ -0,0 +1,2 @@ +{ "o": [ ] +} \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/y/p/ypj8a1df23mmj32g64hykewsqzng41a5zkj006089msq8 b/implementation/fuzz/inputs-genvm-modules-complete-json/y/p/ypj8a1df23mmj32g64hykewsqzng41a5zkj006089msq8 new file mode 100644 index 00000000..3b7743ea --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/y/p/ypj8a1df23mmj32g64hykewsqzng41a5zkj006089msq8 @@ -0,0 +1 @@ + [1111111111111111111111111.1111111111E111,1111111111111111111111111.1111111111E111, 2, 1111111111, 2, 11111111111111E111, 2, 3] \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/y/q/yqmec8gra9kkb9kp03kfsq32en9qf0xnq8e3628mk4msa b/implementation/fuzz/inputs-genvm-modules-complete-json/y/q/yqmec8gra9kkb9kp03kfsq32en9qf0xnq8e3628mk4msa new file mode 100644 index 00000000..5d902a58 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/y/q/yqmec8gra9kkb9kp03kfsq32en9qf0xnq8e3628mk4msa @@ -0,0 +1 @@ +-0 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/y/r/yr76r68778ggn6d8n6npcppzwrkfhzk84jxv5a4ty4rgr b/implementation/fuzz/inputs-genvm-modules-complete-json/y/r/yr76r68778ggn6d8n6npcppzwrkfhzk84jxv5a4ty4rgr new file mode 100644 index 00000000..073c3d37 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/y/r/yr76r68778ggn6d8n6npcppzwrkfhzk84jxv5a4ty4rgr @@ -0,0 +1 @@ +[1111111111191111.11111e-90111 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/y/s/yswexssab5tdnfx7511f6tk9p893yhkvfe0kw4scj03dw b/implementation/fuzz/inputs-genvm-modules-complete-json/y/s/yswexssab5tdnfx7511f6tk9p893yhkvfe0kw4scj03dw new file mode 100644 index 00000000..8259b8ff --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/y/s/yswexssab5tdnfx7511f6tk9p893yhkvfe0kw4scj03dw @@ -0,0 +1,2 @@ +{ + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/y/t/yts85j4ftnhe1nvktt9j6dmch9hj2bhwcqzpjxvws2jrg b/implementation/fuzz/inputs-genvm-modules-complete-json/y/t/yts85j4ftnhe1nvktt9j6dmch9hj2bhwcqzpjxvws2jrg new file mode 100644 index 00000000..ef845566 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/y/t/yts85j4ftnhe1nvktt9j6dmch9hj2bhwcqzpjxvws2jrg @@ -0,0 +1,3 @@ +{ + "foo": [[[[[[[[[[[[[[[[[123, [ + [[[[[[[[[[[[123, [[[[[[[[[[[[[[[[[[[[[[[[[123, "bas ------[@ 1111111111 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/y/v/yvkhkdhwqsd9t5eq7ks3wf602jf3bwt8eczx2vybh6zc0 b/implementation/fuzz/inputs-genvm-modules-complete-json/y/v/yvkhkdhwqsd9t5eq7ks3wf602jf3bwt8eczx2vybh6zc0 new file mode 100644 index 00000000..af523cc9 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/y/v/yvkhkdhwqsd9t5eq7ks3wf602jf3bwt8eczx2vybh6zc0 @@ -0,0 +1,4 @@ + [{ "":{ + "o":{ "":{ + "o":{ "":{ "":{ + "o":{ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/y/w/ywmhyj7wq34fhptmx4amwpefx3nqsww494c8wyrz37eva b/implementation/fuzz/inputs-genvm-modules-complete-json/y/w/ywmhyj7wq34fhptmx4amwpefx3nqsww494c8wyrz37eva new file mode 100644 index 00000000..11a736db --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/y/w/ywmhyj7wq34fhptmx4amwpefx3nqsww494c8wyrz37eva @@ -0,0 +1 @@ +"\ti" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/y/x/yxfmh1pze8kkvezr7abqjr3tnhpqbbxp48kd2qwv0wk54 b/implementation/fuzz/inputs-genvm-modules-complete-json/y/x/yxfmh1pze8kkvezr7abqjr3tnhpqbbxp48kd2qwv0wk54 new file mode 100644 index 00000000..ee5bc3b3 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/y/x/yxfmh1pze8kkvezr7abqjr3tnhpqbbxp48kd2qwv0wk54 @@ -0,0 +1,10 @@ +{ + "foo": false, "foo":false, "foo": false, + false, + + + + + + + diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/0/z0fk59m6rrgjabzhxmr32c09fh750e6k03zfa20k2vrxa b/implementation/fuzz/inputs-genvm-modules-complete-json/z/0/z0fk59m6rrgjabzhxmr32c09fh750e6k03zfa20k2vrxa new file mode 100644 index 00000000..3c002ebe --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/0/z0fk59m6rrgjabzhxmr32c09fh750e6k03zfa20k2vrxa @@ -0,0 +1 @@ + "с\\fffffffffbffffabba\/:fffffffffffffffffffffffffffffabba\ffffffffffffffffffffffffffffabba\fffffffffffffffffffffffffffffgfffffffffffffffffffffffffffabba\/: [b| [bbbb" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/3/z34jsxa265sxqyb2cwx1thqtexxcar9egnjvnpcvkcrvj b/implementation/fuzz/inputs-genvm-modules-complete-json/z/3/z34jsxa265sxqyb2cwx1thqtexxcar9egnjvnpcvkcrvj new file mode 100644 index 00000000..b0853f28 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/3/z34jsxa265sxqyb2cwx1thqtexxcar9egnjvnpcvkcrvj @@ -0,0 +1 @@ +33333333333333333333333333 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/3/z39kydgt59x46cdhf6vjhy39pe44ge3rvkhvb1nkwb2zr b/implementation/fuzz/inputs-genvm-modules-complete-json/z/3/z39kydgt59x46cdhf6vjhy39pe44ge3rvkhvb1nkwb2zr new file mode 100644 index 00000000..3ee15b89 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/3/z39kydgt59x46cdhf6vjhy39pe44ge3rvkhvb1nkwb2zr @@ -0,0 +1 @@ + "\ubabb@" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/3/z3eqckb2scmz4kjf7qt1yztrsfky9qraatwe03x51h7k6 b/implementation/fuzz/inputs-genvm-modules-complete-json/z/3/z3eqckb2scmz4kjf7qt1yztrsfky9qraatwe03x51h7k6 new file mode 100644 index 00000000..8fb22b47 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/3/z3eqckb2scmz4kjf7qt1yztrsfky9qraatwe03x51h7k6 @@ -0,0 +1 @@ +"UUUU3UUUUUUUUTUUUUUUUoUUUUUUUUTUUUUUUUoUsUUUUUUUUUUTUUUUUUUoUUUUUUaUUUUUT," diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/3/z3yvw1ngyxqxp5wn2km4cd12kbm9cye0pz29wcymqgwgp b/implementation/fuzz/inputs-genvm-modules-complete-json/z/3/z3yvw1ngyxqxp5wn2km4cd12kbm9cye0pz29wcymqgwgp new file mode 100644 index 00000000..1de6c58e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/3/z3yvw1ngyxqxp5wn2km4cd12kbm9cye0pz29wcymqgwgp @@ -0,0 +1 @@ +19111222222222221222222222 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/4/z472bjs2xxz4h1frvp4kewrt6hzem2ksne0k68c6w2478 b/implementation/fuzz/inputs-genvm-modules-complete-json/z/4/z472bjs2xxz4h1frvp4kewrt6hzem2ksne0k68c6w2478 new file mode 100644 index 00000000..216546b8 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/4/z472bjs2xxz4h1frvp4kewrt6hzem2ksne0k68c6w2478 @@ -0,0 +1 @@ +"[[1, B" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/5/z5f8bcx0bhxt4bc16ybcgjxgakyhz6081ej47wwb6yr6g b/implementation/fuzz/inputs-genvm-modules-complete-json/z/5/z5f8bcx0bhxt4bc16ybcgjxgakyhz6081ej47wwb6yr6g new file mode 100644 index 00000000..4e7542ea --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/5/z5f8bcx0bhxt4bc16ybcgjxgakyhz6081ej47wwb6yr6g @@ -0,0 +1 @@ + [1, , bbC \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/7/z70ryqvfm418005sc8r4bfm6v9ys4bbrmf0x5nnvsn1m0 b/implementation/fuzz/inputs-genvm-modules-complete-json/z/7/z70ryqvfm418005sc8r4bfm6v9ys4bbrmf0x5nnvsn1m0 new file mode 100644 index 00000000..2e287337 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/7/z70ryqvfm418005sc8r4bfm6v9ys4bbrmf0x5nnvsn1m0 @@ -0,0 +1,2 @@ +"\"2, t" + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/8/z821q1k0181fd425hst88zjpc27fcjs81z16vp3f89rm6 b/implementation/fuzz/inputs-genvm-modules-complete-json/z/8/z821q1k0181fd425hst88zjpc27fcjs81z16vp3f89rm6 new file mode 100644 index 00000000..55919c0a --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/8/z821q1k0181fd425hst88zjpc27fcjs81z16vp3f89rm6 @@ -0,0 +1 @@ + [[11111111111611111111111111E1 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/9/z9ap3tct6s8eqh3eck88e5aw9sqj3ga4yzznm2m2j0604 b/implementation/fuzz/inputs-genvm-modules-complete-json/z/9/z9ap3tct6s8eqh3eck88e5aw9sqj3ga4yzznm2m2j0604 new file mode 100644 index 00000000..8f1ae55c --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/9/z9ap3tct6s8eqh3eck88e5aw9sqj3ga4yzznm2m2j0604 @@ -0,0 +1,2 @@ + +"рbbbbIbb※ r" diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/a/zarvjgwmv5q3vwyd58gkw4gc501v7zkwjx00pkmgkft22 b/implementation/fuzz/inputs-genvm-modules-complete-json/z/a/zarvjgwmv5q3vwyd58gkw4gc501v7zkwjx00pkmgkft22 new file mode 100644 index 00000000..c85d3f60 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/a/zarvjgwmv5q3vwyd58gkw4gc501v7zkwjx00pkmgkft22 @@ -0,0 +1,18 @@ +{ + "foo": [ + "bar", + 123, + -123, + -1e10, + 1e-0, + null, + true, + false, + [1111111111111111111111111111e-111111111111111111, 2, 3] + ], + "bar": [ + "русские буквы 日本", + "mbbbbbbbbbbbbbbaz\t\uabbbbb", + "mbbbbbbabbbbbbbaz\t\\uabbbbb" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/e/zer1ffmaw8crmjm9de5g8zqtarpbwr23epvv20t5bs8x8 b/implementation/fuzz/inputs-genvm-modules-complete-json/z/e/zer1ffmaw8crmjm9de5g8zqtarpbwr23epvv20t5bs8x8 new file mode 100644 index 00000000..75a752b9 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/e/zer1ffmaw8crmjm9de5g8zqtarpbwr23epvv20t5bs8x8 @@ -0,0 +1 @@ +"[\\\\\\\\\\\\\\\\\\\\\\\\\\[1, B\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/e/zewv083f1apdzf1kg8vbg2jjfnvxgz9z00xa1h4mf65sa b/implementation/fuzz/inputs-genvm-modules-complete-json/z/e/zewv083f1apdzf1kg8vbg2jjfnvxgz9z00xa1h4mf65sa new file mode 100644 index 00000000..81724955 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/e/zewv083f1apdzf1kg8vbg2jjfnvxgz9z00xa1h4mf65sa @@ -0,0 +1 @@ + " \uBAb4" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/f/zfg0xsh5caxhzqb9z8nwpjzsvr0q8g0fjkz3y4y43kdjg b/implementation/fuzz/inputs-genvm-modules-complete-json/z/f/zfg0xsh5caxhzqb9z8nwpjzsvr0q8g0fjkz3y4y43kdjg new file mode 100644 index 00000000..a80a7670 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/f/zfg0xsh5caxhzqb9z8nwpjzsvr0q8g0fjkz3y4y43kdjg @@ -0,0 +1 @@ +-0 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/g/zgqxey2qy8j4gqm0rd91k8fbx1p23t4nwmc7gabhafhsm b/implementation/fuzz/inputs-genvm-modules-complete-json/z/g/zgqxey2qy8j4gqm0rd91k8fbx1p23t4nwmc7gabhafhsm new file mode 100644 index 00000000..5f046f0b --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/g/zgqxey2qy8j4gqm0rd91k8fbx1p23t4nwmc7gabhafhsm @@ -0,0 +1,2 @@ +{ "foo" Ћ + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/n/zn265mn3xv8v3v6zetbedfg88vjcvffa19ebk98pc5t6e b/implementation/fuzz/inputs-genvm-modules-complete-json/z/n/zn265mn3xv8v3v6zetbedfg88vjcvffa19ebk98pc5t6e new file mode 100644 index 00000000..3966243d --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/n/zn265mn3xv8v3v6zetbedfg88vjcvffa19ebk98pc5t6e @@ -0,0 +1 @@ +{  \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/n/zntc9yjnew3s8krzbcd9m8b567mmq3d92b7e6henf2nhj b/implementation/fuzz/inputs-genvm-modules-complete-json/z/n/zntc9yjnew3s8krzbcd9m8b567mmq3d92b7e6henf2nhj new file mode 100644 index 00000000..2eff6720 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/n/zntc9yjnew3s8krzbcd9m8b567mmq3d92b7e6henf2nhj @@ -0,0 +1 @@ + " \uDbbb\uDDbB u" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/p/zp2gxjckb10wqsjcp91bmtqq9chq2qq5gpdyym87v6q1j b/implementation/fuzz/inputs-genvm-modules-complete-json/z/p/zp2gxjckb10wqsjcp91bmtqq9chq2qq5gpdyym87v6q1j new file mode 100644 index 00000000..5c1f38fd --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/p/zp2gxjckb10wqsjcp91bmtqq9chq2qq5gpdyym87v6q1j @@ -0,0 +1 @@ +[[[["/ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/p/zpm8204mejxydjsawbrhn7vje3xjgaar0cpk7zy64ws0r b/implementation/fuzz/inputs-genvm-modules-complete-json/z/p/zpm8204mejxydjsawbrhn7vje3xjgaar0cpk7zy64ws0r new file mode 100644 index 00000000..2cafaa5a --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/p/zpm8204mejxydjsawbrhn7vje3xjgaar0cpk7zy64ws0r @@ -0,0 +1,2 @@ +2222222222222222222222.2222222222E22 + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/q/zqwvef7cvxgb2tybnypx352v6tdbpmr49vx29z97z5jtr b/implementation/fuzz/inputs-genvm-modules-complete-json/z/q/zqwvef7cvxgb2tybnypx352v6tdbpmr49vx29z97z5jtr new file mode 100644 index 00000000..b3f965cb --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/q/zqwvef7cvxgb2tybnypx352v6tdbpmr49vx29z97z5jtr @@ -0,0 +1,3 @@ + { + "":0, + "" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/r/zrj953c90pegf5s0v2ehgb286hxrsgzh77cv6mx6zrfa2 b/implementation/fuzz/inputs-genvm-modules-complete-json/z/r/zrj953c90pegf5s0v2ehgb286hxrsgzh77cv6mx6zrfa2 new file mode 100644 index 00000000..6604698f --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/r/zrj953c90pegf5s0v2ehgb286hxrsgzh77cv6mx6zrfa2 @@ -0,0 +1 @@ +[1, \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/t/zt8jegx974khs3jmwa42r8h98wypp5gsv1ss4s8je0166 b/implementation/fuzz/inputs-genvm-modules-complete-json/z/t/zt8jegx974khs3jmwa42r8h98wypp5gsv1ss4s8je0166 new file mode 100644 index 00000000..2f7ef5bc --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/t/zt8jegx974khs3jmwa42r8h98wypp5gsv1ss4s8je0166 @@ -0,0 +1 @@ +": " \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/t/ztkqhjcy7hbng5ndn9f36zaxab33220jxj2d0q7rgt72j b/implementation/fuzz/inputs-genvm-modules-complete-json/z/t/ztkqhjcy7hbng5ndn9f36zaxab33220jxj2d0q7rgt72j new file mode 100644 index 00000000..0f81b3c7 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/t/ztkqhjcy7hbng5ndn9f36zaxab33220jxj2d0q7rgt72j @@ -0,0 +1,11 @@ +[, + + + + + + + + + + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/v/zvcfa3ehdtsn1djntnwmv4mn2jm17t3t659k2b3mn1ryj b/implementation/fuzz/inputs-genvm-modules-complete-json/z/v/zvcfa3ehdtsn1djntnwmv4mn2jm17t3t659k2b3mn1ryj new file mode 100644 index 00000000..02df100e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/v/zvcfa3ehdtsn1djntnwmv4mn2jm17t3t659k2b3mn1ryj @@ -0,0 +1 @@ + [1, [1, [1, [1, " \uEbb \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/w/zwby1chwm64dgy0t105pr72a9se3x4e75xennhgf7fct2 b/implementation/fuzz/inputs-genvm-modules-complete-json/z/w/zwby1chwm64dgy0t105pr72a9se3x4e75xennhgf7fct2 new file mode 100644 index 00000000..a18c6764 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/w/zwby1chwm64dgy0t105pr72a9se3x4e75xennhgf7fct2 @@ -0,0 +1,14 @@ +{ + "11111111111111": 1e20, + + + + + + + + + + "11111111111111111111": 1e20, + "11111111": 1e20, +f \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/x/zx51d2g9vv3w2s6eh0fgy6esppgtmhary97nfcjqgtfza b/implementation/fuzz/inputs-genvm-modules-complete-json/z/x/zx51d2g9vv3w2s6eh0fgy6esppgtmhary97nfcjqgtfza new file mode 100644 index 00000000..cc3ca9b5 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/x/zx51d2g9vv3w2s6eh0fgy6esppgtmhary97nfcjqgtfza @@ -0,0 +1,16 @@ +{ + "bar": [ ], + "bar": [ + "baz\n\\{", + -1e10, + 1e20, + null, + true, + [1, 2, 3] + ], + "bar": [ ], + "bar": [ + "русские mbbbbbbbbb", + "mbbbbbbbbbbbbbbaz\t\\uabbbbb" + ] +} diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/y/zy2w7wxymampccdp97g9rzv76qwxk7vj05z145zenb364 b/implementation/fuzz/inputs-genvm-modules-complete-json/z/y/zy2w7wxymampccdp97g9rzv76qwxk7vj05z145zenb364 new file mode 100644 index 00000000..30d1b498 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/y/zy2w7wxymampccdp97g9rzv76qwxk7vj05z145zenb364 @@ -0,0 +1,2 @@ + ["baz + 01. \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-complete-json/z/z/zzn0apphqhr3g24550pxepzcyb5j2gp8px27fdjj1dt0r b/implementation/fuzz/inputs-genvm-modules-complete-json/z/z/zzn0apphqhr3g24550pxepzcyb5j2gp8px27fdjj1dt0r new file mode 100644 index 00000000..4a125f4c --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-complete-json/z/z/zzn0apphqhr3g24550pxepzcyb5j2gp8px27fdjj1dt0r @@ -0,0 +1,2 @@ + +"рbbbb\\uaaaa 111111d11 r" \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/db91d0d947f0f760465149f837c4bc02bf02c988c7eb7824c7e9496a52884908 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/0/e/0ep4zdf4ndsymnwtkeh8j0tztts0y186jq1bcw3wch8pe similarity index 100% rename from implementation/fuzz/inputs-genvm-modules-normalize-whitespace/db91d0d947f0f760465149f837c4bc02bf02c988c7eb7824c7e9496a52884908 rename to implementation/fuzz/inputs-genvm-modules-normalize-whitespace/0/e/0ep4zdf4ndsymnwtkeh8j0tztts0y186jq1bcw3wch8pe diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/0/p/0pez5en5ybbdkbh9axzqq7c4wgs8rt6mctebe7zf9kzy2 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/0/p/0pez5en5ybbdkbh9axzqq7c4wgs8rt6mctebe7zf9kzy2 new file mode 100644 index 00000000..f01735f8 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/0/p/0pez5en5ybbdkbh9axzqq7c4wgs8rt6mctebe7zf9kzy2 @@ -0,0 +1 @@ + ÍÁÀÀÀÁÍÁÁ diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/03fc8c99262f53a7d60c876faf4876a11a92c2e045c0ad0fcc738399f61fc240 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/03fc8c99262f53a7d60c876faf4876a11a92c2e045c0ad0fcc738399f61fc240 deleted file mode 100644 index 66fc93b8..00000000 --- a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/03fc8c99262f53a7d60c876faf4876a11a92c2e045c0ad0fcc738399f61fc240 +++ /dev/null @@ -1 +0,0 @@ -ÀÀÍÁÀÀÀÁÍÁÁÁ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/06e3c1413644ebd520e20235d3dfa3145613e296cb645884ffe0b885b63bd99b b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/06e3c1413644ebd520e20235d3dfa3145613e296cb645884ffe0b885b63bd99b deleted file mode 100644 index b34cdea2..00000000 --- a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/06e3c1413644ebd520e20235d3dfa3145613e296cb645884ffe0b885b63bd99b +++ /dev/null @@ -1,2 +0,0 @@ -$$$ - $ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/0a150ae9c5d282876a4e896149d6c486e771088809bf02e59aa61ca3d1c3e2e1 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/0a150ae9c5d282876a4e896149d6c486e771088809bf02e59aa61ca3d1c3e2e1 deleted file mode 100644 index 574c6e2c55a90f6da962d9d264fd3e811d7ad6a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 74 zcmXp~P%z~((I~Kmluehd8&S&PH?7$>HIgn9G zfJ=cvflGnQ!^1-vh~2d&2Qs?|abbYT4>?mO^RTREl%KqZ#f_0^@&rcl$?utECkrt0 z0>wTuYHiMEO=M)0oP3cjg3}fV7&tjOB_~U>yal=?kxgQ<0T+0va+X6IQ4CrztCkBN|E<>RE-~i-U4-X7yq6okhdvF$W1O{b)S5IqHL!Opx5iHZ%u zoLG=342agjj>wo{YA=ZcJh@%RM`nDnGmc_S*rpB9t9B^v9z~w#5f3k)yj%j9z1O?> z^(<-C04*G}g9C~ZnR)w5OxS@mgqm}&?*foBm!e+$IuyFM|A-VKLj$A5IE3BQz?Y;` vM}s%zM`B)w5Ff0nRC$sq15*aZlY!}{l|NA0!FMAW*Z@QhwzhV*KpFr!$_D`e literal 0 HcmV?d00001 diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/61c8efd9f69870226747b046f077b5751015cea9dc045849d65509918973b62d b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/61c8efd9f69870226747b046f077b5751015cea9dc045849d65509918973b62d deleted file mode 100644 index 8c006e67..00000000 --- a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/61c8efd9f69870226747b046f077b5751015cea9dc045849d65509918973b62d +++ /dev/null @@ -1 +0,0 @@ -ᘀ˜ᘀᘀᘀ9   ˜ᘀᘀᘀ9    ☀ᘀᘀᘀ˜ᘀᘀᘀᘀ˜ᘀᘀᘀ9    ♀     ᘀᘀᘀ9ᘀ ☀ᘀᘀᘀᘀᘀ9    ♀     ᘀᘀᘀ9ᘀ ☀ᘀᘀᘀ˜ᘀᘀᘀᘀ˜ᘀᘀᘀ9    ˜ᘀᘀᘀᘀ˜ᘀᘀᘀ9   ♀     ᘀᘀᘀ9ᘀ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/620942b003b1bae02a40d38e7b03f3cc4cc9e948192cfd5e7d0cb77b31d069ef b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/620942b003b1bae02a40d38e7b03f3cc4cc9e948192cfd5e7d0cb77b31d069ef deleted file mode 100644 index 6d7d2715..00000000 --- a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/620942b003b1bae02a40d38e7b03f3cc4cc9e948192cfd5e7d0cb77b31d069ef +++ /dev/null @@ -1 +0,0 @@ -         \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/7/4/745nee7h4x050p29a485e3t21m37hsa5y7a1wn9amb3wc b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/7/4/745nee7h4x050p29a485e3t21m37hsa5y7a1wn9amb3wc new file mode 100644 index 00000000..7409ccba --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/7/4/745nee7h4x050p29a485e3t21m37hsa5y7a1wn9amb3wc @@ -0,0 +1 @@ +⁀⁀⁀:⁀⁀:𔀟𔀍⁀:𔀆𔀟:𔀀:𔀟𧀟:𔀟 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/7/c/7ccqs9fgddtc4r3s7axbxz1hr61n8rtqp6nsqc0cd5me6 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/7/c/7ccqs9fgddtc4r3s7axbxz1hr61n8rtqp6nsqc0cd5me6 new file mode 100644 index 0000000000000000000000000000000000000000..322a0216efe73dbdfb75565f4924ff4d49f074a0 GIT binary patch literal 79 mcmaDjqd}ok;?RtTGaBFs!Ud8!a28w+$iNhogh(?mFaQ87lq|*o literal 0 HcmV?d00001 diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/7/f/7fd6ksepb7j5k4q8t8e3p230agfvr357se20qa952dn2r b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/7/f/7fd6ksepb7j5k4q8t8e3p230agfvr357se20qa952dn2r new file mode 100644 index 00000000..8e5db810 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/7/f/7fd6ksepb7j5k4q8t8e3p230agfvr357se20qa952dn2r @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/70546d5fca6e8da3f4320b2bb5a2789bedcac8a5bd30820c7aac957d3c6e1684 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/70546d5fca6e8da3f4320b2bb5a2789bedcac8a5bd30820c7aac957d3c6e1684 deleted file mode 100644 index 04ead9b3..00000000 --- a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/70546d5fca6e8da3f4320b2bb5a2789bedcac8a5bd30820c7aac957d3c6e1684 +++ /dev/null @@ -1,7 +0,0 @@ -1 -1 - 2 5d - - - - diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/7923fd9b7984beaa52f2b5e97ecbf0812db63788b4eb8411bcddc4be7267e428 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/7923fd9b7984beaa52f2b5e97ecbf0812db63788b4eb8411bcddc4be7267e428 deleted file mode 100644 index 09cee908..00000000 --- a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/7923fd9b7984beaa52f2b5e97ecbf0812db63788b4eb8411bcddc4be7267e428 +++ /dev/null @@ -1 +0,0 @@ -ᘀᘀᘀᘀ˜ᘀᘀᘀᘀ˜ᘀᘀᘀ9       ᘀᘀᘀᘀ9ᘀ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/7b2c4f7c87a84c1e2c26e69abf2fe09932db7ef15b4c939c079cf8fb0d275cbc b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/7b2c4f7c87a84c1e2c26e69abf2fe09932db7ef15b4c939c079cf8fb0d275cbc deleted file mode 100644 index 819e9cce..00000000 --- a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/7b2c4f7c87a84c1e2c26e69abf2fe09932db7ef15b4c939c079cf8fb0d275cbc +++ /dev/null @@ -1 +0,0 @@ -⁀⁀⁀:𔀟:𔀟 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/823ded55b18db8759c77a9c684b6d3af75c26871dd228082e3f3171ebda3b5a4 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/823ded55b18db8759c77a9c684b6d3af75c26871dd228082e3f3171ebda3b5a4 deleted file mode 100644 index c4110203b0509f356fc416c536125f323c1b14f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 171 zcmY+6y$XOp41?#k(<>d>swm4JwcwN xRkSCRT%^HQnMu-w86&V9e&la%`qZHnF@!$&{2FrRBi@37FSss1W|i$ga{=Jh5$FH_ diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/85ccfc35f2828100617311f9ebb138147e03034d9acbe149c2c1e93fba076dad b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/85ccfc35f2828100617311f9ebb138147e03034d9acbe149c2c1e93fba076dad deleted file mode 100644 index 76aec5bcb41977fd41829506c5ac66154bfeb5e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43 fcmZQz00J&9UMS$?0s=lR1qiT#P|}J(5pxCrH3|bw diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/891736f80c0acb4550ebf3a53fbde2113736faefe5e5107d3d7da299369df1b0 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/891736f80c0acb4550ebf3a53fbde2113736faefe5e5107d3d7da299369df1b0 deleted file mode 100644 index d1d6647c83a9d2205fdf82cf4a9aeb1fca681d05..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22 WcmZSP diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/9/1/91de5j750xjrn3kyfs8n3vgzt7389p5z7rnpxdw20mfrt b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/9/1/91de5j750xjrn3kyfs8n3vgzt7389p5z7rnpxdw20mfrt new file mode 100644 index 00000000..c1489732 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/9/1/91de5j750xjrn3kyfs8n3vgzt7389p5z7rnpxdw20mfrt @@ -0,0 +1,7 @@ + +2 2 + +1 + +À2 + diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/9/4/94g4fe2jqv1ktz8h03heqvtybz5zekjr3kzgmg73jyzzr b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/9/4/94g4fe2jqv1ktz8h03heqvtybz5zekjr3kzgmg73jyzzr new file mode 100644 index 00000000..4cfd5012 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/9/4/94g4fe2jqv1ktz8h03heqvtybz5zekjr3kzgmg73jyzzr @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +⁀⁀O𔀟𔀟: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/931f79f6a9b51bb5822885e25a66a326e2beae862e1f8493d137870f9526abb0 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/9/7/974px1w6qq7hdrmawg8d8m32fccy4ft8jk32h57863qgc similarity index 93% rename from implementation/fuzz/inputs-genvm-modules-normalize-whitespace/931f79f6a9b51bb5822885e25a66a326e2beae862e1f8493d137870f9526abb0 rename to implementation/fuzz/inputs-genvm-modules-normalize-whitespace/9/7/974px1w6qq7hdrmawg8d8m32fccy4ft8jk32h57863qgc index 4308199a474eba93d32c92ad7d3e90dcd5d5e9f9..64ebffdb0e91d5b7a030c58d7d1e1ba977a1f2b6 100644 GIT binary patch delta 66 zcmZp0-R`nMkd4t~qoOktqvS@#H#>H4>14$ delta 30 dcmdn)(%`y5kZrR8*LijXvC-f+%VYy3b^xtZ3Y`D| diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/9cf2c3c978eb136c0bc952d366b028830ebe2391400b3d6658ac26f5dba36868 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/9cf2c3c978eb136c0bc952d366b028830ebe2391400b3d6658ac26f5dba36868 deleted file mode 100644 index e1ef5a72d107ff0c7926e4c806cc51e250e8ca22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24 Xcmd<&)Z_#LIS^6Lz`y{afq)+X6G;JY diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/8d56d269122a8bbee7db1f44f0d2bc3a834cb31b8d2538dedc5c0b6ff9a740a0 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/a/6/a68wtsxj7hgjqf2j6yrqfqcbqa85px7mms469p8j7n2bw similarity index 60% rename from implementation/fuzz/inputs-genvm-modules-normalize-whitespace/8d56d269122a8bbee7db1f44f0d2bc3a834cb31b8d2538dedc5c0b6ff9a740a0 rename to implementation/fuzz/inputs-genvm-modules-normalize-whitespace/a/6/a68wtsxj7hgjqf2j6yrqfqcbqa85px7mms469p8j7n2bw index dbd2dd8781c4ad61823ccae07ec36d8085805059..dd0e90147930c2d9ae231ccc2bcab4646882928f 100644 GIT binary patch literal 1043 zcmY#T7<#}K2!O6;;Kbr|E-YfBLPH<~6j9xng36^i&xqzWP+$QkrzGd&#)ij@levL_ Wi<`Tio11|XTk=P-L>q-iGzS3BrG*Rt literal 1057 XcmY#T7zLvtFxWysaj-dPd WQdER!=276_=H_ML?SG*W;e&yA4p$OYP^$xOs97DzpOvL(e#x!rFtiHYThyb)Ew#Bv6*lIZ~dl+9C~d zy5E3DdqYS)dj_(`LMOZ?%amTyD4|-OYcYzLW1#;)r0HBcIA@Y(BNAM5rXf!7Vg(^B h79-rQ*Pt=oMTDt&HQe>_kH7B?`W1vyD3)0vBHqcdMacjF literal 0 HcmV?d00001 diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/e/7/e7yvwya7erng8g6r1xee9we5cjd7ys97ejb0yc1crfpzr b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/e/7/e7yvwya7erng8g6r1xee9we5cjd7ys97ejb0yc1crfpzr new file mode 100644 index 00000000..f0b0f494 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/e/7/e7yvwya7erng8g6r1xee9we5cjd7ys97ejb0yc1crfpzr @@ -0,0 +1,3 @@ + + +ÀÍÁ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/e6237eb52e4a8750685e1fb8741b2c0cbac5e873876430bc8f6e41b5ad0209c8 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/e6237eb52e4a8750685e1fb8741b2c0cbac5e873876430bc8f6e41b5ad0209c8 deleted file mode 100644 index 69eddd6a..00000000 --- a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/e6237eb52e4a8750685e1fb8741b2c0cbac5e873876430bc8f6e41b5ad0209c8 +++ /dev/null @@ -1 +0,0 @@ -ᘀ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/e72d0a509f5966a8861516dd92358725c1c5603183da9733bb90a125f85ab9db b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/e72d0a509f5966a8861516dd92358725c1c5603183da9733bb90a125f85ab9db deleted file mode 100644 index 285991b6385f3c409964164803309ad43f227d40..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66 ucmZSJ;^GAZhVx4pctIEl%(#rXY%95p6pR$OxVgDO7z^O#<>cnl-~#|83I_lH diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/e8b6d77f122eb966b7a7cbb6a225ef83020029066c04ad009ec529c273de0fa8 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/e8b6d77f122eb966b7a7cbb6a225ef83020029066c04ad009ec529c273de0fa8 deleted file mode 100644 index 01a1a62a..00000000 --- a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/e8b6d77f122eb966b7a7cbb6a225ef83020029066c04ad009ec529c273de0fa8 +++ /dev/null @@ -1 +0,0 @@ -⁀ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f/7/f717g71e7k6bcs5q565ze8z0f8xna7kpmt8j8kcp7t4rg b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f/7/f717g71e7k6bcs5q565ze8z0f8xna7kpmt8j8kcp7t4rg new file mode 100644 index 00000000..ea1e7ab9 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f/7/f717g71e7k6bcs5q565ze8z0f8xna7kpmt8j8kcp7t4rg @@ -0,0 +1 @@ +…………………………………………………………………………………… \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f/j/fj28aaza5he7xhhe0pff01yxcft748ycsfxjkz1p1pzw2 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f/j/fj28aaza5he7xhhe0pff01yxcft748ycsfxjkz1p1pzw2 new file mode 100644 index 00000000..0ed261c8 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f/j/fj28aaza5he7xhhe0pff01yxcft748ycsfxjkz1p1pzw2 @@ -0,0 +1 @@ +⚀𔀟𔀟:𔀟 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/5df9f5badb887ecd9ffbe572515a25f71356275d18023fb295c80fe8caba5c82 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f/r/fr6sp1b7ghxs3gbj8e6je6nc4bwqra5kpkd4exvremh62 similarity index 100% rename from implementation/fuzz/inputs-genvm-modules-normalize-whitespace/5df9f5badb887ecd9ffbe572515a25f71356275d18023fb295c80fe8caba5c82 rename to implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f/r/fr6sp1b7ghxs3gbj8e6je6nc4bwqra5kpkd4exvremh62 diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f/v/fvq371s3kcysrjp95yrvxpccg93687d7c8c7ypv3xadvg b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f/v/fvq371s3kcysrjp95yrvxpccg93687d7c8c7ypv3xadvg new file mode 100644 index 00000000..14af655f --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f/v/fvq371s3kcysrjp95yrvxpccg93687d7c8c7ypv3xadvg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f/w/fwqe7ds6xt6f0mvqxw2gvqmwnsgb15fas67ge0wb0mbe0 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f/w/fwqe7ds6xt6f0mvqxw2gvqmwnsgb15fas67ge0wb0mbe0 new file mode 100644 index 00000000..940651c6 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f/w/fwqe7ds6xt6f0mvqxw2gvqmwnsgb15fas67ge0wb0mbe0 @@ -0,0 +1 @@ +…………………… \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f35d3bec11953f5914c9ca460ef3d4a1d5d7121d0ff0d8d6cdbc374ae9946c80 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f35d3bec11953f5914c9ca460ef3d4a1d5d7121d0ff0d8d6cdbc374ae9946c80 deleted file mode 100644 index efa9a3eeacc3b481261cca817dfb69f36425d96a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1804 zcmd<(HDfX6vaRGYQZNcn;28z<3;{@>C)6_tfNW)8VPK%A?W1;$h5!{pU^LlMArME6 M7~l{vQcy4j0ICUCPyhe` diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f71d8c3bc20355985702ac0223e06edd28d33945777415f169219fc560a6025b b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f71d8c3bc20355985702ac0223e06edd28d33945777415f169219fc560a6025b deleted file mode 100644 index a7e49d3858daf8799a40dfd4ad52e20f4214bc58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23 acmX@Vgn{?`5(Y*f=4IyP<>CVI>KFiA2?nG9 diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f7e3e6880c7e27d1a97f3a04f448e90e33f72f377cf4fcc582fa70c9fbeec75a b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f7e3e6880c7e27d1a97f3a04f448e90e33f72f377cf4fcc582fa70c9fbeec75a deleted file mode 100644 index d563cdeb0ecdd0a856f8b1e957c8f5b6a8dda4d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4343 zcmeGgyKcfj?5Z*lU)BoUb`nz6p;ATq7?7@Isf73=CPIIq9oX`1lpp9P)b~j2Mg#() zNkwBp;`1v$pY0gdt5kD{%0Ns=H0UzBV*R;H)fg}C{`HY&5nov9D<>!`qQ-b7h81w6 zYF(5d_x=RN!{PkryR3{sMJzHG6>BCJs239-H6K&%P@6cN&Ym>7;a;{DLUPw*cfI&J zMi64?Zz2|n)u1*(u+sO^uobljnl1mW&GLoRZ~7WKOcUJkpAk8b+`HGsnYB zZuKKP!9BnW67l$_0RR&L<%H-7D_78S{xC;!`4MVpXT@tm5)7NUzCugE+jcU75_n(k zO9YT|A?2Vi&}Zc?(Po)$mhZ%5)O2FZvoT&IER10SJJq=4TcJJZ)1w;jqbv9$YiWlX zrCd`zlb(p!uXpzyTR(u+NE5?W~CQTGy?@Nc<0GS*q>sr9rVc z8|U`XQQ+o+3_z6 Q6tn6Yrc)T{2m9t%-{*PBvj6}9 diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/g/e/gecqrc9ajgg1n1dtv2p2v1qjxjgrh535tb5hwqkngyz00 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/g/e/gecqrc9ajgg1n1dtv2p2v1qjxjgrh535tb5hwqkngyz00 new file mode 100644 index 00000000..a0e70779 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/g/e/gecqrc9ajgg1n1dtv2p2v1qjxjgrh535tb5hwqkngyz00 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/h/0/h013nnr4swa87d0ztyyvvrvqb28vkagw6m9xs5vb9grsm b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/h/0/h013nnr4swa87d0ztyyvvrvqb28vkagw6m9xs5vb9grsm new file mode 100644 index 00000000..fd40910d --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/h/0/h013nnr4swa87d0ztyyvvrvqb28vkagw6m9xs5vb9grsm @@ -0,0 +1,4 @@ + + + + diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/h/8/h8rtrgawv1nqn6hg52g9t04zpspzmdrakrktftpejfg4y b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/h/8/h8rtrgawv1nqn6hg52g9t04zpspzmdrakrktftpejfg4y new file mode 100644 index 00000000..842104dc --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/h/8/h8rtrgawv1nqn6hg52g9t04zpspzmdrakrktftpejfg4y @@ -0,0 +1 @@ + ş:𔀟𔀟 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f9024ec809d2d43073ab044fa702ae963fdba5c841b38a76999eb5ccead5518c b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/h/x/hxj83xa25drwh4m46gdt9naav2gzf3yg450m3gtd5xhz4 similarity index 100% rename from implementation/fuzz/inputs-genvm-modules-normalize-whitespace/f9024ec809d2d43073ab044fa702ae963fdba5c841b38a76999eb5ccead5518c rename to implementation/fuzz/inputs-genvm-modules-normalize-whitespace/h/x/hxj83xa25drwh4m46gdt9naav2gzf3yg450m3gtd5xhz4 diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/j/g/jgjsyahmzmj5v16fek5xs8aa88g7nbe8n3mwbkpy4j1ce b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/j/g/jgjsyahmzmj5v16fek5xs8aa88g7nbe8n3mwbkpy4j1ce new file mode 100644 index 00000000..dcfc9f4f --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/j/g/jgjsyahmzmj5v16fek5xs8aa88g7nbe8n3mwbkpy4j1ce @@ -0,0 +1 @@ +   \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/j/j/jj3w58ycvjfwcfsv728ky0ym67zwq5ghv97tr3gvs709w b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/j/j/jj3w58ycvjfwcfsv728ky0ym67zwq5ghv97tr3gvs709w new file mode 100644 index 0000000000000000000000000000000000000000..f721ab19658948bee329cc341b97947c099fa145 GIT binary patch literal 16 Ocmd;LU}Rw6LI3~*QUH1Y literal 0 HcmV?d00001 diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/j/j/jjnrnbpw8tdkz7x7d88ksjpvma82a1eesd5kq3ma7cbma b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/j/j/jjnrnbpw8tdkz7x7d88ksjpvma82a1eesd5kq3ma7cbma new file mode 100644 index 0000000000000000000000000000000000000000..3218f4bfc231897f84b18e365ea431896ffe763f GIT binary patch literal 198 zcmaDjV_G~`kboqL%ti?3$72@H&<|qS1BDbA7!-h%oGF(XmoXQYZ6%kH Vf{_B3LLO8p4#Qvu1;xi#0sxR_Lm2=7 literal 0 HcmV?d00001 diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/0a53edc743484691ae84defc2db71ac98893a8c4afc437239bbf602cadafcf01 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/j/m/jmg6zts2m7cnj5v0cwbp2tzeez12bya52tf8ff84vcx2a similarity index 89% rename from implementation/fuzz/inputs-genvm-modules-normalize-whitespace/0a53edc743484691ae84defc2db71ac98893a8c4afc437239bbf602cadafcf01 rename to implementation/fuzz/inputs-genvm-modules-normalize-whitespace/j/m/jmg6zts2m7cnj5v0cwbp2tzeez12bya52tf8ff84vcx2a index 09976b8f..a3cd1623 100644 --- a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/0a53edc743484691ae84defc2db71ac98893a8c4afc437239bbf602cadafcf01 +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/j/m/jmg6zts2m7cnj5v0cwbp2tzeez12bya52tf8ff84vcx2a @@ -2,8 +2,7 @@ 2 2 1 - -À 2 + +À 2 1 diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/07d0413d5429f6ec807e88ee6428490ca8c4e7486981a814b99a1dcd1460be16 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/j/r/jrm84mt72pk0x462yncar39r2ztrbqa2hz12d6akabk92 similarity index 69% rename from implementation/fuzz/inputs-genvm-modules-normalize-whitespace/07d0413d5429f6ec807e88ee6428490ca8c4e7486981a814b99a1dcd1460be16 rename to implementation/fuzz/inputs-genvm-modules-normalize-whitespace/j/r/jrm84mt72pk0x462yncar39r2ztrbqa2hz12d6akabk92 index dc852db2b7f636e4e28c508b28d1a03803103420..580dd6d7a03f380651f0812c2e80fa82c5dd3053 100644 GIT binary patch delta 115 zcmZ3X-J{O@a7M%AKmpZ>1}u|9m?gO-IUhGR0Fgt2?Zkt&8y75Ln!K8wiw&qs!NFnj zM(%f$6PQ>hm$92~?qKz2+FZ|^z&QB>qs8VtuGwrnj~W|*NYd)Vl!p0}A2MofPGG8M R0!r&o&f_ZIoFd}F2ml9MEO`I` delta 108 zcmeBCU!l$Xa7M%AKo*h7Jj{}l>p2TH_AX(XT*qcJ`2uU@WCN}#lOHe!O?Kv8xjCD~ tp9xJccX9yx>CHhLv)O>E%qDN(W!*fVRhkj5DuBIlau7%PW)C43MgX2~CzAjG diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/j/s/jshb3dwrfzdq3w7zdrmsf5e5ed4djp29a0a2khgaff4ky b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/j/s/jshb3dwrfzdq3w7zdrmsf5e5ed4djp29a0a2khgaff4ky new file mode 100644 index 00000000..0fddc406 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/j/s/jshb3dwrfzdq3w7zdrmsf5e5ed4djp29a0a2khgaff4ky @@ -0,0 +1 @@ +⁀⁀⁀:⁀⁀:𔀟 ⁀⁀E⁀⁀:𔀟 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/24047b08dbc5f81e0d744bee88f975cd94332c54c3887d0305a1b768ed23b1ab b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/k/j/kjzgqk5d7x3mfk4eh2r3erw2bcjvbb2a4tx5bmyg5h7gm similarity index 67% rename from implementation/fuzz/inputs-genvm-modules-normalize-whitespace/24047b08dbc5f81e0d744bee88f975cd94332c54c3887d0305a1b768ed23b1ab rename to implementation/fuzz/inputs-genvm-modules-normalize-whitespace/k/j/kjzgqk5d7x3mfk4eh2r3erw2bcjvbb2a4tx5bmyg5h7gm index 92b715d0..e3d16323 100644 --- a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/24047b08dbc5f81e0d744bee88f975cd94332c54c3887d0305a1b768ed23b1ab +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/k/j/kjzgqk5d7x3mfk4eh2r3erw2bcjvbb2a4tx5bmyg5h7gm @@ -126,133 +126,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/709af572b2d689c93a58cc6beacccd0e41429338d17234b2a1591ffbf28e0aaf b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/k/z/kz1hkv3gm079cr4xbqx5r88g7n89246m27dcckhwdrdn4 similarity index 65% rename from implementation/fuzz/inputs-genvm-modules-normalize-whitespace/709af572b2d689c93a58cc6beacccd0e41429338d17234b2a1591ffbf28e0aaf rename to implementation/fuzz/inputs-genvm-modules-normalize-whitespace/k/z/kz1hkv3gm079cr4xbqx5r88g7n89246m27dcckhwdrdn4 index 8c58ec69cf4f6f428801b8fce38bd1239ab403d3..2ea6ccbb2f3da4a37cf726524cdd2c0949cafa40 100644 GIT binary patch delta 100 zcmaFMKaEfH;fw|a5I8gg$dUwNAhMju;XW}?bz?;%)8?Pdm5iK`oDjf0F;H~#1lCSQ Q1$zQuvKLFj-BKH%?x}RssO1 C7ZB3` diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/b39d82c804f3d1d5d8b219aab4aa30e36f7d4e00e1657d89a4dd2cefc2d47c58 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/m/k/mkvxxgdq2vw8r2zch1k1m1j8w8s48dtst8d6ckyj2hzg6 similarity index 76% rename from implementation/fuzz/inputs-genvm-modules-normalize-whitespace/b39d82c804f3d1d5d8b219aab4aa30e36f7d4e00e1657d89a4dd2cefc2d47c58 rename to implementation/fuzz/inputs-genvm-modules-normalize-whitespace/m/k/mkvxxgdq2vw8r2zch1k1m1j8w8s48dtst8d6ckyj2hzg6 index ed0bddee59266111cd2e6fee2c696d716fc633e5..2e42627a2cc4a05f88d7b4342f9b652ad439daa0 100644 GIT binary patch delta 120 zcmaE;uv%e*IpgGT#uP^H$%VXIHWx7IFivh|d_9RNX!CoPY(@z`9AKiM)aD7yyo^8{ z+nFXYnNBWXVx8Q@wVR7UKmiE2j1;&gf8-L~e1}n(c@mTUWOdf^$+G+(7|ka02?PTG DJ%A*- delta 61 zcmV-D0K)&PAmJdeHvy60Ad@!%WRp+~A+yg0O9PW|4tJAi1-!Gc3_k(0Py#FgvyTXX T0+X-|3bPptz61e4lh_YawJ;S- diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/m/z/mzfpjfw6n0r4khj55ptpnx9cayycmwj6rb0hc1q6m8rb4 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/m/z/mzfpjfw6n0r4khj55ptpnx9cayycmwj6rb0hc1q6m8rb4 new file mode 100644 index 00000000..991aa1a5 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/m/z/mzfpjfw6n0r4khj55ptpnx9cayycmwj6rb0hc1q6m8rb4 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/add963d8792a3271636e0d20bb97a73de0ea4220567f4fba49a271018360f15f b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/n/e/neab4np5n178b82cn37w6wwwew2s3hbz2xgtawd732qm4 similarity index 75% rename from implementation/fuzz/inputs-genvm-modules-normalize-whitespace/add963d8792a3271636e0d20bb97a73de0ea4220567f4fba49a271018360f15f rename to implementation/fuzz/inputs-genvm-modules-normalize-whitespace/n/e/neab4np5n178b82cn37w6wwwew2s3hbz2xgtawd732qm4 index 1901ba93..a02e2345 100644 --- a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/add963d8792a3271636e0d20bb97a73de0ea4220567f4fba49a271018360f15f +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/n/e/neab4np5n178b82cn37w6wwwew2s3hbz2xgtawd732qm4 @@ -10,3 +10,7 @@ + + + + diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/n/r/nr89fnaja49pea92v7ynqbrmtv9fmeqp91kpvb5cxkqj6 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/n/r/nr89fnaja49pea92v7ynqbrmtv9fmeqp91kpvb5cxkqj6 new file mode 100644 index 00000000..b28b04f6 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/n/r/nr89fnaja49pea92v7ynqbrmtv9fmeqp91kpvb5cxkqj6 @@ -0,0 +1,3 @@ + + + diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/p/1/p1zpp6xkygnwpdwe92026bywfvmxgwjmms4xp1p031gne b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/p/1/p1zpp6xkygnwpdwe92026bywfvmxgwjmms4xp1p031gne new file mode 100644 index 00000000..0facbfe4 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/p/1/p1zpp6xkygnwpdwe92026bywfvmxgwjmms4xp1p031gne @@ -0,0 +1 @@ + ぀぀@=== ぀぀@== \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/p/8/p8awpn2bs92fdxdgba32kgfqzy20eqysnv60tc2bdtw00 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/p/8/p8awpn2bs92fdxdgba32kgfqzy20eqysnv60tc2bdtw00 new file mode 100644 index 00000000..79ea433d --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/p/8/p8awpn2bs92fdxdgba32kgfqzy20eqysnv60tc2bdtw00 @@ -0,0 +1,12 @@ + Í +3 +=y +2 2 + +1 + +32 5 +6y +ÁÁ +=y + diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/p/e/pe5n6cfvewh2w64bd0za74k56dm5w120w067p8e7s8zqe b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/p/e/pe5n6cfvewh2w64bd0za74k56dm5w120w067p8e7s8zqe new file mode 100644 index 00000000..a63a7165 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/p/e/pe5n6cfvewh2w64bd0za74k56dm5w120w067p8e7s8zqe @@ -0,0 +1 @@ +2 5 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/167391bcddba8328537beeeb9c29c8ae7c1f4a23113ce87e30aa365fdec40971 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/p/x/pxbseqw4f9cwxkxm8qjv999ydvxydehy9xfrw5x0pynjg similarity index 84% rename from implementation/fuzz/inputs-genvm-modules-normalize-whitespace/167391bcddba8328537beeeb9c29c8ae7c1f4a23113ce87e30aa365fdec40971 rename to implementation/fuzz/inputs-genvm-modules-normalize-whitespace/p/x/pxbseqw4f9cwxkxm8qjv999ydvxydehy9xfrw5x0pynjg index b3b39908dc175af6b93cf60fc9332b8d090ccb2b..0b07e9066f4cba2b3c4d709877d42d5e09e81cc1 100644 GIT binary patch delta 146 zcmdnMbA(&%;fw|aD9~r&QR4vu1_osa#mB>9q@cjSz{5DvtCfWd2sZC#Qe>RW#uO+f zY4u@B!+g$1jSWBq;Q$$vbD8Ql^Dr|qGV*PH$jr;A0@SU*Wyob@YFo(#G|K}FxPT%G UKyiC8%`o{Pa|lQ*&o0{~hA9PI!A diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/q/d/qda1v0f123z425e6e676d6jxpx5depn9zy8mrncp32ky2 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/q/d/qda1v0f123z425e6e676d6jxpx5depn9zy8mrncp32ky2 new file mode 100644 index 00000000..5474ceaa --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/q/d/qda1v0f123z425e6e676d6jxpx5depn9zy8mrncp32ky2 @@ -0,0 +1 @@ +:𔀟 \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/q/d/qdq0byn41gzhq0wqwfcs77e4kcmftqh4r11237dqpg8j4 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/q/d/qdq0byn41gzhq0wqwfcs77e4kcmftqh4r11237dqpg8j4 new file mode 100644 index 00000000..c7a0c8d7 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/q/d/qdq0byn41gzhq0wqwfcs77e4kcmftqh4r11237dqpg8j4 @@ -0,0 +1 @@ +ÀÀÍÁÀÀÀÁÍÁÁÀÀÍÁÀ܀ÍÁÀÀÀÁÍÁÁÀÁÍÁÁÁÁ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/q/j/qjrs2n5jd5yenchgmwk4zny08by0d7qtqq6paysg185h6 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/q/j/qjrs2n5jd5yenchgmwk4zny08by0d7qtqq6paysg185h6 new file mode 100644 index 00000000..297d4117 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/q/j/qjrs2n5jd5yenchgmwk4zny08by0d7qtqq6paysg185h6 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/q/w/qwk9094vv8hx6rmr13g2ncxp0wjj2pbvd73t02498vdq8 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/q/w/qwk9094vv8hx6rmr13g2ncxp0wjj2pbvd73t02498vdq8 new file mode 100644 index 0000000000000000000000000000000000000000..0f541b4504c730797028e7145db4d7ad2958e638 GIT binary patch literal 4 LcmZQjP*4B>0K@=c literal 0 HcmV?d00001 diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/r/5/r5jvp155d7b5sa8zbgqzc2x6176bgs69qz9g0hx99r79e b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/r/5/r5jvp155d7b5sa8zbgqzc2x6176bgs69qz9g0hx99r79e new file mode 100644 index 00000000..d782e2eb --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/r/5/r5jvp155d7b5sa8zbgqzc2x6176bgs69qz9g0hx99r79e @@ -0,0 +1,18 @@ +E + + + + + + + + + + + + + + + + + diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/r/7/r7bm9nh1znjv0nh4qcy272s9brgsz64pz4dq52sx0ajec b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/r/7/r7bm9nh1znjv0nh4qcy272s9brgsz64pz4dq52sx0ajec new file mode 100644 index 00000000..e5e0b204 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/r/7/r7bm9nh1znjv0nh4qcy272s9brgsz64pz4dq52sx0ajec @@ -0,0 +1 @@ +⁀E⁀⁀ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/r/m/rm7j76kpffjnykfqxcgx0925xen98vn3t09atfgxapbmp b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/r/m/rm7j76kpffjnykfqxcgx0925xen98vn3t09atfgxapbmp new file mode 100644 index 00000000..12a6f48e --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/r/m/rm7j76kpffjnykfqxcgx0925xen98vn3t09atfgxapbmp @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/r/r/rrg0pbmdjev80ps4d0js812gzqa86q9jpa7rj5dn29rrp b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/r/r/rrg0pbmdjev80ps4d0js812gzqa86q9jpa7rj5dn29rrp new file mode 100644 index 0000000000000000000000000000000000000000..e58e603162b579e576db80e66819a4bd8b0d6e85 GIT binary patch literal 17 QcmZQjFogpyQwD~502xyP@c;k- literal 0 HcmV?d00001 diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/r/z/rzpzfk0mrj3zpzt3637hkx9zr4578xrbznyq6e2a7w91g b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/r/z/rzpzfk0mrj3zpzt3637hkx9zr4578xrbznyq6e2a7w91g new file mode 100644 index 00000000..597faa26 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/r/z/rzpzfk0mrj3zpzt3637hkx9zr4578xrbznyq6e2a7w91g @@ -0,0 +1 @@ +  ᘀ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/s/j/sjnxj30614zv737b6tjpmtnce0992v52bzadh2rhxzjf0 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/s/j/sjnxj30614zv737b6tjpmtnce0992v52bzadh2rhxzjf0 new file mode 100644 index 00000000..85830459 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/s/j/sjnxj30614zv737b6tjpmtnce0992v52bzadh2rhxzjf0 @@ -0,0 +1 @@ +………… \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/s/s/ssx9arzd57h63sh653erphygbrm9xnq5t4e4yhs2yq5aj b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/s/s/ssx9arzd57h63sh653erphygbrm9xnq5t4e4yhs2yq5aj new file mode 100644 index 00000000..dd9d674b --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/s/s/ssx9arzd57h63sh653erphygbrm9xnq5t4e4yhs2yq5aj @@ -0,0 +1 @@ +………………………………………… \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/s/w/swzsf6kzdrj1gay4k3mpkhwen689j0z2191zpt6qw1bm0 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/s/w/swzsf6kzdrj1gay4k3mpkhwen689j0z2191zpt6qw1bm0 new file mode 100644 index 00000000..1f039545 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/s/w/swzsf6kzdrj1gay4k3mpkhwen689j0z2191zpt6qw1bm0 @@ -0,0 +1,26 @@ + =y + 2 5 +6 +À 2 + +1 +    2 + +1 + + + + + + + +  2 5 +6 +À 2 + +1 + +  =m + 2 5 +6 +À \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/s/y/sybedhhm3tshmxs05mtw2vsqenrw8wv4cvw7wae800jk0 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/s/y/sybedhhm3tshmxs05mtw2vsqenrw8wv4cvw7wae800jk0 new file mode 100644 index 00000000..5459a8c9 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/s/y/sybedhhm3tshmxs05mtw2vsqenrw8wv4cvw7wae800jk0 @@ -0,0 +1 @@ +ᘀ˜ᘀᘀᘀ9   ˜ᘀᘀᘀ9   ☀ᘀᘀᘀ˜ᘀᘀᘀᘀ˜ᘀᘀᘀ    ♀    ‖ᘀᘀᘀ9ᘀ ☀ᘞᘀᘀ˜ᘀᘀᘀᘀ˜ᘀᘀᘀ9 ─  ♀     ᘀᘀᘀ \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/w/9/w9frp6nrpx9teh9vx8q52bwe8pz3gmzv2320qv3mttqtw b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/w/9/w9frp6nrpx9teh9vx8q52bwe8pz3gmzv2320qv3mttqtw new file mode 100644 index 00000000..4b11cd50 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/w/9/w9frp6nrpx9teh9vx8q52bwe8pz3gmzv2320qv3mttqtw @@ -0,0 +1 @@ +     \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/w/a/wa80m1ba2zgfd9y9bqvh13wfm83kqbqpsjwhv4mjmqebj b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/w/a/wa80m1ba2zgfd9y9bqvh13wfm83kqbqpsjwhv4mjmqebj new file mode 100644 index 00000000..4dcc5e79 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/w/a/wa80m1ba2zgfd9y9bqvh13wfm83kqbqpsjwhv4mjmqebj @@ -0,0 +1 @@ +         \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/x/4/x4gh60rdd803axv8pw9kh27xe1enmx1nhfhmjrags7jy8 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/x/4/x4gh60rdd803axv8pw9kh27xe1enmx1nhfhmjrags7jy8 new file mode 100644 index 0000000000000000000000000000000000000000..de0c3e4baf4aee4dfdd83c9c24c602c5d9b0f43a GIT binary patch literal 212 zcmd<(;O6G8=jImYVBqBBlmru;j~g2vH%i7qh*RvVaS-YBacHTzvW*y literal 0 HcmV?d00001 diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/z/g/zg4trx14yq823m5wamqwvdrz61sh6vkhc4y3fps0m02w6 b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/z/g/zg4trx14yq823m5wamqwvdrz61sh6vkhc4y3fps0m02w6 new file mode 100644 index 00000000..4f63c411 --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/z/g/zg4trx14yq823m5wamqwvdrz61sh6vkhc4y3fps0m02w6 @@ -0,0 +1 @@ +……… \ No newline at end of file diff --git a/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/z/x/zx6bt1mp5mztw0q4nzhjezfq249br5779q1v51s6hk85e b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/z/x/zx6bt1mp5mztw0q4nzhjezfq249br5779q1v51s6hk85e new file mode 100644 index 00000000..aba2382c --- /dev/null +++ b/implementation/fuzz/inputs-genvm-modules-normalize-whitespace/z/x/zx6bt1mp5mztw0q4nzhjezfq249br5779q1v51s6hk85e @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/implementation/src/lib.rs b/implementation/src/lib.rs index 387588f3..ec5f273c 100644 --- a/implementation/src/lib.rs +++ b/implementation/src/lib.rs @@ -7,13 +7,35 @@ pub mod web; pub use scripting::filters; +/// code point of the trailing `\uXXXX` escape, if the string ends in one +fn trailing_unicode_escape(s: &str) -> Option { + let start = s.len().checked_sub(6)?; + let b = s.as_bytes(); + + if b[start] != b'\\' || b[start + 1] != b'u' { + return None; + } + + let hex = &s[start + 2..]; + if !hex.bytes().all(|c| c.is_ascii_hexdigit()) { + return None; + } + + let slashes = s[..start].bytes().rev().take_while(|&c| c == b'\\').count(); + if slashes % 2 == 1 { + return None; + } + + u32::from_str_radix(hex, 16).ok() +} + pub fn complete_json(partial: &str) -> String { let mut result = partial.trim_end().to_string(); - let mut stack = Vec::new(); + // each frame is (closing char, whether the current object member already has a colon) + let mut stack: Vec<(char, bool)> = Vec::new(); let mut in_string = false; let mut escape_next = false; - let mut has_colon = false; for ch in partial.chars() { if escape_next { @@ -24,8 +46,8 @@ pub fn complete_json(partial: &str) -> String { match ch { '\\' if in_string => escape_next = true, '"' => in_string = !in_string, - '{' if !in_string => stack.push('}'), - '[' if !in_string => stack.push(']'), + '{' if !in_string => stack.push(('}', false)), + '[' if !in_string => stack.push((']', false)), '}' if !in_string => { stack.pop(); } @@ -33,10 +55,14 @@ pub fn complete_json(partial: &str) -> String { stack.pop(); } ':' if !in_string => { - has_colon = true; + if let Some(frame) = stack.last_mut() { + frame.1 = true; + } } - ',' if !in_string && stack.last() == Some(&'}') => { - has_colon = false; + ',' if !in_string => { + if let Some(frame @ ('}', _)) = stack.last_mut() { + frame.1 = false; + } } _ => {} } @@ -79,6 +105,19 @@ pub fn complete_json(partial: &str) -> String { } } + // a surrogate pair cut in half leaves a lone surrogate, which JSON rejects + while let Some(cp) = trailing_unicode_escape(&result) { + let paired = (0xdc00..0xe000).contains(&cp) + && trailing_unicode_escape(&result[..result.len() - 6]) + .is_some_and(|hi| (0xd800..0xdc00).contains(&hi)); + + if paired || !(0xd800..0xe000).contains(&cp) { + break; + } + + result.truncate(result.len() - 6); + } + result.push('"'); } @@ -89,15 +128,16 @@ pub fn complete_json(partial: &str) -> String { // nothing } else if result.ends_with(':') { result.push_str("null"); - } else if result.ends_with('-') || result.ends_with('.') || result.ends_with('+') { - result.push('0'); - } else if (result.ends_with('e') || result.ends_with('E')) - && result.chars().rev().nth(1).unwrap_or('a').is_ascii_digit() + } else if result.ends_with('-') + || result.ends_with('.') + || result.ends_with('+') + || ((result.ends_with('e') || result.ends_with('E')) + && result.chars().rev().nth(1).unwrap_or('a').is_ascii_digit()) { result.push('0'); } else if result.ends_with(',') { result.pop(); - } else if stack.last() == Some(&'}') && !has_colon && !result.ends_with('{') { + } else if stack.last() == Some(&('}', false)) && !result.ends_with('{') { result.push_str(":null"); } else { const CONSTS: &[&str] = &["true", "false", "null"]; @@ -115,7 +155,7 @@ pub fn complete_json(partial: &str) -> String { } } - while let Some(closing) = stack.pop() { + while let Some((closing, _)) = stack.pop() { result.push(closing); } diff --git a/implementation/src/llm/handler.rs b/implementation/src/llm/handler.rs index cb346e39..30b01c4a 100644 --- a/implementation/src/llm/handler.rs +++ b/implementation/src/llm/handler.rs @@ -190,17 +190,15 @@ impl Inner { consumed_gen: primitive_types::U256::MAX, }); } - if let Some(mlua_err) = err.downcast_ref::() { - if let mlua::Error::ExternalError(ext) = mlua_err { - if ext - .downcast_ref::() - .is_some() - { - return Ok(llm_iface::PromptAnswer { - data: llm_iface::PromptAnswerData::Text(String::new()), - consumed_gen: primitive_types::U256::MAX, - }); - } + if let Some(mlua::Error::ExternalError(ext)) = err.downcast_ref::() { + if ext + .downcast_ref::() + .is_some() + { + return Ok(llm_iface::PromptAnswer { + data: llm_iface::PromptAnswerData::Text(String::new()), + consumed_gen: primitive_types::U256::MAX, + }); } } Err(err) diff --git a/implementation/src/manager/handlers.rs b/implementation/src/manager/handlers.rs index 79721ab0..902f53db 100644 --- a/implementation/src/manager/handlers.rs +++ b/implementation/src/manager/handlers.rs @@ -21,6 +21,8 @@ pub async fn handle_status(ctx: sync::DArc) -> Result Option<&'static str> { Some( r##"The contract was detected to be a plain text contract, however it contains non-UTF8 bytes and hence cannot be parsed. Is deployed runner a valid contract?"##, ) - } else if is_sub_error(error, "invalid_contract absent_runner_comment") { + } else if is_sub_error(error, "invalid_contract runner absent") + || is_sub_error(error, "invalid_contract absent_runner_comment") + { Some( r##"The contract was detected to be a plain text contract, however it does not start with a runner comment (such as `# { "Depends": "py-genlayer:..." }`), hence it is impossible to run. Have you forgotten to add it or is there other content before it?"##, ) diff --git a/implementation/src/manager/mod.rs b/implementation/src/manager/mod.rs index c8f262e5..bc0a2dec 100644 --- a/implementation/src/manager/mod.rs +++ b/implementation/src/manager/mod.rs @@ -29,13 +29,124 @@ pub struct Config { pub base: genvm_common::BaseConfig, pub manifest_path: String, - pub permits: Option, + /// Absent or null keeps every default. + pub permits: Option, #[serde(default = "default_execution_retention")] pub execution_retention: run::ManagerDuration, #[serde(default = "default_max_message_bytes")] pub max_message_bytes: usize, } +/// Concurrency budget, denominated in gigabytes of RAM. +#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)] +pub struct PermitsConfig { + /// Total pool; null derives it from free memory. + #[serde(default)] + pub total: Option, + #[serde(default = "default_permits_per_gib")] + pub per_gib: PermitsPerGig, + #[serde(default = "default_permits_sync")] + pub sync: usize, + #[serde(default = "default_permits_nondet")] + pub nondet: usize, +} + +impl Default for PermitsConfig { + fn default() -> Self { + Self { + total: None, + per_gib: default_permits_per_gib(), + sync: default_permits_sync(), + nondet: default_permits_nondet(), + } + } +} + +/// Permits handed out per gibibyte of free memory. +/// +/// A ratio rather than a float: `1/4` is exactly one permit per four gibibytes, +/// and a config saying so must not depend on how a decimal rounds. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct PermitsPerGig(num_rational::Ratio); + +impl PermitsPerGig { + /// Floors, so a pool is never wider than the memory backing it. + pub fn apply(self, gigabytes: usize) -> usize { + let scaled = gigabytes as u128 * *self.0.numer() as u128 / *self.0.denom() as u128; + scaled.min(usize::MAX as u128) as usize + } +} + +impl std::str::FromStr for PermitsPerGig { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + let (numer, denom) = match s.split_once('/') { + Some((numer, denom)) => (numer.trim(), denom.trim()), + None => (s.trim(), "1"), + }; + let numer: u64 = numer + .parse() + .with_context(|| format!("invalid permits per_gib numerator in {s:?}"))?; + let denom: u64 = denom + .parse() + .with_context(|| format!("invalid permits per_gib denominator in {s:?}"))?; + anyhow::ensure!(numer > 0, "permits per_gib must be positive, got {s:?}"); + anyhow::ensure!(denom > 0, "permits per_gib must not divide by zero"); + + Ok(Self(num_rational::Ratio::new(numer, denom))) + } +} + +impl std::fmt::Display for PermitsPerGig { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}/{}", self.0.numer(), self.0.denom()) + } +} + +impl serde::Serialize for PermitsPerGig { + fn serialize( + &self, + serializer: S, + ) -> std::result::Result { + serializer.collect_str(self) + } +} + +impl<'de> serde::Deserialize<'de> for PermitsPerGig { + fn deserialize>( + deserializer: D, + ) -> std::result::Result { + /// `1` and `"1/4"` are both natural spellings in yaml + #[derive(serde::Deserialize)] + #[serde(untagged)] + enum Repr { + Integer(u64), + Str(String), + } + + use std::str::FromStr as _; + + match Repr::deserialize(deserializer)? { + Repr::Integer(n) => Self::from_str(&n.to_string()), + Repr::Str(s) => Self::from_str(&s), + } + .map_err(serde::de::Error::custom) + } +} + +fn default_permits_per_gib() -> PermitsPerGig { + PermitsPerGig(num_rational::Ratio::from_integer(1)) +} + +fn default_permits_sync() -> usize { + 4 +} + +fn default_permits_nondet() -> usize { + 8 +} + fn default_execution_retention() -> run::ManagerDuration { run::ManagerDuration::try_from("5m").expect("default execution_retention is valid") } @@ -129,6 +240,13 @@ fn internal_error(error: anyhow::Error) -> Response { error_response(StatusCode::INTERNAL_SERVER_ERROR, format!("{:#}", error)) } +/// A malformed body, query or header is the caller's fault: it answers 400 and +/// stays out of the error log, which is for this process' own failures. +fn bad_request(error: anyhow::Error) -> Response { + log_debug!(err:ah = &error; "bad request"); + error_response(StatusCode::BAD_REQUEST, format!("{:#}", error)) +} + fn unwrap_all_anyhow(result: anyhow::Result) -> Response { match result { Ok(response) => response.into_response(), @@ -189,7 +307,7 @@ fn create_router(app_ctx: sync::DArc) -> Router { body: Bytes| async move { let body = match parse_json_body(body) { Ok(body) => body, - Err(error) => return internal_error(error), + Err(error) => return bad_request(error), }; unwrap_all_anyhow(handlers::handle_module_start(ctx, body).await) }, @@ -202,7 +320,7 @@ fn create_router(app_ctx: sync::DArc) -> Router { body: Bytes| async move { let body = match parse_json_body(body) { Ok(body) => body, - Err(error) => return internal_error(error), + Err(error) => return bad_request(error), }; unwrap_all_anyhow(handlers::handle_module_stop(ctx, body).await) }, @@ -215,7 +333,7 @@ fn create_router(app_ctx: sync::DArc) -> Router { body: Bytes| async move { let body = match parse_json_body(body) { Ok(body) => body, - Err(error) => return internal_error(error), + Err(error) => return bad_request(error), }; unwrap_all_anyhow(handlers::handle_module_restart(ctx, body).await) }, @@ -237,7 +355,7 @@ fn create_router(app_ctx: sync::DArc) -> Router { contract_code: Bytes| async move { let deployment_timestamp = match deployment_timestamp(&headers) { Ok(deployment_timestamp) => deployment_timestamp, - Err(error) => return internal_error(error), + Err(error) => return bad_request(error), }; unwrap_all_anyhow( handlers::handle_contract_detect_version( @@ -257,7 +375,7 @@ fn create_router(app_ctx: sync::DArc) -> Router { body: Bytes| async move { let body = match parse_json_body(body) { Ok(body) => body, - Err(error) => return internal_error(error), + Err(error) => return bad_request(error), }; unwrap_all_anyhow(handlers::handle_set_log_level(ctx, body).await) }, @@ -279,7 +397,7 @@ fn create_router(app_ctx: sync::DArc) -> Router { body: Bytes| async move { let body = match parse_json_body(body) { Ok(body) => body, - Err(error) => return internal_error(error), + Err(error) => return bad_request(error), }; unwrap_all_anyhow(handlers::handle_set_permits(ctx, body).await) }, @@ -296,7 +414,7 @@ fn create_router(app_ctx: sync::DArc) -> Router { }; let query = match parse_query(query) { Ok(query) => query, - Err(error) => return internal_error(error), + Err(error) => return bad_request(error), }; unwrap_all_anyhow(handlers::handle_genvm_shutdown(ctx, genvm_id, query).await) }, @@ -310,7 +428,7 @@ fn create_router(app_ctx: sync::DArc) -> Router { }; let query = match parse_query(query) { Ok(query) => query, - Err(error) => return internal_error(error), + Err(error) => return bad_request(error), }; unwrap_all_anyhow( handlers::handle_genvm_status(ctx, genvm_id, query).await, @@ -329,7 +447,7 @@ fn create_router(app_ctx: sync::DArc) -> Router { }; let query = match parse_query(query) { Ok(query) => query, - Err(error) => return internal_error(error), + Err(error) => return bad_request(error), }; unwrap_all_anyhow(handlers::handle_genvm_artifact(ctx, genvm_id, query).await) }, @@ -342,7 +460,7 @@ fn create_router(app_ctx: sync::DArc) -> Router { body: Bytes| async move { let body = match parse_json_body(body) { Ok(body) => body, - Err(error) => return internal_error(error), + Err(error) => return bad_request(error), }; unwrap_all_anyhow(handlers::handle_llm_check(ctx, body).await) }, @@ -355,7 +473,7 @@ fn create_router(app_ctx: sync::DArc) -> Router { query: std::result::Result, QueryRejection>| async move { let query = match parse_query(query) { Ok(query) => query, - Err(error) => return internal_error(error), + Err(error) => return bad_request(error), }; unwrap_all_anyhow(handlers::handle_describe_vm_error(ctx, query).await) }, diff --git a/implementation/src/manager/run.rs b/implementation/src/manager/run.rs index c67ed736..beea74b0 100644 --- a/implementation/src/manager/run.rs +++ b/implementation/src/manager/run.rs @@ -23,6 +23,25 @@ use crate::common::{LogSink, LogSinkElement, LogSinkInner, LoggerWithId, GENVM_B const ARTIFACT_CHUNK_CAP: usize = 256 * 1024; +/// How many delegated (cross-major) hops one chain of contract calls may make. +/// +/// Deliberately far below any line's `VM_RECURSION`: a hop costs a whole +/// executor process, and the manager -- not any single line -- is the only +/// party that sees the chain as a whole. +const CROSS_MAJOR_RECURSION: u32 = 6; + +/// The recursion budget a delegated callee is given: whatever is left of the +/// caller's, but never more than [`CROSS_MAJOR_RECURSION`]. +/// +/// Clamping rather than counting keeps this stateless -- the manager reads one +/// number off the envelope and writes one back -- and it can only ever tighten +/// the bound the caller already had. The subtree below a delegated call is +/// bounded by the same number, which is the point: a chain that has already +/// crossed a boundary does not get to recurse deeply in-process either. +fn cross_major_recursion(remaining: u32) -> u32 { + remaining.min(CROSS_MAJOR_RECURSION) +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ManagerDuration(std::time::Duration); @@ -437,6 +456,9 @@ pub struct Ctx { next_genvm_id: std::sync::atomic::AtomicU64, pub permits: Arc, max_permits: tokio::sync::Mutex, + /// Permits a single run costs, by kind. One permit is one gigabyte of RAM. + permits_sync: usize, + permits_nondet: usize, executors_path: std::path::PathBuf, } @@ -485,6 +507,28 @@ impl Ctx { self.permits.available_permits() } + pub fn permits_sync(&self) -> usize { + self.permits_sync + } + + pub fn permits_nondet(&self) -> usize { + self.permits_nondet + } + + /// Below this the most expensive run could never be admitted. + pub fn min_permits(&self) -> usize { + self.permits_sync.max(self.permits_nondet) + } + + fn permits_for(&self, req: &Request) -> u32 { + let count = if req.needs_modules() { + self.permits_nondet + } else { + self.permits_sync + }; + count as u32 + } + pub async fn set_permits(&self, permits: usize) -> usize { let mut permits_lock = self.max_permits.lock().await; @@ -494,8 +538,9 @@ impl Ctx { // actually this causes drop of previous one, so we can enter more genvms than we have permits, but it's ok for now // especially since this method is expected to be called before starting any genvms at all - if permits < 2 { - log_warn!(permits = permits; "cannot set permits below 2"); + let min = self.min_permits(); + if permits < min { + log_warn!(permits = permits, min = min; "cannot set permits below the most expensive run"); return permits_lock.max; } @@ -662,14 +707,14 @@ impl Ctx { } #[cfg(target_os = "macos")] - fn get_default_permits() -> usize { + fn detect_free_gigabytes() -> usize { log_warn!("automatic permits detection is not supported on macOS, using default value"); - 8 + 32 } #[cfg(not(target_os = "macos"))] - fn get_default_permits() -> usize { + fn detect_free_gigabytes() -> usize { let mut sys = sysinfo::System::new_all(); sys.refresh_memory(); sys.refresh_all(); @@ -685,19 +730,41 @@ impl Ctx { "memory status" ); - let total_mem_kb = free_memory / 1024 + free_swap / 1024; - let total_mem_gb = total_mem_kb / 1024 / 1024; - - (total_mem_gb / 4).max(2) as usize + ((free_memory + free_swap) / (1024 * 1024 * 1024)) as usize } pub fn new(config: &crate::manager::Config) -> anyhow::Result { - let permits = if let Some(p) = config.permits { - p + let config_permits = config.permits.clone().unwrap_or_default(); + let permits_sync = config_permits.sync; + let permits_nondet = config_permits.nondet; + // the upper bound keeps the cast in `permits_for` honest + anyhow::ensure!( + (1..=u32::MAX as usize).contains(&permits_sync) + && (1..=u32::MAX as usize).contains(&permits_nondet), + "per-run permits must be positive and fit in u32" + ); + let min_permits = permits_sync.max(permits_nondet); + + let permits = match config_permits.total { + Some(p) => p, + None => config_permits.per_gib.apply(Self::detect_free_gigabytes()), + }; + let permits = if permits < min_permits { + log_warn!( + permits = permits, min = min_permits; + "permits are below the most expensive run, raising" + ); + min_permits } else { - Self::get_default_permits() + permits }; - log_info!(permits = permits; "estimated concurrent GenVM permits"); + log_info!( + permits = permits, + permits_sync = permits_sync, + permits_nondet = permits_nondet, + per_gib = config_permits.per_gib; + "estimated concurrent GenVM permits" + ); let mut exe_path = std::env::current_exe()?; exe_path.pop(); @@ -716,6 +783,8 @@ impl Ctx { num_throttled: 0, throttled: None, }), + permits_sync, + permits_nondet, executors_path: exe_path, }) @@ -1329,6 +1398,7 @@ fn nested_reply_from_consumed_result( 1 => genvm_modules_interfaces::ResultCode::UserError, 2 => genvm_modules_interfaces::ResultCode::VmError, 3 => genvm_modules_interfaces::ResultCode::InternalError, + 4 => genvm_modules_interfaces::ResultCode::FatalVmError, value => anyhow::bail!("nested executor returned unknown result code {value}"), }; let reported: genvm_modules_interfaces::ReportedResult = calldata::decode_obj(encoded)?; @@ -2045,7 +2115,8 @@ impl Ctx { execution_data.leader_nondet_results = None; execution_data.record_actions.clear(); execution_data.message_fee_allocation.clear(); - execution_data.remaining_recursion = Some(envelope.remaining_recursion); + execution_data.remaining_recursion = + Some(cross_major_recursion(envelope.remaining_recursion)); execution_data.nested = Some(genvm_modules_interfaces::NestedExecutionData { memory_limit: envelope.memory_limit, stack: envelope.stack, @@ -2084,7 +2155,7 @@ async fn supervise_genvm( modules_lock: Box, ) { let ctx = full_ctx.gep(|x| &x.run_ctx); - let permit_count = if req.needs_modules() { 2 } else { 1 }; + let permit_count = ctx.permits_for(&req); let permit_future = acquire_run_permits(ctx.permits.clone(), permit_count); tokio::pin!(permit_future); diff --git a/implementation/src/manager/run_test.rs b/implementation/src/manager/run_test.rs index 9744ad02..1c8a2be8 100644 --- a/implementation/src/manager/run_test.rs +++ b/implementation/src/manager/run_test.rs @@ -13,6 +13,8 @@ fn test_ctx(retention: &str, permits: usize) -> Ctx { num_throttled: 0, throttled: None, }), + permits_sync: 1, + permits_nondet: 2, executors_path: std::path::PathBuf::new(), } } @@ -443,6 +445,18 @@ async fn cancel_while_queued_consumes_no_permit() { assert_eq!(permits.available_permits(), 1); } +#[tokio::test] +async fn permits_cannot_drop_below_the_most_expensive_run() { + let ctx = test_ctx("5m", 8); + assert_eq!(ctx.min_permits(), 2); + + assert_eq!(ctx.set_permits(1).await, 8); + assert_eq!(ctx.get_current_permits(), 8); + + assert_eq!(ctx.set_permits(2).await, 2); + assert_eq!(ctx.get_current_permits(), 2); +} + #[tokio::test] async fn nested_run_does_not_consume_parent_permit() { let ctx = test_ctx("5m", 1); @@ -830,3 +844,36 @@ fn message_schema_matches_the_rust_struct() { assert_eq!(documented_properties("MessageData"), accepted); } + +#[test] +fn a_delegated_chain_is_bounded_more_tightly_than_plain_recursion() { + // The first hop clamps to the cross-major cap, and every hop after it + // spends one, so a chain of delegated calls dies well before the VM + // recursion budget it was minted from would. + let mut remaining = 1_000; + let mut hops = 0; + loop { + remaining = cross_major_recursion(remaining); + if remaining == 0 { + break; + } + hops += 1; + // What an executor spends on the sub-VM it spawns for the next hop. + remaining -= 1; + } + + assert_eq!(hops, CROSS_MAJOR_RECURSION as usize); +} + +#[test] +fn a_delegated_chain_never_widens_the_budget_it_was_given() { + for remaining in [ + 0, + 1, + CROSS_MAJOR_RECURSION - 1, + CROSS_MAJOR_RECURSION, + 1_000, + ] { + assert!(cross_major_recursion(remaining) <= remaining, "{remaining}"); + } +} diff --git a/implementation/src/manager/socket.rs b/implementation/src/manager/socket.rs index e0dd4dab..67b66612 100644 --- a/implementation/src/manager/socket.rs +++ b/implementation/src/manager/socket.rs @@ -48,16 +48,8 @@ struct Writer { } impl Writer { - /// Non-blocking, for the paths that run inside the read loop's error - /// handling and must not park. Everything that can await uses the async - /// twin instead, so a stalled peer applies backpressure rather than - /// costing frames. - fn send_control(&self, frame: Frame) -> Result<()> { - self.control - .try_send(frame) - .context("connection writer queue is full") - } - + /// Parks when the queue is full, so a slow reader is throttled rather than + /// disconnected. async fn send_control_async(&self, frame: Frame) -> Result<()> { self.control .send(frame) @@ -72,8 +64,9 @@ impl Writer { .context("connection writer queue is closed") } - fn error(&self, request_id: u64, code: Errors, message: impl Into) -> Result<()> { - self.send_control(error_frame(request_id, code, message)) + async fn error(&self, request_id: u64, code: Errors, message: impl Into) -> Result<()> { + self.send_control_async(error_frame(request_id, code, message)) + .await } } @@ -390,7 +383,9 @@ where let body = match message.context("reading websocket message")? { Message::Binary(body) => body, Message::Text(_) => { - writer.error(0, Errors::MalformedFrame, "text messages are not valid")?; + writer + .error(0, Errors::MalformedFrame, "text messages are not valid") + .await?; continue; } Message::Close(_) => return Ok(None), @@ -399,7 +394,9 @@ where }; if body.len() < HEADER_LEN { - writer.error(0, Errors::MalformedFrame, "message is shorter than header")?; + writer + .error(0, Errors::MalformedFrame, "message is shorter than header") + .await?; continue; } @@ -409,11 +406,13 @@ where let method = match Methods::try_from(method_id) { Ok(method) => method, Err(()) => { - writer.error( - request_id, - Errors::UnknownMethod, - format!("unknown method id {method_id}"), - )?; + writer + .error( + request_id, + Errors::UnknownMethod, + format!("unknown method id {method_id}"), + ) + .await?; continue; } }; @@ -453,11 +452,13 @@ where async fn dispatch(&mut self, method: Methods, request_id: u64, payload: &[u8]) -> Result<()> { if request_id == 0 { - self.writer.error( - 0, - Errors::BadRequestId, - "client requests must use request_id != 0", - )?; + self.writer + .error( + 0, + Errors::BadRequestId, + "client requests must use request_id != 0", + ) + .await?; return Ok(()); } @@ -468,11 +469,13 @@ where Methods::Ack => self.handle_ack(request_id, payload).await, Methods::GetArtifact => self.handle_get_artifact(request_id, payload).await, Methods::Error | Methods::Hello | Methods::Event => { - self.writer.error( - request_id, - Errors::UnknownMethod, - format!("method {} is not a client request", method.value()), - )?; + self.writer + .error( + request_id, + Errors::UnknownMethod, + format!("method {} is not a client request", method.value()), + ) + .await?; Ok(()) } } @@ -483,7 +486,8 @@ where Ok(req) => req, Err(e) => { self.writer - .error(request_id, Errors::MalformedFrame, e.to_string())?; + .error(request_id, Errors::MalformedFrame, e.to_string()) + .await?; return Ok(()); } }; @@ -493,11 +497,13 @@ where .get(1) .is_some_and(|data| !data.is_empty()) { - self.writer.error( - request_id, - Errors::MalformedFrame, - "host_hello_data for manager-owned host index 1 is not allowed", - )?; + self.writer + .error( + request_id, + Errors::MalformedFrame, + "host_hello_data for manager-owned host index 1 is not allowed", + ) + .await?; return Ok(()); } @@ -505,11 +511,13 @@ where match super::modules::Ctx::get_module_locks(self.ctx.gep(|x| &x.mod_ctx)).await { Some(lock) => Some(lock), None => { - self.writer.error( - request_id, - Errors::Internal, - "modules are required but not running", - )?; + self.writer + .error( + request_id, + Errors::Internal, + "modules are required but not running", + ) + .await?; return Ok(()); } } @@ -524,7 +532,8 @@ where Ok(id) => id, Err(e) => { self.writer - .error(request_id, Errors::Internal, format!("{:#}", e))?; + .error(request_id, Errors::Internal, format!("{:#}", e)) + .await?; return Ok(()); } }; @@ -532,24 +541,28 @@ where Ok(result) => result, Err(e) => { self.writer - .error(request_id, Errors::UnknownId, format!("{:#}", e))?; + .error(request_id, Errors::UnknownId, format!("{:#}", e)) + .await?; return Ok(()); } }; - self.writer.send_control(Frame::new( - Methods::Run, - request_id, - &RunResponse { genvm_id }, - ))?; + self.writer + .send_control_async(Frame::new( + Methods::Run, + request_id, + &RunResponse { genvm_id }, + )) + .await?; if let run::Snapshot::Event(event) = snapshot { - self.writer.send_control(event_frame(event))?; + self.writer.send_control_async(event_frame(event)).await?; } // Subscribing last keeps the frames ordered: the receiver was taken // above, so nothing is missed, but a terminal landing meanwhile cannot // produce an event for a genvm_id the client has not been told yet. if let Err(e) = self.subscribe(genvm_id, Ok(rx)) { self.writer - .error(request_id, Errors::UnknownId, format!("{:#}", e))?; + .error(request_id, Errors::UnknownId, format!("{:#}", e)) + .await?; return Ok(()); } Ok(()) @@ -560,7 +573,8 @@ where Ok(req) => req, Err(e) => { self.writer - .error(request_id, Errors::MalformedFrame, e.to_string())?; + .error(request_id, Errors::MalformedFrame, e.to_string()) + .await?; return Ok(()); } }; @@ -570,23 +584,30 @@ where Ok(result) => result, Err(e) if e.to_string() == "boot_id_mismatch" => { self.writer - .error(request_id, Errors::BootIdMismatch, "boot_id_mismatch")?; + .error(request_id, Errors::BootIdMismatch, "boot_id_mismatch") + .await?; return Ok(()); } Err(e) => { self.writer - .error(request_id, Errors::UnknownId, format!("{:#}", e))?; + .error(request_id, Errors::UnknownId, format!("{:#}", e)) + .await?; return Ok(()); } }; + self.writer + .send_control_async(Frame::new( + Methods::Attach, + request_id, + &AttachResponse { + snapshot: snapshot_payload(snapshot), + }, + )) + .await?; + // Subscribing last, as in `handle_run`: the receiver was taken above so + // nothing is missed, and the client cannot see an event that predates + // the snapshot it is answered with. self.subscribe(req.genvm_id, Ok(rx))?; - self.writer.send_control(Frame::new( - Methods::Attach, - request_id, - &AttachResponse { - snapshot: snapshot_payload(snapshot), - }, - ))?; Ok(()) } @@ -595,19 +616,22 @@ where Ok(req) => req, Err(e) => { self.writer - .error(request_id, Errors::MalformedFrame, e.to_string())?; + .error(request_id, Errors::MalformedFrame, e.to_string()) + .await?; return Ok(()); } }; match self.ctx.run_ctx.cancel(req.genvm_id).await { - Ok(()) => self.writer.send_control(Frame::new( - Methods::Cancel, - request_id, - &EmptyResponse {}, - ))?, - Err(e) => self - .writer - .error(request_id, Errors::UnknownId, format!("{:#}", e))?, + Ok(()) => { + self.writer + .send_control_async(Frame::new(Methods::Cancel, request_id, &EmptyResponse {})) + .await? + } + Err(e) => { + self.writer + .error(request_id, Errors::UnknownId, format!("{:#}", e)) + .await? + } } Ok(()) } @@ -617,7 +641,8 @@ where Ok(req) => req, Err(e) => { self.writer - .error(request_id, Errors::MalformedFrame, e.to_string())?; + .error(request_id, Errors::MalformedFrame, e.to_string()) + .await?; return Ok(()); } }; @@ -626,19 +651,19 @@ where if let Some(handle) = self.subscriptions.remove(&req.genvm_id) { handle.abort(); } - self.writer.send_control(Frame::new( - Methods::Ack, - request_id, - &EmptyResponse {}, - ))?; + self.writer + .send_control_async(Frame::new(Methods::Ack, request_id, &EmptyResponse {})) + .await?; } run::AckOutcome::NotFinished => { self.writer - .error(request_id, Errors::NotFinished, "run has not finished")? + .error(request_id, Errors::NotFinished, "run has not finished") + .await? } run::AckOutcome::Unknown => { self.writer - .error(request_id, Errors::UnknownId, "unknown_id")? + .error(request_id, Errors::UnknownId, "unknown_id") + .await? } } Ok(()) @@ -650,7 +675,8 @@ where Ok(req) => req, Err(e) => { self.writer - .error(request_id, Errors::MalformedFrame, e.to_string())?; + .error(request_id, Errors::MalformedFrame, e.to_string()) + .await?; return Ok(()); } }; @@ -674,11 +700,14 @@ where } Err(e) if e.to_string() == "unknown_id" => { self.writer - .error(request_id, Errors::UnknownId, "unknown_id")? + .error(request_id, Errors::UnknownId, "unknown_id") + .await? + } + Err(e) => { + self.writer + .error(request_id, Errors::MalformedFrame, format!("{:#}", e)) + .await? } - Err(e) => self - .writer - .error(request_id, Errors::MalformedFrame, format!("{:#}", e))?, } Ok(()) } @@ -733,9 +762,10 @@ pub async fn handle_connection(socket: WebSocket, ctx: sync::DArc) { artifact: artifact_tx, }; - let writer_task = tokio::spawn(writer_loop(writer_stream, control_rx, artifact_rx)); + let mut writer_task = tokio::spawn(writer_loop(writer_stream, control_rx, artifact_rx)); if writer - .send_control(hello_frame(ctx.run_ctx.boot_id())) + .send_control_async(hello_frame(ctx.run_ctx.boot_id())) + .await .is_err() { writer_task.abort(); @@ -762,7 +792,18 @@ pub async fn handle_connection(socket: WebSocket, ctx: sync::DArc) { _ = cancel.chan.closed() => {} } - match writer_task.await { + // The same peer defeats the select above if it stops reading: `sink.send` + // parks once the socket buffers fill, so the writer never drains its queue + // and never returns. + let writer_result = tokio::select! { + result = &mut writer_task => result, + _ = cancel.chan.closed() => { + writer_task.abort(); + return; + } + }; + + match writer_result { Ok(Ok(())) => {} Ok(Err(e)) => log_debug!(error:ah = e; "manager websocket writer stopped"), Err(e) if e.is_cancelled() => {} diff --git a/implementation/src/manager/socket_test.rs b/implementation/src/manager/socket_test.rs index 452f16c8..97ebf2a3 100644 --- a/implementation/src/manager/socket_test.rs +++ b/implementation/src/manager/socket_test.rs @@ -137,7 +137,8 @@ async fn full_control_queue_does_not_kill_the_subscription() { // until the peer reads. A stalled client's connection looks exactly like // this from the manager's side. writer - .send_control(test_frame(Methods::Event, 99, "occupier")) + .control + .try_send(test_frame(Methods::Event, 99, "occupier")) .unwrap(); let forwarder = tokio::spawn(forward_events(writer.clone(), events_rx)); diff --git a/implementation/src/scripting/ctx/dflt.rs b/implementation/src/scripting/ctx/dflt.rs index d3942f4e..bd0a90cd 100644 --- a/implementation/src/scripting/ctx/dflt.rs +++ b/implementation/src/scripting/ctx/dflt.rs @@ -17,8 +17,7 @@ use super::CtxPart; static START: std::sync::LazyLock = std::sync::LazyLock::new(std::time::Instant::now); -/// Process-relative monotonic milliseconds: comparable only within one process, -/// not a wall clock. Exists because the Lua sandbox loads no os library. +/// Process-relative monotonic milliseconds fn monotonic_ms() -> mlua::Integer { let elapsed = START.elapsed().as_millis(); elapsed.min(mlua::Integer::MAX as u128) as mlua::Integer diff --git a/implementation/tests/dflt_requests.rs b/implementation/tests/dflt_requests.rs index 721ad908..eda571f0 100644 --- a/implementation/tests/dflt_requests.rs +++ b/implementation/tests/dflt_requests.rs @@ -1,3 +1,5 @@ +// genvm-tool-test-tags: feature-web-request-body, feature-web-request-status, needs-web + use std::collections::BTreeMap; use std::sync::Arc; diff --git a/implementation/tests/manager_permits.rs b/implementation/tests/manager_permits.rs new file mode 100644 index 00000000..c8dfebe0 --- /dev/null +++ b/implementation/tests/manager_permits.rs @@ -0,0 +1,66 @@ +use genvm_modules::manager::{PermitsConfig, PermitsPerGig}; + +fn per_gib(yaml: &str) -> PermitsPerGig { + parse(&format!("per_gib: {yaml}")).per_gib +} + +fn parse(yaml: &str) -> PermitsConfig { + serde_yaml::from_str(yaml).unwrap() +} + +fn parse_err(yaml: &str) -> String { + serde_yaml::from_str::(&format!("per_gib: {yaml}")) + .unwrap_err() + .to_string() +} + +#[test] +fn a_ratio_is_exact() { + assert_eq!(per_gib("1/4").apply(16), 4); + assert_eq!(per_gib("1/4").apply(15), 3); + assert_eq!(per_gib("2/3").apply(10), 6); +} + +#[test] +fn an_integer_is_a_whole_ratio() { + assert_eq!(per_gib("1").apply(7), 7); + assert_eq!(per_gib("3").apply(7), 21); + assert_eq!(per_gib("'3/1'").to_string(), "3/1"); +} + +#[test] +fn defaults_hand_out_one_permit_per_gibibyte() { + let config = parse("{}"); + assert_eq!(config.per_gib.apply(12), 12); + assert_eq!(config.total, None); + assert_eq!(config.sync, 4); + assert_eq!(config.nondet, 8); +} + +#[test] +fn a_ratio_is_normalized_when_printed() { + assert_eq!(per_gib("2/8").to_string(), "1/4"); +} + +#[test] +fn scaling_saturates_instead_of_wrapping() { + let huge = format!("{}", u64::MAX); + assert_eq!(per_gib(&huge).apply(usize::MAX), usize::MAX); +} + +#[test] +fn a_zero_or_malformed_ratio_is_refused() { + for (input, expected) in [ + ("0", "must be positive"), + ("1/0", "divide by zero"), + ("'1/'", "denominator"), + ("'-1'", "numerator"), + ("'1/2/3'", "denominator"), + ] { + let err = parse_err(input); + assert!( + err.contains(expected), + "{input}: expected {expected:?}, got {err}" + ); + } +} diff --git a/implementation/tests/merge.rs b/implementation/tests/merge.rs index 6aa9cec3..1ce611e2 100644 --- a/implementation/tests/merge.rs +++ b/implementation/tests/merge.rs @@ -1,3 +1,5 @@ +// genvm-tool-test-tags: feature-prompt + use genvm_modules::llm::merge::{merge_extra, merge_values, MergeStrategy}; use serde_json::json; use std::collections::BTreeMap; diff --git a/implementation/tests/overloaded.rs b/implementation/tests/overloaded.rs index 5bdeb774..fe431994 100644 --- a/implementation/tests/overloaded.rs +++ b/implementation/tests/overloaded.rs @@ -1,3 +1,5 @@ +// genvm-tool-test-tags: feature-prompt-text, needs-llm, needs-web + use genvm_common::logger; use genvm_common::*; use genvm_modules_interfaces::llm::{self as llm_iface}; diff --git a/implementation/tests/policy_dispatch.rs b/implementation/tests/policy_dispatch.rs index 28ad1cb9..c2d7f061 100644 --- a/implementation/tests/policy_dispatch.rs +++ b/implementation/tests/policy_dispatch.rs @@ -1,3 +1,5 @@ +// genvm-tool-test-tags: feature-prompt-text, feature-prompt-json + // End-to-end tests for the LLM dispatch script after backend selection and the // retry state machine were delegated to the `llm_policy` engine. Everything here // runs offline against fake local TCP backends; no API keys, no network. diff --git a/implementation/tests/providers.rs b/implementation/tests/providers.rs index c41ad70a..680c8801 100644 --- a/implementation/tests/providers.rs +++ b/implementation/tests/providers.rs @@ -1,5 +1,7 @@ #![allow(non_upper_case_globals, dead_code)] +// genvm-tool-test-tags: feature-prompt-text, feature-prompt-json, needs-llm, needs-web + use std::collections::BTreeMap; use std::collections::HashMap; diff --git a/implementation/tests/request_body_limit.rs b/implementation/tests/request_body_limit.rs index 6cfa568f..e3fb32e8 100644 --- a/implementation/tests/request_body_limit.rs +++ b/implementation/tests/request_body_limit.rs @@ -1,3 +1,5 @@ +// genvm-tool-test-tags: feature-web-request-body, needs-web + use std::collections::BTreeMap; use genvm_common::*; diff --git a/implementation/tests/request_localhost.rs b/implementation/tests/request_localhost.rs index 105bf453..bded29d6 100644 --- a/implementation/tests/request_localhost.rs +++ b/implementation/tests/request_localhost.rs @@ -1,3 +1,5 @@ +// genvm-tool-test-tags: feature-web-request, needs-web + use genvm_common::*; use genvm_modules::common; use genvm_modules::scripting::{self, send_request_get_lua_compatible_response_bytes, Metrics}; diff --git a/implementation/tests/signing_server.rs b/implementation/tests/signing_server.rs index bbe57d7d..e0dfc9a1 100644 --- a/implementation/tests/signing_server.rs +++ b/implementation/tests/signing_server.rs @@ -1,3 +1,5 @@ +// genvm-tool-test-tags: feature-web-request-body, feature-web-request-signed, needs-web + use std::collections::BTreeMap; use std::sync::Arc; diff --git a/implementation/tests/timeout.rs b/implementation/tests/timeout.rs index 45bd15a1..3953f561 100644 --- a/implementation/tests/timeout.rs +++ b/implementation/tests/timeout.rs @@ -1,3 +1,5 @@ +// genvm-tool-test-tags: feature-prompt-text, needs-time + use genvm_common::logger; use genvm_common::*; use std::collections::BTreeMap; diff --git a/implementation/tests/web_render_webdriver.rs b/implementation/tests/web_render_webdriver.rs index ae80f1a8..24b5e23e 100644 --- a/implementation/tests/web_render_webdriver.rs +++ b/implementation/tests/web_render_webdriver.rs @@ -4,6 +4,8 @@ //! would otherwise drop. That connection must therefore go through the unfiltered //! client -- while contract-driven `Request` traffic stays filtered. +//! genvm-tool-test-tags: feature-web-render, feature-web-request, needs-web + use std::collections::BTreeMap; use std::sync::Arc; diff --git a/install/bin/genvm-post-install b/install/bin/genvm-post-install index 3c4de8e7..948894b1 100755 --- a/install/bin/genvm-post-install +++ b/install/bin/genvm-post-install @@ -47,7 +47,8 @@ genvm_root_dir = Path(__file__).parent.parent def requirements_for(base: Path) -> Path: - """The requirements to install into the venv. + """ + The requirements to install into the venv. lief is a heavy binary wheel whose only job is rewriting the ELF interpreter, so `--use-patchelf` drops it — patchelf does that instead. The venv is keyed diff --git a/install/config/genvm-manager.yaml b/install/config/genvm-manager.yaml index a33cdd78..930a47c3 100644 --- a/install/config/genvm-manager.yaml +++ b/install/config/genvm-manager.yaml @@ -7,6 +7,10 @@ log_disable: tracing*,polling*,tungstenite*,tokio_tungstenite* log_level: info manifest_path: ${exeDir}/../data/manifest.yaml -permits: null # if null will be auto-discovered; full VM takes 2, sync VM takes 1 +permits: # 1 permit is 1 GiB of RAM + total: null # if null, free memory times `per_gib` + per_gib: 1 # permits per gibibyte of free memory, an integer or a ratio (1/4 = one permit per 4 GiB) + sync: 4 # permits a sync run costs + nondet: 8 # permits a nondet run costs, also the minimum for `total` execution_retention: 5m # finished executions are retained until ack or this TTL max_message_bytes: 67108864 # 64 MiB manager websocket message cap diff --git a/install/lib/python/post-install/__main__.py b/install/lib/python/post-install/__main__.py index 3d492862..5caf5f32 100644 --- a/install/lib/python/post-install/__main__.py +++ b/install/lib/python/post-install/__main__.py @@ -324,7 +324,8 @@ def patch_executable(path: Path): def detect_executable_platform(path: Path) -> BinaryOS | None: - """Sniff a binary's header to identify its target OS: ELF -> linux, Mach-O + """ + Sniff a binary's header to identify its target OS: ELF -> linux, Mach-O (any variant/byte order) -> macos. Returns None for anything unrecognized (wrapper scripts, truncated/empty files, unknown formats).""" try: @@ -340,7 +341,8 @@ def detect_executable_platform(path: Path) -> BinaryOS | None: def check_executable_platform(path: Path): - """Refuse a wrong-OS binary before we trust it. A bad release once shipped a + """ + Refuse a wrong-OS binary before we trust it. A bad release once shipped a macOS (Mach-O) executor inside a linux tarball; the missing-only download guard accepted it and it surfaced as an opaque `Exec format error` at runtime. Here we error on a clear OS mismatch instead. Unrecognized formats @@ -435,7 +437,7 @@ def _download_template(descr: str, templates: list[str], vars: dict[str, str]) - def download_runners_from_json( - file: str | Path, runners_dir: Path, verify_hash: bool = True + file: str | Path, runners_dir: Path, extension: str, verify_hash: bool = True ): # `verify_hash` is disabled for the v0.2.x legacy line, whose registry hashes # use Nix base32 rather than the Crockford scheme `runner_check_bytes` @@ -454,7 +456,7 @@ def download_runners_from_json( for name, hashes in all_runners.items(): for hash in hashes: - cur_dst = runners_dir.joinpath(name, hash[:2], hash[2:] + '.tar') + cur_dst = runners_dir.joinpath(name, hash[:2], hash[2:] + '.' + extension) if cur_dst.exists(): if not verify_hash: @@ -476,6 +478,7 @@ def download_runners_from_json( 'hash': hash, 'hash_0_2': hash[:2], 'hash_2_': hash[2:], + 'ext': extension, }, ) if verify_hash and not runner_check_bytes(data, hash): @@ -486,7 +489,8 @@ def download_runners_from_json( def download_executor(executor_version: str): - """Fetch an executor line from its own release and unpack it at the install root. + """ + Fetch an executor line from its own release and unpack it at the install root. Since the repo split the manager release carries no executors: each line is released separately, under its own executor-version. The tarball is laid out @@ -578,7 +582,8 @@ def process_executor_version(executor_version: str): # root (executor//legacy-runners, see its genvm.yaml); every # other line shares the manager-root runners/ dir. v0.2.x also uses a # Nix-base32 registry hash this installer can't reproduce, so hash - # verification is left to that executor's `check` command. + # verification is left to that executor's `check` command, and it packages + # its runners as ustar rather than the zip every other line uses. is_legacy = (major, minor) == (0, 2) if is_legacy: runners_dir = executor_root_dir.joinpath('legacy-runners') @@ -587,6 +592,7 @@ def process_executor_version(executor_version: str): download_runners_from_json( executor_root_dir.joinpath('data', 'all.json'), runners_dir, + extension='tar' if is_legacy else 'zip', verify_hash=not is_legacy, ) diff --git a/libs/iconv.nix b/libs/iconv.nix index c0651d19..f1b5b7a5 100644 --- a/libs/iconv.nix +++ b/libs/iconv.nix @@ -8,7 +8,7 @@ let iconv-src = deps."libiconv-1.18"; in pkgs.stdenvNoCC.mkDerivation { - name = "libiconv"; + name = "genvm-libiconv"; src = iconv-src; diff --git a/libs/libc.nix b/libs/libc.nix index 6a0468c5..40953087 100644 --- a/libs/libc.nix +++ b/libs/libc.nix @@ -14,7 +14,7 @@ let aarch64-compiler-rt = deps."compiler-rt-aarch64-21.1.5-1"; in pkgs.stdenvNoCC.mkDerivation { - name = "libc-${name-target}"; + name = "genvm-libc-${name-target}"; src = musl-src; diff --git a/libs/liblua.nix b/libs/liblua.nix index 3af8ff98..1846b8e6 100644 --- a/libs/liblua.nix +++ b/libs/liblua.nix @@ -14,7 +14,7 @@ let installNameFlag = if isMacos then "-Wl,-install_name,@rpath/liblua.dylib" else ""; in pkgs.stdenvNoCC.mkDerivation { - name = "liblua-${name-target}"; + name = "genvm-liblua-${name-target}"; inherit version; diff --git a/libs/lsqlite3.nix b/libs/lsqlite3.nix index 5db3e106..43162e42 100644 --- a/libs/lsqlite3.nix +++ b/libs/lsqlite3.nix @@ -11,7 +11,7 @@ let isMacos = name-target == "arm64-macos"; in pkgs.stdenvNoCC.mkDerivation { - name = "lsqlite3-${name-target}"; + name = "genvm-lsqlite3-${name-target}"; src = lsqlite3-src; diff --git a/ruff.toml b/ruff.toml index c2ceb589..8fe74f41 100644 --- a/ruff.toml +++ b/ruff.toml @@ -1,6 +1,6 @@ indent-width = 2 -exclude = ["executors/**"] +exclude = ["executors/**", "libs/unhardcoded-engine"] [format] indent-style = "tab" @@ -13,4 +13,15 @@ skip-magic-trailing-comma = false [lint] ignore = ["E741"] -extend-select = ["I"] +[lint.per-file-ignores] +# contract assets: the v0.2 sdk is used through a star import +"tests/system/**/assets/**" = ["F403", "F405"] + +extend-select = [ + "E9", + "F", + "ASYNC", + "RUF006", + "D213", # docstring summary on next line + "I", # sort imports +] diff --git a/runners/default.nix b/runners/default.nix index df37cd8d..c5e9312f 100644 --- a/runners/default.nix +++ b/runners/default.nix @@ -25,7 +25,4 @@ in list forExecutor ; - - # We always build all of them: { uid -> derivation } over the full list. - universal = import ./views/universal.nix args list; } diff --git a/support/ci/pipelines/tests.py b/support/ci/pipelines/tests.py index 10654dcb..7219e213 100644 --- a/support/ci/pipelines/tests.py +++ b/support/ci/pipelines/tests.py @@ -209,7 +209,9 @@ def group(gh_step: str, name: str, stage: Stage, body: GithubStep) -> None: tool_step=Stage( data=ToolTest( tests_name_filter_for_or='^executors/', - tests_tags_filter_for_or='rust', + # integration cases tag their Rust contracts `rust` too, and those need + # a built manager -- which this cell deliberately does not build + tests_tags_filter_for_or='rust & !integration', ), ), ) @@ -297,7 +299,7 @@ def _cell( QUEUE_CELLS = [ - _cell('other', TEST_OTHER), + _cell('other', TEST_OTHER, fuzz_host=True), _cell('rust-executors', TEST_RUST_EXECUTORS, fuzz_host=True, disk_reclaim=True), _cell('rust-manager', TEST_RUST_MANAGER, fuzz_host=True, disk_reclaim=True), _cell( diff --git a/support/ci/tools/open_executor_prs.py b/support/ci/tools/open_executor_prs.py index 68b7fe7c..85da2307 100644 --- a/support/ci/tools/open_executor_prs.py +++ b/support/ci/tools/open_executor_prs.py @@ -173,7 +173,7 @@ def open_executor_prs(ctx: gh_common.Ctx) -> None: continue url = existing_pr(ctx, head, base) or open_pr(ctx, head, base) print(f'{line}: executor PR {url}') - lines.append(f'executor: {url}') + lines.append(f'executor: {url} ({line})') if lines: upsert_comment(ctx, lines) else: diff --git a/support/manifest-base.yaml b/support/manifest-base.yaml index 25b07e31..654bad6f 100644 --- a/support/manifest-base.yaml +++ b/support/manifest-base.yaml @@ -3,7 +3,7 @@ # is derived from the active executor submodules; everything here is # build-independent and lives under version control. runners_download_urls: - - "https://storage.googleapis.com/gh-af/genvm_runners/{name}/{hash}.tar" + - "https://storage.googleapis.com/gh-af/genvm_runners/{name}/{hash}.{ext}" # Each executor line is released on its own, in its own repo, tagged with its # executor-version — the manager bundle does not carry them. `{version}` is that # tag and `{platform}` is the nix-style token (amd64-linux, arm64-macos, ...). diff --git a/support/runner-script.py b/support/runner-script.py index 39bfc1b9..20628778 100755 --- a/support/runner-script.py +++ b/support/runner-script.py @@ -52,8 +52,7 @@ def run_verify_file(args): path = Path(args.file) expected_hash: str | None = args.expected_hash if expected_hash is None: - expected_hash = path.name - expected_hash = expected_hash.removesuffix('.tar') + expected_hash = path.stem if not all([x in HASH_VALID_CHARS for x in expected_hash]): print(f'invalid hash {expected_hash}', file=sys.stderr) @@ -93,12 +92,12 @@ def _load_registry(file: str) -> dict[str, list[str]]: return ret -def _object_gcs_path(name: str, hash: str) -> str: - return f'genvm_runners/{name}/{hash}.tar' +def _object_gcs_path(name: str, hash: str, ext: str) -> str: + return f'genvm_runners/{name}/{hash}.{ext}' -def _download_single(name: str, hash: str) -> bytes: - url = f'https://storage.googleapis.com/gh-af/{_object_gcs_path(name, hash)}' +def _download_single(name: str, hash: str, ext: str) -> bytes: + url = f'https://storage.googleapis.com/gh-af/{_object_gcs_path(name, hash, ext)}' with urllib.request.urlopen(url) as f: return f.read() @@ -141,7 +140,7 @@ def run_download(args): for name, hashes in registry.items(): for hash in hashes: try: - cur_dst = dst.joinpath(name, hash[:2], hash[2:] + '.tar') + cur_dst = dst.joinpath(name, hash[:2], hash[2:] + '.' + args.extension) if cur_dst.exists(): data = cur_dst.read_bytes() @@ -154,7 +153,7 @@ def run_download(args): else: print(f'info: not found {cur_dst}') - data = _download_single(name, hash) + data = _download_single(name, hash, args.extension) if not check_bytes(data, hash): raise ValueError('hash mismatch') @@ -175,11 +174,11 @@ def run_download(args): print(json.dumps({'downloaded': successful}, sort_keys=True)) -def _upload_single(name: str, hash: str, contents: bytes, *, token: str): +def _upload_single(name: str, hash: str, contents: bytes, *, ext: str, token: str): if not check_bytes(contents, hash): raise ValueError('hash mismatch') - object_name = urllib.parse.quote_plus(_object_gcs_path(name, hash)) + object_name = urllib.parse.quote_plus(_object_gcs_path(name, hash, ext)) upload_url = f'https://storage.googleapis.com/upload/storage/v1/b/gh-af/o?uploadType=media&name={object_name}' @@ -249,8 +248,10 @@ def run_upload(args): for hash in hashes: try: print(f'trying {name}:{hash} ...') - data = root.joinpath(name, hash[:2], hash[2:] + '.tar').read_bytes() - _upload_single(name, hash, data, token=token) + data = root.joinpath( + name, hash[:2], hash[2:] + '.' + args.extension + ).read_bytes() + _upload_single(name, hash, data, ext=args.extension, token=token) except Exception as e: print(f'warn: failed to upload {name}:{hash}, {e}', file=sys.stderr) @@ -273,7 +274,8 @@ def run_merge(args): def _expand_targets(targets: set[str]) -> set[str]: - """Add the per-platform alias of every per-line executor target. + """ + Add the per-platform alias of every per-line executor target. Every executor line builds against the same dependency set, so the registry keys them by platform (`executor-amd64-linux`), while the build targets name @@ -493,6 +495,11 @@ def run_mirror_to_gcs(args): verify_file_parser.set_defaults(func=run_verify_file) download_parser = subparsers.add_parser('download') + download_parser.add_argument( + '--extension', + default='zip', + help='runner archive extension; the frozen v0.2.x line uses `tar`', + ) download_parser.add_argument('--dest', default='.') download_parser.add_argument('--allow-partial', default=False, action='store_true') download_parser.add_argument('--nix-preload', default=False, action='store_true') @@ -500,6 +507,11 @@ def run_mirror_to_gcs(args): download_parser.set_defaults(func=run_download) upload_file_parser = subparsers.add_parser('upload') + upload_file_parser.add_argument( + '--extension', + default='zip', + help='runner archive extension; the frozen v0.2.x line uses `tar`', + ) upload_file_parser.add_argument('--root', default='.') upload_file_parser.add_argument('--registry', required=True, metavar='FILE') upload_file_parser.set_defaults(func=run_upload) diff --git a/support/scripts/check-commit-message.py b/support/scripts/check-commit-message.py index e82dc297..3d8ffa39 100755 --- a/support/scripts/check-commit-message.py +++ b/support/scripts/check-commit-message.py @@ -112,7 +112,8 @@ class CommitPart: def parse_commit(message: str) -> list[CommitPart]: - """Split a commit message into parts to validate independently. + """ + Split a commit message into parts to validate independently. A squash carries a bullet per collapsed commit, each its own subject and body; the umbrella takes what precedes the first bullet. @@ -211,7 +212,8 @@ def validate_part(part: CommitPart) -> tuple[list[str], list[str]]: def _check_control_chars(message: str, errors: list[str]) -> None: - """Reject control characters: a message is text, newlines and tabs. + """ + Reject control characters: a message is text, newlines and tabs. Anything else is invisible where the message is written and meaningful to something downstream that reads it. diff --git a/support/scripts/check-source-text.py b/support/scripts/check-source-text.py index 0046e8a5..86bf8414 100644 --- a/support/scripts/check-source-text.py +++ b/support/scripts/check-source-text.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 -"""Pre-commit guard: keep source text plain and citation-free. +""" +Pre-commit guard: keep source text plain and citation-free. Comments should read on their own terms and stay ASCII. Rejected anywhere in a scanned file: architecture-decision and issue-ticket references -- they diff --git a/support/scripts/ci-changes.py b/support/scripts/ci-changes.py index 402f588d..cb92f2ca 100755 --- a/support/scripts/ci-changes.py +++ b/support/scripts/ci-changes.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 -"""Report what each repo changed in this CI run, as JSON. +""" +Report what each repo changed in this CI run, as JSON. Emits one entry per repo: the manager keyed as ``.``, every executor submodule by its path, each holding ``base_commit``, ``branch_commit`` and ``has_changes``. @@ -60,7 +61,8 @@ def endpoints(base: str, head: str, path: str) -> tuple[str | None, str | None]: def fetch_pr_refs(base_ref: str, pr_number: str) -> tuple[str, str]: - """Materialize the base tip and the PR head, and return (merge_base, head). + """ + Materialize the base tip and the PR head, and return (merge_base, head). A `pull_request` checkout leaves HEAD on the merge commit, and the base branch is usually not fetched at all, so both sides are fetched by explicit @@ -97,7 +99,8 @@ def gh(*args: str) -> str: def base_ref_of(pr_number: str) -> str: - """The PR's base branch, read from the API. + """ + The PR's base branch, read from the API. `GITHUB_BASE_REF` is only set on `pull_request` events, but these checks also run on the panel's `workflow_dispatch`, where the PR number is known and the diff --git a/support/scripts/get-all-git.py b/support/scripts/get-all-git.py index c2293673..e90e272e 100755 --- a/support/scripts/get-all-git.py +++ b/support/scripts/get-all-git.py @@ -108,7 +108,8 @@ def _read_gitmodules_entries(root: Path) -> dict[str, dict[str, str]]: def _gitlink_hash(root: Path, path: str) -> str: - """The commit ``path`` is pinned to, read from the index like git does. + """ + The commit ``path`` is pinned to, read from the index like git does. Staged and committed agree except right after a gitlink bump, where the index is the one the next commit will carry. @@ -214,7 +215,8 @@ def has_commit(repo: Path, commit: str) -> bool: def open_cache(root: Path, url: str, env: dict[str, str]) -> Path: - """Create (if needed) and configure the bare cache repo for ``url``. + """ + Create (if needed) and configure the bare cache repo for ``url``. Every submodule sharing this URL is checked out of this one repository, so its objects are fetched once and its refs are what keeps them alive. @@ -265,7 +267,8 @@ def open_cache(root: Path, url: str, env: dict[str, str]) -> Path: def fetch_pins( root: Path, cache: Path, submodules: list[SubmoduleGitInfo], env: dict[str, str] ) -> None: - """Make sure every pinned commit is in ``cache``, and keep it reachable. + """ + Make sure every pinned commit is in ``cache``, and keep it reachable. An unreferenced commit is only kept alive by the worktree HEADs pointing at it, and those checkouts do not exist yet — hence a ref per pin. @@ -338,7 +341,8 @@ def has_staged_changes(path: Path) -> bool: def clear_staging(staging: Path, name: str) -> None: - """Remove ``staging``, provided it is a leftover of an interrupted conversion. + """ + Remove ``staging``, provided it is a leftover of an interrupted conversion. Which holds one `--no-checkout` worktree, so at most a `.git` file. Anything else under that name is somebody's data. @@ -356,7 +360,8 @@ def clear_staging(staging: Path, name: str) -> None: def adopt_as_worktree( root: Path, cache: Path, dest: Path, head: str, env: dict[str, str] ) -> None: - """Give the populated directory ``dest`` the `.git` of a worktree at ``head``. + """ + Give the populated directory ``dest`` the `.git` of a worktree at ``head``. `git worktree add` cannot be pointed at a directory that has files in it, so the worktree is created empty beside it and only its `.git` file moves. No @@ -406,7 +411,8 @@ def adopt_as_worktree( def convert_from_dangling( root: Path, cache: Path, submodule: SubmoduleGitInfo, env: dict[str, str] ) -> None: - """Re-attach a checkout whose `.git` names a gitdir that is gone. + """ + Re-attach a checkout whose `.git` names a gitdir that is gone. The files are all there is to go on, so the checkout is re-attached at the gitlink. Files that the old checkout had at some other commit stay as they @@ -422,7 +428,8 @@ def convert_to_worktree( gitdir: Path | None, env: dict[str, str], ) -> None: - """Re-point an existing checkout at ``cache``, keeping every file in place. + """ + Re-point an existing checkout at ``cache``, keeping every file in place. Deleting and re-adding the directory would take the ignored content with it — the materialized third-party trees above all — so only the `.git` file is diff --git a/support/scripts/md-local-links.py b/support/scripts/md-local-links.py index f1c75760..82ec3d95 100644 --- a/support/scripts/md-local-links.py +++ b/support/scripts/md-local-links.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 -"""Pre-commit guard: verify local file-path links in Markdown resolve. +""" +Pre-commit guard: verify local file-path links in Markdown resolve. Validates that **local** link targets (and reference definitions) point at existing files; ignores external links (http(s)/mailto/other schemes), @@ -55,7 +56,8 @@ def _rel(p: Path, root: Path) -> str: def broken_links(md: Path, root: Path) -> list[str]: - """Return human-readable messages for each broken local link in `md`. + """ + Return human-readable messages for each broken local link in `md`. Targets resolve relative to the markdown file's directory; a leading `/` is repo-root-relative (`root`). Paths in messages are shown relative to `root`. diff --git a/support/tools/genvm-tool/default.nix b/support/tools/genvm-tool/default.nix index c0cc1d19..cd479fe8 100644 --- a/support/tools/genvm-tool/default.nix +++ b/support/tools/genvm-tool/default.nix @@ -8,7 +8,14 @@ python.pkgs.buildPythonApplication { pname = "genvm-tool"; version = "0.1.0"; - src = ./.; + src = pkgs.lib.cleanSourceWith { + src = ./.; + filter = + path: type: + pkgs.lib.cleanSourceFilter path type + && !pkgs.lib.hasSuffix ".nix" path + && baseNameOf path != "flake.lock"; + }; pyproject = true; build-system = [ python.pkgs.setuptools ]; @@ -27,9 +34,11 @@ python.pkgs.buildPythonApplication { pkgs.git pkgs.installShellFiles pkgs.pre-commit - python.pkgs.pytestCheckHook ]; + doCheck = false; + dontUsePytestCheck = true; + # Generate the shell completions and man page from the freshly built binary # (shtab / argparse-manpage both walk the whole argparse command tree) and drop # them in the standard share/ locations. @@ -42,8 +51,6 @@ python.pkgs.buildPythonApplication { installManPage genvm-tool.1 ''; - pytestFlags = [ "unit_tests" ]; - meta = { description = "GenVM monorepo git helper (build, tests, hooks, ls)"; mainProgram = "genvm-tool"; diff --git a/support/tools/genvm-tool/flake.lock b/support/tools/genvm-tool/flake.lock new file mode 100644 index 00000000..db686c56 --- /dev/null +++ b/support/tools/genvm-tool/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1767313136, + "narHash": "sha256-16KkgfdYqjaeRGBaYsNrhPRRENs0qzkQVUooNHtoy2w=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ac62194c3917d5f474c1a844b6fd6da2db95077d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/support/tools/genvm-tool/flake.nix b/support/tools/genvm-tool/flake.nix new file mode 100644 index 00000000..47cde49f --- /dev/null +++ b/support/tools/genvm-tool/flake.nix @@ -0,0 +1,65 @@ +{ + description = "genvm-tool unit-test Python environment (pinned, independent flake)"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = + { + self, + nixpkgs, + flake-utils, + }: + flake-utils.lib.eachDefaultSystem ( + system: + let + pkgs = import nixpkgs { inherit system; }; + python = pkgs.python312; + # The tool itself, only to borrow its dependency list: duplicating the + # one in `default.nix` here is what would drift. + tool = pkgs.callPackage ./default.nix { inherit python; }; + # Instruments a fuzz target for AFL; not in nixpkgs. The same derivation + # is in executors/v0.3.x/support/nix/py-test/flake.nix, which cannot be + # shared from here: it lives in another repository. + pythonAfl = python.pkgs.buildPythonPackage rec { + pname = "python-afl"; + version = "0.7.3"; + pyproject = true; + + src = pkgs.fetchPypi { + inherit pname version; + hash = "sha256-s3MZbXRyZiMLvoQu2qrWWWJTY4V8jnZVBddl0GE/lUQ="; + }; + + build-system = with python.pkgs; [ + cython + setuptools + wheel + ]; + pythonImportsCheck = [ "afl" ]; + }; + # `genvm_tool` is NOT installed into this env. The pytest plugin puts the + # project root on PYTHONPATH so the tests import the working tree, the + # same way genlayer-py-std's tests import `src/`. + pythonEnv = python.withPackages ( + ps: + [ ps.pytest ] + ++ tool.propagatedBuildInputs + ++ pkgs.lib.optionals (system == "x86_64-linux") [ pythonAfl ] + ); + in + { + # AFL++ carries `afl-fuzz` and friends, which the fuzz cases exec from + # this env's bin/ (the python-afl wrappers are not used) + packages.default = pkgs.buildEnv { + name = "genvm-tool-test"; + paths = [ + pythonEnv + ] + ++ pkgs.lib.optionals (system == "x86_64-linux") [ pkgs.aflplusplus ]; + }; + } + ); +} diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/0/a/0a77zeewq0aqkcykz2bb1xwhdr99xh4w8sajwhz3k7t4c b/support/tools/genvm-tool/fuzz/inputs/scheduling/0/a/0a77zeewq0aqkcykz2bb1xwhdr99xh4w8sajwhz3k7t4c new file mode 100644 index 0000000000000000000000000000000000000000..0dcb79eb2f480feb52d401838539ad27d678d133 GIT binary patch literal 26 XcmcDqfdEDZo8^XB85H%CROMMeGp9|Z!*$w|p64h#%}4OzKaAP}0>kp6<9ej!95Pz6{a T!+)=2pvc0_n{Eq|xW4^XB85H%CROMMeGp9|Z!*$w|p64p~`Qp;-;-FBs|i|FE5{8US1vr1poj4ZvfFC0AgbZLZm=s8V~~j_Wm91 literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/5/q/5qh9w8qmh1wz818jmnwnrd7aqq6f7y39hx1fqn6gret3a b/support/tools/genvm-tool/fuzz/inputs/scheduling/5/q/5qh9w8qmh1wz818jmnwnrd7aqq6f7y39hx1fqn6gret3a new file mode 100644 index 0000000000000000000000000000000000000000..e003a5b661bdedbd7ff2d6cf5b412ff6fc900ce1 GIT binary patch literal 61 zcmYc*i8OIEtqKHEy0e literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/7/m/7mne39ergtbmmtvn8dwf5rts4c4k5aaac1t6rf7rypn1y b/support/tools/genvm-tool/fuzz/inputs/scheduling/7/m/7mne39ergtbmmtvn8dwf5rts4c4k5aaac1t6rf7rypn1y new file mode 100644 index 00000000..2373feab --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/7/m/7mne39ergtbmmtvn8dwf5rts4c4k5aaac1t6rf7rypn1y @@ -0,0 +1 @@ +23•••••••3••3 \ No newline at end of file diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/8/h/8h406nwh64gfav2jxv96hbmhrb1t03yqf5e61s7jf7tfm b/support/tools/genvm-tool/fuzz/inputs/scheduling/8/h/8h406nwh64gfav2jxv96hbmhrb1t03yqf5e61s7jf7tfm new file mode 100644 index 00000000..f6a5679b --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/8/h/8h406nwh64gfav2jxv96hbmhrb1t03yqf5e61s7jf7tfm @@ -0,0 +1 @@ +ËccGuxhËccd êê \ No newline at end of file diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/8/v/8vfbamrjk4e8cm6nc8qmp2jx8dkqqhfs13wkb1hb5rq90 b/support/tools/genvm-tool/fuzz/inputs/scheduling/8/v/8vfbamrjk4e8cm6nc8qmp2jx8dkqqhfs13wkb1hb5rq90 new file mode 100644 index 0000000000000000000000000000000000000000..859fd8586464ba2caf2664d0c33bfcbec9efaa5e GIT binary patch literal 44 kcmZq3XvpZuXl6))Qpw3&PVyiCXUNOf|7Vjo^zzC8074uL%K!iX literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/9/v/9vv23ykykwfjgdmnsfxxtrqzfjx5r0b30frarwecm3rd8 b/support/tools/genvm-tool/fuzz/inputs/scheduling/9/v/9vv23ykykwfjgdmnsfxxtrqzfjx5r0b30frarwecm3rd8 new file mode 100644 index 0000000000000000000000000000000000000000..91f09c04ddc93b159f85a27aeeb3faf537f79b11 GIT binary patch literal 19 acmYch6ij3N|DTmX;J;u7mms&1AQu2S6a?@9 literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/9/w/9wmhqg28z4ergsgh57jkqfyx2p66pdby1r1zs5wth779p b/support/tools/genvm-tool/fuzz/inputs/scheduling/9/w/9wmhqg28z4ergsgh57jkqfyx2p66pdby1r1zs5wth779p new file mode 100644 index 00000000..9a18f1fd --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/9/w/9wmhqg28z4ergsgh57jkqfyx2p66pdby1r1zs5wth779p @@ -0,0 +1 @@ +hŸc$h*—üÿ€c \ No newline at end of file diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/a/0/a03g00cnvfa0gs77n0y1ww0tdn8908qnja4bxw9a7gpmw b/support/tools/genvm-tool/fuzz/inputs/scheduling/a/0/a03g00cnvfa0gs77n0y1ww0tdn8908qnja4bxw9a7gpmw new file mode 100644 index 0000000000000000000000000000000000000000..3f8316e7e24fa12749cced18a54fc2a3b4680161 GIT binary patch literal 20 bcmazvEO#;J@vzKtGfj6g%wXt9$>0J2K|Tfu literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/a/4/a4r7021ggw1rmd6qz9p3spjn266k328eh5vr8pg0pm2gm b/support/tools/genvm-tool/fuzz/inputs/scheduling/a/4/a4r7021ggw1rmd6qz9p3spjn266k328eh5vr8pg0pm2gm new file mode 100644 index 0000000000000000000000000000000000000000..5d97b58f2a14e70a8c64bea47c2c1abc92444850 GIT binary patch literal 22 ZcmYdhcn${7faD9t=g&_+e=hJo1pvBS5F7vi literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/a/7/a77dmacngtkjb9y93610yv1zh6a9rtd1s6dt3vjz00zcg b/support/tools/genvm-tool/fuzz/inputs/scheduling/a/7/a77dmacngtkjb9y93610yv1zh6a9rtd1s6dt3vjz00zcg new file mode 100644 index 0000000000000000000000000000000000000000..349de638cecdd46412195d7ae4289ec6bedf5329 GIT binary patch literal 21 bcmYdx&qzMwKK*|^14Bk~GLYk*k--H3U&#mm literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/a/y/ayj9117xzpdr731k488aawap9fa25kbg0yez0yxncp8r6 b/support/tools/genvm-tool/fuzz/inputs/scheduling/a/y/ayj9117xzpdr731k488aawap9fa25kbg0yez0yxncp8r6 new file mode 100644 index 0000000000000000000000000000000000000000..eae688e594cd97c1addaa4b6798c1db1d418344b GIT binary patch literal 50 ncmYe!4opeONbxggaOz5KU`S3rfC_+;hae)!Tnr2h4oN8hZG;%p literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/a/z/azat8a0r7d706fa7tnee39qz1rbdc92ekgbxtgejyntrc b/support/tools/genvm-tool/fuzz/inputs/scheduling/a/z/azat8a0r7d706fa7tnee39qz1rbdc92ekgbxtgejyntrc new file mode 100644 index 00000000..dd825a3f --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/a/z/azat8a0r7d706fa7tnee39qz1rbdc92ekgbxtgejyntrc @@ -0,0 +1,3 @@ +ccÿ€ +dcÿ€ +dh8h8 \ No newline at end of file diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/b/h/bh4wrvwgtw8a0xw2836gdfej6qxws1f66ej3hxtqf480m b/support/tools/genvm-tool/fuzz/inputs/scheduling/b/h/bh4wrvwgtw8a0xw2836gdfej6qxws1f66ej3hxtqf480m new file mode 100644 index 00000000..20cf60aa --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/b/h/bh4wrvwgtw8a0xw2836gdfej6qxws1f66ej3hxtqf480m @@ -0,0 +1 @@ +ÿ»»»»»»¼»ý diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/c/a/ca97ypke6xjfbx2n9jpex04wy2rd0nh950vrteqpx6v4c b/support/tools/genvm-tool/fuzz/inputs/scheduling/c/a/ca97ypke6xjfbx2n9jpex04wy2rd0nh950vrteqpx6v4c new file mode 100644 index 00000000..30c800a5 --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/c/a/ca97ypke6xjfbx2n9jpex04wy2rd0nh950vrteqpx6v4c @@ -0,0 +1,3 @@ + +h +ÄÄÄÄÄä \ No newline at end of file diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/d/1/d1ftb59xsy5bkg0vacd8wrqrhm8c5s10zd3xcpc7edtn4 b/support/tools/genvm-tool/fuzz/inputs/scheduling/d/1/d1ftb59xsy5bkg0vacd8wrqrhm8c5s10zd3xcpc7edtn4 new file mode 100644 index 00000000..56d0e0f0 --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/d/1/d1ftb59xsy5bkg0vacd8wrqrhm8c5s10zd3xcpc7edtn4 @@ -0,0 +1 @@ +cÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/d/j/djj76h73qn7c9yh8r6xfzehdtvsbn0hkxvz5gz1w8cw6r b/support/tools/genvm-tool/fuzz/inputs/scheduling/d/j/djj76h73qn7c9yh8r6xfzehdtvsbn0hkxvz5gz1w8cw6r new file mode 100644 index 00000000..0b3721bb --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/d/j/djj76h73qn7c9yh8r6xfzehdtvsbn0hkxvz5gz1w8cw6r @@ -0,0 +1 @@ +cdhÑ \ No newline at end of file diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/d/s/ds11mdgj72234c89gzj6k0cvw7vpb5v2n3c9327rmch3a b/support/tools/genvm-tool/fuzz/inputs/scheduling/d/s/ds11mdgj72234c89gzj6k0cvw7vpb5v2n3c9327rmch3a new file mode 100644 index 0000000000000000000000000000000000000000..ed29f75af059798e75435a581485fb93b3ca9dc4 GIT binary patch literal 5 McmezMi-A!d00{5`6#xJL literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/d/t/dtjpxmbt1f6axs8fh7kz3mb4xhstcm3erhpx9nnsmb5c8 b/support/tools/genvm-tool/fuzz/inputs/scheduling/d/t/dtjpxmbt1f6axs8fh7kz3mb4xhstcm3erhpx9nnsmb5c8 new file mode 100644 index 00000000..04fe2cda --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/d/t/dtjpxmbt1f6axs8fh7kz3mb4xhstcm3erhpx9nnsmb5c8 @@ -0,0 +1 @@ +6tYf9A5zPÑmN7bC3x4fA5zQ1mN7b \ No newline at end of file diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/d/t/dtt19bz3ejma3sk5xyk9bhnz9yna4w7qwc5xvqt12n1nr b/support/tools/genvm-tool/fuzz/inputs/scheduling/d/t/dtt19bz3ejma3sk5xyk9bhnz9yna4w7qwc5xvqt12n1nr new file mode 100644 index 0000000000000000000000000000000000000000..89c283db41e78749772a94f0489ff82b690f8bcb GIT binary patch literal 30 TcmZP&Fa!f52!%|3Yp4eRQuPMV literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/e/5/e56xem18j5vnd0db4gmheccjjrzp6114yjzv0rwpvkarr b/support/tools/genvm-tool/fuzz/inputs/scheduling/e/5/e56xem18j5vnd0db4gmheccjjrzp6114yjzv0rwpvkarr new file mode 100644 index 00000000..416e0b93 --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/e/5/e56xem18j5vnd0db4gmheccjjrzp6114yjzv0rwpvkarr @@ -0,0 +1 @@ +c}____________o_____________h diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/e/k/ek756vzwq4xcp9g7ncsqmc1n0bpa2391kkjwa70anx5km b/support/tools/genvm-tool/fuzz/inputs/scheduling/e/k/ek756vzwq4xcp9g7ncsqmc1n0bpa2391kkjwa70anx5km new file mode 100644 index 00000000..0c8aeb1b --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/e/k/ek756vzwq4xcp9g7ncsqmc1n0bpa2391kkjwa70anx5km @@ -0,0 +1 @@ +czQ1mN7bC3xV8kL2pR6tY4wD0sdh diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/e/w/ewzaq332qw2ef9kjhgknt5jgzqvq9959t18a9netpe7n2 b/support/tools/genvm-tool/fuzz/inputs/scheduling/e/w/ewzaq332qw2ef9kjhgknt5jgzqvq9959t18a9netpe7n2 new file mode 100644 index 0000000000000000000000000000000000000000..cda97f7a1db6a2b924c8a828469623ec39edf905 GIT binary patch literal 79 xcmd-q=`JZLdHM2M!^@YuCBe*>$YAAp5V*j3{`^BAfHOcG1lZ4z0@MuzvH<*HI{N?s literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/f/2/f2977sr15mekm241hw6307vdxw6jfpvtzcv96e0kpb30t b/support/tools/genvm-tool/fuzz/inputs/scheduling/f/2/f2977sr15mekm241hw6307vdxw6jfpvtzcv96e0kpb30t new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/f/2/f2977sr15mekm241hw6307vdxw6jfpvtzcv96e0kpb30t @@ -0,0 +1 @@ + diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/f/r/frwjgmhyf89bdtnk33sfphqeqh99a7bgnjm672d7491sp b/support/tools/genvm-tool/fuzz/inputs/scheduling/f/r/frwjgmhyf89bdtnk33sfphqeqh99a7bgnjm672d7491sp new file mode 100644 index 0000000000000000000000000000000000000000..7833cd80dacf035b2b66c37e1ded5cf0c25059f1 GIT binary patch literal 21 bcmYdx&qzMwp7Fn)fgvL~8OU+Z$lwA1T?hxz literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/f/s/fs19mwm00yyna4dgd0vfdd2xsz9tta24qqnb3a5j2fpb4 b/support/tools/genvm-tool/fuzz/inputs/scheduling/f/s/fs19mwm00yyna4dgd0vfdd2xsz9tta24qqnb3a5j2fpb4 new file mode 100644 index 0000000000000000000000000000000000000000..5d0bffa059a165e1b6de398305e232f824922f1f GIT binary patch literal 13 UcmYdx&qx+v$Vm3ha4+Ek02^Qf%K!iX literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/f/y/fypk3np5dvfnrfhm0mp84qmkpbweyfyqtenpb9tybvv4r b/support/tools/genvm-tool/fuzz/inputs/scheduling/f/y/fypk3np5dvfnrfhm0mp84qmkpbweyfyqtenpb9tybvv4r new file mode 100644 index 0000000000000000000000000000000000000000..18704e0022863042da14ea4e5514b181067dc921 GIT binary patch literal 25 gcmYe!4opeO@bU9yaPCTOs83E#R;~!k;POiW0CLj^qyPW_ literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/g/k/gk362a9qzh27m009584enyxjpcgrydm3gpvh2pfgragvp b/support/tools/genvm-tool/fuzz/inputs/scheduling/g/k/gk362a9qzh27m009584enyxjpcgrydm3gpvh2pfgragvp new file mode 100644 index 0000000000000000000000000000000000000000..4170489786e1321cb80b0c5f8dcc807ff45b9c89 GIT binary patch literal 19 YcmYdOoaM+M5NMn0=fwa7-fpJG04)jw{{R30 literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/g/s/gs7tthhttxra0bw9pr03wswx1zca0tasa30ban582d1ry b/support/tools/genvm-tool/fuzz/inputs/scheduling/g/s/gs7tthhttxra0bw9pr03wswx1zca0tasa30ban582d1ry new file mode 100644 index 00000000..36175568 --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/g/s/gs7tthhttxra0bw9pr03wswx1zca0tasa30ban582d1ry @@ -0,0 +1 @@ +WWWdch0"00ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠchŸdh diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/h/0/h0rj8gfaf7y5xn1bd2f55dxj285rfmrv8ja0zypgzdjc2 b/support/tools/genvm-tool/fuzz/inputs/scheduling/h/0/h0rj8gfaf7y5xn1bd2f55dxj285rfmrv8ja0zypgzdjc2 new file mode 100644 index 0000000000000000000000000000000000000000..3ad4a98b5dd31fa7888c984c29dba201e2bb0bfe GIT binary patch literal 46 zcmXTRO0G&tDXB_vNJ&X%V32%~kdT;=kPx4d%`iLTN`?Rf14G8=41xcQ4h;Vj5&({} B5ZC|! literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/h/2/h2vx2w3me566fak1gsq86nytqw7x2egsgqntxh4m811rp b/support/tools/genvm-tool/fuzz/inputs/scheduling/h/2/h2vx2w3me566fak1gsq86nytqw7x2egsgqntxh4m811rp new file mode 100644 index 00000000..5593c0ac --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/h/2/h2vx2w3me566fak1gsq86nytqw7x2egsgqntxh4m811rp @@ -0,0 +1 @@ +bdhYYYYYYYYYYYYYYY diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/h/8/h8s06mw10v4v4hs3dd98gfqnpszmh7s2bfp3bgstpx1sc b/support/tools/genvm-tool/fuzz/inputs/scheduling/h/8/h8s06mw10v4v4hs3dd98gfqnpszmh7s2bfp3bgstpx1sc new file mode 100644 index 0000000000000000000000000000000000000000..219bc57046475954d326defa07159b8fee2e3901 GIT binary patch literal 42 wcmYexVsJ0<{EJU0RO%VQ~&?~ literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/h/k/hke62nwahseh6j9eb81qsbggf2k585jf9t01jf5s49cwt b/support/tools/genvm-tool/fuzz/inputs/scheduling/h/k/hke62nwahseh6j9eb81qsbggf2k585jf9t01jf5s49cwt new file mode 100644 index 0000000000000000000000000000000000000000..a59f6c4d05db244e33c1fcca67a7ad57feedf4b1 GIT binary patch literal 21 bcmZR`jEegI|9?YN7-ME8kR6qhlEDQ4X}t)~ literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/j/g/jgvxrb5teh8rxxejpttpqzwhthnpctfrnxma8fzf07zqt b/support/tools/genvm-tool/fuzz/inputs/scheduling/j/g/jgvxrb5teh8rxxejpttpqzwhthnpctfrnxma8fzf07zqt new file mode 100644 index 00000000..dad5f9ed --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/j/g/jgvxrb5teh8rxxejpttpqzwhthnpctfrnxma8fzf07zqt @@ -0,0 +1 @@ + t‹ttt»»» \ No newline at end of file diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/j/q/jq7d47bpcygzb55b6jsjwh3xb7nq5p5swwg52dv0je7qt b/support/tools/genvm-tool/fuzz/inputs/scheduling/j/q/jq7d47bpcygzb55b6jsjwh3xb7nq5p5swwg52dv0je7qt new file mode 100644 index 00000000..033187ab --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/j/q/jq7d47bpcygzb55b6jsjwh3xb7nq5p5swwg52dv0je7qt @@ -0,0 +1,3 @@ +chå +œd +hcdhdr diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/j/t/jt773qwy1mj50y89pkcasgkkm326mykrzx9yvx94ts4kw b/support/tools/genvm-tool/fuzz/inputs/scheduling/j/t/jt773qwy1mj50y89pkcasgkkm326mykrzx9yvx94ts4kw new file mode 100644 index 0000000000000000000000000000000000000000..d6c91e947cf9b161f884f02305f29a2e76fb7c68 GIT binary patch literal 10 PcmZSJU}$h)0AdaR2U-D< literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/j/t/jtccnqnb3bh8m1dtcd9wh20qxbyhggqhk559d4xafecb8 b/support/tools/genvm-tool/fuzz/inputs/scheduling/j/t/jtccnqnb3bh8m1dtcd9wh20qxbyhggqhk559d4xafecb8 new file mode 100644 index 0000000000000000000000000000000000000000..825fb8b6be40d175bbc51761683d632640757435 GIT binary patch literal 64 xcmezW5(pR=7#u+K%Jb)eB-bkt_JUPOm!VLgyv0RW(g3fTYv literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/t/t/ttdsymeqpec56fp0mrr72150b33memf6nex59dhnbkqfg b/support/tools/genvm-tool/fuzz/inputs/scheduling/t/t/ttdsymeqpec56fp0mrr72150b33memf6nex59dhnbkqfg new file mode 100644 index 0000000000000000000000000000000000000000..7056e77a2ffee575297954c43d14261501f92539 GIT binary patch literal 14 ScmezM3k=wP>n0~LG5`Qn;RwqB literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/t/z/tzhred7xrw335kmfkv4px3sppvkjx8kff9ykcv0nfr1gg b/support/tools/genvm-tool/fuzz/inputs/scheduling/t/z/tzhred7xrw335kmfkv4px3sppvkjx8kff9ykcv0nfr1gg new file mode 100644 index 0000000000000000000000000000000000000000..43f54c2f336e45338465c233c03c205bb304c1ad GIT binary patch literal 12 RcmezWzkz{~m64GN2ml;E0*?Ry literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/t/z/tzm8wzrej02f2qhyj478hsx7jzj55ge236qr4hz2zajdt b/support/tools/genvm-tool/fuzz/inputs/scheduling/t/z/tzm8wzrej02f2qhyj478hsx7jzj55ge236qr4hz2zajdt new file mode 100644 index 0000000000000000000000000000000000000000..413a4e9453c96400a838c4f6691897bcef593f8b GIT binary patch literal 6 NcmZR0`Tzg_dH@ay1ZDsL literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/v/9/v9bn5x7sxq15qm7yckys35008w0b0d4mp59gcp0th6hta b/support/tools/genvm-tool/fuzz/inputs/scheduling/v/9/v9bn5x7sxq15qm7yckys35008w0b0d4mp59gcp0th6hta new file mode 100644 index 0000000000000000000000000000000000000000..00ddcc4f32285e0c41057d7d44e581844c48feca GIT binary patch literal 36 QcmezW9|{B*U@Qz80A!6J?*IS* literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/v/q/vq8mbh2tkh0ce4nq474f49zrg0egdva3bxyhs2m0jhv7m b/support/tools/genvm-tool/fuzz/inputs/scheduling/v/q/vq8mbh2tkh0ce4nq474f49zrg0egdva3bxyhs2m0jhv7m new file mode 100644 index 0000000000000000000000000000000000000000..d4c79f400afda03755a06ebe9f926c91d308651b GIT binary patch literal 51 wcmZ3*`uxi(AZB1-NMT4x@w)K7oq>xH#7pry4`z!pg1}3L3@*lJPk^ky0N!E{egFUf literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/w/9/w9b8068b46gp8ajd9xzv810kws9j84q5eb2rj5pgmn9t2 b/support/tools/genvm-tool/fuzz/inputs/scheduling/w/9/w9b8068b46gp8ajd9xzv810kws9j84q5eb2rj5pgmn9t2 new file mode 100644 index 00000000..16063911 --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/w/9/w9b8068b46gp8ajd9xzv810kws9j84q5eb2rj5pgmn9t2 @@ -0,0 +1 @@ +cdh* \ No newline at end of file diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/w/9/w9exq2ds6v5amcy0sv3q7s2c8thhpb4tafjsmawb7f132 b/support/tools/genvm-tool/fuzz/inputs/scheduling/w/9/w9exq2ds6v5amcy0sv3q7s2c8thhpb4tafjsmawb7f132 new file mode 100644 index 00000000..cf99539d --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/w/9/w9exq2ds6v5amcy0sv3q7s2c8thhpb4tafjsmawb7f132 @@ -0,0 +1 @@ +gcbgcb diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/w/b/wbjmbw1dr6vxhxvmavvsa3zq0h4mm209am9qteesgyekg b/support/tools/genvm-tool/fuzz/inputs/scheduling/w/b/wbjmbw1dr6vxhxvmavvsa3zq0h4mm209am9qteesgyekg new file mode 100644 index 00000000..25038d7b --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/w/b/wbjmbw1dr6vxhxvmavvsa3zq0h4mm209am9qteesgyekg @@ -0,0 +1 @@ +cd \ No newline at end of file diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/w/h/whza2rpj7esftmqkevjy248v1p0a13rawsz3cz6jg172a b/support/tools/genvm-tool/fuzz/inputs/scheduling/w/h/whza2rpj7esftmqkevjy248v1p0a13rawsz3cz6jg172a new file mode 100644 index 00000000..c67b7b40 --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/w/h/whza2rpj7esftmqkevjy248v1p0a13rawsz3cz6jg172a @@ -0,0 +1 @@ +c2 \ No newline at end of file diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/w/j/wj4fkpxc9em4mhhhymes72frtqxkjckgjbvwn5cdnzy4e b/support/tools/genvm-tool/fuzz/inputs/scheduling/w/j/wj4fkpxc9em4mhhhymes72frtqxkjckgjbvwn5cdnzy4e new file mode 100644 index 00000000..d17f3443 --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/w/j/wj4fkpxc9em4mhhhymes72frtqxkjckgjbvwn5cdnzy4e @@ -0,0 +1,3 @@ +`h +d›—h +Cdh diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/x/2/x25dmm6a6rbny7cwfsbxz7p2ccdjg3r42cfxqjaqj0vea b/support/tools/genvm-tool/fuzz/inputs/scheduling/x/2/x25dmm6a6rbny7cwfsbxz7p2ccdjg3r42cfxqjaqj0vea new file mode 100644 index 00000000..e9efb02b --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/x/2/x25dmm6a6rbny7cwfsbxz7p2ccdjg3r42cfxqjaqj0vea @@ -0,0 +1 @@ +ÿÿÿ \ No newline at end of file diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/x/3/x36pbrm7ks6yytqpe4eye2n8zbhh15n3fnkng3p5m9a9w b/support/tools/genvm-tool/fuzz/inputs/scheduling/x/3/x36pbrm7ks6yytqpe4eye2n8zbhh15n3fnkng3p5m9a9w new file mode 100644 index 0000000000000000000000000000000000000000..90522c992da10637ea7fdcef4289cfc5f5d09b86 GIT binary patch literal 25 gcmYe!4opeONbxggaPCTOU`S3*=BfzG;7UpX0BtD!*8e|$<^1`}0GYrI{Qv*} literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/x/x/xxthw0f8kdytdk9ww8p3pb17seayx23p73ye02px68sra b/support/tools/genvm-tool/fuzz/inputs/scheduling/x/x/xxthw0f8kdytdk9ww8p3pb17seayx23p73ye02px68sra new file mode 100644 index 00000000..40c042a5 --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/x/x/xxthw0f8kdytdk9ww8p3pb17seayx23p73ye02px68sra @@ -0,0 +1 @@ +ch diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/x/y/xyechygnfyvjc98mxcqa33pxqdtny51d3avkgy5rqrmbc b/support/tools/genvm-tool/fuzz/inputs/scheduling/x/y/xyechygnfyvjc98mxcqa33pxqdtny51d3avkgy5rqrmbc new file mode 100644 index 0000000000000000000000000000000000000000..86c36258438f0b8164ecf2fd81024a516cdfc880 GIT binary patch literal 53 ncmezW5(pR=7#u+K%Jb(z6qs@TKM1_*^J|Nk`rey%mj literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/y/3/y3sn7080jpjd06ttd23q11f1gvf7e8x2vksq2987e74x6 b/support/tools/genvm-tool/fuzz/inputs/scheduling/y/3/y3sn7080jpjd06ttd23q11f1gvf7e8x2vksq2987e74x6 new file mode 100644 index 0000000000000000000000000000000000000000..28ca77f7b82db0fa75236c8a1f4903a3b1bc7886 GIT binary patch literal 8 PcmYdhWcZz&@jn>=4Ko9c literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/y/b/yb13jgagqpa7t8wm0p1cm563cqzs3t7bnma3b1c15ks70 b/support/tools/genvm-tool/fuzz/inputs/scheduling/y/b/yb13jgagqpa7t8wm0p1cm563cqzs3t7bnma3b1c15ks70 new file mode 100644 index 00000000..b538e360 --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/y/b/yb13jgagqpa7t8wm0p1cm563cqzs3t7bnma3b1c15ks70 @@ -0,0 +1 @@ +cttttttt»»»»»»»»»»»»»»»»»»»»»»tttttht diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/y/e/yep2zs7xpq5936mtf5cachrha72j0j1512g1c8hbgvmnm b/support/tools/genvm-tool/fuzz/inputs/scheduling/y/e/yep2zs7xpq5936mtf5cachrha72j0j1512g1c8hbgvmnm new file mode 100644 index 00000000..c194d9bc --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/y/e/yep2zs7xpq5936mtf5cachrha72j0j1512g1c8hbgvmnm @@ -0,0 +1,2 @@ +ÎÎÎÎÎÎÜÎÎÎéÎÎÎÎÎÎÎÎ + diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/y/m/ym3qhn9hdmjz2f11dxm70nzrwmb4akc4rh536xmx8mkvj b/support/tools/genvm-tool/fuzz/inputs/scheduling/y/m/ym3qhn9hdmjz2f11dxm70nzrwmb4akc4rh536xmx8mkvj new file mode 100644 index 0000000000000000000000000000000000000000..e6efd8edf27098e218b07de52545f337caf07d03 GIT binary patch literal 4 LcmYdhVB!J*0iFPG literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/z/1/z1tpx2ffwwzkhmysrgp72696z3nwm1b9c0w0rjqs21ge0 b/support/tools/genvm-tool/fuzz/inputs/scheduling/z/1/z1tpx2ffwwzkhmysrgp72696z3nwm1b9c0w0rjqs21ge0 new file mode 100644 index 00000000..0395fed0 --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/z/1/z1tpx2ffwwzkhmysrgp72696z3nwm1b9c0w0rjqs21ge0 @@ -0,0 +1 @@ +cd555555 \ No newline at end of file diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/z/a/za6qeb27pkvczyyz2b75c59yaa5c9sghmgrekcr80ea28 b/support/tools/genvm-tool/fuzz/inputs/scheduling/z/a/za6qeb27pkvczyyz2b75c59yaa5c9sghmgrekcr80ea28 new file mode 100644 index 0000000000000000000000000000000000000000..760fa2c36c4771911b543de349555e5757f49df5 GIT binary patch literal 25 gcmYe!4opeONbxggaPCTOU`kF-=BfzG;7UpX0Bt`ABme*a literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/z/e/zef9y9cs4pzfg1bwv73k271wp240w8gnpgdbs1532n3mp b/support/tools/genvm-tool/fuzz/inputs/scheduling/z/e/zef9y9cs4pzfg1bwv73k271wp240w8gnpgdbs1532n3mp new file mode 100644 index 00000000..70e179a8 --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/z/e/zef9y9cs4pzfg1bwv73k271wp240w8gnpgdbs1532n3mp @@ -0,0 +1,2 @@ +ÿžžžžžžÿh +ÿh \ No newline at end of file diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/z/j/zj9tvrqmg8a20yn6zjg040fznngbfzqc6wd8hxqjza3de b/support/tools/genvm-tool/fuzz/inputs/scheduling/z/j/zj9tvrqmg8a20yn6zjg040fznngbfzqc6wd8hxqjza3de new file mode 100644 index 00000000..e6c0fb33 --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/z/j/zj9tvrqmg8a20yn6zjg040fznngbfzqc6wd8hxqjza3de @@ -0,0 +1 @@ +1G11511111111111tY4wÿ0sH9ðÿ \ No newline at end of file diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/z/m/zm2bj14d4d6jx6t9dwevjz9qjy9hvkm6yq0zsvhq0traa b/support/tools/genvm-tool/fuzz/inputs/scheduling/z/m/zm2bj14d4d6jx6t9dwevjz9qjy9hvkm6yq0zsvhq0traa new file mode 100644 index 0000000000000000000000000000000000000000..64d860c4ae67afc7a674efd6082fe0dc681b41fe GIT binary patch literal 13 RcmezWKO-3k8W?~C7XUFA1*QN1 literal 0 HcmV?d00001 diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/z/t/ztgvvbrx1tcewc1h1932qkz4qm9yjdbs7g3072ackqg06 b/support/tools/genvm-tool/fuzz/inputs/scheduling/z/t/ztgvvbrx1tcewc1h1932qkz4qm9yjdbs7g3072ackqg06 new file mode 100644 index 00000000..a1d4813f --- /dev/null +++ b/support/tools/genvm-tool/fuzz/inputs/scheduling/z/t/ztgvvbrx1tcewc1h1932qkz4qm9yjdbs7g3072ackqg06 @@ -0,0 +1 @@ +odh diff --git a/support/tools/genvm-tool/fuzz/inputs/scheduling/z/t/ztkrh5101zazqjygn9mnf19aa05ybkq9hyh1w1as4pbjc b/support/tools/genvm-tool/fuzz/inputs/scheduling/z/t/ztkrh5101zazqjygn9mnf19aa05ybkq9hyh1w1as4pbjc new file mode 100644 index 0000000000000000000000000000000000000000..ce6bfaae95f4f1f34b4b49487ea0c4e1cd9d73f0 GIT binary patch literal 86 zcmd-q=`JbxU;qDq!^@YucbAluynOib int: + if self.offset >= len(self.data): + return 0 + result = self.data[self.offset] + self.offset += 1 + return result + + def mask(self, width: int) -> int: + result = 0 + for shift in range(0, width, 8): + result |= self.byte() << shift + return result + + +def _service_closure(service: Service) -> set[Service]: + result: set[Service] = set() + pending = [service] + while pending: + current = pending.pop() + if current in result: + continue + result.add(current) + pending.extend(current.depends_on or []) + return result + + +def _closure_of(services: Iterable[Service]) -> set[Service]: + result: set[Service] = set() + for service in services: + result.update(_service_closure(service)) + return result + + +def _case_services(case: genvm_tool.tests.test.Case) -> set[Service]: + return _closure_of(case.description.needed_services) + + +def _conflict_free(services: set[Service]) -> bool: + claimed: set[Semaphore] = set() + for service in services: + if claimed & service.semaphores: + return False + claimed.update(service.semaphores) + return True + + +def _make_services(reader: Reader) -> list[Service]: + semaphore_count = reader.byte() % (MAX_SEMAPHORES + 1) + semaphores = [Semaphore(f'mutex-{index}') for index in range(semaphore_count)] + services: list[Service] = [] + + for index in range(reader.byte() % (MAX_SERVICES + 1)): + semaphore_mask = reader.mask(semaphore_count) + service = Service( + name=f'service-{index}', + manager=_Service(), + semaphores=frozenset( + semaphore + for bit, semaphore in enumerate(semaphores) + if semaphore_mask & (1 << bit) + ), + order=index, + depends_on=[], + ) + # A service whose closure holds two owners of one semaphore could never be + # up, since starting the second one stops the first + dependency_mask = reader.mask(index) + closure = {service} + for bit, dependency in enumerate(services): + if not dependency_mask & (1 << bit): + continue + candidate = closure | _service_closure(dependency) + if _conflict_free(candidate): + service.depends_on.append(dependency) + closure = candidate + services.append(service) + + return services + + +def _cover_case(service: Service, index: int) -> genvm_tool.tests.test.Case: + return genvm_tool.tests.test.StepsCase( + description=genvm_tool.tests.test.Description( + name=f'cover-{index}', + needed_services=frozenset({service}), + ), + steps=[], + ) + + +def _service_timeline(services: list[Service]) -> list[Service]: + """ + The order the scheduler starts ``services`` in, when every one of them is + needed and no test dependency constrains their lifetimes. + + Taken from a probe schedule rather than recomputed here: the timeline is the + scheduler's own policy, and a harness reimplementing it would only be + checking its copy against the original. What the invariants below check is + the meaning of a schedule, not this order. + """ + probe = Env( + cases=[_cover_case(service, index) for index, service in enumerate(services)], + args=Namespace(), + ) + return [ + action.service + for action in scheduling.run(None, probe).actions + if isinstance(action, scheduling.StartService) + ] + + +class _Timeline: + """Which services can be up together, given the order they are started in.""" + + def __init__(self, services: list[Service]): + self.order = _service_timeline(services) + self.position = {service: index for index, service in enumerate(self.order)} + + def _survives(self, service: Service, until: int) -> bool: + # Starting a service stops every owner of a semaphore it takes, and + # whatever depends on those transitively + closure = _service_closure(service) + for other in self.order[self.position[service] + 1 : until + 1]: + if any( + member.semaphores & other.semaphores + for member in closure + if member is not other + ): + return False + return True + + def phase(self, services: set[Service]) -> int: + """When the last of ``services`` starts, or -1 for a case needing none.""" + return max((self.position[service] for service in services), default=-1) + + def can_be_up_together(self, services: set[Service]) -> bool: + until = self.phase(services) + return all(self._survives(service, until) for service in services) + + def can_precede(self, before: set[Service], after: set[Service]) -> bool: + """ + Whether a case on ``before`` may be a dependency of one on ``after``. + + Their shared semaphores are handed over in one direction only, and the + dependency has to have run by the time the dependent's services are up + """ + if self.phase(before) > self.phase(after): + return False + return all( + self.position[left] < self.position[right] + for left in before + for right in after + if left is not right and left.semaphores & right.semaphores + ) + + +def _make_input(data: bytes) -> Env: + reader = Reader(data) + services = _make_services(reader) + timeline = _Timeline(services) + + # Every service is covered, so the timeline the cases are built against is the + # one the scheduler ends up using. A service no case needs is not an input the + # scheduler ever sees: it reaches it through the cases alone + cases = [_cover_case(service, index) for index, service in enumerate(services)] + case_services: list[set[Service]] = [_case_services(case) for case in cases] + case_dependencies: list[set[int]] = [set() for _ in cases] + + for index in range(reader.byte() % (MAX_CASES + 1)): + service_mask = reader.mask(len(services)) + needed: set[Service] = set() + for bit, service in enumerate(services): + if not service_mask & (1 << bit): + continue + candidate = _closure_of(needed | {service}) + if timeline.can_be_up_together(candidate): + needed.add(service) + required = _closure_of(needed) + + dependency_mask = reader.mask(len(cases)) + dependencies: set[int] = set() + for bit in range(len(cases)): + if not dependency_mask & (1 << bit): + continue + candidate_dependencies = {bit} | case_dependencies[bit] + if all( + timeline.can_precede(case_services[dependency], required) + for dependency in candidate_dependencies + ): + dependencies.update(candidate_dependencies) + + case_services.append(required) + case_dependencies.append(dependencies) + cases.append( + genvm_tool.tests.test.StepsCase( + description=genvm_tool.tests.test.Description( + name=f'case-{index}', + needed_services=frozenset(needed), + console_pool=bool(reader.byte() & 1), + depends_on=frozenset( + cases[dependency].description.name for dependency in dependencies + ), + ), + steps=[], + ) + ) + + # Collection order is whatever the suites happened to register, and the + # schedule must not depend on it + for index in range(len(cases) - 1, 0, -1): + other = reader.byte() % (index + 1) + cases[index], cases[other] = cases[other], cases[index] + + return Env(cases=cases, args=Namespace()) + + +def _test_dependencies( + case: genvm_tool.tests.test.Case, + cases_by_name: dict[str, genvm_tool.tests.test.Case], +) -> set[str]: + result: set[str] = set() + pending = list(case.description.depends_on) + while pending: + name = pending.pop() + if name in result: + continue + result.add(name) + pending.extend(cases_by_name[name].description.depends_on) + return result + + +def _check_invariants( + cases: list[genvm_tool.tests.test.Case], + actions: list[scheduling.Action], +) -> None: + cases_by_name = {case.description.name: case for case in cases} + needed_services = {service for case in cases for service in _case_services(case)} + active_services: set[Service] = set() + started_services: set[Service] = set() + stopped_services: set[Service] = set() + started_cases: set[str] = set() + running_batches: dict[int, list[genvm_tool.tests.test.Case]] = {} + seen_batches: set[int] = set() + + for action in actions: + if isinstance(action, scheduling.StartService): + service = action.service + assert service in needed_services + assert service not in started_services + assert set(service.depends_on or []).issubset(active_services) + assert all( + not service.semaphores & active.semaphores for active in active_services + ) + started_services.add(service) + active_services.add(service) + elif isinstance(action, scheduling.StopService): + service = action.service + assert service in active_services + assert all( + service not in _service_closure(active) - {active} for active in active_services + ) + assert all( + service not in _case_services(case) + for batch in running_batches.values() + for case in batch + ) + active_services.remove(service) + stopped_services.add(service) + elif isinstance(action, scheduling.StartCases): + assert action.id not in seen_batches + assert action.cases + assert len({case.description.name for case in action.cases}) == len(action.cases) + previously_started = set(started_cases) + for case in action.cases: + assert cases_by_name.get(case.description.name) is case + assert case.description.name not in started_cases + assert _case_services(case).issubset(active_services) + if case.description.console_pool: + # It holds the whole case pool, so nothing it waits for may + # still be waiting for the runner to start it + assert len(action.cases) == 1 + assert _test_dependencies(case, cases_by_name).issubset(previously_started) + started_cases.add(case.description.name) + seen_batches.add(action.id) + running_batches[action.id] = action.cases + elif isinstance(action, scheduling.AwaitAllCases): + assert action.id in running_batches + batch = running_batches.pop(action.id) + for case in batch: + # The runner blocks here, so a dependency that has not started by + # now never will + assert _test_dependencies(case, cases_by_name).issubset(started_cases) + else: + raise AssertionError(f'unknown scheduling action: {action!r}') + + assert started_cases == set(cases_by_name) + assert started_services == needed_services + assert stopped_services == needed_services + assert not active_services + assert not running_batches + + +def fuzz(data: bytes) -> None: + collection_env = _make_input(data) + schedule = scheduling.run(None, collection_env) + _check_invariants(collection_env.cases, schedule.actions) + + +def main() -> None: + import afl + + stream = sys.stdin.buffer + while afl.loop(1000): + stream.seek(0) + fuzz(stream.read()) + + +if __name__ == '__main__': + main() diff --git a/support/tools/genvm-tool/genvm_tool/__init__.py b/support/tools/genvm-tool/genvm_tool/__init__.py index 84e96444..d5838fef 100644 --- a/support/tools/genvm-tool/genvm_tool/__init__.py +++ b/support/tools/genvm-tool/genvm_tool/__init__.py @@ -4,7 +4,9 @@ 'common', 'formatter', 'gvm32', + 'io', 'manifest', + 'misc', ) @@ -12,5 +14,7 @@ common, formatter, gvm32, + io, manifest, + misc, ) diff --git a/support/tools/genvm-tool/genvm_tool/__main__.py b/support/tools/genvm-tool/genvm_tool/__main__.py index 9cd56b92..b0e68bc0 100644 --- a/support/tools/genvm-tool/genvm_tool/__main__.py +++ b/support/tools/genvm-tool/genvm_tool/__main__.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 -"""Command-line interface for genvm-tool. +""" +Command-line interface for genvm-tool. Top-level commands (`configure`, `test`) sit alongside command *groups* (`git` with `git ls` / `git list-repo`). Each group is a sub-package exposing @@ -24,13 +25,21 @@ cmd_codegen, cmd_configure, cmd_docs, + cmd_fuzz_corpus, cmd_test, common, formatter, git, ) -TOPLEVEL = [cmd_configure, cmd_test, cmd_build_manifest, cmd_codegen, cmd_docs] +TOPLEVEL = [ + cmd_configure, + cmd_test, + cmd_build_manifest, + cmd_codegen, + cmd_docs, + cmd_fuzz_corpus, +] GROUPS = [git] # One-line tagline for the man page NAME line and completion header; the fuller @@ -67,7 +76,8 @@ def _rst_to_plain(text: str) -> str: def _long_help(mod): - """The module docstring as a subparser `description` (falls back to HELP). + """ + The module docstring as a subparser `description` (falls back to HELP). `inspect.getdoc` dedents and strips; `_rst_to_plain` drops the RST markup so the rich per-command docstrings feed both the subcommand's `-h` and the man @@ -88,7 +98,8 @@ def _add_leaf(subparsers, mod) -> None: class _PrintManpageAction(argparse.Action): - """`--print-manpage`: emit a roff man page for the whole tree, then exit. + """ + `--print-manpage`: emit a roff man page for the whole tree, then exit. The manager's `default.nix` pipes this into `installManPage` at build time, mirroring how shtab's `--print-completion` feeds `installShellCompletion`. diff --git a/support/tools/genvm-tool/genvm_tool/cmd_build_manifest.py b/support/tools/genvm-tool/genvm_tool/cmd_build_manifest.py index 0058c0fe..c6d5e164 100644 --- a/support/tools/genvm-tool/genvm_tool/cmd_build_manifest.py +++ b/support/tools/genvm-tool/genvm_tool/cmd_build_manifest.py @@ -1,4 +1,5 @@ -"""`genvm-tool build-manifest` — generate the manager's `data/manifest.yaml`. +""" +`genvm-tool build-manifest` — generate the manager's `data/manifest.yaml`. Writes the runtime manifest (executor versions from the active submodules plus the static base fields) to `--output`. Used by release packaging; dev builds get diff --git a/support/tools/genvm-tool/genvm_tool/cmd_codegen.py b/support/tools/genvm-tool/genvm_tool/cmd_codegen.py index 7bbe5923..505bb122 100644 --- a/support/tools/genvm-tool/genvm_tool/cmd_codegen.py +++ b/support/tools/genvm-tool/genvm_tool/cmd_codegen.py @@ -1,4 +1,5 @@ -"""`genvm-tool codegen` — generate language bindings from genvm data JSON. +""" +`genvm-tool codegen` — generate language bindings from genvm data JSON. Renders a data JSON file (`-i`) to a `--lang` backend (rust/python/rst/go) at `-o`. The build runs this for the rust/python/rst outputs; `--lang go` is a diff --git a/support/tools/genvm-tool/genvm_tool/cmd_configure.py b/support/tools/genvm-tool/genvm_tool/cmd_configure.py index 25bcbce0..ad1285ec 100644 --- a/support/tools/genvm-tool/genvm_tool/cmd_configure.py +++ b/support/tools/genvm-tool/genvm_tool/cmd_configure.py @@ -1,4 +1,5 @@ -"""`genvm-tool configure` — generate the build graph. +""" +`genvm-tool configure` — generate the build graph. Writes `build/build.ninja` and `build/info.json`, from which `ninja -C build` drives the cargo builds, `genvm-tool codegen` outputs, the runner build, and the @@ -26,7 +27,8 @@ class ExecVersion(NamedTuple): - """One active executor line resolved to its on-disk locations. + """ + One active executor line resolved to its on-disk locations. - ``key``: the top-level version line (e.g. ``v0.3``) as listed in ``.genvm-monorepo-root``. @@ -42,7 +44,8 @@ class ExecVersion(NamedTuple): def _load_versions(monorepo_cfg, source_dir: Path) -> tuple[str, list[ExecVersion]]: - """Resolve every active executor line from ``.genvm-monorepo-root``. + """ + Resolve every active executor line from ``.genvm-monorepo-root``. Each active line is mounted at ``executors/.x`` and its ``manifest.json`` pins the concrete ``executor-version`` that becomes the @@ -59,7 +62,8 @@ def _load_versions(monorepo_cfg, source_dir: Path) -> tuple[str, list[ExecVersio def build_independent_info(monorepo_cfg, source_dir: Path) -> dict: - """The parts of ``info.json`` derivable from source alone — no build needed. + """ + The parts of ``info.json`` derivable from source alone — no build needed. ``executor_versions`` maps each active line (e.g. ``v0.3``) to its built ``out/executor/`` directory name; ``primary_executor_version`` is the @@ -79,7 +83,8 @@ def build_independent_info(monorepo_cfg, source_dir: Path) -> dict: def base_info( monorepo_cfg, source_dir: Path, build_dir: Path, rust_target_dir: Path ) -> dict: - """Every ``info.json`` key that does not depend on having built anything. + """ + Every ``info.json`` key that does not depend on having built anything. Two commands write ``info.json``: ``configure``, and the test harness when it finds none (so CI can run tests without configuring first, see the @@ -102,7 +107,8 @@ def base_info( def rust_target_dirs_info( monorepo_cfg, source_dir: Path, rust_target_dir: Path ) -> dict: - """``rust_target_dirs``: line checkout (``executors/v0.3.x``) → its cargo target dir. + """ + ``rust_target_dirs``: line checkout (``executors/v0.3.x``) → its cargo target dir. Keyed by mount so a consumer only has to ask which one contains its crate; crates under none of them use ``rust_target_dir`` itself. Why lines cannot @@ -138,7 +144,8 @@ def detect_rust_target() -> str: def _line_configurator(ctx: common.Context, source_dir: Path, exec_rel: str): - """Resolve a line's `configure(line)` hook from its `.genvm-tool.py`. + """ + Resolve a line's `configure(line)` hook from its `.genvm-tool.py`. Falls back to the plugin's default (committed-registry-or-nix) when the line carries no hook, so a line without one still configures sensibly. @@ -315,9 +322,12 @@ def main(ctx: common.Context, args) -> int: ) public_abi_py = source_dir / 'tests/runner/origin/public_abi.py' constants_rst = source_dir / 'docs/website/src/spec/appendix/constants.rst' - # Pending public-abi constants (ADR-012): documented in their own appendix - # page so the spec can reference them, without feeding the runner-hashed - # `public_abi.py`. Sourced from the primary line's pending data file. + internal_constants_rst = ( + source_dir / 'docs/website/src/spec/appendix/internal-constants.rst' + ) + # Public-ABI constants staged for a future release: documented in their own + # appendix page so the spec can reference them, without feeding the + # runner-hashed `public_abi.py`. Empty while nothing is staged. constants_pending_rst = ( source_dir / 'docs/website/src/spec/appendix/constants-pending.rst' ) @@ -329,6 +339,11 @@ def main(ctx: common.Context, args) -> int: n.codegen(manager_socket_consts_rst, 'rst', shared_data / 'manager-api.json') n.codegen(public_abi_py, 'python', p_data / 'public-abi.json') n.codegen(constants_rst, 'rst', p_data / 'public-abi.json') + n.codegen( + internal_constants_rst, + 'rst', + p_data / 'internal-constants.json', + ) n.codegen( constants_pending_rst, 'rst', @@ -343,6 +358,7 @@ def main(ctx: common.Context, args) -> int: manager_socket_consts_rst, public_abi_py, constants_rst, + internal_constants_rst, constants_pending_rst, ): codegen_phony.add_dependency(out) @@ -352,6 +368,7 @@ def main(ctx: common.Context, args) -> int: # CI mode forbids touching Cargo.lock during the build. locked = ['--locked'] if args.ci else [] + # Lint edges (clippy) never create `$out`, so ninja re-runs them every time. n.rule( 'cargo', command=[ @@ -368,12 +385,6 @@ def main(ctx: common.Context, args) -> int: ninja.RawStr('$target_dir'), *locked, ninja.RawStr('$extra_args'), - ninja.AND, - 'cd', - str(build_dir), - ninja.AND, - 'touch', - ninja.VAR_OUT, ], description='Running cargo $subcommand', pool='console', diff --git a/support/tools/genvm-tool/genvm_tool/cmd_docs.py b/support/tools/genvm-tool/genvm_tool/cmd_docs.py index 1cd05782..6b034e7f 100644 --- a/support/tools/genvm-tool/genvm_tool/cmd_docs.py +++ b/support/tools/genvm-tool/genvm_tool/cmd_docs.py @@ -1,4 +1,5 @@ -"""`genvm-tool docs` — list the contributor documentation. +""" +`genvm-tool docs` — list the contributor documentation. Walks each quadrant of `docs/contributing/` (tutorial, how-to, explanation), reads every page's one-line description from that quadrant's `README.md` index, and prints diff --git a/support/tools/genvm-tool/genvm_tool/cmd_fuzz_corpus.py b/support/tools/genvm-tool/genvm_tool/cmd_fuzz_corpus.py new file mode 100644 index 00000000..17e21b5f --- /dev/null +++ b/support/tools/genvm-tool/genvm_tool/cmd_fuzz_corpus.py @@ -0,0 +1,429 @@ +""" +`genvm-tool fuzz-corpus` — seed the fuzz corpora from a finished test run. + +The integration suite encodes real calldata, reads real contract code and +collects real leader results on every run, then leaves them in the artifacts +dir. This walks that dir, maps each blob to the fuzz targets that consume its +format, and writes the new ones into the committed `fuzz/inputs-` +corpora, named by content hash exactly as `test run --fuzz-update-corpus` does. + +Meant to be run by hand after a suite run, and followed by a fuzz run with +`--fuzz-update-corpus`: that one `cmin`s the union back down before the corpus +is committed. +""" + +import dataclasses +import json +import os +import pickle +import re +import shutil +import subprocess +import tempfile +from collections.abc import Iterator +from pathlib import Path + +from . import common, misc + +NAME = 'fuzz-corpus' +HELP = 'seed the fuzz corpora from a finished test run' + +# `arbitrary::Unstructured::int_in_range` eats the first byte and takes it modulo +# the number of variants, so a leading zero selects the variant that hands the +# rest of the input to the parser verbatim. A target taking `|data: &[u8]|` +# parses the whole input and needs no such byte. +_RAW = b'\x00' + + +@dataclasses.dataclass(frozen=True) +class Target: + """A fuzz target that accepts bytes a run produced, and how to frame them.""" + + crate: str + name: str + prefix: bytes = b'' + + +# What each kind of harvested blob is a seed for. Only the targets that take a +# format are listed: a `-structured` target and its op-sequence kin take a +# serialized value instead, which a run does not produce. Seed those by driving +# their mutator library, as `docs/contributing/howto/testing/fuzzing.md` describes. +# +# Each `-raw` target is paired with the un-split name the older lines still use, +# where the payload is still one `Arbitrary` variant behind a selector byte. A +# name no line has resolves to no corpus dir and is skipped. +TARGETS: dict[str, tuple[Target, ...]] = { + 'calldata': ( + Target('executor/crates/calldata', 'genvm-common-decode'), + Target('executor', 'entry-data-raw'), + Target('executor', 'entry-data', _RAW), + ), + 'code': ( + Target('executor', 'runners-parse-raw'), + Target('executor', 'runners-parse', _RAW), + ), + 'leader-result': ( + Target('executor', 'leader-result-raw'), + Target('executor', 'leader-result', _RAW), + ), +} + +_LINE_DIR = re.compile(r'v(\d+\.\d+)\.x') +# Fed to `afl-showmap`, matching what the fuzz cases use. +_EXEC_TIMEOUT_MS = '5000' + + +@dataclasses.dataclass(frozen=True) +class Blob: + """One recovered payload: `kind` says which format it is in.""" + + line: str + kind: str + data: bytes + origin: str + + +@dataclasses.dataclass +class Corpus: + """The seeds one target gained, against what its corpus already holds.""" + + line: str + target: Target + inputs: Path + known: set[str] + seeds: dict[str, bytes] = dataclasses.field(default_factory=dict) + + +def configure(parser): + parser.add_argument( + '--artifacts-dir', + help='run to harvest, defaults to the configured artifacts dir', + ) + parser.add_argument( + '--max-size', + type=int, + default=64 * 1024, + help='drop a seed above this many bytes (default: 65536)', + ) + parser.add_argument( + '-n', + '--dry-run', + action='store_true', + help='report what would be added without writing it', + ) + parser.add_argument( + '--no-verify', + action='store_true', + help='keep every new seed, without checking with afl-showmap that it ' + 'reaches code the corpus does not', + ) + + +def main(ctx: common.Context, args) -> int: + config = common.monorepo_config(ctx.root) + if args.artifacts_dir: + artifacts = Path(args.artifacts_dir) + else: + artifacts = ctx.root / config.get('artifacts_dir', 'build/test-artifacts') + cases = artifacts / 'cases' + if not cases.is_dir(): + raise common.ToolError(f'no case artifacts under {cases}: run the suite first') + + # The blobs are recovered with the repo's own encoders, which live on the + # test runner's import path rather than in this package. + common.add_extra_python_paths(ctx.root) + + plan = _plan(ctx, args, _blobs(ctx, cases)) + verify = not args.no_verify and _have_showmap(ctx) + + total = 0 + for corpus in sorted(plan.values(), key=lambda c: c.inputs): + seeds = _verified(ctx, corpus) if verify else corpus.seeds + if not seeds: + continue + if not args.dry_run: + for name, data in seeds.items(): + path = misc.fuzz_input_path(corpus.inputs, name) + path.parent.mkdir(parents=True, exist_ok=True) + path.write_bytes(data) + total += len(seeds) + ctx.printer.put( + 'seeded', + corpus=str(corpus.inputs.relative_to(ctx.root)), + added=len(seeds), + had=len(corpus.known), + ) + + ctx.printer.put('fuzz-corpus', added=total, dry_run=bool(args.dry_run)) + return 0 + + +# --- harvesting ------------------------------------------------------------- + + +def _case_line(path: Path, cases: Path) -> str | None: + """The executor line an artifact belongs to, or None when it names none.""" + parts = path.relative_to(cases).parts + if len(parts) < 2 or parts[0] != 'executors': + return None + match = _LINE_DIR.fullmatch(parts[1]) + return match.group(1) if match else None + + +def _blobs(ctx: common.Context, cases: Path) -> Iterator[Blob]: + """Every payload a finished run left behind, in no particular order.""" + import genvm_tool_plugins.runners as runners + from gvm_extra.case_inputs import encode_calldata + + unresolved = '' + for config_path in sorted(cases.rglob('config.json')): + line = _case_line(config_path, cases) + if line is None: + continue + conf = json.loads(config_path.read_text()) + if 'calldata' not in conf: # not an integration case + continue + + try: + calldata = encode_calldata(conf) + except Exception as exc: + print(f'{config_path}: calldata does not evaluate: {exc}') + else: + yield Blob(line, 'calldata', calldata, str(config_path)) + + code = _code_path(conf, config_path.parent) + if code is None: + continue + data = code.read_bytes() + try: + data = runners.substitute(data, ctx.root) + except (KeyError, FileNotFoundError) as exc: + # A uid token only differs from the built uid by its bytes, so the + # seed is still worth keeping; the run itself would have failed. + unresolved = str(exc) + yield Blob(line, 'code', data, str(code)) + + if unresolved: + ctx.logger.warning('kept runner uid tokens verbatim', reason=unresolved) + + for pickle_path in sorted(cases.rglob('*_leader_nondet.pickle')): + line = _case_line(pickle_path, cases) + if line is None: + continue + # Written by the leader step of the same suite, as `code || payload` + # frames -- which is what a validator's parser is handed. + for index, result in enumerate(pickle.loads(pickle_path.read_bytes())): + yield Blob(line, 'leader-result', bytes(result), f'{pickle_path}#{index}') + + +def _code_path(conf: dict, case_dir: Path) -> Path | None: + """The contract code as the executor saw it, or None if the case ships none.""" + code = conf.get('code') + if code is None: + return None + path = Path(code) + if path.suffix == '.wat': + # `.wat` is a source the run compiles next to the config; the parser only + # ever sees the module. + path = case_dir / path.with_suffix('.wasm').name + return path if path.is_file() else None + + +# --- planning --------------------------------------------------------------- + + +def _plan(ctx: common.Context, args, blobs: Iterator[Blob]) -> dict[Path, Corpus]: + """Group the seeds worth adding by corpus, printing every rejection.""" + plan: dict[Path, Corpus] = {} + for blob in blobs: + for target in TARGETS[blob.kind]: + inputs = _inputs_dir(ctx.root, blob.line, target) + if inputs is None: # the line has no such target + continue + + data = target.prefix + blob.data + if len(data) > args.max_size: + print(f'{blob.origin}: {len(data)} bytes, over --max-size') + continue + host_path = _host_path(ctx.root, data) + if host_path is not None: + print(f'{blob.origin}: embeds a host path ({host_path})') + continue + + corpus = plan.get(inputs) + if corpus is None: + known = _known(inputs) | { + misc.fuzz_input_name(data) for data in _curated(inputs).values() + } + corpus = Corpus(line=blob.line, target=target, inputs=inputs, known=known) + plan[inputs] = corpus + + name = misc.fuzz_input_name(data) + if name not in corpus.known and name not in corpus.seeds: + corpus.seeds[name] = data + return plan + + +def _known(inputs: Path) -> set[str]: + return {entry.name for entry in misc.fuzz_corpus_entries(inputs)} + + +def _curated(inputs: Path) -> dict[str, bytes]: + """ + The hand-written seeds beside a corpus, by their free-form file names. + + They are fed to the fuzzer as seeds and never rewritten, so a harvested blob + one of them already holds is not worth adding. + """ + curated = inputs.parent / f'{inputs.name}-curated' + if not curated.is_dir(): + return {} + return { + entry.name: entry.read_bytes() + for entry in sorted(curated.iterdir()) + if entry.is_file() and not entry.name.startswith('.') + } + + +def _inputs_dir(root: Path, line: str, target: Target) -> Path | None: + """A line's corpus dir for `target`, or None when that line lacks the target.""" + fuzz = root / 'executors' / f'v{line}.x' / target.crate / 'fuzz' + if not fuzz.joinpath(f'{target.name}.rs').is_file(): + return None + return fuzz / f'inputs-{target.name}' + + +def _host_path(root: Path, data: bytes) -> str | None: + """ + The first path of the harvesting machine `data` carries, if any. + + Corpus entries are committed, and a zip or a wasm built here embeds the + directory it was built in; that turns a seed into a record of somebody's + home dir. + """ + for candidate in (str(root), str(Path.home()), '/nix/store'): + if candidate.encode() in data: + return candidate + return None + + +# --- verification ----------------------------------------------------------- + + +def _have_showmap(ctx: common.Context) -> bool: + if shutil.which('cargo-afl'): + return True + ctx.logger.warning('cargo-afl not found, keeping every seed unverified') + return False + + +def _verified(ctx: common.Context, corpus: Corpus) -> dict[str, bytes]: + """ + The seeds that reach an edge the corpus does not already cover. + + A harvested blob can be rejected by the target for a reason of its own -- + the wrong line's format, a shape the parser drops at the first byte -- and + then it only makes the committed corpus bigger. + """ + binary = _fuzz_binary(ctx.root, corpus.line, corpus.target.name) + if binary is None: + ctx.logger.warning( + 'fuzz target is not built, keeping its seeds unverified', + target=corpus.target.name, + line=corpus.line, + ) + return corpus.seeds + + with tempfile.TemporaryDirectory() as tmp_name: + tmp = Path(tmp_name) + staged = tmp / 'seeds' + staged.mkdir() + for name, data in corpus.seeds.items(): + staged.joinpath(name).write_bytes(data) + + # What the committed seeds already reach: a harvested blob is only worth + # adding on top of both dirs, the curated one included + baseline = tmp / 'baseline' + baseline.mkdir() + for name, data in _curated(corpus.inputs).items(): + # Curated names are free-form, so they are not guaranteed to differ + # from the corpus' content hashes + baseline.joinpath(f'curated-{name}').write_bytes(data) + # Flattened: `showmap` keys its output by file name, which is unique anyway + for entry in misc.fuzz_corpus_entries(corpus.inputs): + shutil.copyfile(entry, baseline / entry.name) + + covered: set[int] = set() + if any(baseline.iterdir()): + for edges in _showmap(binary, baseline, tmp / 'corpus').values(): + covered |= edges + reached = _showmap(binary, staged, tmp / 'new') + + kept: dict[str, bytes] = {} + # Smallest first, so a seed is judged against the cheapest cover of its edges. + for name, data in sorted(corpus.seeds.items(), key=lambda item: len(item[1])): + edges = reached.get(name) + if not edges: + print(f'{corpus.inputs}/{name}: the target did not run it') + continue + if edges <= covered: + print(f'{corpus.inputs}/{name}: reaches nothing new') + continue + covered |= edges + kept[name] = data + return kept + + +def _showmap(binary: Path, inputs: Path, out: Path) -> dict[str, set[int]]: + """Edge ids each file in `inputs` reaches, batched through one forkserver.""" + env = dict(os.environ) + # The targets are persistent, so a run reseeds itself from the entropy the + # shim fakes; without it two runs of one input disagree on their edges. + preload = binary.parent.parent / 'libgenvm_fuzz_preload.so' + if preload.is_file(): + env['AFL_PRELOAD'] = str(preload) + + result = subprocess.run( + [ + 'cargo-afl', + 'afl', + 'showmap', + '-i', + str(inputs), + '-o', + str(out), + '-t', + _EXEC_TIMEOUT_MS, + '--', + str(binary), + ], + env=env, + capture_output=True, + text=True, + ) + if not out.is_dir(): + raise common.ToolError( + f'afl-showmap failed for {binary.name}: {result.stderr.strip()}' + ) + + edges: dict[str, set[int]] = {} + for path in out.iterdir(): + edges[path.name] = { + int(line.split(':', 1)[0]) for line in path.read_text().splitlines() if line + } + return edges + + +def _fuzz_binary(root: Path, line: str, name: str) -> Path | None: + """Where `afl build` puts a target, as `configure` recorded the target dirs.""" + info_path = root / 'build' / 'info.json' + if not info_path.is_file(): + return None + info = json.loads(info_path.read_text()) + target_dir = info.get('rust_target_dirs', {}).get(f'executors/v{line}.x') + if target_dir is None: + return None + binary = ( + Path(target_dir) / info['rust_target'] / 'debug' / 'examples' / f'fuzz-{name}' + ) + return binary if binary.is_file() else None diff --git a/support/tools/genvm-tool/genvm_tool/cmd_test.py b/support/tools/genvm-tool/genvm_tool/cmd_test.py index f8f781b2..b221ab73 100644 --- a/support/tools/genvm-tool/genvm_tool/cmd_test.py +++ b/support/tools/genvm-tool/genvm_tool/cmd_test.py @@ -1,4 +1,5 @@ -"""`genvm-tool test` — run the test suite. +""" +`genvm-tool test` — run the test suite. Everything after `test` is forwarded to the test runner, which has its own `run` and `show plan|test|services|tags` subcommands plus filter flags. Run diff --git a/support/tools/genvm-tool/genvm_tool/codegen/__init__.py b/support/tools/genvm-tool/genvm_tool/codegen/__init__.py index 05aac43d..0578fe8e 100644 --- a/support/tools/genvm-tool/genvm_tool/codegen/__init__.py +++ b/support/tools/genvm-tool/genvm_tool/codegen/__init__.py @@ -1,4 +1,5 @@ -"""`genvm-tool codegen` language backends. +""" +`genvm-tool codegen` language backends. A single front-end (:mod:`genvm_tool.codegen.model`) parses the codegen data JSON into a typed model + shared string-trie; each language module renders that model. diff --git a/support/tools/genvm-tool/genvm_tool/codegen/go.py b/support/tools/genvm-tool/genvm_tool/codegen/go.py index 818e5a8d..2561fde7 100644 --- a/support/tools/genvm-tool/genvm_tool/codegen/go.py +++ b/support/tools/genvm-tool/genvm_tool/codegen/go.py @@ -1,4 +1,5 @@ -"""Go backend for ``genvm-tool codegen``. +""" +Go backend for ``genvm-tool codegen``. Ports the standalone go generator (trie builders emit flat ``func``s rather than structs). The package name is configurable via ``--go-package`` since the @@ -73,8 +74,17 @@ def render(defs: list[Definition], *, go_package: str = 'genvm', **_opts) -> str buf.append(f'package {go_package}\n') needs_fmt = any(isinstance(d, StrTrie) and _has_param(d.root) for d in defs) - if needs_fmt: - buf.append('\nimport "fmt"\n') + needs_strings = any(isinstance(d, StrTrie) and d.suffix is not None for d in defs) + imports = [ + n for n, needed in (('fmt', needs_fmt), ('strings', needs_strings)) if needed + ] + if len(imports) == 1: + buf.append(f'\nimport "{imports[0]}"\n') + elif imports: + buf.append('\nimport (\n') + for name in imports: + buf.append(f'\t"{name}"\n') + buf.append(')\n') for d in defs: if isinstance(d, Enum): @@ -99,6 +109,14 @@ def render(defs: list[Definition], *, go_package: str = 'genvm', **_opts) -> str root_camel = to_camel(d.name) buf.append(f'\ntype {root_camel} string\n\n') _trie_inner(d.root, root_camel, buf) + for name, _parts in d.suffix.leaves if d.suffix else []: + # Mirrors the rust/python guard: a value carries at most one detail. + buf.append( + f'func (v {root_camel}) {to_camel(name)}() {root_camel} {{ ' + f'if strings.Contains(string(v), " # ") {{ ' + f'panic("a value carries at most one detail") }}; ' + f'return v + {_dump(f" # {name}")} }}\n' + ) return ''.join(buf) diff --git a/support/tools/genvm-tool/genvm_tool/codegen/model.py b/support/tools/genvm-tool/genvm_tool/codegen/model.py index a7912d99..e9f319c0 100644 --- a/support/tools/genvm-tool/genvm_tool/codegen/model.py +++ b/support/tools/genvm-tool/genvm_tool/codegen/model.py @@ -1,4 +1,5 @@ -"""Shared front-end for the ``genvm-tool codegen`` language backends. +""" +Shared front-end for the ``genvm-tool codegen`` language backends. Parses the codegen data JSON (a list of typed definitions) into a small typed model and provides the shared string-trie machinery every backend walks. The @@ -45,7 +46,8 @@ class Consts: @dataclasses.dataclass class TrieNode: - """One node of an unfolded string trie. + """ + One node of an unfolded string trie. ``suffix`` is the CamelCase concatenation of the path heads from the root to this node (``''`` at the root); backends use it to name the generated @@ -76,13 +78,18 @@ class StrTrie: root: TrieNode entries: list # unfolded entries, kept for flat path enumeration (rst) docs: dict[str, str] + # Details reachable from any built value, spelled `` # ``. A + # root-level ``#`` entry declares them; they are not paths, so they stay out + # of ``root``/``entries`` and out of the generated validity check. + suffix: TrieNode | None = None Definition = Enum | Const | Consts | StrTrie def _unfold(entry): - """Normalize a trie entry to ``{'head', 'tail'}`` form (recursively). + """ + Normalize a trie entry to ``{'head', 'tail'}`` form (recursively). A bare string ``"x"`` becomes ``{'head': 'x', 'tail': []}``; a dict whose ``tail`` is a list has each child unfolded; everything else (``$param`` tails) @@ -167,6 +174,29 @@ def enumerate_paths(entries, prefix: str = ''): return result +DETAIL_HEAD = '#' +"""Head of the root entry declaring a trie's detail suffixes.""" + + +def _split_details(name: str, entries: list) -> tuple[list, TrieNode | None]: + """Carve the ``#`` entry out of a trie's root, returning ``(paths, details)``.""" + found = [e for e in entries if e is not None and e['head'] == DETAIL_HEAD] + if not found: + return entries, None + if len(found) > 1: + raise ValueError(f'{name}: more than one {DETAIL_HEAD!r} entry') + tail = found[0]['tail'] + if not isinstance(tail, list): + raise ValueError(f'{name}: {DETAIL_HEAD!r} must list details') + for detail in tail: + # A detail is appended to an already-built value, so it has no place to + # hang a subtree off and no argument to render. + if detail is None or detail['tail'] != []: + raise ValueError(f'{name}: a detail may not be nested or take a parameter') + paths = [e for e in entries if e is None or e['head'] != DETAIL_HEAD] + return paths, _build(tail, [], '', False) + + def parse(data) -> list[Definition]: defs: list[Definition] = [] for t in data: @@ -178,13 +208,14 @@ def parse(data) -> list[Definition]: elif kind == 'consts': defs.append(Consts(t['name'], t['repr'], t['values'])) elif kind == 'str_trie': - entries = [_unfold(e) for e in t['values']] + entries, details = _split_details(t['name'], [_unfold(e) for e in t['values']]) defs.append( StrTrie( t['name'], _build(entries, [], '', False), entries, t.get('docs', {}), + details, ) ) else: diff --git a/support/tools/genvm-tool/genvm_tool/codegen/python.py b/support/tools/genvm-tool/genvm_tool/codegen/python.py index 6c07c3a5..122ad849 100644 --- a/support/tools/genvm-tool/genvm_tool/codegen/python.py +++ b/support/tools/genvm-tool/genvm_tool/codegen/python.py @@ -1,4 +1,5 @@ -"""Python backend for ``genvm-tool codegen`` (ports the old ``py.rb`` template). +""" +Python backend for ``genvm-tool codegen`` (ports the old ``py.rb`` template). Output is byte-for-byte identical to the previous ruby generator (tab-indented, single-quoted), so regeneration produces no diff. @@ -83,6 +84,11 @@ def _trie(t: StrTrie, buf: list[str]) -> None: buf.append('\t@staticmethod\n') buf.append(f"\tdef {head.lower()}() -> '_{root_name}{child.suffix}':\n") buf.append(f'\t\treturn _{root_name}{child.suffix}()\n') + if t.suffix is not None: + for name, _parts in t.suffix.leaves: + buf.append(f"\tdef {name.lower()}(self) -> '{root_name}':\n") + buf.append("\t\tassert ' # ' not in self.value\n") + buf.append(f"\t\treturn {root_name}(f'{{self.value}} # {name}')\n") buf.append('\n') diff --git a/support/tools/genvm-tool/genvm_tool/codegen/rst.py b/support/tools/genvm-tool/genvm_tool/codegen/rst.py index e21e48a2..6b495b71 100644 --- a/support/tools/genvm-tool/genvm_tool/codegen/rst.py +++ b/support/tools/genvm-tool/genvm_tool/codegen/rst.py @@ -1,4 +1,5 @@ -"""reStructuredText backend for ``genvm-tool codegen`` (ports ``rst.rb``). +""" +reStructuredText backend for ``genvm-tool codegen`` (ports ``rst.rb``). Generates the spec appendix listing every constant/enum/trie path with stable ``.. _gvm-def-*`` cross-reference anchors. @@ -66,6 +67,16 @@ def render(defs: list[Definition], rst_anchor_ns: str = '', **_opts) -> str: buf.append(f'Param: {param}\n\n') if path in d.docs: buf.append(d.docs[path].rstrip() + '\n\n') + if d.suffix is not None: + for name, _parts in d.suffix.leaves: + path = f'{model.DETAIL_HEAD} {name}' + buf.append( + f'.. _gvm-def-{ns}str-trie-detail-{_dash(d.name)}-{_dash(name)}:\n\n' + ) + buf.append(f'``{path}``\n') + buf.append('~' * (len(path) + 4) + '\n\n') + if path in d.docs: + buf.append(d.docs[path].rstrip() + '\n\n') # Sections are emitted blank-line-separated, so the last one leaves a trailing # blank line that `end-of-file-fixer` would strip — permanent codegen drift. return ''.join(buf).rstrip('\n') + '\n' diff --git a/support/tools/genvm-tool/genvm_tool/codegen/rust.py b/support/tools/genvm-tool/genvm_tool/codegen/rust.py index 68e52f03..649e4064 100644 --- a/support/tools/genvm-tool/genvm_tool/codegen/rust.py +++ b/support/tools/genvm-tool/genvm_tool/codegen/rust.py @@ -1,4 +1,5 @@ -"""Rust backend for ``genvm-tool codegen`` (ports the old ``rs.rb`` template). +""" +Rust backend for ``genvm-tool codegen`` (ports the old ``rs.rb`` template). Output follows the previous ruby generator, plus the later `prefix_` and `is_valid_` additions: the build regenerates these files in-tree and a non-empty @@ -207,6 +208,21 @@ def _trie(t: StrTrie, buf: list[str]) -> None: ) buf.append('}\n\n') + if t.suffix is not None: + buf.append('#[rustfmt::skip]\n') + buf.append(f'impl {root_name} {{\n') + for name, _parts in t.suffix.leaves: + # A value carries at most one detail: the reader splits on the first + # separator, so a second one would be silently dropped. Checked in + # release too, so the invariant does not depend on the build -- these + # are error paths, and the scan is over a short fixed string. + buf.append( + f' pub fn {name.lower()}(self) -> Self {{ ' + f'assert!(!self.0.contains(" # "), "a value carries at most one detail"); ' + f'Self(Cow::Owned(format!("{{}} # {name}", self.0))) }}\n' + ) + buf.append('}\n\n') + _emit_is_valid(t, root_name, buf) @@ -267,7 +283,7 @@ def render(defs: list[Definition], **_opts) -> str: has_serialize = has_deserialize or has_str_trie buf: list[str] = [] buf.append('// This file is auto-generated. Do not edit!\n\n') - buf.append('#![allow(dead_code, clippy::redundant_static_lifetimes)]\n') + buf.append('#![allow(dead_code, clippy::all)]\n') buf.append('\n') if has_deserialize: buf.append('use serde::{Deserialize, Serialize};\n\n') diff --git a/support/tools/genvm-tool/genvm_tool/common.py b/support/tools/genvm-tool/genvm_tool/common.py index 35c1b1c7..9b81b6d0 100644 --- a/support/tools/genvm-tool/genvm_tool/common.py +++ b/support/tools/genvm-tool/genvm_tool/common.py @@ -1,4 +1,5 @@ -"""Shared primitives: repo discovery and git queries. +""" +Shared primitives: repo discovery and git queries. A "repo" is the manager root plus every executor submodule (`executors/.x/`, discovered from `.genvm-monorepo-root`). @@ -9,6 +10,7 @@ import os import re import subprocess +import sys import types from dataclasses import dataclass from pathlib import Path @@ -125,6 +127,21 @@ def active_versions_from_config(config: dict) -> list[str]: return sorted(vers, key=_ver_key) +def add_extra_python_paths(root: Path) -> None: + """ + Put `extra_python_paths` on `sys.path` (the repo's importable test plugins). + + They are libraries of the repo rather than of this package, so anything that + reaches for one imports it lazily, after this call. + """ + for entry in monorepo_config(root).get('extra_python_paths', []): + path = Path(entry) + if not path.is_absolute(): + path = root / path + if str(path) not in sys.path: + sys.path.append(str(path)) + + def executor_rel(version: str) -> str: """Manager-relative checkout/gitlink path for an executor version line.""" return f'executors/v{_bare(version)}.x' @@ -153,13 +170,15 @@ def prefix(self, rel_path: str) -> str: @property def line(self) -> str | None: - """The version-line tag (e.g. `v0.3`) for an executor submodule, or None + """ + The version-line tag (e.g. `v0.3`) for an executor submodule, or None for the manager.""" m = re.fullmatch(r'executors/(v\d+\.\d+)\.x', self.name) return m.group(1) if m else None def feature_branch(self, name: str) -> str: - """Physical branch name for the logical feature branch `name` in this repo. + """ + Physical branch name for the logical feature branch `name` in this repo. The manager is its own repo, so it carries `name` verbatim. Every executor submodule, however, shares ONE remote (`genvm-executor`): a bare `name` diff --git a/support/tools/genvm-tool/genvm_tool/formatter.py b/support/tools/genvm-tool/genvm_tool/formatter.py index 34319c24..aad44ba6 100644 --- a/support/tools/genvm-tool/genvm_tool/formatter.py +++ b/support/tools/genvm-tool/genvm_tool/formatter.py @@ -1,4 +1,5 @@ -"""Structured text/json output. +""" +Structured text/json output. A `Formatter` is both a leveled logger (`logger.info('msg', key=val)`) and a `Sink` (`printer.put('topic', **kv)`). Output is rendered either as indented @@ -8,6 +9,7 @@ import abc import collections.abc +import dataclasses import enum import io import json @@ -232,6 +234,10 @@ def accepts(self, level: Level) -> bool: def _do_dump(self, f: io.TextIOBase, ind, data): if isinstance(data, (set, frozenset, BaseException)): data = _log_unwrap(data) + if dataclasses.is_dataclass(data): + data = { + field.name: getattr(data, field.name) for field in dataclasses.fields(data) + } if isinstance(data, collections.abc.Mapping): for k, v in data.items(): diff --git a/support/tools/genvm-tool/genvm_tool/git/check_for_push.py b/support/tools/genvm-tool/genvm_tool/git/check_for_push.py index 53695a9d..4bd9ad12 100644 --- a/support/tools/genvm-tool/genvm_tool/git/check_for_push.py +++ b/support/tools/genvm-tool/genvm_tool/git/check_for_push.py @@ -1,4 +1,5 @@ -"""`genvm-tool git check-for-push` — pre-push status across the sub-repos. +""" +`genvm-tool git check-for-push` — pre-push status across the sub-repos. Read-only survey of the manager and every executor submodule. For each repo it reports whether it is dirty, on a branch, committed into the manager, and in sync @@ -53,7 +54,8 @@ def _origin_url(repo: common.Repo) -> str: def _worktree_state( repo: common.Repo, ignore_submodules: bool ) -> tuple[int, bool, bool]: - """Porcelain summary: (changed-line count, has-staged, has-unstaged/untracked). + """ + Porcelain summary: (changed-line count, has-staged, has-unstaged/untracked). The manager passes ``--ignore-submodules=dirty`` so a submodule's own dirty tree is left to that submodule's row, while a *moved gitlink* (new commits) @@ -84,7 +86,8 @@ def _committed_in_manager( def _launch_origin_queries(targets: list[tuple[common.Repo, str]]): - """Start one parallel `ls-remote` per distinct origin URL. + """ + Start one parallel `ls-remote` per distinct origin URL. `targets` is (repo, branch) for the repos we want a live remote answer for. Repos that share an origin URL (the executor submodules) are batched into a @@ -120,7 +123,8 @@ def _launch_origin_queries(targets: list[tuple[common.Repo, str]]): def _collect_origin_queries(launched) -> dict[str, tuple[str | None, bool]]: - """Wait for the launched `ls-remote` processes and map each repo to its remote + """ + Wait for the launched `ls-remote` processes and map each repo to its remote branch hash: `{repo.name: (hash | None, reachable)}` (None hash = branch absent). """ procs, result = launched diff --git a/support/tools/genvm-tool/genvm_tool/git/create_branches.py b/support/tools/genvm-tool/genvm_tool/git/create_branches.py index ba1c0f63..e90ae20e 100644 --- a/support/tools/genvm-tool/genvm_tool/git/create_branches.py +++ b/support/tools/genvm-tool/genvm_tool/git/create_branches.py @@ -1,4 +1,5 @@ -"""`genvm-tool git create-branches` — branch the sub-repos that have new content. +""" +`genvm-tool git create-branches` — branch the sub-repos that have new content. Surveys the manager and every checked-out executor submodule, keeps the ones with uncommitted or unpushed work, lets you tick which of those to branch, and creates @@ -35,7 +36,8 @@ def _git(repo: common.Repo, *args: str) -> subprocess.CompletedProcess: def _new_content(repo: common.Repo) -> str | None: - """Describe a repo's pending work, or None if it has nothing to branch. + """ + Describe a repo's pending work, or None if it has nothing to branch. "New content" is a dirty working tree (staged / unstaged / untracked) or commits ahead of the upstream branch — anything a fresh branch would capture. @@ -80,7 +82,8 @@ def _current_branch(repo: common.Repo) -> str: def _default_name(repo: common.Repo) -> str: - """The manager's current branch as a prompt default, unless it is a release/ + """ + The manager's current branch as a prompt default, unless it is a release/ branch-model branch (main / version / dev) or detached — then no default. """ cur = _current_branch(repo) diff --git a/support/tools/genvm-tool/genvm_tool/git/verify_pushed_executors.py b/support/tools/genvm-tool/genvm_tool/git/verify_pushed_executors.py index ba689a79..b1d707b1 100644 --- a/support/tools/genvm-tool/genvm_tool/git/verify_pushed_executors.py +++ b/support/tools/genvm-tool/genvm_tool/git/verify_pushed_executors.py @@ -1,4 +1,5 @@ -"""Verify that an outgoing manager commit pins published executor commits. +""" +Verify that an outgoing manager commit pins published executor commits. The manager ref defaults to ``PRE_COMMIT_TO_REF`` in a pre-push hook and to ``HEAD`` for manual runs. The active executor set and gitlinks are read from @@ -157,7 +158,8 @@ def _targets_from_commit( def _published(target: _Target, remote: str) -> tuple[bool | None, str]: - """Whether ``remote`` already holds the gitlink commit. + """ + Whether ``remote`` already holds the gitlink commit. ``--negotiate-only`` runs the fetch negotiation and stops before any transfer, printing the commits both sides have. Our own sha comes back only diff --git a/support/tools/genvm-tool/genvm_tool/io.py b/support/tools/genvm-tool/genvm_tool/io.py new file mode 100644 index 00000000..3375d8e2 --- /dev/null +++ b/support/tools/genvm-tool/genvm_tool/io.py @@ -0,0 +1,82 @@ +""" +Filesystem helpers that do not block the event loop. + +Python has no real asynchronous file IO, so every helper here is the +corresponding :mod:`pathlib` call handed to a worker thread. +""" + +__all__ = ( + 'AsyncFile', + 'read_file_bytes', + 'read_file_text', + 'write_file_bytes', + 'write_file_text', + 'open_file', + 'path_exists', + 'make_dir', +) + +import asyncio +import typing +from pathlib import Path + + +async def read_file_bytes(path: Path) -> bytes: + return await asyncio.to_thread(path.read_bytes) + + +async def read_file_text(path: Path) -> str: + return await asyncio.to_thread(path.read_text) + + +async def write_file_bytes(path: Path, data: bytes) -> None: + await asyncio.to_thread(path.write_bytes, data) + + +async def write_file_text(path: Path, data: str) -> None: + await asyncio.to_thread(path.write_text, data) + + +class AsyncFile[T: (str, bytes)]: + """ + Open file whose `open` and `close` do not block the event loop. + + `raw` is the underlying file object, for an fd (subprocess redirection) or a + write path too hot to pay a thread hop per call. + """ + + def __init__(self, raw: typing.IO[T]): + self.raw = raw + + async def __aenter__(self) -> typing.Self: + return self + + async def __aexit__(self, *_args) -> None: + await self.close() + + async def close(self) -> None: + await asyncio.to_thread(self.raw.close) + + +@typing.overload +async def open_file( + path: Path, mode: typing.Literal['r', 'w', 'a'] +) -> AsyncFile[str]: ... + + +@typing.overload +async def open_file( + path: Path, mode: typing.Literal['rb', 'wb', 'ab'] +) -> AsyncFile[bytes]: ... + + +async def open_file(path: Path, mode: str) -> AsyncFile: + return AsyncFile(await asyncio.to_thread(open, path, mode)) + + +async def path_exists(path: Path) -> bool: + return await asyncio.to_thread(path.exists) + + +async def make_dir(path: Path) -> None: + await asyncio.to_thread(path.mkdir, parents=True, exist_ok=True) diff --git a/support/tools/genvm-tool/genvm_tool/manifest.py b/support/tools/genvm-tool/genvm_tool/manifest.py index 4b36039b..e6696d82 100644 --- a/support/tools/genvm-tool/genvm_tool/manifest.py +++ b/support/tools/genvm-tool/genvm_tool/manifest.py @@ -1,4 +1,5 @@ -"""Assemble the manager's runtime manifest (`data/manifest.yaml`). +""" +Assemble the manager's runtime manifest (`data/manifest.yaml`). The manager reads this YAML at startup: `executor_versions` maps each active executor version to its `available_after` timestamp, alongside the runner @@ -33,7 +34,8 @@ def _executor_manifest(root: Path, bare_version: str) -> dict: def build(root: Path): - """Return the manifest document: `executor_versions` followed by the static + """ + Return the manifest document: `executor_versions` followed by the static base fields. Keeps ruamel's round-trip type so comments/quoting in the base file survive the dump.""" executor_versions: dict = {} diff --git a/support/tools/genvm-tool/genvm_tool/misc.py b/support/tools/genvm-tool/genvm_tool/misc.py new file mode 100644 index 00000000..cd6620e3 --- /dev/null +++ b/support/tools/genvm-tool/genvm_tool/misc.py @@ -0,0 +1,71 @@ +import hashlib +from pathlib import Path + +from . import gvm32 + + +def fuzz_input_name(data: bytes) -> str: + """ + The file name a fuzzing corpus entry is stored under. + + Named by content, in the encoding the rest of GenVM names hashes in. The + digest is truncated to 224 bits: it only has to tell two corpus entries + apart. + + :param data: the corpus entry + :return: its name + """ + return gvm32.encode(hashlib.sha3_224(data).digest()) + + +def fuzz_input_path(inputs_dir: Path, name: str) -> Path: + """ + Where a corpus entry of that name lives. + + Sharded by the first two characters of the name, so a corpus of thousands of + entries is a tree of small directories rather than one unreadable listing. + + :param inputs_dir: the corpus + :param name: as `fuzz_input_name` gives it + :return: the file to write + """ + return inputs_dir / name[0] / name[1] / name + + +def fuzz_corpus_entries(inputs_dir: Path) -> list[Path]: + """ + Every entry of a corpus, sharded or not. + + Entries written before sharding sit directly in the corpus dir and are still + read from there; nothing rewrites them until a corpus update replaces the + whole dir. + + :param inputs_dir: the corpus + :return: its entries, in path order + """ + if not inputs_dir.is_dir(): + return [] + return sorted( + entry + for entry in inputs_dir.rglob('*') + if entry.is_file() and not entry.name.startswith('.') and entry.name != 'README.txt' + ) + + +def parse_duration(s: str) -> float: + """ + Parse a duration string into seconds. + + :param s: The duration string to parse. + :return: The duration in seconds. + """ + if s.endswith('ms'): + return float(s[:-2]) / 1000.0 + elif s.endswith('s'): + return float(s[:-1]) + elif s.endswith('m'): + return float(s[:-1]) * 60.0 + elif s.endswith('h'): + return float(s[:-1]) * 3600.0 + else: + raise ValueError(f'Invalid duration string: {s} , expected 30s | 2m | 1h') diff --git a/support/tools/genvm-tool/genvm_tool/tests/__init__.py b/support/tools/genvm-tool/genvm_tool/tests/__init__.py index 3c372951..acf5214e 100644 --- a/support/tools/genvm-tool/genvm_tool/tests/__init__.py +++ b/support/tools/genvm-tool/genvm_tool/tests/__init__.py @@ -7,6 +7,7 @@ 'const', 'exec', 'test', + 'tags', 'stage', 'util', 'formatter', @@ -23,6 +24,7 @@ from genvm_tool import common, formatter from genvm_tool.formatter import Formatter, Sink +from . import tags from .util.watchdog import Watchdog _UNSAFE_NAME_RE = re.compile(r'[^A-Za-z0-9._-]+') @@ -67,6 +69,8 @@ class SharedContext: _git_files: list[Path] | None = None _interrupted: threading.Event = field(default_factory=threading.Event) _config: dict[str, Any] | None = None + _tags_registry: tags.Registry | None = None + _tags_registry_loaded: bool = False def bump_metric[T](self, name: str, initial: T, delta: T) -> None: """Increment a named metric by ``delta``, locked: collectors are threads.""" @@ -75,7 +79,8 @@ def bump_metric[T](self, name: str, initial: T, delta: T) -> None: @property def config(self) -> dict[str, Any]: - """Runner config (``artifacts_dir`` / ``extra_python_paths``). + """ + Runner config (``artifacts_dir`` / ``extra_python_paths``). Read from the monorepo marker ``.genvm-monorepo-root``, which doubles as the top-level runner config. @@ -91,6 +96,20 @@ def config(self) -> dict[str, Any]: self._config = conf return conf + @property + def tags_registry(self) -> tags.Registry | None: + if self._tags_registry_loaded: + return self._tags_registry + + registry_path = self.config.get('tags_registry') + if registry_path is not None: + path = Path(registry_path) + if not path.is_absolute(): + path = self.root_dir / path + self._tags_registry = tags.load(path) + self._tags_registry_loaded = True + return self._tags_registry + @property def artifacts_dir(self) -> Path: """Get the artifacts directory from config, or default to root_dir/build/test-artifacts.""" @@ -128,6 +147,10 @@ def git_files(self) -> list[Path]: capture_output=True, text=True, env=common.git_env(), + # The paths below are resolved against the root, so they have to be + # listed from there: run from a subdirectory, git would print them + # relative to that instead + cwd=self.root_dir, ) r = [ diff --git a/support/tools/genvm-tool/genvm_tool/tests/cli.py b/support/tools/genvm-tool/genvm_tool/tests/cli.py index 4d83c6a5..f729d170 100755 --- a/support/tools/genvm-tool/genvm_tool/tests/cli.py +++ b/support/tools/genvm-tool/genvm_tool/tests/cli.py @@ -13,7 +13,7 @@ import genvm_tool.tests import genvm_tool.tests.stage -from genvm_tool import formatter +from genvm_tool import common, formatter from .stage.pipeline import ( CollectionStage, @@ -131,12 +131,15 @@ def _show_execution_plan( immediate_await_batches.add(action.id) def _case_info(case: genvm_tool.tests.test.Case) -> str | dict: + info: dict[str, typing.Any] = {} if case.description.depends_on: - return { - 'name': case.description.name, - 'depends_on': sorted(case.description.depends_on), - } - return case.description.name + info['depends_on'] = sorted(case.description.depends_on) + if case.description.permits > 1 and not case.description.console_pool: + # Otherwise a case holding a third of the pool looks like any other one + info['permits'] = case.description.permits + if not info: + return case.description.name + return {'name': case.description.name, **info} plan_items = [] for action in actions: @@ -334,6 +337,8 @@ async def workflow_services( info: dict[str, typing.Any] = {'name': svc.name} if svc.depends_on: info['depends_on'] = [dep.name for dep in svc.depends_on] + if svc.semaphores: + info['semaphores'] = sorted(semaphore.name for semaphore in svc.semaphores) services_info.append(info) shared_context.printer.put( @@ -376,7 +381,8 @@ def run( root: Path, suite: typing.Callable, ) -> None: - """Run the test runner under genvm-tool's shared ``logger`` / ``printer``. + """ + Run the test runner under genvm-tool's shared ``logger`` / ``printer``. ``argv`` is everything after ``genvm-tool test`` — the runner's own ``run`` / ``show ...`` subcommands plus suite-provided filter flags. The @@ -400,14 +406,7 @@ def run( suite=suite, ) - for p in shared_context.config.get('extra_python_paths', []): - extra_path = Path(p) - if not extra_path.is_absolute(): - extra_path = shared_context.root_dir / extra_path - extra_path_str = str(extra_path) - if extra_path_str not in sys.path: - logger.debug('adding extra python path', path=extra_path) - sys.path.append(extra_path_str) + common.add_extra_python_paths(shared_context.root_dir) parser_result = create_parser() diff --git a/support/tools/genvm-tool/genvm_tool/tests/exec/command.py b/support/tools/genvm-tool/genvm_tool/tests/exec/command.py index a13a138b..6ec73e10 100644 --- a/support/tools/genvm-tool/genvm_tool/tests/exec/command.py +++ b/support/tools/genvm-tool/genvm_tool/tests/exec/command.py @@ -1,10 +1,13 @@ import asyncio import collections.abc +import contextlib import enum +import functools import io import os import re import shlex +import signal import sys import time from dataclasses import dataclass @@ -14,6 +17,47 @@ _ANSI_ESCAPE_RE = re.compile(rb'\x1b\[[0-9;]*[A-Za-z]') +# A command gets its own session, so a signal aimed at ours never reaches it: it +# has to be killed by pid, and it outlives us if we die before doing that +_KILL_GRACE = 5.0 + + +def _kill(pid: int, *, group: bool) -> None: + """ + Kill ``pid``, politely first. + + Runs in the watchdog, which is not the parent and can reap nothing, so the + exit is waited for by looking rather than by `wait`. + """ + send = os.killpg if group else os.kill + for sig in (signal.SIGINT, signal.SIGTERM, signal.SIGKILL): + try: + send(pid, sig) + except OSError: + return + deadline = time.monotonic() + _KILL_GRACE + while time.monotonic() < deadline: + time.sleep(0.1) + try: + send(pid, 0) + except OSError: + return + + +def kill_session_cleanup(pid: int) -> functools.partial: + """ + The picklable cleanup the watchdog runs for a command left behind. + + The whole group goes, not the session leader alone: what leaks is the fleet + the command spawned. + """ + return functools.partial(_kill, pid, group=True) + + +def kill_process_cleanup(pid: int) -> functools.partial: + """Same, for a process sharing our own group, which must survive this.""" + return functools.partial(_kill, pid, group=False) + @dataclass class Result: @@ -144,7 +188,19 @@ async def run(self, ctx: SharedContext, *, mode: RunMode) -> Result: os.close(stderr_writer) ctx.logger.debug('process started', pid=process.pid, id=uid) - res = await process.wait() + # Registered for as long as it runs: a hard death of the tool leaves the + # watchdog to kill it, and a cancellation is handled right here + token = ctx.watchdog.register(kill_session_cleanup(process.pid)) + try: + res = await process.wait() + except asyncio.CancelledError: + # Ask it to stop and leave the cleanup registered: whatever survives + # this is killed when the watchdog is stopped, or when it notices we + # are gone + with contextlib.suppress(OSError): + os.killpg(process.pid, signal.SIGINT) + raise + ctx.watchdog.unregister(token) end = time.monotonic() ctx.logger.debug('process ended', pid=process.pid, exit_code=res, id=uid) diff --git a/support/tools/genvm-tool/genvm_tool/tests/exec/process.py b/support/tools/genvm-tool/genvm_tool/tests/exec/process.py new file mode 100644 index 00000000..3b41b772 --- /dev/null +++ b/support/tools/genvm-tool/genvm_tool/tests/exec/process.py @@ -0,0 +1,46 @@ +import asyncio + + +async def stop( + process: asyncio.subprocess.Process, + *, + terminate_timeout: float = 5.0, + kill_timeout: float = 5.0, +) -> None: + """ + End a process without ever waiting on it indefinitely. + + A reap that never lands leaves a zombie, which is the lesser evil: the + process has been killed either way, and a teardown that cannot finish wedges + the whole run. + """ + try: + process.terminate() + except ProcessLookupError: + return + try: + await asyncio.wait_for(process.wait(), timeout=terminate_timeout) + return + except asyncio.TimeoutError: + pass + process.kill() + try: + await asyncio.wait_for(process.wait(), timeout=kill_timeout) + except asyncio.TimeoutError: + pass + + +async def drain(tasks: list[asyncio.Task], *, timeout: float = 5.0) -> None: + """ + End tasks reading a process' pipes, without waiting for EOF. + + A reader only sees EOF once every process holding the write end is gone, and + children the process spawned inherit it, so EOF may never come. Whatever is + still unread when the timeout expires is dropped. + """ + _, pending = await asyncio.wait(tasks, timeout=timeout) + for task in pending: + task.cancel() + # every task, not just the cancelled ones: an exception nobody retrieves + # resurfaces as a warning at collection time + await asyncio.gather(*tasks, return_exceptions=True) diff --git a/support/tools/genvm-tool/genvm_tool/tests/exec/service.py b/support/tools/genvm-tool/genvm_tool/tests/exec/service.py index cda1081c..138bef82 100644 --- a/support/tools/genvm-tool/genvm_tool/tests/exec/service.py +++ b/support/tools/genvm-tool/genvm_tool/tests/exec/service.py @@ -4,19 +4,63 @@ class Handle(metaclass=abc.ABCMeta): + # Budgets for a plain service; a subclass whose probe is slower to answer + # (see :class:`ContainerHandle`) raises them. + STARTUP_TIMEOUT = 60.0 + INTERRUPT_TIMEOUT = 30.0 + @abc.abstractmethod async def healthy(self) -> bool: ... @abc.abstractmethod async def interrupt(self) -> None: ... + async def death_reason(self) -> str | None: + """ + Why the service can no longer become healthy, or None while it still might. + """ + return None + + async def shutdown(self) -> None: + """ + :meth:`interrupt` that cannot outlive its budget. + """ + try: + await asyncio.wait_for(self.interrupt(), timeout=self.INTERRUPT_TIMEOUT) + except asyncio.TimeoutError: + raise RuntimeError( + f'Service did not stop within {self.INTERRUPT_TIMEOUT:g}s' + ) from None + async def await_startup(self) -> typing.Self: - for i in range(10): - if await self.healthy(): - return self - await asyncio.sleep(1) - await self.interrupt() - raise RuntimeError('Service failed to become healthy') + # the deadline covers the probes themselves, not just the gaps between them + try: + async with asyncio.timeout(self.STARTUP_TIMEOUT): + while True: + reason = await self.death_reason() + if reason is not None: + break + if await self.healthy(): + return self + await asyncio.sleep(1) + except TimeoutError: + reason = f'it was not healthy within {self.STARTUP_TIMEOUT:g}s' + teardown = await self._shutdown_after_failure() + if teardown is not None: + reason = f'{reason}; teardown failed too: {teardown}' + raise RuntimeError(f'Service failed to start: {reason}') + + async def _shutdown_after_failure(self) -> str | None: + """ + Tear down a service that never started; reports why teardown itself failed. + """ + # reported rather than raised: a container left behind must not hide why + # the service never came up + try: + await self.shutdown() + except Exception as e: + return str(e) + return None class Service(metaclass=abc.ABCMeta): diff --git a/support/tools/genvm-tool/genvm_tool/tests/exec/step.py b/support/tools/genvm-tool/genvm_tool/tests/exec/step.py index e40970d3..9d6720be 100644 --- a/support/tools/genvm-tool/genvm_tool/tests/exec/step.py +++ b/support/tools/genvm-tool/genvm_tool/tests/exec/step.py @@ -27,6 +27,14 @@ def to_str(self) -> str: return f'export {self.key}={shlex.quote(str(self.value))}' +@dataclass +class UnsetEnv: + key: str + + def to_str(self) -> str: + return f'unset {self.key}' + + @dataclass class Run: args: collections.abc.Sequence[str | Path] @@ -63,13 +71,14 @@ async def run(self, previous_results: list[typing.Any]) -> typing.Any: return await self.func(previous_results) -type Step = SetCwd | SetEnv | Run | MkDir | Python +type Step = SetCwd | SetEnv | UnsetEnv | Run | MkDir | Python def optimize_steps(steps: list[Step]) -> list[Step]: has_effect = [False] * len(steps) last_cwd_idx: int | None = None - last_env: dict[str, tuple[int, str | Path]] = {} + # `None` is "unset", which only matters after the key was set + last_env: dict[str, tuple[int, str | Path | None]] = {} for i, step in enumerate(steps): if isinstance(step, SetCwd): if last_cwd_idx is None or steps[last_cwd_idx].path != step.path: @@ -77,6 +86,9 @@ def optimize_steps(steps: list[Step]) -> list[Step]: elif isinstance(step, SetEnv): if step.key not in last_env or last_env[step.key][1] != step.value: last_env[step.key] = (i, step.value) + elif isinstance(step, UnsetEnv): + if last_env.get(step.key, (0, None))[1] is not None: + last_env[step.key] = (i, None) elif isinstance(step, Run): has_effect[i] = True # run always has effect if last_cwd_idx is not None: @@ -107,6 +119,8 @@ async def run_steps(ctx: SharedContext, steps: list[Step]) -> list[typing.Any]: cwd = s.path elif isinstance(s, SetEnv): env[s.key] = str(s.value) + elif isinstance(s, UnsetEnv): + env.pop(s.key, None) elif isinstance(s, Run): cmd = command.Command(s.args, cwd, env) results.append( diff --git a/support/tools/genvm-tool/genvm_tool/tests/stage/collection.py b/support/tools/genvm-tool/genvm_tool/tests/stage/collection.py index 537228df..e23bb33f 100644 --- a/support/tools/genvm-tool/genvm_tool/tests/stage/collection.py +++ b/support/tools/genvm-tool/genvm_tool/tests/stage/collection.py @@ -6,18 +6,32 @@ from typing import NamedTuple import genvm_tool.tests -from genvm_tool.tests import SharedContext, const +from genvm_tool.tests import SharedContext, const, tags from .configuration import Env as ConfigurationEnv from .configuration import eval_module +@dataclass(frozen=False, eq=False) +class Semaphore: + name: str + + def __hash__(self): + return id(self) + + def __eq__(self, other): + return self is other + + @dataclass(frozen=False, eq=False) class Service: name: str manager: genvm_tool.tests.exec.service.Service depends_on: list['Service'] | None = None + semaphores: frozenset[Semaphore] = frozenset() meta: dict[str, typing.Any] = field(default_factory=dict) + handle: genvm_tool.tests.exec.service.Handle | None = None + order: int = 0 def __hash__(self): return id(self) @@ -30,23 +44,46 @@ class Context: shared: SharedContext configuration: ConfigurationEnv _all_services: list[Service] + _all_semaphores: list[Semaphore] _all_cases: list[genvm_tool.tests.test.Case] + _tag_offenders: dict[str, set[str]] + _tag_declaration_errors: set[tuple[str, str]] + + def new_semaphore(self, name: str) -> Semaphore: + semaphore = Semaphore(name=name) + self._all_semaphores.append(semaphore) + return semaphore def new_service( self, name: str, manager: genvm_tool.tests.exec.service.Service, depends_on: list['Service'] | None = None, + semaphores: typing.Iterable[Semaphore] = (), ) -> Service: - svc = Service(name=name, manager=manager, depends_on=depends_on) + svc = Service( + name=name, + manager=manager, + depends_on=depends_on, + semaphores=frozenset(semaphores), + order=len(self._all_services), + ) + self._all_services.append(svc) return svc def add_case(self, case: genvm_tool.tests.test.Case): assert isinstance(case, genvm_tool.tests.test.Case) self._all_cases.append(case) + def add_tag_offender(self, name: str, invalid: frozenset[str]) -> None: + self._tag_offenders.setdefault(name, set()).update(invalid) + + def add_tag_declaration_error(self, name: str, error: str) -> None: + self._tag_declaration_errors.add((name, error)) + def collect_dir(self, relative: str, **kwargs: typing.Any) -> None: - """Evaluate ``/test.py`` and invoke its ``collect(ctx, **kwargs)``. + """ + Evaluate ``/test.py`` and invoke its ``collect(ctx, **kwargs)``. This is how a test suite registers its cases: the ``test.py`` next to the tests owns the discovery + case-building, keeping it out of the importable @@ -67,11 +104,42 @@ def run(shared: SharedContext, configuration: ConfigurationEnv) -> Env: ctx.shared = shared ctx.configuration = configuration ctx._all_services = [] + ctx._all_semaphores = [] ctx._all_cases = [] + ctx._tag_offenders = {} + ctx._tag_declaration_errors = set() for collector in configuration.collectors: collector(ctx) + registry = shared.tags_registry + for case in ctx._all_cases: + expanded = tags.expand(case.description.tags, registry=registry) + case.description = case.description._replace(tags=expanded) + if registry is not None and (invalid := tags.unknown(registry, expanded)): + ctx.add_tag_offender(case.description.name, invalid) + + if ctx._tag_offenders or ctx._tag_declaration_errors: + errors = [ + (name, f'unknown test tags: {", ".join(sorted(invalid))}') + for name, invalid in ctx._tag_offenders.items() + ] + errors.extend(ctx._tag_declaration_errors) + errors.sort() + shown = errors[:20] + lines = [f'{name}: {error}' for name, error in shown] + if remaining := len(errors) - len(shown): + lines.append(f'... and {remaining} more errors') + registry_path = shared.config.get('tags_registry') + registry_detail = ( + f'; valid tags are loaded from {registry_path}' + if registry_path is not None + else '' + ) + raise ValueError( + f'Invalid test tag declarations{registry_detail}:\n' + '\n'.join(lines) + ) + return Env( cases=ctx._all_cases, args=configuration.args, diff --git a/support/tools/genvm-tool/genvm_tool/tests/stage/configuration.py b/support/tools/genvm-tool/genvm_tool/tests/stage/configuration.py index 3de2bdfa..93e5b06a 100644 --- a/support/tools/genvm-tool/genvm_tool/tests/stage/configuration.py +++ b/support/tools/genvm-tool/genvm_tool/tests/stage/configuration.py @@ -15,7 +15,8 @@ def eval_module(file: Path, root_dir: Path) -> types.ModuleType: - """Compile and exec ``file`` as a throwaway module, returning it. + """ + Compile and exec ``file`` as a throwaway module, returning it. The module is registered in ``sys.modules`` (under a dotted name derived from its path relative to ``root_dir``) so its own relative imports resolve. Used diff --git a/support/tools/genvm-tool/genvm_tool/tests/stage/execution.py b/support/tools/genvm-tool/genvm_tool/tests/stage/execution.py index e007d35a..5b0d3989 100644 --- a/support/tools/genvm-tool/genvm_tool/tests/stage/execution.py +++ b/support/tools/genvm-tool/genvm_tool/tests/stage/execution.py @@ -158,12 +158,19 @@ async def wait(self): await self._event.wait() +# Spawning a service is not yet covered by a Handle's own budget, and the work +# behind it (`docker run`, say) can wedge before there is anything to time out. +SPAWN_TIMEOUT = 300.0 + + async def _start_service(ctx: _ExecutionContext, service: Service) -> None: """Start a service and track its handle.""" ctx.shared.logger.info('Starting service', service_name=service.name) try: - handle = await service.manager.start() + async with asyncio.timeout(SPAWN_TIMEOUT): + handle = await service.manager.start() await handle.await_startup() + service.handle = handle ctx.running_services[service.name] = handle ctx.shared.logger.info('Service started', service_name=service.name) except Exception as e: @@ -178,10 +185,11 @@ async def _start_service(ctx: _ExecutionContext, service: Service) -> None: async def _stop_service(ctx: _ExecutionContext, service: Service) -> None: """Stop a running service.""" handle = ctx.running_services.pop(service.name, None) + service.handle = None if handle is not None: ctx.shared.logger.info('Stopping service', service_name=service.name) try: - await handle.interrupt() + await handle.shutdown() ctx.shared.logger.info('Service stopped', service_name=service.name) except Exception as e: ctx.shared.logger.error( @@ -199,7 +207,7 @@ async def _stop_all_services(ctx: _ExecutionContext) -> None: if handle is not None: ctx.shared.logger.info('Stopping service (cleanup)', service_name=name) try: - await handle.interrupt() + await handle.shutdown() except Exception as e: ctx.shared.logger.error( 'Failed to stop service during cleanup', @@ -250,9 +258,12 @@ async def _run_case( ) return - permits = 1 - if case.description.console_pool: - permits = ctx.semaphore.max_value + permits = min( + ctx.semaphore.max_value, + ctx.semaphore.max_value + if case.description.console_pool + else max(1, case.description.permits), + ) await ctx.semaphore.acquire(permits) try: if ctx.should_stop.is_set(): diff --git a/support/tools/genvm-tool/genvm_tool/tests/stage/filter.py b/support/tools/genvm-tool/genvm_tool/tests/stage/filter.py index 6076edd2..a47f46af 100644 --- a/support/tools/genvm-tool/genvm_tool/tests/stage/filter.py +++ b/support/tools/genvm-tool/genvm_tool/tests/stage/filter.py @@ -35,6 +35,10 @@ def add_args(parser: argparse.ArgumentParser) -> None: ) +def _is_tag_char(char: str) -> bool: + return char.isalnum() or char in '-_' + + def _tokenize_expr(expr: str) -> list[str]: tokens = [] idx = 0 @@ -47,7 +51,7 @@ def _tokenize_expr(expr: str) -> list[str]: idx += 1 continue word_end = idx - while word_end < len(expr) and expr[word_end].isalpha(): + while word_end < len(expr) and _is_tag_char(expr[word_end]): word_end += 1 if word_end == idx: raise ValueError(f'Unexpected character at position {idx}: {expr[idx]}') @@ -72,7 +76,7 @@ def _parse_tags_expr( inner = _parse_tags_expr(toks, 0) return lambda tags: not inner(tags) tag = toks.pop() - if not tag[0].isalpha(): + if not _is_tag_char(tag[0]): raise ValueError(f'Unexpected token in tags expression: {tag}') if tag == 'true': return lambda tags: True diff --git a/support/tools/genvm-tool/genvm_tool/tests/stage/scheduling.py b/support/tools/genvm-tool/genvm_tool/tests/stage/scheduling.py index 2657fcfa..0641ee2d 100644 --- a/support/tools/genvm-tool/genvm_tool/tests/stage/scheduling.py +++ b/support/tools/genvm-tool/genvm_tool/tests/stage/scheduling.py @@ -35,36 +35,94 @@ class Env(typing.NamedTuple): args: SimpleNamespace -def _topo_sort_services(services: set[Service]) -> list[Service]: - """ - Topological sort of services via DFS. - Returns services in dependency order: dependencies come before dependents. - """ - result: list[Service] = [] - visited: set[str] = set() - in_stack: set[str] = set() - - def visit(svc: Service) -> None: - if svc.name in visited: - return - if svc.name in in_stack: - raise ValueError(f'Circular dependency detected involving {svc.name}') - - in_stack.add(svc.name) - - # Visit dependencies first - if svc.depends_on: - for dep in svc.depends_on: - if dep in services: - visit(dep) - - in_stack.remove(svc.name) - visited.add(svc.name) - result.append(svc) +def _service_closure(service: Service) -> set[Service]: + result: set[Service] = set() + pending = [service] + while pending: + current = pending.pop() + if current in result: + continue + result.add(current) + pending.extend(current.depends_on or []) + return result - for svc in services: - visit(svc) +def _topo_sort_services( + services: set[Service], + precedence: set[tuple[Service, Service]], +) -> list[Service]: + """ + The order the services are started in. + + Dependencies come before dependents, and the owners of one semaphore come one + after another, with the whole dependent subtree of the previous owner started + before the next one takes it. Which owner goes first is a free choice, and + two semaphores whose owners depend on each other can only be ordered jointly, + so the choices are searched rather than fixed one semaphore at a time. Among + the services that may go next the one declared first wins, so an + unconstrained suite keeps its declaration order. + """ + closures = {service: _service_closure(service) & services for service in services} + predecessors: dict[Service, set[Service]] = { + service: { + dependency for dependency in service.depends_on or [] if dependency in services + } + for service in services + } + for before, after in precedence: + if before in services and after in services: + predecessors[after].add(before) + + def can_start( + candidate: Service, + started: frozenset[Service], + remaining: tuple[Service, ...], + ) -> bool: + if not predecessors[candidate].issubset(started): + return False + # Taking a semaphore stops whoever owns it and everything depending on + # that owner, so all of it has to have been started already + return not any( + holder in started and holder.semaphores & candidate.semaphores + for other in remaining + if other is not candidate + for holder in closures[other] + ) + + # One dead end is enough to rule out every way of reaching the same set of + # started services, which keeps the search out of the combinatorial case + dead_ends: set[frozenset[Service]] = set() + + def search( + started: frozenset[Service], + remaining: tuple[Service, ...], + ) -> list[Service] | None: + if not remaining: + return [] + if started in dead_ends: + return None + for candidate in remaining: + if not can_start(candidate, started, remaining): + continue + tail = search( + started | {candidate}, + tuple(item for item in remaining if item is not candidate), + ) + if tail is not None: + return [candidate, *tail] + dead_ends.add(started) + return None + + result = search( + frozenset(), + tuple(sorted(services, key=lambda service: service.order)), + ) + if result is None: + names = ', '.join(sorted(service.name for service in services)) + raise ValueError( + 'services cannot be started in any order, their dependencies and ' + f'semaphores contradict each other: {names}' + ) return result @@ -103,40 +161,30 @@ def visit(name: str) -> None: return cases_by_name -def _get_effective_services( +def _case_services(case: genvm_tool.tests.test.Case) -> set[Service]: + services: set[Service] = set() + for svc in case.description.needed_services: + services.update(_service_closure(svc)) + return services + + +def _test_dependency_names( case: genvm_tool.tests.test.Case, cases_by_name: dict[str, genvm_tool.tests.test.Case], - _memo: dict[str, frozenset[str]] | None = None, + memo: dict[str, frozenset[str]], ) -> frozenset[str]: - """ - Compute effective service names for a test case: its own services plus - services of all transitive test dependencies. This ensures a dependent - test is never placed in an earlier batch than its dependency. - """ - if _memo is None: - _memo = {} + if case.description.name in memo: + return memo[case.description.name] - name = case.description.name - if name in _memo: - return _memo[name] - - names: set[str] = set() - # Own services - for svc in case.description.needed_services: - names.add(svc.name) - if svc.depends_on: - for dep in svc.depends_on: - names.add(dep.name) - - # Transitive test dependency services - for dep_name in case.description.depends_on: - dep_case = cases_by_name.get(dep_name) - if dep_case is not None: - names.update(_get_effective_services(dep_case, cases_by_name, _memo)) - - result = frozenset(names) - _memo[name] = result - return result + result: set[str] = set() + for name in case.description.depends_on: + dependency = cases_by_name.get(name) + if dependency is None: + continue + result.add(name) + result.update(_test_dependency_names(dependency, cases_by_name, memo)) + memo[case.description.name] = frozenset(result) + return memo[case.description.name] def run(shared: SharedContext, collection_env: CollectionEnv) -> Env: @@ -149,117 +197,194 @@ def run(shared: SharedContext, collection_env: CollectionEnv) -> Env: # Validate test dependencies and build name lookup cases_by_name = _validate_test_dependencies(collection_env.cases) - # Collect all services needed by all cases (using effective services) + # Collect all services needed by the selected cases all_needed_services: set[Service] = set() for case in collection_env.cases: - # Collect direct services - for svc in case.description.needed_services: - all_needed_services.add(svc) - if svc.depends_on: - for dep in svc.depends_on: - all_needed_services.add(dep) - # Also collect services from test dependencies (transitively) - for dep_name in case.description.depends_on: + all_needed_services.update(_case_services(case)) + + # A dependency between tests using different holders of one semaphore orders + # those service lifetimes. The dependency runs first, then its holder can be + # stopped and the dependent's holder started + service_precedence: set[tuple[Service, Service]] = set() + test_dependencies_memo: dict[str, frozenset[str]] = {} + for case in collection_env.cases: + for dep_name in _test_dependency_names( + case, + cases_by_name, + test_dependencies_memo, + ): dep_case = cases_by_name.get(dep_name) - if dep_case is not None: - for svc in dep_case.description.needed_services: - all_needed_services.add(svc) - if svc.depends_on: - for dep in svc.depends_on: - all_needed_services.add(dep) + if dep_case is None: + continue + for before in _case_services(dep_case): + for after in _case_services(case): + if before is not after and before.semaphores & after.semaphores: + service_precedence.add((before, after)) # Topo sort: dependencies first, dependents last - topo_sorted_services = _topo_sort_services(all_needed_services) - - # Use effective services for batch placement - effective_services_memo: dict[str, frozenset[str]] = {} - - def get_effective_service_names(case: genvm_tool.tests.test.Case) -> frozenset[str]: - return _get_effective_services(case, cases_by_name, effective_services_memo) + service_names = [service.name for service in all_needed_services] + if len(service_names) != len(set(service_names)): + duplicates = sorted( + {name for name in service_names if service_names.count(name) > 1} + ) + raise ValueError(f'duplicate service names: {", ".join(duplicates)}') + topo_sorted_services = _topo_sort_services( + all_needed_services, + service_precedence, + ) + services_by_name = {service.name: service for service in topo_sorted_services} - # Separate cases by whether they have effective services - cases_without_services: list[genvm_tool.tests.test.Case] = [] - cases_with_services: list[genvm_tool.tests.test.Case] = [] + def get_required_service_names(case: genvm_tool.tests.test.Case) -> frozenset[str]: + return frozenset(service.name for service in _case_services(case)) for case in collection_env.cases: - if len(get_effective_service_names(case)) > 0: - cases_with_services.append(case) - else: - cases_without_services.append(case) - - # Schedule cases without services first (they can run immediately) - parallel_batch_no_services: list[genvm_tool.tests.test.Case] = [] - for case in cases_without_services: - if case.description.console_pool: - # Console pool: run alone, await immediately - actions.append(StartCases(id=next_id, cases=[case])) - actions.append(AwaitAllCases(id=next_id)) - next_id += 1 - else: - parallel_batch_no_services.append(case) - - if parallel_batch_no_services: - batch_id = next_id - next_id += 1 - actions.append(StartCases(id=batch_id, cases=parallel_batch_no_services)) - running_batches[batch_id] = set() # No service dependencies - - # Now schedule cases with services - # Start services in topo order, start tests as soon as their services are ready + services = [services_by_name[name] for name in get_required_service_names(case)] + for i, left in enumerate(services): + for right in services[i + 1 :]: + shared_semaphores = left.semaphores & right.semaphores + if shared_semaphores: + names = ', '.join(sorted(item.name for item in shared_semaphores)) + raise ValueError( + f'{case.description.name} requires mutually exclusive services ' + f'{left.name} and {right.name} (semaphores: {names})' + ) + + # Start services in topo order and cases as soon as their services are ready active_services: set[str] = set() - remaining_cases = list(cases_with_services) + remaining_cases = list(collection_env.cases) + scheduled_cases: set[str] = set() + + def await_batches_for(service_names: set[str]) -> None: + for batch_id, batch_services in list(running_batches.items()): + if batch_services & service_names: + actions.append(AwaitAllCases(id=batch_id)) + del running_batches[batch_id] + + def stop_services(service_names: set[str]) -> None: + await_batches_for(service_names) + for service in reversed(topo_sorted_services): + if service.name in service_names and service.name in active_services: + actions.append(StopService(service=service)) + active_services.remove(service.name) + + def services_ready(case: genvm_tool.tests.test.Case) -> bool: + return get_required_service_names(case).issubset(active_services) + + def dependencies_ready( + case: genvm_tool.tests.test.Case, + also_starting: frozenset[str], + ) -> bool: + return _test_dependency_names( + case, + cases_by_name, + test_dependencies_memo, + ).issubset(scheduled_cases | also_starting) + + def schedule_ready_cases() -> None: + nonlocal next_id, remaining_cases + + while True: + # A batch is awaited as a whole, so a case waiting for a dependency + # that only starts after that await would block the runner forever. + # Cases of one batch run concurrently, hence may depend on each other + parallel_batch = [ + case + for case in remaining_cases + if not case.description.console_pool and services_ready(case) + ] + while True: + starting = frozenset(case.description.name for case in parallel_batch) + kept = [case for case in parallel_batch if dependencies_ready(case, starting)] + if len(kept) == len(parallel_batch): + break + parallel_batch = kept + + if parallel_batch: + batch_id = next_id + next_id += 1 + batch_services: set[str] = set() + for case in parallel_batch: + batch_services.update(get_required_service_names(case)) + scheduled_cases.add(case.description.name) + started = {case.description.name for case in parallel_batch} + remaining_cases = [ + case for case in remaining_cases if case.description.name not in started + ] + actions.append(StartCases(id=batch_id, cases=parallel_batch)) + running_batches[batch_id] = batch_services + + # A console case holds the whole case pool, so it runs alone. Start it + # only once every case it depends on has started, otherwise it would + # wait for a later service that cannot start while it holds the pool + ready_console = next( + ( + case + for case in remaining_cases + if case.description.console_pool + and services_ready(case) + and dependencies_ready(case, frozenset()) + ), + None, + ) + if ready_console is not None: + remaining_cases.remove(ready_console) + scheduled_cases.add(ready_console.description.name) + actions.append(StartCases(id=next_id, cases=[ready_console])) + actions.append(AwaitAllCases(id=next_id)) + next_id += 1 + + # A console case that finished may unblock cases that depend on it + if not parallel_batch and ready_console is None: + return + + # Cases without services can start before the first service + schedule_ready_cases() for svc in topo_sorted_services: + conflicting = { + name + for name in active_services + if services_by_name[name].semaphores & svc.semaphores + } + if conflicting: + # A dependent cannot outlive a service being displaced by a mutually + # exclusive alternative + while True: + dependents = { + name + for name in active_services + if any( + dep.name in conflicting for dep in services_by_name[name].depends_on or [] + ) + } + if dependents.issubset(conflicting): + break + conflicting.update(dependents) + stop_services(conflicting) + + missing_dependencies = { + dep.name for dep in svc.depends_on or [] if dep.name not in active_services + } + if missing_dependencies: + raise ValueError( + f'{svc.name} cannot start after mutually exclusive dependencies stopped: ' + + ', '.join(sorted(missing_dependencies)) + ) + # Start this service actions.append(StartService(service=svc)) active_services.add(svc.name) - # Find cases that can now run (all their effective services are active) - ready_cases: list[genvm_tool.tests.test.Case] = [] - still_waiting: list[genvm_tool.tests.test.Case] = [] - - for case in remaining_cases: - required_services = get_effective_service_names(case) - if required_services.issubset(active_services): - ready_cases.append(case) - else: - still_waiting.append(case) - - remaining_cases = still_waiting - - # Schedule ready cases - parallel_batch: list[genvm_tool.tests.test.Case] = [] - for case in ready_cases: - if case.description.console_pool: - # Console pool: run alone, await immediately - actions.append(StartCases(id=next_id, cases=[case])) - actions.append(AwaitAllCases(id=next_id)) - next_id += 1 - else: - parallel_batch.append(case) - - if parallel_batch: - batch_id = next_id - next_id += 1 - # Track which services this batch depends on - batch_services: set[str] = set() - for case in parallel_batch: - batch_services.update(get_effective_service_names(case)) - actions.append(StartCases(id=batch_id, cases=parallel_batch)) - running_batches[batch_id] = batch_services + schedule_ready_cases() + + if remaining_cases: + names = ', '.join(case.description.name for case in remaining_cases) + raise ValueError( + f'cases could not be scheduled before their services stopped: {names}' + ) # Ending: stop services in reverse topo order (dependents first, dependencies last) - for svc in reversed(topo_sorted_services): - # Await all batches that depend on this service - batches_to_await = [ - batch_id for batch_id, services in running_batches.items() if svc.name in services - ] - for batch_id in batches_to_await: - actions.append(AwaitAllCases(id=batch_id)) - del running_batches[batch_id] - - # Stop this service - actions.append(StopService(service=svc)) + stop_services(set(active_services)) # Await any remaining batches (e.g., those without service dependencies) for batch_id in list(running_batches.keys()): diff --git a/support/tools/genvm-tool/genvm_tool/tests/tags.py b/support/tools/genvm-tool/genvm_tool/tests/tags.py new file mode 100644 index 00000000..f457339f --- /dev/null +++ b/support/tools/genvm-tool/genvm_tool/tests/tags.py @@ -0,0 +1,68 @@ +"""Tag registry: expansion of hierarchical feature tags and validation.""" + +import json +from dataclasses import dataclass +from pathlib import Path + +FEATURE_PREFIX = 'feature-' + + +@dataclass(frozen=True) +class Registry: + general: dict[str, str] + features: dict[str, str] + + @property + def known(self) -> frozenset[str]: + return frozenset(self.general) | frozenset( + FEATURE_PREFIX + name for name in self.features + ) + + +def load(path: Path) -> Registry: + try: + raw = json.loads(path.read_text()) + except json.JSONDecodeError as error: + raise ValueError(f'{path}: {error}') from error + if not isinstance(raw, dict): + raise ValueError(f'{path}: tag registry must be an object') + + values: dict[str, dict[str, str]] = {} + for section in ('general', 'features'): + value = raw.get(section) + if not isinstance(value, dict) or not all( + isinstance(name, str) and isinstance(description, str) + for name, description in value.items() + ): + raise ValueError(f'{path}: {section} must map tag names to descriptions') + values[section] = value + + return Registry(general=values['general'], features=values['features']) + + +def expand(tags: frozenset[str], *, registry: Registry | None) -> frozenset[str]: + """ + Add every declared ancestor of a hierarchical feature tag. + + ``feature-web-request-body`` also emits ``feature-web-request`` and + ``feature-web``, so selecting a root selects the whole subtree while matching + stays exact. Ancestors are declared dash-prefixes in the registry, preserving + compound path segments such as ``runner-map-vm``. Without a registry, tags are + returned unchanged. + """ + expanded = set(tags) + if registry is None: + return frozenset(expanded) + for tag in tags: + if not tag.startswith(FEATURE_PREFIX): + continue + expanded.update( + FEATURE_PREFIX + name + for name in registry.features + if tag.startswith(FEATURE_PREFIX + name + '-') + ) + return frozenset(expanded) + + +def unknown(registry: Registry, tags: frozenset[str]) -> frozenset[str]: + return tags - registry.known diff --git a/support/tools/genvm-tool/genvm_tool/tests/test.py b/support/tools/genvm-tool/genvm_tool/tests/test.py index 2a74cb88..639ae204 100644 --- a/support/tools/genvm-tool/genvm_tool/tests/test.py +++ b/support/tools/genvm-tool/genvm_tool/tests/test.py @@ -17,6 +17,9 @@ class Description(typing.NamedTuple): tags: frozenset[str] = frozenset() console_pool: bool = False depends_on: frozenset[str] = frozenset() + # How much of the case pool this case occupies. Above one for a case that is + # itself a fleet of processes, so the pool bounds threads and not cases + permits: int = 1 def with_tags(self, new_tags: typing.Iterable[str]) -> 'Description': return self._replace(tags=self.tags.union(new_tags)) diff --git a/support/tools/genvm-tool/genvm_tool/tests/util/watchdog.py b/support/tools/genvm-tool/genvm_tool/tests/util/watchdog.py index a6796753..63348c67 100644 --- a/support/tools/genvm-tool/genvm_tool/tests/util/watchdog.py +++ b/support/tools/genvm-tool/genvm_tool/tests/util/watchdog.py @@ -1,6 +1,9 @@ +import os +import selectors import subprocess import sys import threading +import time import typing from pathlib import Path @@ -8,7 +11,8 @@ class Watchdog: - """Owns the lifecycle of registered cleanups (e.g. ``docker stop``). + """ + Owns the lifecycle of registered cleanups (e.g. ``docker stop``). Cleanups are picklable zero-argument callables shipped to a watchdog subprocess. The subprocess is the single executor: it runs a cleanup when @@ -22,6 +26,10 @@ class Watchdog: cleanly). Otherwise a broken watchdog would silently leak every container. """ + # Has to outlast the slowest cleanup the watchdog runs for us: `docker stop` + # gives a container 10s to exit and is itself capped at 30s. + ACK_TIMEOUT = 60.0 + def __init__(self, process: subprocess.Popen): self._process = process self._lock = threading.Lock() @@ -30,6 +38,7 @@ def __init__(self, process: subprocess.Popen): # Cleared as soon as the watchdog misses anything we asked of it: from # then on its exit status says nothing about what it actually ran. self._healthy = True + self._ack_buffer = b'' @staticmethod def start() -> 'Watchdog': @@ -75,7 +84,8 @@ def unregister(self, token: int) -> None: self._send({'action': 'remove', 'token': token}) def kill(self, token: int) -> None: - """Run a registered cleanup now (via the watchdog) and forget it. + """ + Run a registered cleanup now (via the watchdog) and forget it. Blocks until the watchdog acknowledges completion, so callers may rely on the resource (e.g. a container's port) being released on return. Safe to @@ -93,23 +103,44 @@ def kill(self, token: int) -> None: _run_cleanup(cleanup) def _await_ack(self, token: int) -> bool: - """Wait for this kill's ack, skipping stale ones. ``False`` on EOF.""" + """ + Wait for this kill's ack, skipping stale ones. ``False`` on EOF or timeout. + + The wait is bounded because this runs on a thread holding :attr:`_lock`: + a watchdog that stops answering would otherwise block every later + :meth:`register` and :meth:`kill`, and hang the interpreter at exit. + """ assert self._process.stdout is not None - while True: - try: - line = self._process.stdout.readline() - except (OSError, ValueError): - return False - if not line: - return False - try: - if int(line) == token: - return True - except ValueError: - return False + deadline = time.monotonic() + self.ACK_TIMEOUT + with selectors.DefaultSelector() as selector: + selector.register(self._process.stdout, selectors.EVENT_READ) + while True: + # Lines are cut from our own buffer rather than read through the + # stream's: a line the stream has already buffered is one the + # selector can no longer see, and we would wait out the deadline + # with the answer in hand. The remainder outlives the call, so + # back-to-back kills do not drop each other's ack. + while b'\n' in self._ack_buffer: + line, _, self._ack_buffer = self._ack_buffer.partition(b'\n') + try: + if int(line) == token: + return True + except ValueError: + return False + remaining = deadline - time.monotonic() + if remaining <= 0 or not selector.select(remaining): + return False + try: + chunk = os.read(self._process.stdout.fileno(), 4096) + except (OSError, ValueError): + return False + if not chunk: + return False + self._ack_buffer += chunk def stop(self) -> None: - """Stop the watchdog, running any cleanups still registered. + """ + Stop the watchdog, running any cleanups still registered. Closing stdin signals the subprocess to exit: it tears down every dangling cleanup first, so we wait for it to finish. It exits 0 only after they all @@ -128,7 +159,12 @@ def stop(self) -> None: code = self._process.wait(timeout=60) except subprocess.TimeoutExpired: self._process.kill() - code = self._process.wait() + try: + code = self._process.wait(timeout=10) + except subprocess.TimeoutExpired: + # Killed and still not reaped. Ending the run matters more than + # the exit status; below, a non-zero one runs the cleanups here. + code = -1 with self._lock: cleanups, self._cleanups = self._cleanups, {} healthy = self._healthy diff --git a/support/tools/genvm-tool/unit_tests/test_codegen_detail_suffix.py b/support/tools/genvm-tool/unit_tests/test_codegen_detail_suffix.py new file mode 100644 index 00000000..b0951ea0 --- /dev/null +++ b/support/tools/genvm-tool/unit_tests/test_codegen_detail_suffix.py @@ -0,0 +1,94 @@ +"""A ``#`` trie entry becomes a detail suffix on the built value, not a path.""" + +import pytest +from genvm_tool.codegen import go, model, python, rst, rust + +DATA = [ + { + 'type': 'str_trie', + 'name': 'vm_error', + 'values': [ + 'timeout', + {'head': 'out_of', 'tail': ['memory']}, + {'head': '#', 'tail': ['internal', 'external']}, + ], + } +] + + +@pytest.fixture +def defs(): + return model.parse(DATA) + + +def test_suffix_is_kept_out_of_the_path_trie(defs): + (trie,) = defs + assert [head for head, _ in trie.root.methods] == ['out_of'] + assert [path for path, _ in model.enumerate_paths(trie.entries)] == [ + 'timeout', + 'out_of memory', + ] + assert [name for name, _ in trie.suffix.leaves] == ['internal', 'external'] + + +def test_rust_emits_detail_methods_on_the_value(defs): + out = rust.render(defs) + for name in ('internal', 'external'): + assert ( + f'pub fn {name}(self) -> Self ' + '{ assert!(!self.0.contains(" # "), "a value carries at most one detail"); ' + f'Self(Cow::Owned(format!("{{}} # {name}", self.0))) }}' in out + ) + + +def test_every_backend_refuses_to_stack_two_details(defs): + assert out_has_guard(rust.render(defs)) + assert out_has_guard(python.render(defs)) + assert out_has_guard(go.render(defs)) + assert 'strings' in go.render(defs) + + +def out_has_guard(out: str) -> bool: + return out.count(' # ') >= 2 and 'at most one detail' in out or "' # ' not in" in out + + +def test_a_detail_with_a_non_list_tail_is_rejected(): + data = [ + { + 'type': 'str_trie', + 'name': 'vm_error', + 'values': [{'head': '#', 'tail': [{'head': 'internal', 'tail': '$str'}]}], + } + ] + with pytest.raises(ValueError, match='nested'): + model.parse(data) + + +def test_rust_is_valid_ignores_details(defs): + out = rust.render(defs) + assert '"out_of memory"' in out + assert '# internal' not in out.split('pub fn is_valid_')[1] + + +def test_python_emits_detail_methods_on_the_value(defs): + out = python.render(defs) + assert "\tdef internal(self) -> 'VmError':\n" in out + assert "\t\treturn VmError(f'{self.value} # internal')\n" in out + + +def test_rst_documents_details_under_the_trie(defs): + out = rst.render(defs) + assert '``# internal``' in out + assert '``# external``' in out + + +def test_a_nested_detail_is_rejected(): + data = [ + { + 'type': 'str_trie', + 'name': 'vm_error', + 'values': [{'head': '#', 'tail': [{'head': 'a', 'tail': ['b']}]}], + } + ] + with pytest.raises(ValueError, match='nested'): + model.parse(data) diff --git a/support/tools/genvm-tool/unit_tests/test_fuzz_corpus.py b/support/tools/genvm-tool/unit_tests/test_fuzz_corpus.py new file mode 100644 index 00000000..90944777 --- /dev/null +++ b/support/tools/genvm-tool/unit_tests/test_fuzz_corpus.py @@ -0,0 +1,150 @@ +"""What a harvested blob becomes: a framed seed, in the corpus of its own line.""" + +import types + +import pytest +from genvm_tool import cmd_fuzz_corpus +from genvm_tool.misc import fuzz_input_name, fuzz_input_path + + +@pytest.fixture +def root(tmp_path): + """A repo with the split targets on v0.3 only, and calldata on both lines.""" + for line, targets in ( + ('0.3', ('executor/fuzz/runners-parse-raw', 'executor/fuzz/entry-data-raw')), + ('0.2', ()), + ): + for target in targets: + path = tmp_path / 'executors' / f'v{line}.x' / f'{target}.rs' + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text('fn main() {}') + decode = ( + tmp_path + / 'executors' + / f'v{line}.x' + / 'executor/crates/calldata/fuzz/genvm-common-decode.rs' + ) + decode.parent.mkdir(parents=True, exist_ok=True) + decode.write_text('fn main() {}') + return tmp_path + + +def _plan(root, *blobs, max_size=1024): + ctx = types.SimpleNamespace(root=root) + args = types.SimpleNamespace(max_size=max_size) + return cmd_fuzz_corpus._plan(ctx, args, iter(blobs)) + + +def _blob(kind, data, line='0.3'): + return cmd_fuzz_corpus.Blob(line=line, kind=kind, data=data, origin='') + + +def test_code_reaches_a_raw_target_verbatim(root): + plan = _plan(root, _blob('code', b'PK\x03\x04zip')) + + (corpus,) = plan.values() + assert ( + corpus.inputs == root / 'executors/v0.3.x/executor/fuzz/inputs-runners-parse-raw' + ) + ((name, data),) = corpus.seeds.items() + assert data == b'PK\x03\x04zip' + assert name == fuzz_input_name(data) + + +def test_a_line_that_has_not_split_still_gets_the_selector_byte(root): + """The un-split target reads its payload through `Arbitrary`, which eats a byte.""" + unsplit = root / 'executors/v0.2.x/executor/fuzz/runners-parse.rs' + unsplit.parent.mkdir(parents=True, exist_ok=True) + unsplit.write_text('fn main() {}') + + plan = _plan(root, _blob('code', b'PK\x03\x04zip', line='0.2')) + + (corpus,) = plan.values() + assert corpus.inputs == root / 'executors/v0.2.x/executor/fuzz/inputs-runners-parse' + ((_, data),) = corpus.seeds.items() + assert data == b'\x00PK\x03\x04zip' + + +def test_calldata_seeds_every_target_that_parses_it(root): + plan = _plan(root, _blob('calldata', b'\x00')) + + assert {corpus.inputs.name for corpus in plan.values()} == { + 'inputs-genvm-common-decode', + 'inputs-entry-data-raw', + } + assert all( + data == b'\x00' for corpus in plan.values() for data in corpus.seeds.values() + ) + + +def test_a_line_only_gets_the_targets_it_has(root): + plan = _plan(root, _blob('code', b'wasm', line='0.2')) + + assert plan == {} + + +def test_an_entry_the_corpus_already_holds_is_not_re_added(root): + inputs = root / 'executors/v0.3.x/executor/fuzz/inputs-entry-data-raw' + path = fuzz_input_path(inputs, fuzz_input_name(b'seen')) + path.parent.mkdir(parents=True) + path.write_bytes(b'seen') + + plan = _plan(root, _blob('calldata', b'seen'), _blob('calldata', b'seen')) + + assert plan[inputs].seeds == {} + assert plan[inputs].known == {fuzz_input_name(b'seen')} + + +def test_an_entry_left_unsharded_by_an_older_run_still_counts(root): + inputs = root / 'executors/v0.3.x/executor/fuzz/inputs-entry-data-raw' + inputs.mkdir() + inputs.joinpath(fuzz_input_name(b'seen')).write_bytes(b'seen') + + plan = _plan(root, _blob('calldata', b'seen')) + + assert plan[inputs].seeds == {} + + +def test_a_blob_a_curated_seed_already_holds_is_not_added(root): + """Curated names are free-form, so the blob is matched by content.""" + curated = root / 'executors/v0.3.x/executor/fuzz/inputs-entry-data-raw-curated' + curated.mkdir() + curated.joinpath('empty-calldata').write_bytes(b'seen') + + plan = _plan(root, _blob('calldata', b'seen')) + + inputs = root / 'executors/v0.3.x/executor/fuzz/inputs-entry-data-raw' + assert plan[inputs].seeds == {} + + +def test_an_oversized_blob_is_dropped(root, capsys): + plan = _plan(root, _blob('code', b'x' * 100), max_size=10) + + assert plan == {} + assert 'over --max-size' in capsys.readouterr().out + + +def test_a_blob_carrying_a_host_path_is_dropped(root, capsys): + plan = _plan(root, _blob('code', b'\x00asm' + str(root).encode())) + + assert plan == {} + assert str(root) in capsys.readouterr().out + + +def test_case_line_names_the_executor_the_artifact_came_from(tmp_path): + cases = tmp_path / 'cases' + assert ( + cmd_fuzz_corpus._case_line(cases / 'executors/v0.3.x/tests/x/config.json', cases) + == '0.3' + ) + assert cmd_fuzz_corpus._case_line(cases / 'tests/system/x/config.json', cases) is None + + +def test_a_wat_case_yields_the_module_the_run_compiled(tmp_path): + case_dir = tmp_path / 'case' + case_dir.mkdir() + case_dir.joinpath('contract.wasm').write_bytes(b'\0asm') + + conf = {'code': str(tmp_path / 'src' / 'contract.wat')} + assert cmd_fuzz_corpus._code_path(conf, case_dir) == case_dir / 'contract.wasm' + assert cmd_fuzz_corpus._code_path({}, case_dir) is None diff --git a/support/tools/genvm-tool/unit_tests/test_fuzz_corpus_layout.py b/support/tools/genvm-tool/unit_tests/test_fuzz_corpus_layout.py new file mode 100644 index 00000000..29537fd0 --- /dev/null +++ b/support/tools/genvm-tool/unit_tests/test_fuzz_corpus_layout.py @@ -0,0 +1,27 @@ +"""Where a corpus entry is written, and what counts as one when reading back.""" + +from genvm_tool.misc import fuzz_corpus_entries, fuzz_input_name, fuzz_input_path + + +def test_an_entry_is_sharded_by_the_first_two_characters_of_its_name(tmp_path): + name = fuzz_input_name(b'payload') + + assert fuzz_input_path(tmp_path, name) == tmp_path / name[0] / name[1] / name + + +def test_reading_a_corpus_takes_sharded_and_unsharded_entries(tmp_path): + sharded = fuzz_input_path(tmp_path, fuzz_input_name(b'new')) + sharded.parent.mkdir(parents=True) + sharded.write_bytes(b'new') + tmp_path.joinpath(fuzz_input_name(b'old')).write_bytes(b'old') + tmp_path.joinpath('.hidden').write_bytes(b'') + tmp_path.joinpath('README.txt').write_bytes(b'') + + assert {entry.name for entry in fuzz_corpus_entries(tmp_path)} == { + fuzz_input_name(b'new'), + fuzz_input_name(b'old'), + } + + +def test_a_corpus_that_does_not_exist_yet_is_empty(tmp_path): + assert fuzz_corpus_entries(tmp_path / 'inputs-nothing') == [] diff --git a/support/tools/genvm-tool/unit_tests/test_process_teardown.py b/support/tools/genvm-tool/unit_tests/test_process_teardown.py new file mode 100644 index 00000000..d6500e41 --- /dev/null +++ b/support/tools/genvm-tool/unit_tests/test_process_teardown.py @@ -0,0 +1,90 @@ +"""Ending a service must not depend on a reap landing or a pipe reaching EOF.""" + +import asyncio + +from genvm_tool.tests.exec import process + + +class _Process: + """A process that ignores every signal and is never reaped.""" + + returncode = None + + def __init__(self): + self.terminated = False + self.killed = False + + def terminate(self): + self.terminated = True + + def kill(self): + self.killed = True + + async def wait(self): + await asyncio.Event().wait() + + +class _ExitingProcess(_Process): + async def wait(self): + self.returncode = 0 + return 0 + + +def test_a_process_that_exits_is_not_killed(): + proc = _ExitingProcess() + asyncio.run(process.stop(proc)) + assert proc.terminated + assert not proc.killed + + +def test_an_unreapable_process_does_not_wedge_teardown(): + proc = _Process() + + async def go(): + await asyncio.wait_for( + process.stop(proc, terminate_timeout=0.1, kill_timeout=0.1), timeout=5 + ) + + asyncio.run(go()) + assert proc.killed + + +def test_a_vanished_process_is_not_an_error(): + class _Gone(_Process): + def terminate(self): + raise ProcessLookupError + + asyncio.run(process.stop(_Gone())) + + +def test_readers_that_never_see_eof_are_cancelled(): + async def go(): + tasks = [asyncio.create_task(asyncio.Event().wait()) for _ in range(2)] + await asyncio.wait_for(process.drain(tasks, timeout=0.1), timeout=5) + return tasks + + tasks = asyncio.run(go()) + assert all(task.cancelled() for task in tasks) + + +def test_a_reader_that_finished_is_left_alone(): + async def go(): + tasks = [asyncio.create_task(asyncio.sleep(0))] + await process.drain(tasks, timeout=5) + return tasks + + tasks = asyncio.run(go()) + assert all(task.done() and not task.cancelled() for task in tasks) + + +def test_a_reader_that_raised_does_not_warn(): + async def boom(): + raise RuntimeError('log write failed') + + async def go(): + tasks = [asyncio.create_task(boom())] + await process.drain(tasks, timeout=5) + # retrieved by drain, so nothing resurfaces at collection time + assert tasks[0].exception() is not None + + asyncio.run(go()) diff --git a/support/tools/genvm-tool/unit_tests/test_service_semaphores.py b/support/tools/genvm-tool/unit_tests/test_service_semaphores.py new file mode 100644 index 00000000..f5d5a1f1 --- /dev/null +++ b/support/tools/genvm-tool/unit_tests/test_service_semaphores.py @@ -0,0 +1,356 @@ +from argparse import Namespace + +import genvm_tool.tests +from genvm_tool.tests.stage import scheduling +from genvm_tool.tests.stage.collection import Env, Semaphore, Service + + +class _Service(genvm_tool.tests.exec.service.Service): + async def start(self): + raise NotImplementedError + + +def _case( + name: str, + service: Service | None, + *, + depends_on: frozenset[str] = frozenset(), + console_pool: bool = False, +): + return genvm_tool.tests.test.StepsCase( + description=genvm_tool.tests.test.Description( + name=name, + needed_services=frozenset() if service is None else frozenset({service}), + depends_on=depends_on, + console_pool=console_pool, + ), + steps=[], + ) + + +def _service_action_index(actions, action_type, service): + return next( + index + for index, action in enumerate(actions) + if isinstance(action, action_type) and action.service is service + ) + + +def test_mutually_exclusive_services_do_not_overlap(): + semaphore = Semaphore('manager-listener') + first = Service('first', _Service(), semaphores=frozenset({semaphore}), order=0) + second = Service('second', _Service(), semaphores=frozenset({semaphore}), order=1) + + env = scheduling.run( + None, + Env( + cases=[_case('first-case', first), _case('second-case', second)], args=Namespace() + ), + ) + + actions = env.actions + stop_first = _service_action_index(actions, scheduling.StopService, first) + start_second = _service_action_index(actions, scheduling.StartService, second) + assert stop_first < start_second + assert isinstance(actions[stop_first - 1], scheduling.AwaitAllCases) + + +def test_dependents_finish_before_conflicting_service_starts(): + semaphore = Semaphore('manager-listener') + manager = Service('manager', _Service(), semaphores=frozenset({semaphore}), order=0) + replacement = Service( + 'replacement', _Service(), semaphores=frozenset({semaphore}), order=1 + ) + webdriver = Service('webdriver', _Service(), order=2) + modules = Service('modules', _Service(), depends_on=[manager, webdriver], order=3) + + env = scheduling.run( + None, + Env( + cases=[_case('integration', modules), _case('replacement-case', replacement)], + args=Namespace(), + ), + ) + + actions = env.actions + start_modules = _service_action_index(actions, scheduling.StartService, modules) + stop_modules = _service_action_index(actions, scheduling.StopService, modules) + stop_manager = _service_action_index(actions, scheduling.StopService, manager) + start_replacement = _service_action_index( + actions, scheduling.StartService, replacement + ) + stop_webdriver = _service_action_index(actions, scheduling.StopService, webdriver) + assert start_modules < stop_manager + assert stop_modules < stop_manager + assert stop_manager < start_replacement + assert start_replacement < stop_webdriver + + +def test_case_cannot_require_mutually_exclusive_services(): + semaphore = Semaphore('manager-listener') + first = Service('first', _Service(), semaphores=frozenset({semaphore}), order=0) + second = Service('second', _Service(), semaphores=frozenset({semaphore}), order=1) + case = genvm_tool.tests.test.StepsCase( + description=genvm_tool.tests.test.Description( + name='impossible', + needed_services=frozenset({first, second}), + ), + steps=[], + ) + + try: + scheduling.run(None, Env(cases=[case], args=Namespace())) + except ValueError as exc: + assert 'mutually exclusive services' in str(exc) + else: + raise AssertionError('mutually exclusive service requirement was accepted') + + +def test_test_dependency_crosses_semaphore_transition(): + semaphore = Semaphore('manager-listener') + first = Service('first', _Service(), semaphores=frozenset({semaphore}), order=0) + second = Service('second', _Service(), semaphores=frozenset({semaphore}), order=1) + first_case = _case('first-case', first) + second_case = _case( + 'second-case', + second, + depends_on=frozenset({'first-case'}), + ) + + env = scheduling.run( + None, + Env(cases=[first_case, second_case], args=Namespace()), + ) + actions = env.actions + stop_first = _service_action_index(actions, scheduling.StopService, first) + start_second = _service_action_index(actions, scheduling.StartService, second) + assert isinstance(actions[stop_first - 1], scheduling.AwaitAllCases) + assert stop_first < start_second + + +def test_test_dependency_can_reverse_service_registration_order(): + semaphore = Semaphore('manager-listener') + dependent_service = Service( + 'dependent', + _Service(), + semaphores=frozenset({semaphore}), + order=0, + ) + prerequisite_service = Service( + 'prerequisite', + _Service(), + semaphores=frozenset({semaphore}), + order=1, + ) + prerequisite = _case('prerequisite-case', prerequisite_service) + dependent = _case( + 'dependent-case', + dependent_service, + depends_on=frozenset({'prerequisite-case'}), + ) + + env = scheduling.run( + None, + Env(cases=[dependent, prerequisite], args=Namespace()), + ) + actions = env.actions + stop_prerequisite = _service_action_index( + actions, + scheduling.StopService, + prerequisite_service, + ) + start_dependent = _service_action_index( + actions, + scheduling.StartService, + dependent_service, + ) + assert stop_prerequisite < start_dependent + + +def test_console_dependency_is_started_before_scheduler_waits(): + service = Service('service', _Service(), order=0) + prerequisite = _case('prerequisite', service, console_pool=True) + dependent = _case( + 'dependent', + service, + depends_on=frozenset({'prerequisite'}), + console_pool=True, + ) + + actions = scheduling.run( + None, + Env(cases=[dependent, prerequisite], args=Namespace()), + ).actions + # Waiting for a case whose dependency has not started yet never ends + batches: dict[int, list] = {} + started: set[str] = set() + for action in actions: + if isinstance(action, scheduling.StartCases): + batches[action.id] = action.cases + started.update(case.description.name for case in action.cases) + elif isinstance(action, scheduling.AwaitAllCases): + for case in batches[action.id]: + assert case.description.depends_on.issubset(started) + assert started == {'prerequisite', 'dependent'} + + +def test_console_case_waits_until_later_service_dependency_is_scheduled(): + console_service = Service('console-service', _Service(), order=0) + prerequisite_service = Service('prerequisite-service', _Service(), order=1) + prerequisite = _case('prerequisite', prerequisite_service) + dependent = _case( + 'dependent', + console_service, + depends_on=frozenset({'prerequisite'}), + console_pool=True, + ) + + actions = scheduling.run( + None, + Env(cases=[dependent, prerequisite], args=Namespace()), + ).actions + start_prerequisite_service = _service_action_index( + actions, + scheduling.StartService, + prerequisite_service, + ) + start_dependent = next( + index + for index, action in enumerate(actions) + if isinstance(action, scheduling.StartCases) and action.cases == [dependent] + ) + assert start_prerequisite_service < start_dependent + + +def test_no_service_console_case_waits_for_service_dependency(): + service = Service('service', _Service(), order=0) + prerequisite = _case('prerequisite', service) + dependent = _case( + 'dependent', + None, + depends_on=frozenset({'prerequisite'}), + console_pool=True, + ) + + actions = scheduling.run( + None, + Env(cases=[dependent, prerequisite], args=Namespace()), + ).actions + start_service = _service_action_index(actions, scheduling.StartService, service) + start_dependent = next( + index + for index, action in enumerate(actions) + if isinstance(action, scheduling.StartCases) and action.cases == [dependent] + ) + assert start_service < start_dependent + + +def test_case_cannot_depend_on_a_case_of_a_later_service(): + # `replacement` displaces `first`, so `early-case` is over before `last-case` + # can even start; waiting for it would hang the runner + semaphore = Semaphore('manager-listener') + first = Service('first', _Service(), semaphores=frozenset({semaphore}), order=0) + replacement = Service( + 'replacement', _Service(), semaphores=frozenset({semaphore}), order=1 + ) + unrelated = Service('unrelated', _Service(), order=2) + early = _case( + 'early-case', + first, + depends_on=frozenset({'last-case'}), + ) + + try: + scheduling.run( + None, + Env( + cases=[ + early, + _case('replacement-case', replacement), + _case('last-case', unrelated), + ], + args=Namespace(), + ), + ) + except ValueError as exc: + assert 'could not be scheduled' in str(exc) + else: + raise AssertionError('a case waiting for a case that runs later was accepted') + + +def test_semaphore_handover_order_is_chosen_across_semaphores(): + # `both` conflicts with either other service, so it has to run on its own; + # ordering the owners of one semaphore at a time claims that is impossible + left = Semaphore('left') + right = Semaphore('right') + first = Service('first', _Service(), semaphores=frozenset({right}), order=0) + both = Service('both', _Service(), semaphores=frozenset({left, right}), order=1) + dependent = Service( + 'dependent', + _Service(), + semaphores=frozenset({left}), + depends_on=[first], + order=2, + ) + + actions = scheduling.run( + None, + Env( + cases=[ + _case('first-case', first), + _case('both-case', both), + _case('dependent-case', dependent), + ], + args=Namespace(), + ), + ).actions + start_first = _service_action_index(actions, scheduling.StartService, first) + start_dependent = _service_action_index(actions, scheduling.StartService, dependent) + stop_dependent = _service_action_index(actions, scheduling.StopService, dependent) + start_both = _service_action_index(actions, scheduling.StartService, both) + assert start_first < start_dependent + assert stop_dependent < start_both + + +def test_crossed_semaphore_dependencies_are_orderable(): + # Each semaphore's owners can be handed over in one order only, and the two + # orders are opposite: the second `left` owner depends on the second `right` + # one and vice versa + left = Semaphore('left') + right = Semaphore('right') + first_left = Service('first-left', _Service(), semaphores=frozenset({left}), order=0) + first_right = Service( + 'first-right', _Service(), semaphores=frozenset({right}), order=1 + ) + second_left = Service( + 'second-left', + _Service(), + semaphores=frozenset({left}), + depends_on=[first_right], + order=2, + ) + second_right = Service( + 'second-right', + _Service(), + semaphores=frozenset({right}), + depends_on=[first_left], + order=3, + ) + + services = [first_left, first_right, second_left, second_right] + actions = scheduling.run( + None, + Env( + cases=[_case(f'{service.name}-case', service) for service in services], + args=Namespace(), + ), + ).actions + started = [ + action.service for action in actions if isinstance(action, scheduling.StartService) + ] + assert set(started) == set(services) + for service in services: + start = _service_action_index(actions, scheduling.StartService, service) + for dependency in service.depends_on or []: + stop = _service_action_index(actions, scheduling.StopService, dependency) + assert start < stop diff --git a/support/tools/genvm-tool/unit_tests/test_service_startup.py b/support/tools/genvm-tool/unit_tests/test_service_startup.py new file mode 100644 index 00000000..4d999b09 --- /dev/null +++ b/support/tools/genvm-tool/unit_tests/test_service_startup.py @@ -0,0 +1,79 @@ +"""A service that never comes up must not wedge the run.""" + +import asyncio + +import pytest +from genvm_tool.tests.exec import service + + +class _Handle(service.Handle): + STARTUP_TIMEOUT = 0.3 + INTERRUPT_TIMEOUT = 0.2 + + def __init__(self, *, healthy_after: int = 10**9, reason: str | None = None): + self.probes = 0 + self.interrupted = False + self._healthy_after = healthy_after + self._reason = reason + + async def healthy(self) -> bool: + self.probes += 1 + return self.probes >= self._healthy_after + + async def death_reason(self) -> str | None: + return self._reason + + async def interrupt(self) -> None: + self.interrupted = True + + +class _WedgedHandle(_Handle): + async def interrupt(self) -> None: + await asyncio.Event().wait() + + +def test_a_healthy_service_is_not_torn_down(): + handle = _Handle(healthy_after=1) + assert asyncio.run(handle.await_startup()) is handle + assert not handle.interrupted + + +def test_startup_gives_up_on_its_own_deadline(): + handle = _Handle() + with pytest.raises(RuntimeError, match='not healthy within'): + asyncio.run(handle.await_startup()) + assert handle.interrupted + + +def test_a_dead_service_is_not_waited_out(): + handle = _Handle(reason='exited with code 1') + with pytest.raises(RuntimeError, match='exited with code 1'): + asyncio.run(handle.await_startup()) + assert handle.probes == 0 + + +def test_shutdown_outlives_a_hanging_interrupt(): + async def go(): + with pytest.raises(RuntimeError, match='did not stop'): + await asyncio.wait_for(_WedgedHandle().shutdown(), timeout=5) + + asyncio.run(go()) + + +def test_a_hanging_interrupt_does_not_mask_the_startup_failure(): + async def go(): + with pytest.raises(RuntimeError, match='not healthy within.*teardown failed too'): + await asyncio.wait_for(_WedgedHandle().await_startup(), timeout=5) + + asyncio.run(go()) + + +def test_a_wedged_probe_cannot_outlive_the_deadline(): + class _WedgedProbe(_Handle): + async def healthy(self) -> bool: + await asyncio.Event().wait() + + handle = _WedgedProbe() + with pytest.raises(RuntimeError, match='not healthy within'): + asyncio.run(asyncio.wait_for(handle.await_startup(), timeout=5)) + assert handle.interrupted diff --git a/support/tools/genvm-tool/unit_tests/test_watchdog_ack.py b/support/tools/genvm-tool/unit_tests/test_watchdog_ack.py new file mode 100644 index 00000000..3f96e68d --- /dev/null +++ b/support/tools/genvm-tool/unit_tests/test_watchdog_ack.py @@ -0,0 +1,55 @@ +"""A watchdog that stops answering must not block the thread that asked it.""" + +import contextlib +import os +import time +import types + +import pytest +from genvm_tool.tests.util import watchdog + + +@pytest.fixture +def pipe(): + read_fd, write_fd = os.pipe() + reader = os.fdopen(read_fd, 'rb') + try: + yield reader, write_fd + finally: + reader.close() + # a test may have closed the write end itself, to signal EOF + with contextlib.suppress(OSError): + os.close(write_fd) + + +def _dog(reader, *, timeout: float = 5.0) -> watchdog.Watchdog: + dog = watchdog.Watchdog(types.SimpleNamespace(stdout=reader)) + dog.ACK_TIMEOUT = timeout + return dog + + +def test_a_silent_watchdog_times_out(pipe): + reader, _write_fd = pipe + dog = _dog(reader, timeout=0.2) + start = time.monotonic() + # the write end stays open, so this can only end on the deadline + assert dog._await_ack(1) is False + assert time.monotonic() - start < 5 + + +def test_the_matching_ack_is_accepted(pipe): + reader, write_fd = pipe + os.write(write_fd, b'7\n') + assert _dog(reader)._await_ack(7) is True + + +def test_stale_acks_are_skipped(pipe): + reader, write_fd = pipe + os.write(write_fd, b'3\n7\n') + assert _dog(reader)._await_ack(7) is True + + +def test_a_closed_pipe_is_not_mistaken_for_an_ack(pipe): + reader, write_fd = pipe + os.close(write_fd) + assert _dog(reader)._await_ack(1) is False diff --git a/tests/presets/python-fuzz.txt b/tests/presets/python-fuzz.txt new file mode 100644 index 00000000..4efb4837 --- /dev/null +++ b/tests/presets/python-fuzz.txt @@ -0,0 +1 @@ +python & needs-fuzz diff --git a/tests/presets/python.txt b/tests/presets/python.txt index fdc793e7..b215238b 100644 --- a/tests/presets/python.txt +++ b/tests/presets/python.txt @@ -1 +1 @@ -python +python & !needs-fuzz diff --git a/tests/runner/genvm_tool_plugins/afl.py b/tests/runner/genvm_tool_plugins/afl.py new file mode 100644 index 00000000..10ded7ae --- /dev/null +++ b/tests/runner/genvm_tool_plugins/afl.py @@ -0,0 +1,594 @@ +import asyncio +import atexit +import collections.abc +import contextlib +import functools +import math +import os +import shutil +import signal +import tempfile +import typing +from pathlib import Path + +import genvm_tool.tests + +Command = collections.abc.Sequence[str | Path] +Wrapper = collections.abc.Callable[[Command], Command] + +# Secondaries outlive their step only if it never finishes — a cancelled case, +# `--fail-fast`, Ctrl-C. `run_steps` has no cleanup hook, so the fleet is bounded +# by its own `-V` and, when the tool itself goes away, by this +_live: set[asyncio.subprocess.Process] = set() + + +@atexit.register +def _stop_live_fuzzers() -> None: + for process in list(_live): + if process.returncode is None: + with contextlib.suppress(OSError): + process.send_signal(signal.SIGINT) + _live.clear() + + +# What a fuzzing run wants and a minimization run must not have: `cmin` measures +# one input per run through `afl-showmap`, and these either steer `afl-fuzz` +# alone or (`AFL_FUZZER_LOOPCOUNT`) make the target loop instead of returning +FUZZ_ONLY_ENV = ( + 'AFL_AUTORESUME', + 'AFL_BENCH_UNTIL_CRASH', + 'AFL_FUZZER_LOOPCOUNT', + 'AFL_NO_FASTRESUME', + 'AFL_TRY_AFFINITY', +) + + +def register(ctx: genvm_tool.tests.stage.configuration.Context) -> None: + ctx.run_parser.add_argument( + '--fuzz-timeout', + type=str, + default='30s', + help='Timeout for each fuzzing run (e.g. 30s, 5m, 1h)', + ) + ctx.run_parser.add_argument( + '--fuzz-jobs', + type=int, + default=0, + help='Fuzzer processes per target, defaults to the cores left over by --fuzz-concurrent', + ) + ctx.run_parser.add_argument( + '--fuzz-concurrent', + type=int, + default=0, + help='Fuzz targets to run side by side, defaults to the core count minus two. ' + 'Above one there is no AFL console, only the logs', + ) + ctx.run_parser.add_argument( + '--fuzz-update-corpus', + default=False, + action='store_true', + help='Whether to update the fuzzing corpus', + ) + + +def _budget() -> int: + """Cores this machine is willing to hand to fuzzing.""" + return max(1, (os.cpu_count() or 1) - 2) + + +@functools.cache +def concurrent(ctx: genvm_tool.tests.stage.collection.Context) -> int: + """ + How many fuzz targets may run at once. + + Different targets are worth more than instances of one: a fleet only shares + its corpus every `AFL_SYNC_TIME`, so below that it is one search duplicated, + while another target explores code the first one never reaches. + """ + # `test show` builds cases without the `run` parser, so the flags may be absent + requested = getattr(ctx.configuration.args, 'fuzz_concurrent', 0) + source = '--fuzz-concurrent' + if requested <= 0: + requested = _budget() + source = f'os.cpu_count() - 2 = {requested}' + ctx.shared.logger.info('Concurrent fuzz targets', count=requested, source=source) + return requested + + +@functools.cache +def jobs(ctx: genvm_tool.tests.stage.collection.Context) -> int: + requested = getattr(ctx.configuration.args, 'fuzz_jobs', 0) + source = '--fuzz-jobs' + if requested <= 0: + requested = max(1, min(8, _budget() // concurrent(ctx))) + source = f'(os.cpu_count() - 2) // {concurrent(ctx)}' + ctx.shared.logger.info('Fuzz jobs', count=requested, source=source) + return requested + + +def pool_usage(ctx: genvm_tool.tests.stage.collection.Context) -> dict[str, typing.Any]: + """ + How a fuzz case takes the case pool. + + A lone target owns the console and therefore the whole pool; several of them + share it, each holding as many permits as it starts fuzzer processes. + """ + solo = concurrent(ctx) == 1 + return {'console_pool': solo, 'permits': 1 if solo else jobs(ctx)} + + +def timeout(ctx: genvm_tool.tests.stage.collection.Context) -> int: + value = str(getattr(ctx.configuration.args, 'fuzz_timeout', '30s')) + return max(1, math.ceil(genvm_tool.misc.parse_duration(value))) + + +def environment(base: dict[str, str]) -> dict[str, str]: + """``base`` plus the AFL knobs every target shares.""" + env = dict(base) + env.update( + { + # The output dir is reused so a rerun continues the search; without + # this AFL refuses to start on it. NB it then reads its own queue and + # ignores `-i`, so a corpus update only takes effect after the output + # dir is removed + 'AFL_AUTORESUME': '1', + # Stop *successfully* on the first saved crash, so a finding is + # reported by `fleet_steps` rather than by the exit code + 'AFL_BENCH_UNTIL_CRASH': '1', + 'AFL_FUZZER_LOOPCOUNT': '20', # without it no coverage will be written! + 'AFL_NO_CFG_FUZZING': '1', + # The fast-resume cache was observed to fail the next run with `Bad + # file descriptor` after a fleet was interrupted + 'AFL_NO_FASTRESUME': '1', + # Persistent mode carries state across iterations, so calibration + # reports most of the corpus as unstable; the warning is pure noise + 'AFL_NO_WARN_INSTABILITY': '1', + # A fleet wants a core each, and AFL aborts rather than share one; on + # a busy machine an unbound instance is still better than a failed case + 'AFL_TRY_AFFINITY': '1', + } + ) + return env + + +def output_dir( + shared: genvm_tool.tests.SharedContext, project_dir: Path, name: str +) -> Path: + """ + Where one target's AFL output lives. + + Keyed by project, not by target name alone: the executor lines share fuzz + target stems, and one output dir per stem would mix their corpora — which + `cmin` then writes back into the committed inputs. + """ + return shared.artifacts_dir / 'fuzz' / project_dir.relative_to(shared.root_dir) / name + + +def current_umask() -> int: + mask = os.umask(0) + os.umask(mask) + return mask + + +def saved_findings(path: Path) -> list[Path]: + """Inputs AFL saved in one of its finding dirs, minus the README it drops there.""" + if not path.is_dir(): + return [] + return sorted( + entry + for entry in path.iterdir() + if entry.is_file() and entry.name != 'README.txt' and not entry.name.startswith('.') + ) + + +def curated_dir(inputs_dir: Path) -> Path: + """ + Where a target's hand-written seeds live, beside its generated corpus. + + Not in it: a corpus update replaces that dir with a `cmin` of the queue, and a + seed someone wrote to pin a format down has to survive the run that decides it + is redundant. Names here are free-form, they are for humans to read. + """ + return inputs_dir.parent / f'{inputs_dir.name}-curated' + + +def curated_inputs(inputs_dir: Path) -> dict[str, bytes]: + """Curated seeds of a target, keyed by the name the corpus would give them.""" + result: dict[str, bytes] = {} + for entry in saved_findings(curated_dir(inputs_dir)): + data = entry.read_bytes() + result[genvm_tool.misc.fuzz_input_name(data)] = data + return result + + +def add_to_corpus( + inputs_dir: Path, findings: collections.abc.Iterable[Path] +) -> list[str]: + """ + Commit findings as generated corpus entries, under the names a corpus uses. + + A crash is only replayed by a later run if some dir handed to `-i` holds it, + and the output dir it was saved in is wiped by the next run's crash reset. + """ + known = set(curated_inputs(inputs_dir)) | { + entry.name for entry in genvm_tool.misc.fuzz_corpus_entries(inputs_dir) + } + added: list[str] = [] + for entry in findings: + data = entry.read_bytes() + name = genvm_tool.misc.fuzz_input_name(data) + if name in known: + continue + path = genvm_tool.misc.fuzz_input_path(inputs_dir, name) + path.parent.mkdir(parents=True, exist_ok=True) + path.write_bytes(data) + known.add(name) + added.append(name) + return added + + +def fleet_steps( + ctx: genvm_tool.tests.stage.collection.Context, + *, + cwd: Path, + env: dict[str, str], + inputs_dir: Path, + out_dir: Path, + launcher: Command, + target: Command, + extra_args: Command = (), + wrap: Wrapper = lambda argv: argv, + prepare_command: Command | None = None, + status_command: Command | None = None, + replay: str | None = None, +) -> list[genvm_tool.tests.exec.step.Step]: + """ + Steps running one AFL fleet over ``target`` and reporting what it saved. + + One `-M` plus N-1 `-S` instances share ``out_dir`` and sync their corpora + through it, so the whole fleet is one case with one verdict. ``wrap`` gets + the last word on the argv, for a launcher that has to be reached through a + shell (the Python env, say). + """ + instances = ['main'] + [f'sec{i}' for i in range(1, jobs(ctx))] + secondaries: list[tuple[asyncio.subprocess.Process, typing.IO[bytes]]] = [] + watchdog_tokens: dict[int, int] = {} + # AFL takes one `-i`, so the two committed dirs are staged into one + seeds_dir = out_dir.parent / f'{out_dir.name}-seeds' + # Targets sharing the terminal cannot each draw a full-screen UI, so with more + # than one in flight nobody does and `main` is read from its log like the rest + solo = concurrent(ctx) == 1 + env = dict(env) if solo else {**env, 'AFL_NO_UI': '1'} + + def command(role: str, instance: str) -> Command: + return wrap( + [ + *launcher, + # CmpLog needs a second instrumented binary and buys little on + # these targets, see the fuzzing explanation page + '-c', + '-', + role, + instance, + '-i', + seeds_dir, + '-o', + out_dir, + '-V', + str(timeout(ctx)), + *extra_args, + *target, + ] + ) + + def crash_dirs() -> list[Path]: + # Globbed, not derived from `instances`: a run with fewer jobs than the + # last one still has to account for what the wider fleet left behind + return sorted(out_dir.glob('*/crashes')) + + async def stage_seeds(_) -> genvm_tool.tests.test.Result | None: + # Rebuilt every run: a curated seed added since the last one has to reach + # `-i`, and one removed from either dir must not linger + shutil.rmtree(seeds_dir, ignore_errors=True) + seeds_dir.mkdir(parents=True) + # Flattened: the corpus is sharded by name, and AFL is happier with one dir + for entry in genvm_tool.misc.fuzz_corpus_entries(inputs_dir): + shutil.copyfile(entry, seeds_dir / entry.name) + for name, data in curated_inputs(inputs_dir).items(): + seeds_dir.joinpath(name).write_bytes(data) + + staged = saved_findings(seeds_dir) + # A result either way: this is the first step, so the error check after it + # has nothing else to read + return genvm_tool.tests.test.Result( + passed=bool(staged), + context={'error': f'no seeds in {inputs_dir} or {curated_dir(inputs_dir)}'} + if not staged + else {'seeds': len(staged)}, + elapsed_seconds=0, + ) + + async def drop_previous_crashes(_): + # The verdict below describes this run. AFL keeps what earlier ones saved, + # and the output dir is deliberately reused so fuzzing resumes rather than + # restarts + for path in crash_dirs(): + shutil.rmtree(path, ignore_errors=True) + + async def stop(process: asyncio.subprocess.Process, log: typing.IO[bytes]) -> None: + try: + if process.returncode is None: + # AFL writes its queue out on SIGINT, so the next run resumes + process.send_signal(signal.SIGINT) + else: + # It was gone before the fleet was stopped, so it never fuzzed for + # its whole `-V`; the case still passes on `main` alone + ctx.shared.logger.warning( + 'a fuzz secondary exited early', + returncode=process.returncode, + log=str(getattr(log, 'name', '')), + ) + try: + await asyncio.wait_for(process.wait(), timeout=30) + except TimeoutError: + process.kill() + await process.wait() + finally: + log.close() + _live.discard(process) + token = watchdog_tokens.pop(process.pid, None) + if token is not None: + ctx.shared.watchdog.unregister(token) + + async def start_secondaries(_): + # The console, when there is one, belongs to `main`; the others write to a + # log next to their queue instead. They exit on their own `-V`; the stop + # step is for the run that ends early, on a crash or a failure of `main` + try: + for instance in instances[1:]: + log = (out_dir / f'{instance}.log').open('wb') + try: + process = await asyncio.create_subprocess_exec( + *command('-S', instance), + cwd=cwd, + env=env, + stdin=asyncio.subprocess.DEVNULL, + stdout=log, + stderr=asyncio.subprocess.STDOUT, + ) + except BaseException: + log.close() + raise + secondaries.append((process, log)) + _live.add(process) + # `_live` only covers an orderly exit; a fleet outliving a killed + # tool is what the watchdog is for + watchdog_tokens[process.pid] = ctx.shared.watchdog.register( + genvm_tool.tests.exec.command.kill_process_cleanup(process.pid) + ) + except BaseException: + # A half-started fleet would otherwise hold its cores and its output + # dir for the rest of the suite + for process, log in secondaries: + await stop(process, log) + secondaries.clear() + raise + + async def stop_secondaries(previous_results: list[typing.Any]) -> typing.Any: + for process, log in secondaries: + try: + await stop(process, log) + except Exception as error: + # One instance that will not die must not strand the others + ctx.shared.logger.warning('could not stop a fuzz secondary', error=error) + secondaries.clear() + # `CommandToResultStep` reads the step before it, which must stay the + # command result of `main` + return previous_results[-1] + + async def save_main_log(previous_results: list[typing.Any]) -> typing.Any: + result = previous_results[-1] + assert isinstance(result, genvm_tool.tests.exec.command.Result) + # Without the console `main`'s output is only in the case log, next to + # everything else; the fleet's own logs are what one reads afterwards + (out_dir / 'main.log').write_text(result.stdout + result.stderr) + return result + + async def report_findings( + previous_results: list[typing.Any], + ) -> genvm_tool.tests.test.Result: + result = previous_results[-1] + assert isinstance(result, genvm_tool.tests.test.Result) + + crashes = [crash for path in crash_dirs() for crash in saved_findings(path)] + context = dict(result.context) + if crashes: + context['crashes'] = [str(crash) for crash in crashes] + if replay is not None: + context['replay'] = replay + added = add_to_corpus(inputs_dir, crashes) + if added: + context['corpus'] = f'{len(added)} crash(es) added to {inputs_dir}' + if status_command is not None and len(instances) > 1: + # `-M`'s console shows that instance alone, so the fleet is invisible + # without asking for the aggregate + try: + process = await asyncio.create_subprocess_exec( + *status_command, + cwd=cwd, + env=env, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.DEVNULL, + ) + summary, _ = await process.communicate() + context['fleet'] = ( + summary.decode(errors='replace') + if process.returncode == 0 + else f'{status_command[0]} exited with {process.returncode}' + ) + except OSError as error: + # A status tool that cannot run must not turn a clean run into a + # failure + context['fleet'] = f'{status_command[0]}: {error}' + + return genvm_tool.tests.test.Result( + passed=result.passed and not crashes, + context=context, + elapsed_seconds=result.elapsed_seconds, + ) + + return [ + genvm_tool.tests.exec.step.SetCwd(path=cwd), + *[genvm_tool.tests.exec.step.SetEnv(key=k, value=v) for k, v in env.items()], + genvm_tool.tests.exec.step.MkDir(path=out_dir), + genvm_tool.tests.exec.step.PythonFunction(stage_seeds), + genvm_tool.tests.test.ResultStopIfErrorStep(), + genvm_tool.tests.exec.step.PythonFunction(drop_previous_crashes), + *( + [] + if prepare_command is None + else [ + genvm_tool.tests.exec.step.Run( + args=prepare_command, + mode=genvm_tool.tests.exec.command.RunMode.INTERACTIVE, + ), + genvm_tool.tests.test.CommandToResultStep(), + genvm_tool.tests.test.ResultStopIfErrorStep(), + ] + ), + genvm_tool.tests.exec.step.PythonFunction(start_secondaries), + genvm_tool.tests.exec.step.Run( + # A lone instance runs as `-S`: `-M` would add the deterministic + # stage, which a short budget cannot afford + args=command('-M' if len(instances) > 1 else '-S', 'main'), + mode=genvm_tool.tests.exec.command.RunMode.INTERACTIVE_TTY + if solo + else genvm_tool.tests.exec.command.RunMode.SILENT, + ), + *([] if solo else [genvm_tool.tests.exec.step.PythonFunction(save_main_log)]), + genvm_tool.tests.exec.step.PythonFunction(stop_secondaries), + genvm_tool.tests.test.CommandToResultStep(), + # Findings are reported before the abort check, so a run that crashed and + # then failed still names the crash + genvm_tool.tests.exec.step.PythonFunction(report_findings), + genvm_tool.tests.test.ResultStopIfErrorStep(), + ] + + +def corpus_update_steps( + ctx: genvm_tool.tests.stage.collection.Context, + *, + inputs_dir: Path, + out_dir: Path, + cmin_command: collections.abc.Callable[[Path, Path], Command], + unset_env: collections.abc.Sequence[str] = (), +) -> list[genvm_tool.tests.exec.step.Step]: + """ + Steps replacing the committed corpus with a `cmin` of what the fleet found. + + ``cmin_command`` is given the input and the output dir, in that order. These + steps go after `fleet_steps`, whose cwd and environment they reuse. + """ + if not getattr(ctx.configuration.args, 'fuzz_update_corpus', False): + return [] + + opt_dir = out_dir.parent / f'{out_dir.name}-opt' + # `cmin` walks its input dir recursively and skips only dotfiles, so it would + # otherwise mistake crashes and instance logs for corpus entries + queue_dir = out_dir.parent / f'{out_dir.name}-queue' + + async def prepare(_) -> genvm_tool.tests.test.Result | None: + for path in (opt_dir, queue_dir): + shutil.rmtree(path, ignore_errors=True) + path.mkdir(parents=True) + + for entry in sorted(out_dir.glob('*/queue/*')): + if not entry.is_file() or entry.name.startswith('.'): + continue + data = entry.read_bytes() + queue_dir.joinpath(genvm_tool.misc.fuzz_input_name(data)).write_bytes(data) + + if not any(queue_dir.iterdir()): + return genvm_tool.tests.test.Result( + passed=False, + context={'error': f'no queue entries under {out_dir}'}, + elapsed_seconds=0, + ) + return None + + async def replace(_) -> genvm_tool.tests.test.Result: + minimized = saved_findings(opt_dir) + # A curated seed is fed to every run, so `cmin` keeps it whenever it is + # worth keeping; written back it would be committed twice + curated = set(curated_inputs(inputs_dir)) + kept: dict[str, bytes] = {} + for entry in minimized: + data = entry.read_bytes() + name = genvm_tool.misc.fuzz_input_name(data) + if name not in curated: + kept[name] = data + + if not minimized: + # The old corpus is the only copy of the seeds someone wrote by hand, + # so an empty minimization is a failure, not a reason to delete it + return genvm_tool.tests.test.Result( + passed=False, + context={'error': f'cmin produced no inputs in {opt_dir}'}, + elapsed_seconds=0, + ) + + inputs_dir.parent.mkdir(parents=True, exist_ok=True) + staged = Path( + tempfile.mkdtemp(prefix=f'.{inputs_dir.name}.new-', dir=inputs_dir.parent) + ) + # `mkdtemp` is 0700, and this directory ends up as the committed corpus + staged.chmod(0o777 & ~current_umask()) + backup: Path | None = None + try: + for name, data in kept.items(): + path = genvm_tool.misc.fuzz_input_path(staged, name) + path.parent.mkdir(parents=True, exist_ok=True) + path.write_bytes(data) + if inputs_dir.exists(): + backup = Path( + tempfile.mkdtemp(prefix=f'.{inputs_dir.name}.old-', dir=inputs_dir.parent) + ) + backup.rmdir() + inputs_dir.rename(backup) + try: + staged.rename(inputs_dir) + except BaseException as error: + if backup is not None: + try: + backup.rename(inputs_dir) + except OSError: + raise RuntimeError( + f'corpus swap failed and the old corpus is left in {backup}' + ) from error + raise + if backup is not None: + shutil.rmtree(backup, ignore_errors=True) + finally: + shutil.rmtree(staged, ignore_errors=True) + + context = {'corpus': f'{len(kept)} inputs written to {inputs_dir}'} + if len(kept) != len(minimized): + context['curated'] = ( + f'{len(minimized) - len(kept)} kept by {curated_dir(inputs_dir)}' + ) + return genvm_tool.tests.test.Result(passed=True, context=context, elapsed_seconds=0) + + return [ + genvm_tool.tests.exec.step.PythonFunction(prepare), + genvm_tool.tests.test.ResultStopIfErrorStep(), + *[genvm_tool.tests.exec.step.UnsetEnv(key=key) for key in FUZZ_ONLY_ENV], + *[genvm_tool.tests.exec.step.UnsetEnv(key=key) for key in unset_env], + genvm_tool.tests.exec.step.Run( + args=cmin_command(queue_dir, opt_dir), + mode=genvm_tool.tests.exec.command.RunMode.INTERACTIVE, + ), + genvm_tool.tests.test.CommandToResultStep(), + genvm_tool.tests.test.ResultStopIfErrorStep(), + genvm_tool.tests.exec.step.PythonFunction(replace), + genvm_tool.tests.test.ResultStopIfErrorStep(), + ] diff --git a/tests/runner/genvm_tool_plugins/cargo.py b/tests/runner/genvm_tool_plugins/cargo.py index 528fcf89..35884bf1 100644 --- a/tests/runner/genvm_tool_plugins/cargo.py +++ b/tests/runner/genvm_tool_plugins/cargo.py @@ -1,13 +1,15 @@ import json import os +import re import shutil import subprocess import sys from pathlib import Path import genvm_tool.tests +import genvm_tool_plugins.afl as afl import tomllib -from genvm_tool.tests.test import CONST_PASSED +from genvm_tool.tests import tags as test_tags local_ctx = genvm_tool.tests.stage.configuration.current_context() @@ -75,16 +77,6 @@ def _get_default_env() -> dict[str, str]: else: env['LLVM_PROFILE_FILE'] = '/dev/null' - env['AFL_FUZZER_LOOPCOUNT'] = '20' # without it no coverage will be written! - env['AFL_NO_CFG_FUZZING'] = '1' - env['AFL_BENCH_UNTIL_CRASH'] = '1' - # persistent mode carries state across iterations, so calibration reports - # most of the corpus as unstable; the warning is pure noise here - env['AFL_NO_WARN_INSTABILITY'] = '1' - # drops one "attempting dry run" line per corpus entry; seeds are calibrated - # lazily instead, so broken ones surface when they are first fuzzed - env['AFL_NO_STARTUP_CALIBRATION'] = '1' - return env @@ -235,11 +227,14 @@ def _artifact_dir(target_dir: Path) -> Path: def _load_cargo_config( - rust_root_dir: Path, flags_key: str = 'cargo_test_flags' -) -> tuple[dict, dict[str, str], list[str]]: - """Load .ya-test-config.json and return (config, env, extra_flags).""" + ctx: genvm_tool.tests.stage.collection.Context, + rust_root_dir: Path, + flags_key: str = 'cargo_test_flags', +) -> tuple[dict, dict[str, str], list[str], dict[str, list[str]]]: + """Load .ya-test-config.json and return config, env, flags and case tags.""" test_env = _get_default_env() extra_flags: list[str] = [] + case_tags: dict[str, list[str]] = {} extra_config = rust_root_dir.joinpath('.ya-test-config.json') extra_conf: dict = {} @@ -249,8 +244,21 @@ def _load_cargo_config( for name in extra_conf.get('keep_env', []): if name in os.environ: test_env[name] = os.environ[name] - - return extra_conf, test_env, extra_flags + raw_case_tags = extra_conf.get('tags', {}) + if not isinstance(raw_case_tags, dict): + raise ValueError(f'{extra_config}: tags must be an object') + for case_name, raw_tags in raw_case_tags.items(): + if case_name != 'lib' and not case_name.startswith('bin/'): + raise ValueError(f'{extra_config}: invalid tag target {case_name!r}') + if not isinstance(raw_tags, list) or not all( + isinstance(tag, str) for tag in raw_tags + ): + raise ValueError( + f'{extra_config}: tags for {case_name!r} must be a list of strings' + ) + case_tags[case_name] = _validate_declared_tags(ctx, extra_config, raw_tags) + + return extra_conf, test_env, extra_flags, case_tags def _add_cargo_case( @@ -279,8 +287,53 @@ def _add_cargo_case( ctx.add_case(case) +_TAGS_MARKER = 'genvm-tool-test-tags:' +_TAGS_LINE = re.compile(r'^\s*//[/!]?\s*genvm-tool-test-tags:\s*(?P.*?)\s*$') + + +def _tag_source_name(ctx: genvm_tool.tests.stage.collection.Context, path: Path) -> str: + try: + return str(path.relative_to(ctx.shared.root_dir)) + except ValueError: + return str(path) + + +def _validate_declared_tags( + ctx: genvm_tool.tests.stage.collection.Context, path: Path, tags: list[str] +) -> list[str]: + declared = frozenset(tags) + registry = ctx.shared.tags_registry + if registry is None: + return sorted(declared) + invalid = test_tags.unknown(registry, declared) + if invalid: + ctx.add_tag_offender(_tag_source_name(ctx, path), invalid) + return sorted(declared - invalid) + + +def _tags_from_source( + ctx: genvm_tool.tests.stage.collection.Context, path: Path +) -> list[str]: + """Extra tags declared by a `// genvm-tool-test-tags: a,b,c` comment.""" + tags: list[str] = [] + for line_number, line in enumerate(path.read_text().splitlines(), 1): + if not line.lstrip().startswith('//') or _TAGS_MARKER not in line: + continue + match = _TAGS_LINE.fullmatch(line) + if match is None: + ctx.add_tag_declaration_error( + f'{_tag_source_name(ctx, path)}:{line_number}', + f'malformed {_TAGS_MARKER} marker', + ) + continue + line_tags = [tag.strip() for tag in match.group('tags').split(',') if tag.strip()] + tags.extend(line_tags) + return _validate_declared_tags(ctx, path, tags) + + def _is_skipped(skip_conf, key: str, name: str | None = None) -> bool: - """Check if a test category or specific name is skipped. + """ + Check if a test category or specific name is skipped. skip_conf[key] can be: - true: skip all @@ -299,12 +352,27 @@ def cargo_test( *, rust_root_dir: Path, ): - extra_conf, test_env, extra_flags = _load_cargo_config(rust_root_dir) + extra_conf, test_env, extra_flags, case_tags = _load_cargo_config(ctx, rust_root_dir) skip_conf = extra_conf.get('skip', {}) rel_dir = rust_root_dir.relative_to(local_ctx.shared.root_dir) cargo_toml = tomllib.loads(rust_root_dir.joinpath('Cargo.toml').read_text()) + has_lib = 'lib' in cargo_toml or rust_root_dir.joinpath('src', 'lib.rs').exists() + bins: list[dict] = list(cargo_toml.get('bin', [])) + if rust_root_dir.joinpath('src', 'main.rs').exists(): + pkg_name = cargo_toml.get('package', {}).get('name', rust_root_dir.name) + if not any(binary.get('name') == pkg_name for binary in bins): + bins.append({'name': pkg_name, 'path': 'src/main.rs'}) + known_tag_targets = {'lib'} if has_lib else set() + known_tag_targets.update(f'bin/{binary["name"]}' for binary in bins) + unknown_tag_targets = set(case_tags) - known_tag_targets + if unknown_tag_targets: + extra_config = rust_root_dir / '.ya-test-config.json' + raise ValueError( + f'{extra_config}: tags declared for unknown Cargo cases: ' + f'{", ".join(sorted(unknown_tag_targets))}' + ) target_dir = _target_dir(rust_root_dir) @@ -351,7 +419,7 @@ def cargo_test( + extra_flags, rust_root_dir=rust_root_dir, test_env=test_env, - tags=['rust', 'example'], + tags=['rust', 'example'] + _tags_from_source(ctx, rust_root_dir / ex_path), ) # 2. Test files in tests/ @@ -367,11 +435,10 @@ def cargo_test( command=base_cmd + ['--test', test_name], rust_root_dir=rust_root_dir, test_env=test_env, - tags=['rust', 'unit'], + tags=['rust', 'unit'] + _tags_from_source(ctx, test_file), ) # 3. --lib test - has_lib = 'lib' in cargo_toml or rust_root_dir.joinpath('src', 'lib.rs').exists() if has_lib and not _is_skipped(skip_conf, 'lib'): _add_cargo_case( ctx, @@ -379,19 +446,11 @@ def cargo_test( command=base_cmd + ['--lib'], rust_root_dir=rust_root_dir, test_env=test_env, - tags=['rust', 'unit'], + tags=['rust', 'unit'] + case_tags.get('lib', []), ) # 4. --bin tests for every binary if not _is_skipped(skip_conf, 'bins'): - bins: list[dict] = list(cargo_toml.get('bin', [])) - - # Implicit binary from src/main.rs - if rust_root_dir.joinpath('src', 'main.rs').exists(): - pkg_name = cargo_toml.get('package', {}).get('name', rust_root_dir.name) - if not any(b.get('name') == pkg_name for b in bins): - bins.append({'name': pkg_name, 'path': 'src/main.rs'}) - for bin_entry in bins: bin_name = bin_entry['name'] if _is_skipped(skip_conf, 'bins', bin_name): @@ -402,7 +461,7 @@ def cargo_test( command=base_cmd + ['--bin', bin_name], rust_root_dir=rust_root_dir, test_env=test_env, - tags=['rust', 'unit'], + tags=['rust', 'unit'] + case_tags.get(f'bin/{bin_name}', []), ) @@ -413,138 +472,177 @@ def cargo_fuzz( rust_root_dir: Path, name: str, ): - desc = desc.with_tags(['rust', 'fuzz'])._replace( - console_pool=True, + desc = desc.with_tags( + ['rust', 'fuzz', 'needs-fuzz'] + + _tags_from_source(ctx, rust_root_dir / 'fuzz' / f'{name}.rs') + )._replace( + **afl.pool_usage(ctx), ) - _extra_conf, test_env, extra_flags = _load_cargo_config( - rust_root_dir, 'cargo_afl_build_flags' + _extra_conf, test_env, extra_flags, _case_tags = _load_cargo_config( + ctx, rust_root_dir, 'cargo_afl_build_flags' ) target_dir = _target_dir(rust_root_dir) - # Keyed by crate, not by target name: the lines share fuzz target stems, and - # one AFL output dir per stem would mix their corpora — which `cmin` then - # writes back into `fuzz/inputs-` under `--fuzz-update-corpus`. - out_dir = ( - local_ctx.shared.artifacts_dir - / 'fuzz' - / rust_root_dir.relative_to(local_ctx.shared.root_dir) - / name + # Fake entropy, so that a saved crash replays: `std`'s randomness seeds + # tokio's scheduler and every `HashMap`. `test_env` is a fresh copy, keeping + # this out of `cargo test`; the shim reaches the target through AFL, which + # turns `AFL_PRELOAD` into an `LD_PRELOAD` for the child only. + preload_manifest = ( + local_ctx.shared.root_dir / 'crates' / 'fuzzing' / 'preload' / 'Cargo.toml' ) + test_env['AFL_PRELOAD'] = str(_artifact_dir(target_dir) / 'libgenvm_fuzz_preload.so') + # A target with a mutator crate next to it takes its input as a serialized + # value, and the crate mutates that value structurally instead of editing + # its bytes. + # + # AFL's own mutations are deliberately left on. `AFL_CUSTOM_MUTATOR_ONLY` + # looks right — a havoc'd buffer usually fails to decode, and the target + # rejects it — but it measures worse: on `genvm-common-encode` over 15s, + # 20.55% coverage with `_ONLY` against 27.48% without, and 24.07% for the + # `arbitrary` generator this replaced. A rejected input costs one cheap + # execution, while the ones that do decode reach values the structural + # mutator does not propose. Set `GENVM_FUZZ_MUTATOR_ONLY=1` to compare. + mutator_manifest = rust_root_dir / 'fuzz' / 'mutators' / name / 'Cargo.toml' + if mutator_manifest.is_file(): + library = f'libfuzz_mutator_{name.replace("-", "_")}.so' + test_env['AFL_CUSTOM_MUTATOR_LIBRARY'] = str(_artifact_dir(target_dir) / library) + if os.environ.get('GENVM_FUZZ_MUTATOR_ONLY') == '1': + test_env['AFL_CUSTOM_MUTATOR_ONLY'] = '1' + else: + mutator_manifest = None + + out_dir = afl.output_dir(local_ctx.shared, rust_root_dir, name) + + fuzz_binary = _artifact_dir(target_dir) / 'examples' / f'fuzz-{name}' # Track fuzz binary for coverage if _is_coverage_enabled(): - fuzz_binary = _artifact_dir(target_dir) / 'examples' / f'fuzz-{name}' if fuzz_binary not in _profile_objects: _profile_objects.append(fuzz_binary) + inputs_dir = rust_root_dir / 'fuzz' / f'inputs-{name}' + fuzz_env = afl.environment(test_env) + # Drops one "attempting dry run" line per corpus entry; seeds are calibrated + # lazily instead, so broken ones surface when they are first fuzzed. Rust + # only: python-afl's forkserver does not survive skipping the dry run + fuzz_env['AFL_NO_STARTUP_CALIBRATION'] = '1' + # `fuzz_env` is the whole environment of this case, secondaries included, so + # what the builds below need lives in it too + fuzz_env['CARGO'] = 'cargo' + steps: list[genvm_tool.tests.exec.step.Step] = [] steps.extend( [ genvm_tool.tests.exec.step.SetCwd(path=rust_root_dir), ] - + [genvm_tool.tests.exec.step.SetEnv(key=k, value=v) for k, v in test_env.items()] - + [genvm_tool.tests.exec.step.SetEnv(key='CARGO', value='cargo')] + # The builds below need the AFL env too: without `AFL_NO_CFG_FUZZING` the + # example is built with `--cfg fuzzing`, which pulls `libfuzzer-sys` in + # through a dependency and collides with AFL's own coverage runtime + + [genvm_tool.tests.exec.step.SetEnv(key=k, value=v) for k, v in fuzz_env.items()] + [ genvm_tool.tests.exec.step.Run( args=[ - 'cargo-afl', - 'afl', + 'cargo', 'build', + '--manifest-path', + str(preload_manifest), '--target', RUST_TARGET, '--target-dir', target_dir, - '--example', - f'fuzz-{name}', '--color=always', - ] - + extra_flags, + ], mode=genvm_tool.tests.exec.command.RunMode.INTERACTIVE, ), genvm_tool.tests.test.CommandToResultStep(), genvm_tool.tests.test.ResultStopIfErrorStep(), - genvm_tool.tests.exec.step.MkDir(path=out_dir), + ] + + ( + [] + if mutator_manifest is None + else [ + genvm_tool.tests.exec.step.Run( + args=[ + 'cargo', + 'build', + '--manifest-path', + str(mutator_manifest), + '--target', + RUST_TARGET, + '--target-dir', + target_dir, + '--color=always', + ], + mode=genvm_tool.tests.exec.command.RunMode.INTERACTIVE, + ), + genvm_tool.tests.test.CommandToResultStep(), + genvm_tool.tests.test.ResultStopIfErrorStep(), + ] + ) + + [ genvm_tool.tests.exec.step.Run( args=[ 'cargo-afl', 'afl', - 'fuzz', - '-c', - '-', - '-M', - 'main', - '-i', - f'./fuzz/inputs-{name}', - '-o', - str(out_dir), - '-V', - str(getattr(ctx.configuration.args, 'fuzz_timeout', 30)), - '-t', - '5000', - str(_artifact_dir(target_dir) / f'examples/fuzz-{name}'), - ], - mode=genvm_tool.tests.exec.command.RunMode.INTERACTIVE_TTY, + 'build', + '--target', + RUST_TARGET, + '--target-dir', + target_dir, + '--example', + f'fuzz-{name}', + '--color=always', + ] + + extra_flags, + mode=genvm_tool.tests.exec.command.RunMode.INTERACTIVE, ), genvm_tool.tests.test.CommandToResultStep(), genvm_tool.tests.test.ResultStopIfErrorStep(), ] ) - - if getattr(ctx.configuration.args, 'fuzz_update_corpus', False): - opt_dir = out_dir.parent / f'{name}-opt' - - async def remove_opt_dir(_): - if opt_dir.exists(): - shutil.rmtree(opt_dir, ignore_errors=True) - opt_dir.mkdir(parents=True, exist_ok=True) - - inputs_dir = rust_root_dir.joinpath('fuzz', f'inputs-{name}') - - async def remove_inputs_dir(_): - if inputs_dir.exists(): - shutil.rmtree(inputs_dir, ignore_errors=True) - inputs_dir.mkdir(parents=True, exist_ok=True) - - steps.append(genvm_tool.tests.exec.step.PythonFunction(remove_opt_dir)) - steps.append( - genvm_tool.tests.exec.step.Run( - args=[ - 'cargo-afl', - 'afl', - 'cmin', - '-T', - 'all', - '-o', - str(opt_dir), - '-i', - str(out_dir), - '--', - str(_artifact_dir(target_dir) / f'examples/fuzz-{name}'), - ], - mode=genvm_tool.tests.exec.command.RunMode.INTERACTIVE, - ) - ) - steps.extend( - [ - genvm_tool.tests.test.CommandToResultStep(), - genvm_tool.tests.test.ResultStopIfErrorStep(), - genvm_tool.tests.exec.step.PythonFunction(remove_inputs_dir), - ] + steps.extend( + afl.fleet_steps( + ctx, + cwd=rust_root_dir, + env=fuzz_env, + inputs_dir=inputs_dir, + out_dir=out_dir, + launcher=['cargo-afl', 'afl', 'fuzz'], + target=[fuzz_binary], + extra_args=['-t', '5000'], + status_command=['cargo-afl', 'afl', 'whatsup', '-s', out_dir], + # A persistent-mode target expects a forkserver, so replaying an input + # means going through AFL rather than piping it into the binary. The + # preload has to come along, or the replay reseeds itself + replay=( + f'AFL_PRELOAD={fuzz_env["AFL_PRELOAD"]} ' + f'cargo-afl afl showmap -o /dev/null -- {fuzz_binary} <' + ), ) - steps.append( - genvm_tool.tests.exec.step.Run( - args=[ - sys.executable, - f'{local_ctx.shared.root_dir}/runners/genlayer-py-std/fuzz/resave.py', - opt_dir, - inputs_dir, - ], - mode=genvm_tool.tests.exec.command.RunMode.INTERACTIVE, - ) + ) + + steps.extend( + afl.corpus_update_steps( + ctx, + inputs_dir=inputs_dir, + out_dir=out_dir, + cmin_command=lambda queue_dir, opt_dir: [ + 'cargo-afl', + 'afl', + 'cmin', + '-T', + 'all', + '-o', + opt_dir, + '-i', + queue_dir, + '--', + fuzz_binary, + ], ) - steps.append(CONST_PASSED) + ) case = genvm_tool.tests.test.StepsCase( description=desc, diff --git a/tests/runner/genvm_tool_plugins/docker.py b/tests/runner/genvm_tool_plugins/docker.py index 38a9b77a..c48812f1 100644 --- a/tests/runner/genvm_tool_plugins/docker.py +++ b/tests/runner/genvm_tool_plugins/docker.py @@ -122,9 +122,18 @@ def _stop_cleanup(container_id: str) -> functools.partial: class ContainerHandle(genvm_tool.tests.exec.service.Handle): + # The webdriver image asks for a 10s start-period and probes every 30s, so a + # first verdict lands well after half a minute and each retry costs another + # interval. Room for several of them, not for all ten the image allows. + STARTUP_TIMEOUT = 180.0 + # Outlasts the teardown chain: the watchdog's ack budget, and behind it a + # `docker stop` capped at 30s. + INTERRUPT_TIMEOUT = 120.0 + def __init__(self, container_id: str, *, ci: bool): self._container_id = container_id self._ci = ci + self._last_inspect: 'genvm_tool.tests.exec.command.Result | None' = None self._watchdog_token = local_ctx.shared.watchdog.register( _stop_cleanup(container_id) ) @@ -187,22 +196,39 @@ async def run( container_id = res.stdout.strip() return ContainerHandle(container_id=container_id, ci=ci) + async def _inspect(self) -> 'genvm_tool.tests.exec.command.Result': + """ + State and health of the container in one call, cached for one probe. + + :meth:`healthy` runs immediately before :meth:`death_reason` on every + poll, so the second reads what the first fetched rather than forking a + docker of its own. + """ + cmd = genvm_tool.tests.exec.command.Command( + args=[ + 'docker', + 'inspect', + '--format', + '{{.State.Status}}|' + '{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}', + self._container_id, + ], + cwd=local_ctx.shared.root_dir, + env=DEFAULT_ENV, + ) + self._last_inspect = await cmd.run( + ctx=local_ctx.shared, mode=genvm_tool.tests.exec.command.RunMode.SILENT + ) + return self._last_inspect + + @staticmethod + def _split_inspect(res: 'genvm_tool.tests.exec.command.Result') -> tuple[str, str]: + state, _, health = res.stdout.strip().partition('|') + return state, health + async def healthy(self) -> bool: try: - cmd = genvm_tool.tests.exec.command.Command( - args=[ - 'docker', - 'inspect', - '--format', - '{{.State.Health.Status}}', - self._container_id, - ], - cwd=local_ctx.shared.root_dir, - env=DEFAULT_ENV, - ) - res = await cmd.run( - ctx=local_ctx.shared, mode=genvm_tool.tests.exec.command.RunMode.SILENT - ) + res = await self._inspect() if res.exit_code != 0: if self._ci: logs = await self.get_logs() @@ -213,17 +239,17 @@ async def healthy(self) -> bool: logs=logs, ) return False - status = res.stdout.strip() - if status != 'healthy': + _, health = self._split_inspect(res) + if health != 'healthy': if self._ci: logs = await self.get_logs() local_ctx.shared.logger.warning( 'Container not healthy', container_id=self._container_id, - status=status, + status=health, logs=logs, ) - return status == 'healthy' + return health == 'healthy' except Exception as e: local_ctx.shared.logger.error( 'Failed to check container health', @@ -232,6 +258,28 @@ async def healthy(self) -> bool: ) return False + async def death_reason(self) -> str | None: + res, self._last_inspect = self._last_inspect, None + try: + if res is None: + res = await self._inspect() + # a probe of our own is not a probe the next call may reuse + self._last_inspect = None + except Exception: + return None # healthy() reports the probe itself failing + if res.exit_code != 0: + # `docker run --rm` drops the container the moment it exits; any + # other inspect failure is the daemon being flaky, so keep waiting + if 'no such' in (res.stdout + res.stderr).lower(): + return f'container {self._container_id} is gone' + return None + state, health = self._split_inspect(res) + if state in ('exited', 'dead'): + return f'container {state}, logs: {await self.get_logs()}' + if health == 'unhealthy': + return f'container unhealthy, logs: {await self.get_logs()}' + return None + async def interrupt(self) -> None: # Tear the container down through the watchdog so creation and teardown # always go through the same owner; blocks until the stop completes. diff --git a/tests/runner/genvm_tool_plugins/genvm.py b/tests/runner/genvm_tool_plugins/genvm.py index 5c72890d..c0513e2c 100644 --- a/tests/runner/genvm_tool_plugins/genvm.py +++ b/tests/runner/genvm_tool_plugins/genvm.py @@ -2,10 +2,13 @@ import json import os import typing +from collections.abc import Mapping from pathlib import Path import aiohttp +import genvm_tool.io as gvm_io import genvm_tool.tests +import genvm_tool.tests.exec.process import genvm_tool.tests.exec.service import genvm_tool_plugins.docker as docker @@ -86,52 +89,80 @@ async def _read_log_pipe( class ManagerHandle(genvm_tool.tests.exec.service.Handle): def __init__( self, - port: int, + port: int | None, process: asyncio.subprocess.Process | None, - log_file: typing.IO[str] | None, + log_file: gvm_io.AsyncFile[str] | None, log_tasks: list[asyncio.Task] | None, + socket_path: Path | None = None, + restart: typing.Callable[[], typing.Awaitable['ManagerHandle']] | None = None, ): self._port = port + self._socket_path = socket_path self._process = process self._log_file = log_file self._log_tasks = log_tasks + self._restart = restart @property - def port(self) -> int: + def port(self) -> int | None: return self._port @property def uri(self) -> str: + if self._socket_path is not None: + return f'unix://{self._socket_path}' return f'http://localhost:{self._port}' + @property + def socket_path(self) -> Path | None: + return self._socket_path + + @property + def process(self) -> asyncio.subprocess.Process | None: + return self._process + async def healthy(self) -> bool: try: - async with aiohttp.ClientSession() as session: + connector = ( + aiohttp.UnixConnector(path=str(self._socket_path)) + if self._socket_path is not None + else None + ) + async with aiohttp.ClientSession(connector=connector) as session: async with session.get( - f'{self.uri}/status', + 'http://localhost/status' + if self._socket_path is not None + else f'{self.uri}/status', timeout=aiohttp.ClientTimeout(total=5), ) as response: return response.status == 200 except Exception: return False + async def death_reason(self) -> str | None: + if self._process is None or self._process.returncode is None: + return None + return f'manager exited with code {self._process.returncode}' + async def interrupt(self) -> None: if self._process is not None: - try: - self._process.terminate() - except Exception: - pass - - try: - await asyncio.wait_for(self._process.wait(), timeout=5) - except asyncio.TimeoutError: - self._process.kill() - await self._process.wait() + await genvm_tool.tests.exec.process.stop(self._process) if self._log_tasks is not None: - for task in self._log_tasks: - await task + await genvm_tool.tests.exec.process.drain(self._log_tasks) if self._log_file is not None: - self._log_file.close() + await self._log_file.close() + + async def restart(self) -> None: + if self._restart is None: + raise RuntimeError('manager service is not restartable') + await self.interrupt() + replacement = await self._restart() + self._port = replacement._port + self._socket_path = replacement._socket_path + self._process = replacement._process + self._log_file = replacement._log_file + self._log_tasks = replacement._log_tasks + await self.await_startup() class ManagerService(genvm_tool.tests.exec.service.Service): @@ -142,46 +173,66 @@ def __init__( bin_path: Path, log_path: Path | None = None, ci: bool = False, + port: int | None = None, + config: Mapping[str, typing.Any] | None = None, + socket_path: Path | None = None, ): self._bin_path = bin_path self._log_path = log_path self._env = env self._ci = ci + self._port = port + self._config = dict(config or {}) + self._socket_path = socket_path + self._has_started = False async def start(self) -> ManagerHandle: + handle = await self._start_once() + handle._restart = self._start_once + return handle + + async def _start_once(self) -> ManagerHandle: log_file = None log_tasks = None use_pipe = self._log_path is not None if use_pipe and self._log_path: - log_file = open(self._log_path, 'w') + self._log_path.parent.mkdir(parents=True, exist_ok=True) + log_file = await gvm_io.open_file( + self._log_path, + 'a' if self._has_started else 'w', + ) + self._has_started = True - port = get_manager_port(self._env) + port = self._port if self._port is not None else get_manager_port(self._env) config_dir = self._log_path.parent if self._log_path is not None else Path('/tmp') config_dir.mkdir(parents=True, exist_ok=True) config_path = config_dir / 'genvm-manager.yaml' manifest_path = self._bin_path.parent.parent / 'data' / 'manifest.yaml' + config = { + 'threads': 4, + 'blocking_threads': 48, + 'log_disable': 'tracing*,polling*,tungstenite*,tokio_tungstenite*', + 'log_level': 'info', + 'manifest_path': str(manifest_path), + 'permits': None, + 'execution_retention': '5m', + 'max_message_bytes': 67108864, + } + config.update(self._config) config_path.write_text( - '\n'.join( - [ - 'threads: 4', - 'blocking_threads: 48', - 'log_disable: tracing*,polling*,tungstenite*,tokio_tungstenite*', - 'log_level: info', - f'manifest_path: {json.dumps(str(manifest_path))}', - 'permits: null', - 'execution_retention: 5m', - 'max_message_bytes: 67108864', - '', - ] - ) + '\n'.join(f'{key}: {json.dumps(value)}' for key, value in config.items()) + '\n' ) + listener_args = ( + ['--socket', str(self._socket_path)] + if self._socket_path is not None + else ['--port', str(port)] + ) process = await asyncio.subprocess.create_subprocess_exec( str(self._bin_path), 'manager', - '--port', - str(port), + *listener_args, '--die-with-parent', '--config', str(config_path), @@ -195,14 +246,20 @@ async def start(self) -> ManagerHandle: logger = local_ctx.shared.logger log_tasks = [ asyncio.create_task( - _read_log_pipe(process.stdout, log_file, logger, ci=self._ci) + _read_log_pipe(process.stdout, log_file.raw, logger, ci=self._ci) ), asyncio.create_task( - _read_log_pipe(process.stderr, log_file, logger, ci=self._ci) + _read_log_pipe(process.stderr, log_file.raw, logger, ci=self._ci) ), ] - handle = ManagerHandle(port, process, log_file, log_tasks) + handle = ManagerHandle( + None if self._socket_path is not None else port, + process, + log_file, + log_tasks, + socket_path=self._socket_path, + ) return handle diff --git a/tests/runner/genvm_tool_plugins/integration.py b/tests/runner/genvm_tool_plugins/integration.py index de2db945..20335dab 100644 --- a/tests/runner/genvm_tool_plugins/integration.py +++ b/tests/runner/genvm_tool_plugins/integration.py @@ -25,10 +25,14 @@ from pathlib import Path import genvm_tool.gvm32 +import genvm_tool.io as gvm_io import genvm_tool.tests +import genvm_tool_plugins.runners as runners +import gvm_extra.case_inputs as case_inputs import origin.base_host as base_host import origin.calldata as gvm_calldata import origin.fees as fees +import origin.host_fns as host_fns import origin.log_asserts as log_asserts import origin.logger as origin_logger import origin.public_abi as public_abi @@ -210,7 +214,7 @@ def log(self, level: str, msg: str, **kwargs) -> None: def _unfold_conf(x: typing.Any, vars: dict[str, str]) -> typing.Any: """Recursively substitute variables in configuration.""" if isinstance(x, str): - return re.sub(r'\$\{[a-zA-Z\-_]+\}', lambda m: vars[m.group()[2:-1]], x) + return re.sub(r'\$\{[a-zA-Z0-9\-_]+\}', lambda m: vars[m.group()[2:-1]], x) if isinstance(x, list): return [_unfold_conf(item, vars) for item in x] if isinstance(x, dict): @@ -219,7 +223,8 @@ def _unfold_conf(x: typing.Any, vars: dict[str, str]) -> typing.Any: def _routing_payload(route: int | str) -> bytes: - """Where a host places a callee: a major, or a version naming a line. + """ + Where a host places a callee: a major, or a version naming a line. A major is resolved by the manifest's rules, which cannot separate the live lines while every one of them is semver major 0 — a version string is what @@ -258,6 +263,11 @@ def _flatten_tree( # as `py-genlayer:test`, and that alias only resolves from `unsafe` up. _DEBUG_MODES = ('disabled', 'safe', 'safe-unbounded', 'unsafe', 'unsafe-tracing') _DEBUG_MODE_DEFAULT = 'unsafe' +_PHASE_TAG_BY_MODE = { + 'l': 'phase-leader', + 'v': 'phase-validator', + 's': 'phase-sync', +} @dataclass @@ -416,7 +426,7 @@ async def run( # Set up base storage base_mock_storage = MockStorage() if storage_json := top_level_conf.get('storage_json'): - storage_b64 = json.loads(Path(storage_json).read_text()) + storage_b64 = json.loads(await gvm_io.read_file_text(Path(storage_json))) base_mock_storage._storages = { Address(a): { base64.b64decode(k): bytearray(base64.b64decode(v)) for k, v in kv.items() @@ -425,8 +435,7 @@ async def run( } empty_storage = tmp_dir.joinpath('empty-storage.pickle') - with open(empty_storage, 'wb') as f: - pickle.dump(base_mock_storage, f) + await gvm_io.write_file_bytes(empty_storage, pickle.dumps(base_mock_storage)) return genvm_tool.tests.test.Result( passed=True, @@ -575,18 +584,7 @@ async def _run_single_step( my_tmp_dir.joinpath('config.json').write_text(config_str) # Prepare calldata - calldata_eval_vars = {} - calldata_eval_vars['Address'] = gvm_calldata.Address - calldata_eval_vars['true'] = True - calldata_eval_vars['false'] = False - - calldata_bytes = gvm_calldata.encode( - eval( - single_conf['calldata'], - calldata_eval_vars, - single_conf.get('vars', {}).copy(), - ) - ) + calldata_bytes = case_inputs.encode_calldata(single_conf) # Process code file code_path = single_conf.get('code') @@ -619,7 +617,9 @@ async def _run_single_step( }, } code_path = str(out_path) - code = Path(code_path).read_bytes() + code = runners.substitute( + await gvm_io.read_file_bytes(Path(code_path)), local_ctx.shared.root_dir + ) # Process message addresses single_conf['message']['contract_address'] = Address( @@ -652,8 +652,9 @@ async def _run_single_step( else: leader_nondet = single_conf.get('leader_nondet', None) if leader_nondet is None: - with open(path_to_which_leader_puts_result, 'rb') as f: - leader_nondet = pickle.load(f) + leader_nondet = pickle.loads( + await gvm_io.read_file_bytes(path_to_which_leader_puts_result) + ) if leader_nondet is not None: encoded_nondet = [] for res in leader_nondet: @@ -700,6 +701,18 @@ async def _run_single_step( # manifest keys rather than name a directory). routes = {Address(k): v for k, v in single_conf.get('executor_routes', {}).items()} hook_calls = routes != {} or single_conf.get('hook_cross_contract_calls', False) + route_requests: list[dict[str, typing.Any]] = [] + + def resolve_executor(address, state, advisory_major): + route_requests.append( + { + 'contract_address': address.as_hex, + 'state_mode': int(state), + 'advisory_major': advisory_major, + } + ) + return _routing_payload(routes[address]) if address in routes else None + host = MockHost( path=str(mock_sock_path), storage_path_post=post_storage, @@ -707,11 +720,7 @@ async def _run_single_step( balances={Address(k): v for k, v in single_conf.get('balances', {}).items()}, running_address=running_address, ctx=ctx, - resolve_callcontract_executor_hook=( - lambda address, _state, _major: ( - _routing_payload(routes[address]) if address in routes else None - ) - ), + resolve_callcontract_executor_hook=resolve_executor, ) host.balances.setdefault(running_address, 0) @@ -778,7 +787,9 @@ async def _run_single_step( gas_data=single_conf.get('gas_data'), leader_nondet_results=leader_nondet, message_fee_allocation=message_fee_allocation, - unsafe_overrides=base_host.UnsafeOverrides(reroute_to=reroute_to), + unsafe_overrides=base_host.UnsafeOverrides( + reroute_to=single_conf.get('reroute_to', reroute_to) + ), request_extra=request_extra, # A case may state the major the host claims, for the # cases whose subject is what the executor does with a @@ -788,14 +799,21 @@ async def _run_single_step( # Nested executors dial the same listener; wind their loops down # so a failure on that side surfaces here. await mock_host.stop_connections() + expected_route_requests = single_conf.get('expected_executor_route_requests') + assert ( + expected_route_requests is None or route_requests == expected_route_requests + ), ( + route_requests, + expected_route_requests, + ) return_part = '' - if res.result_kind == public_abi.ResultCode.RETURN: + if res.result_kind == host_fns.ResultCode.RETURN: return_part += ( f'executed with `Return({gvm_calldata.to_str(res.result_data)})`\n' ) - elif res.result_kind == public_abi.ResultCode.VM_ERROR: + elif res.result_kind == host_fns.ResultCode.VM_ERROR: return_part += f'executed with `VMError("{res.result_data}")`\n' - elif res.result_kind == public_abi.ResultCode.USER_ERROR: + elif res.result_kind == host_fns.ResultCode.USER_ERROR: if isinstance(res.result_data, str): return_part += f'executed with `UserError("{res.result_data}")`\n' else: @@ -836,8 +854,9 @@ async def _run_single_step( if is_leader: nondet_list = res.result_nondet_results - with open(path_to_which_leader_puts_result, 'wb') as f: - pickle.dump(nondet_list, f) + await gvm_io.write_file_bytes( + path_to_which_leader_puts_result, pickle.dumps(nondet_list) + ) # Save outputs my_tmp_dir.joinpath('stdout.txt').write_text(res.stdout) @@ -851,11 +870,10 @@ async def _run_single_step( # Save RunHostAndProgramRes pickle result_path = Path(single_conf['result_path']) - result_path.parent.mkdir(exist_ok=True, parents=True) - with open(result_path, 'wb') as f: - pickle.dump(res, f) + await gvm_io.make_dir(result_path.parent) + await gvm_io.write_file_bytes(result_path, pickle.dumps(res)) - if res.result_kind == public_abi.ResultCode.INTERNAL_ERROR: + if res.result_kind == host_fns.ResultCode.INTERNAL_ERROR: return { 'passed': False, 'context': { @@ -894,8 +912,8 @@ async def _run_single_step( semantics_path.write_text(semantics) exp_semantics_path = Path(single_conf['expected_semantics_path']) - if exp_semantics_path.exists(): - exp_text = exp_semantics_path.read_text() + if await gvm_io.path_exists(exp_semantics_path): + exp_text = await gvm_io.read_file_text(exp_semantics_path) diff = _get_diffs(exp_text, semantics, lambda x: x) if diff is not None: return { @@ -912,7 +930,7 @@ async def _run_single_step( } else: # Create expected output file - exp_semantics_path.write_text(semantics) + await gvm_io.write_file_text(exp_semantics_path, semantics) # ADR-012 load-action log-grep assertions. A case may declare # `runner_load_asserts` on a step to assert on the executor's stable @@ -957,9 +975,7 @@ async def _run_single_step( compares_golden = False check_expected_hash = expected_hash_path is not None - if ( - res.result_kind == public_abi.ResultCode.VM_ERROR and res.result_data == 'timeout' - ): + if res.result_kind == host_fns.ResultCode.VM_ERROR and res.result_data == 'timeout': check_expected_hash = False # Don't check hash for timeouts, as they can be flaky if check_expected_hash: @@ -1096,7 +1112,8 @@ def _digest_file(path: Path) -> str: def _resolve_import(base: str, rel: str, jpathdir: list[str]) -> Path: - """Where jsonnet would find ``rel``, imported from a file in ``base``. + """ + Where jsonnet would find ``rel``, imported from a file in ``base``. Unresolved: a nested import resolves against this path. """ @@ -1169,7 +1186,8 @@ def _connection(self) -> sqlite3.Connection: @staticmethod def _deps_hold(deps: list[list[str]], jpathdir: list[str]) -> bool: - """Whether every import still resolves where it did, to the same bytes. + """ + Whether every import still resolves where it did, to the same bytes. Re-resolved, not just re-digested: a new file of that name beside the case steals an import that fell through to the search path. @@ -1289,10 +1307,37 @@ def integration_test_single_executor( save_hashes = executor_integration_conf.get( 'save-hashes', not executor_integration_conf.get('ignore-hash', False) ) + integration_test_directory( + ctx, + cases_dir=CASES_DIR, + reroute_to=reroute_to, + save_hashes=save_hashes, + manager_service=manager_service, + modules_service=modules_service, + webdriver_service=webdriver_service, + ci=ci, + ) + + +def integration_test_directory( + ctx: genvm_tool.tests.stage.collection.Context, + *, + cases_dir: Path, + reroute_to: str, + save_hashes: bool, + manager_service: genvm_tool.tests.stage.collection.Service, + modules_service: genvm_tool.tests.stage.collection.Service, + webdriver_service: genvm_tool.tests.stage.collection.Service, + ci: bool, +) -> None: + """Collect one Jsonnet suite with the standard integration machinery.""" + import _jsonnet + + globals()['_jsonnet'] = _jsonnet # type: ignore glob_start = time.monotonic() jsonnet_files = list( - x for x in CASES_DIR.glob('**/*.jsonnet') if not x.name.startswith('_') + x for x in cases_dir.glob('**/*.jsonnet') if not x.name.startswith('_') ) glob_end = time.monotonic() # Bumped, not assigned: this runs once per executor line. @@ -1310,7 +1355,7 @@ def integration_test_single_executor( ctx, jsonnet_file, jsonnet_cache, - cases_dir=CASES_DIR, + cases_dir=cases_dir, reroute_to=reroute_to, save_hashes=save_hashes, manager_service=manager_service, @@ -1425,6 +1470,10 @@ def _single_integration_test( 'jsonnetDir': str(jsonnet_file.parent), 'fileBaseName': jsonnet_file.stem, 'tmpDir': str(tmp_dir), + **{ + 'executor' + key.replace('.', '').upper(): value + for key, value in build_info['executor_versions'].items() + }, }, ) @@ -1445,7 +1494,7 @@ def _single_integration_test( prepare_desc = genvm_tool.tests.test.Description( name=prepare_name, needed_services=frozen_services, - tags=frozen_tags, + tags=frozen_tags | {'phase-prepare'}, ) ctx.add_case( IntegrationPrepareCase( @@ -1467,6 +1516,13 @@ def _single_integration_test( for tree_path, depends_on_tree_path, single_conf in flat_steps: step_name = step_names[tree_path] is_benchmark = single_conf.get('benchmark', False) + mode = single_conf.get('mode') + try: + phase_tag = _PHASE_TAG_BY_MODE[mode] + except (KeyError, TypeError): + raise ValueError( + f'{jsonnet_file}: step {tree_path}: unexpected mode {mode!r}' + ) from None if depends_on_tree_path is None: deps = frozenset([prepare_name]) @@ -1476,7 +1532,7 @@ def _single_integration_test( step_desc = genvm_tool.tests.test.Description( name=step_name, needed_services=frozen_services, - tags=frozen_tags, + tags=frozen_tags | {phase_tag}, depends_on=deps, ) diff --git a/tests/runner/genvm_tool_plugins/ninja.py b/tests/runner/genvm_tool_plugins/ninja.py index 4d34c31d..6eefdbef 100644 --- a/tests/runner/genvm_tool_plugins/ninja.py +++ b/tests/runner/genvm_tool_plugins/ninja.py @@ -1,4 +1,5 @@ -"""Ninja build-graph DSL + per-line `configure` helpers (importable plugin). +""" +Ninja build-graph DSL + per-line `configure` helpers (importable plugin). Extracted from ``genvm-tool configure`` so each executor line can own its own build configuration. The shared machinery lives here — the ninja DSL @@ -36,7 +37,8 @@ def target_dir_for_line(rust_target_dir: Path, key: str) -> Path: - """Cargo target dir for one executor line. + """ + Cargo target dir for one executor line. Lines ship crates with identical names and versions; cargo's artifact hash does not cover where a package came from, so in a shared target dir two lines @@ -83,7 +85,8 @@ def _escape(s: str) -> str: def glob(base: Path, pattern: str) -> list[Path]: - """Mirror Ruby's `Pathname#glob`: a depth-first, per-component sorted walk + """ + Mirror Ruby's `Pathname#glob`: a depth-first, per-component sorted walk that skips dotfile entries (no FNM_DOTMATCH). Sorting by path *components* (not the joined string) is what makes @@ -110,7 +113,8 @@ def is_subpath(path: Path, base: Path) -> bool: # Nix expressions that evaluate a checkout's runner derivations to their # {id: hash} (latest.json) and {id: [hash]} (all.json) maps. def runner_manifest_expr(version: str, kind: str) -> str: - """Nix expr for one executor's `latest`/`all` runner manifest. + """ + Nix expr for one executor's `latest`/`all` runner manifest. The umbrella's ./runners owns this: `all` is every runner compatible up to `version`, `latest` is that executor's own current runners. Evaluated with @@ -276,7 +280,8 @@ def build(self, rule: str, *outputs) -> Build: def codegen( self, out: Path, lang: str, data: Path, extra_flags: list[str] | None = None ) -> None: - """Emit one `codegen` edge (`genvm-tool codegen --lang `). + """ + Emit one `codegen` edge (`genvm-tool codegen --lang `). Requires the `codegen` rule. The generated file depends on its data JSON and on the codegen backend sources (``codegen_deps``, set by the command) so an @@ -331,8 +336,10 @@ def register_cargo( clippy_lints = ['--', '-A', 'clippy::upper_case_acronyms', '-Dwarnings'] + # Lint/format edges declare no inputs and produce no output file: cargo does + # its own staleness tracking, and a stale ninja stamp hid real diagnostics. + clippy = self.build('cargo', 'target/' + rel_path + '/clippy') - clippy.add_dependency(files_trg) clippy.var('subcommand', 'clippy') clippy.var('wd', crate_dir) clippy.var('extra_args', extra_args + clippy_lints) @@ -381,7 +388,8 @@ def register_cargo( @dataclass class LineContext: - """Everything one executor line's ``configure(line)`` hook needs. + """ + Everything one executor line's ``configure(line)`` hook needs. Built by the configure command per active line. The hook composes the ``register_standard_*`` / ``install_tree`` steps and chooses a runner-registry @@ -435,16 +443,24 @@ def register_standard_codegen(self) -> None: 'python', data / 'public-abi.json', ) - pending_abi = self.exec_root / 'executor/codegen/data/public-abi-pending.json' + pending_abi = data / 'public-abi-pending.json' if pending_abi.exists(): self.codegen( self.exec_root / 'executor/crates/common/src/public_abi_pending.rs', 'rust', - self.exec_root / 'executor/codegen/data/public-abi-pending.json', + pending_abi, + ) + internal_constants = data / 'internal-constants.json' + if internal_constants.exists(): + self.codegen( + self.exec_root / 'executor/crates/common/src/internal_constants.rs', + 'rust', + internal_constants, ) def register_standard_crates(self) -> None: - """Build this line's `genvm` binary plus its `common`/`sdk-rs` crates. + """ + Build this line's `genvm` binary plus its `common`/`sdk-rs` crates. `calldata` and `calldata-derive` live in this line's tree too but get no edge of their own — they are path deps of the crates listed here. @@ -459,7 +475,8 @@ def register_standard_crates(self) -> None: self.n.register_cargo(f'{self.exec_rel}/executor/crates/sdk-rs', target_dir=td) def frozen_registry(self) -> None: - """Copy this line's committed ``executor/registry`` runner manifests verbatim. + """ + Copy this line's committed ``executor/registry`` runner manifests verbatim. Frozen legacy lines ship the exact ``latest.json``/``all.json`` from their release, which the nix build copies verbatim (see that line's @@ -474,7 +491,8 @@ def frozen_registry(self) -> None: self.data_phony.add_dependency(out) def nix_manifests(self) -> None: - """Derive this line's `latest`/`all` runner manifests via the nix machinery. + """ + Derive this line's `latest`/`all` runner manifests via the nix machinery. Manifests are derived by the umbrella machinery (which imports every active line's runners), so both the line's and the umbrella's nix inputs matter. @@ -499,7 +517,8 @@ def install_tree(self) -> None: def configure_line_default(line: LineContext) -> None: - """Fallback per-line configuration for a line whose `.genvm-tool.py` has no + """ + Fallback per-line configuration for a line whose `.genvm-tool.py` has no `configure` hook: the standard codegen + crates + install, resolving the runner registry from a committed ``executor/registry`` when present, else nix. """ diff --git a/tests/runner/genvm_tool_plugins/pytest.py b/tests/runner/genvm_tool_plugins/pytest.py index 5cb172f0..3d0398ab 100644 --- a/tests/runner/genvm_tool_plugins/pytest.py +++ b/tests/runner/genvm_tool_plugins/pytest.py @@ -4,6 +4,7 @@ from pathlib import Path import genvm_tool.tests +import genvm_tool_plugins.afl as afl default_env = { k: v @@ -11,9 +12,6 @@ if genvm_tool.tests.util.environ.DEFAULT_FILTER(k, v) } -default_env['AFL_FUZZER_LOOPCOUNT'] = '20' # without it no coverage will be written! -default_env['AFL_NO_CFG_FUZZING'] = '1' -default_env['AFL_BENCH_UNTIL_CRASH'] = '1' default_env.pop('VIRTUAL_ENV', None) local_ctx = genvm_tool.tests.stage.configuration.current_context() @@ -21,7 +19,7 @@ # The Python unit-test interpreter is provided by a standalone, pinned nix flake # (executors/v0.3.x/support/nix/py-test) that replaced genlayer-py-std's poetry # env. It is realised lazily at run time (not collection time, so `test show` -# stays cheap); pytest / py-afl-fuzz are exec'd from its bin/. +# stays cheap); tools are exec'd from its bin/. py_test_flake_dir = local_ctx.shared.root_dir.joinpath( 'executors', 'v0.3.x', 'support', 'nix', 'py-test' ) @@ -30,34 +28,62 @@ ) -def nix_env_command(argv: collections.abc.Sequence[str | Path]) -> list[str]: - """Wrap ``argv`` so it runs against the py-test flake's Python env. +def env_flake_dir(project_root_dir: Path) -> Path: + """ + The flake whose env a project's tests run under. + + A project carrying its own `flake.nix` gets that one: its tests need its own + dependencies, and the shared env holds only what genlayer-py-std's need. + """ + if project_root_dir.joinpath('flake.nix').is_file(): + return project_root_dir + return py_test_flake_dir + + +def nix_env_command( + argv: collections.abc.Sequence[str | Path], + flake_dir: Path | None = None, +) -> list[str]: + """ + Wrap ``argv`` so it runs against a py-test flake's Python env. Builds (or reuses, via the gc-root out-link) the flake's env under ``build/ya-build/py-test-env``, then execs ``/bin/`` with the - remaining args. ``argv[0]`` is a bin name (``pytest``, ``py-afl-fuzz``); the + remaining args. ``argv[0]`` is a bin name (for example ``pytest``); the rest pass through verbatim. """ + flake_dir = flake_dir or py_test_flake_dir + # One out-link per flake, or the envs would evict each other's gc-root and + # the next run would rebuild + out_link = py_test_env_link.with_name( + f'{py_test_env_link.name}-{flake_dir.name}' + if flake_dir != py_test_flake_dir + else py_test_env_link.name + ) script = ( 'set -eu\n' - f'mkdir -p {shlex.quote(str(py_test_env_link.parent))}\n' + f'mkdir -p {shlex.quote(str(out_link.parent))}\n' 'env_dir="$(nix build --print-out-paths' - f' --out-link {shlex.quote(str(py_test_env_link))}' - f' {shlex.quote("path:" + str(py_test_flake_dir))})"\n' + f' --out-link {shlex.quote(str(out_link))}' + f' {shlex.quote("path:" + str(flake_dir))})"\n' + 'export PATH="$env_dir/bin:$PATH"\n' 'exec "$env_dir/bin/$0" "$@"' ) return ['bash', '-c', script, *map(str, argv)] def pytest_env(project_root_dir: Path) -> dict: - """``default_env`` plus PYTHONPATH for the in-tree packages under test. + """ + ``default_env`` plus PYTHONPATH for the in-tree packages under test. - The nix env ships only the test deps; ``genlayer`` (src/) and - ``genlayer_embeddings`` / ``onnx`` (src-emb/) are imported via PYTHONPATH, - mirroring the editable install poetry used to provide. + The nix env ships only the dependencies; the package under test is imported + from the working tree, mirroring the editable install poetry used to + provide. That is ``src/`` + ``src-emb/`` for genlayer-py-std, and the + project root itself for a flat layout such as `genvm_tool`. """ env = dict(default_env) pythonpath = [ + str(project_root_dir), str(project_root_dir.joinpath('src')), str(project_root_dir.joinpath('src-emb')), ] @@ -77,7 +103,7 @@ def pytest( desc = desc.with_tags(['python', 'unit'])._replace(console_pool=True) case = genvm_tool.tests.test.SimpleCommandCase( description=desc, - command=nix_env_command(['pytest', '--color=yes']), + command=nix_env_command(['pytest', '--color=yes'], env_flake_dir(project_root_dir)), cwd=project_root_dir, env=pytest_env(project_root_dir), mode=genvm_tool.tests.exec.command.RunMode.INTERACTIVE, @@ -93,34 +119,82 @@ def py_fuzz( project_root_dir: Path, name: str, ): - desc = desc.with_tags(['python', 'fuzz'])._replace( - console_pool=True, + desc = desc.with_tags(['python', 'fuzz', 'needs-fuzz'])._replace( + **afl.pool_usage(ctx), ) inputs_dir = project_root_dir.joinpath('fuzz', 'inputs', name) - outputs_dir = project_root_dir.joinpath('fuzz', 'outputs', name) + out_dir = afl.output_dir(local_ctx.shared, project_root_dir, name) src_file = project_root_dir.joinpath('fuzz', 'src', f'{name}.py') - # NB: the py-test flake omits python-afl (not in nixpkgs), so `py-afl-fuzz` - # is absent from its bin/. The fuzz collector is disabled; re-add python-afl - # to the flake before enabling this. - case = genvm_tool.tests.test.SimpleCommandCase( - description=desc, - command=nix_env_command( - [ - 'py-afl-fuzz', - '-i', - inputs_dir, - '-o', - outputs_dir, - '-V', - str(getattr(ctx.configuration.args, 'fuzz_timeout', 30)), - '--', - src_file, - ] - ), - cwd=project_root_dir, - env=pytest_env(project_root_dir), - mode=genvm_tool.tests.exec.command.RunMode.INTERACTIVE, + # A target imports its project's own packages, so it runs under the same env + # as that project's unit tests; python-afl and AFL++ are in both + flake_dir = env_flake_dir(project_root_dir) + + def env_command(argv: collections.abc.Sequence[str | Path]) -> list[str]: + return nix_env_command(argv, flake_dir) + + env = afl.environment(pytest_env(project_root_dir)) + # What `py-afl-fuzz` exports before handing over to `afl-fuzz`. `AFL_SKIP_CHECKS` + # is left out: it is the pre-1.20b spelling, which the pinned AFL++ only warns + # about. The rest of the wrapper is the PATH lookup `nix_env_command` does + env.update( + { + 'AFL_DUMB_FORKSRV': '1', + 'AFL_SKIP_BIN_CHECK': '1', + 'PYTHON_AFL_PERSISTENT': '1', + 'PYTHON_AFL_SIGNAL': 'SIGUSR1', + } ) + steps: list[genvm_tool.tests.exec.step.Step] = list( + afl.fleet_steps( + ctx, + cwd=project_root_dir, + env=env, + inputs_dir=inputs_dir, + out_dir=out_dir, + launcher=['afl-fuzz'], + target=['--', src_file], + wrap=env_command, + # Realising the env once: every fleet member would otherwise pay a + # `nix build` before `exec`, staggering the instances' `-V` windows + prepare_command=env_command(['python3', '-c', '']), + status_command=env_command(['afl-whatsup', '-s', out_dir]), + # The target is a forkserver, so a saved input replays through AFL + # rather than by piping it into the script + replay=shlex.join( + str(arg) + for arg in env_command(['afl-showmap', '-o', '/dev/null', '--', src_file]) + ) + + ' <', + ) + ) + + steps.extend( + afl.corpus_update_steps( + ctx, + inputs_dir=inputs_dir, + out_dir=out_dir, + cmin_command=lambda queue_dir, opt_dir: env_command( + [ + 'afl-cmin', + '-T', + 'all', + '-o', + opt_dir, + '-i', + queue_dir, + '--', + src_file, + ] + ), + # `afl-cmin` measures one input per run through `afl-showmap`, so it + # gets the plain forkserver `py-afl-cmin` gives it; kept, the + # persistent loop shifts which inputs survive minimization + unset_env=('AFL_DUMB_FORKSRV', 'PYTHON_AFL_PERSISTENT'), + ) + ) + + case = genvm_tool.tests.test.StepsCase(description=desc, steps=steps) + ctx.add_case(case) diff --git a/tests/runner/genvm_tool_plugins/runners.py b/tests/runner/genvm_tool_plugins/runners.py new file mode 100644 index 00000000..e558febd --- /dev/null +++ b/tests/runner/genvm_tool_plugins/runners.py @@ -0,0 +1,55 @@ +import functools +import json +import re +from pathlib import Path + +# `@RUNNER_LATEST__@`, where `` is `v0.3` or `v0.3.x` and +# `` is a key of that line's `latest.json`, e.g. `py-genlayer`. +TOKEN = re.compile(rb'@RUNNER_LATEST_(v\d+\.\d+(?:\.x)?)_([A-Za-z0-9_.-]+)@') + + +def _line(line: str) -> str: + return line[:-2] if line.endswith('.x') else line + + +@functools.cache +def latest(root_dir: Path, line: str) -> dict[str, str]: + """Runner id -> uid for the newest runners `line`'s executor was built with.""" + info_path = root_dir / 'build' / 'info.json' + versions = json.loads(info_path.read_text())['executor_versions'] + version = versions.get(_line(line)) + if version is None: + known = ', '.join(sorted(versions)) or '' + raise KeyError(f'unknown executor line {line!r}, built lines are {known}') + path = root_dir / 'build' / 'out' / 'executor' / version / 'data' / 'latest.json' + if not path.exists(): + raise FileNotFoundError( + f'{path} is absent: build the runners before running this test' + ) + return json.loads(path.read_text()) + + +def uid(root_dir: Path, line: str, runner: str) -> str: + """Uid of one runner, as `latest.json` has it after the last build.""" + known = latest(root_dir, line) + if runner not in known: + raise KeyError( + f'{line} has no runner {runner!r}, it has {", ".join(sorted(known))}' + ) + return known[runner] + + +def substitute(data: bytes, root_dir: Path) -> bytes: + """ + Replaces every `@RUNNER_LATEST__@` with the built uid. + + A runner's uid changes with its contents, so a test that pins one by hand + goes stale on every runner edit. The token spares the test that pin. + """ + + def replace(match: re.Match[bytes]) -> bytes: + line = match.group(1).decode('utf-8') + runner = match.group(2).decode('utf-8') + return uid(root_dir, line, runner).encode('utf-8') + + return TOKEN.sub(replace, data) diff --git a/tests/runner/gvm_extra/case_inputs.py b/tests/runner/gvm_extra/case_inputs.py new file mode 100644 index 00000000..e3318677 --- /dev/null +++ b/tests/runner/gvm_extra/case_inputs.py @@ -0,0 +1,17 @@ +import origin.calldata as gvm_calldata + + +def encode_calldata(conf: dict) -> bytes: + """ + Calldata bytes an integration case config asks for. + + ``calldata`` is a python expression, evaluated against the case's ``vars``: + the jsonnet side keeps it as source so a case can build an + :class:`~origin.calldata.Address` or reuse a var. + """ + names = { + 'Address': gvm_calldata.Address, + 'true': True, + 'false': False, + } + return gvm_calldata.encode(eval(conf['calldata'], names, dict(conf.get('vars', {})))) diff --git a/tests/runner/origin/base_host.py b/tests/runner/origin/base_host.py index 2b2cd4bb..f35cf414 100644 --- a/tests/runner/origin/base_host.py +++ b/tests/runner/origin/base_host.py @@ -102,7 +102,8 @@ def __init__(self, error_code: host_fns.Errors, message: str = ''): @dataclass(frozen=True) class UnsafeOverrides: - """Request overrides that reach boundaries production traffic cannot. + """ + Request overrides that reach boundaries production traffic cannot. Each member states the `debug_mode` the manager requires before it applies: `reroute_to` from `safe`, `initial_recursion` from `unsafe`. With debugging @@ -477,7 +478,8 @@ def emit_host_loop_stats(): class ConsumedResultDecodeError(Exception): - """`consumed_result` bytes did not parse into a `ConsumedResult` at all. + """ + `consumed_result` bytes did not parse into a `ConsumedResult` at all. Distinct from `ConsumedResult.internal_error(...)`, which is itself a valid (if unhappy) result value produced from bytes that *did* parse: @@ -493,7 +495,7 @@ class ConsumedResult: """The decoded `consumed_result` blob: a `ResultCode` byte plus calldata.""" execution_hash: bytes - result_kind: public_abi.ResultCode + result_kind: host_fns.ResultCode result_data: gvm_calldata.Decoded result_fingerprint: ResultFingerprint | None = None result_storage_changes: list[tuple[bytes, bytes]] = field(default_factory=list) @@ -505,7 +507,7 @@ class ConsumedResult: def internal_error(cls, message: str) -> 'ConsumedResult': return cls( execution_hash=b'', - result_kind=public_abi.ResultCode.INTERNAL_ERROR, + result_kind=host_fns.ResultCode.INTERNAL_ERROR, result_data=message, ) @@ -522,7 +524,7 @@ def decode(cls, raw: typing.Any) -> 'ConsumedResult': ) empty = not as_bytes if not empty: - result_kind = public_abi.ResultCode(as_bytes[0]) + result_kind = host_fns.ResultCode(as_bytes[0]) decoded = gvm_calldata.decode(as_bytes[1:]) except Exception as exc: # Unreadable bytes are a protocol violation rather than a result, so @@ -538,6 +540,10 @@ def decode(cls, raw: typing.Any) -> 'ConsumedResult': return cls.internal_error('empty_result') if not isinstance(decoded, dict): return cls.internal_error('result is not a mapping') + # The executor reports fatality; degrading it to an ordinary VM error + # is the host's job, so that a caller in another major can still see it + if result_kind == host_fns.ResultCode.FATAL_VM_ERROR: + result_kind = host_fns.ResultCode.VM_ERROR return cls( execution_hash=decoded.get('execution_hash', b''), result_kind=result_kind, @@ -560,7 +566,7 @@ class RunHostAndProgramRes: execution_hash: bytes - result_kind: public_abi.ResultCode + result_kind: host_fns.ResultCode result_data: gvm_calldata.Decoded result_fingerprint: ResultFingerprint | None result_storage_changes: list[tuple[bytes, bytes]] @@ -615,7 +621,8 @@ class ManagerRunLost(Exception): class ManagerRunNotStarted(Exception): - """A run never reached execution, so retrying it re-executes nothing. + """ + A run never reached execution, so retrying it re-executes nothing. Raised for the two ways the manager can refuse before the genvm runs -- a rejected RUN request and a `failed_to_start` terminal. Retry policy belongs @@ -633,7 +640,8 @@ def __init__(self, message: str, *, retryable: bool, reason: str): class TerminalResultUnavailable(Exception): - """A run reached a terminal `finished` state, but its result could not be + """ + A run reached a terminal `finished` state, but its result could not be retrieved or decoded -- artifact transfer failed, or `consumed_result` was empty/malformed. @@ -763,7 +771,8 @@ async def attach(self, boot_id: int, genvm_id: int) -> RunState: def _require_current_generation( self, boot_id: int, genvm_id: int, *, op: str ) -> None: - """Refuse to act on a run from a manager generation we have since left. + """ + Refuse to act on a run from a manager generation we have since left. `CANCEL`/`ACK`/`GET_ARTIFACT` identify a run to the manager by `genvm_id` alone -- the wire protocol has no `boot_id` field for them @@ -1124,7 +1133,8 @@ def _duration_string(seconds: float | None) -> str | None: def _decode_genvm_log(data: bytes) -> list[dict[str, typing.Any]]: - """Decodes the genvm log artifact, which is json lines. + """ + Decodes the genvm log artifact, which is json lines. Split on newline bytes only. `str.splitlines` also breaks on U+2028, U+2029 and U+0085, none of which json escapes and all of which therefore appear raw @@ -1324,9 +1334,9 @@ async def cancel_on_shutdown(): ) from exc if ( status.get('cause') == 'deadline' - and consumed.result_kind != public_abi.ResultCode.RETURN + and consumed.result_kind != host_fns.ResultCode.RETURN ): - consumed.result_kind = public_abi.ResultCode.VM_ERROR + consumed.result_kind = host_fns.ResultCode.VM_ERROR consumed.result_data = str(public_abi.VmError.timeout()) else: # A failed_to_start terminal means the genvm was accepted but never @@ -1346,7 +1356,7 @@ async def cancel_on_shutdown(): raise ManagerRunNotStarted(error, retryable=retryable, reason=reason) vm_error_description: str | None = None - if consumed.result_kind == public_abi.ResultCode.VM_ERROR and isinstance( + if consumed.result_kind == host_fns.ResultCode.VM_ERROR and isinstance( consumed.result_data, str ): try: diff --git a/tests/runner/origin/fees.py b/tests/runner/origin/fees.py index ed3b3069..47ba4019 100644 --- a/tests/runner/origin/fees.py +++ b/tests/runner/origin/fees.py @@ -1,4 +1,5 @@ -"""Message-fee allocation tree types. +""" +Message-fee allocation tree types. Mirrors the executor's `genvm_common::domain::fees` module: the fee parameters and the nested `MessageAllocationNode` tree that is passed alongside an diff --git a/tests/runner/origin/host_fns.py b/tests/runner/origin/host_fns.py index 316d11e8..9715e1be 100644 --- a/tests/runner/origin/host_fns.py +++ b/tests/runner/origin/host_fns.py @@ -19,25 +19,19 @@ class Methods(IntEnum): RUN_NESTED = 8 +class ResultCode(IntEnum): + RETURN = 0 + USER_ERROR = 1 + VM_ERROR = 2 + INTERNAL_ERROR = 3 + FATAL_VM_ERROR = 4 + + class Errors(IntEnum): OK = 0 EVM_REVERTED = 1 FORBIDDEN = 2 -class VmErrorDetail: - __slots__ = ('value',) - def __init__(self, value: str): - self.value = value - def __str__(self) -> str: - return self.value - @staticmethod - def internal() -> 'VmErrorDetail': - return VmErrorDetail('internal') - @staticmethod - def external() -> 'VmErrorDetail': - return VmErrorDetail('external') - - CURRENT_MAJOR: typing.Final[int] = 0 diff --git a/tests/runner/origin/log_asserts.py b/tests/runner/origin/log_asserts.py index a46507a6..21c0618a 100644 --- a/tests/runner/origin/log_asserts.py +++ b/tests/runner/origin/log_asserts.py @@ -1,4 +1,5 @@ -"""Assertions over the executor's structured log records. +""" +Assertions over the executor's structured log records. The manager captures every executor-emitted log line and surfaces them as ``RunHostAndProgramRes.genvm_log`` — a list of JSON objects shaped like @@ -6,12 +7,10 @@ under ``debug_mode >= safe-unbounded`` (integration tests run ``unsafe``), so no record is evicted regardless of how chatty the run is. -The ADR-012 load action emits one stable ``"runner load"`` record per load, -carrying: +The load action emits one stable ``"runner load"`` record per load, carrying: - ``runner`` — the canonical runner id (``chain:``/``custom:``/``name:hash``); -- ``runner_load_cost`` — the flat per-load constant - (``public_abi::memory_limiter_consts::RUNNER_LOAD_COST``); +- ``runner_load_cost`` — the flat per-load memory limiter constant; - ``size`` — the charged content size (archive ``total_size``); - ``status`` — ``"charged"`` (first load in this VM) or ``"cached"`` (already in the VM's loaded set — free). @@ -62,7 +61,8 @@ def extract( match: dict | None = None, runner_prefix: str | None = None, ) -> list[dict]: - """Return the ``genvm_log`` records matching ``match`` (defaulting to the + """ + Return the ``genvm_log`` records matching ``match`` (defaulting to the ``runner load`` message) and an optional ``runner`` prefix.""" return _select(genvm_log, match or {}, runner_prefix) diff --git a/tests/runner/origin/public_abi.py b/tests/runner/origin/public_abi.py index cc3445bb..abb7a496 100644 --- a/tests/runner/origin/public_abi.py +++ b/tests/runner/origin/public_abi.py @@ -11,7 +11,6 @@ class ResultCode(IntEnum): RETURN = 0 USER_ERROR = 1 VM_ERROR = 2 - INTERNAL_ERROR = 3 class StorageType(IntEnum): @@ -30,16 +29,6 @@ class Permissions(IntEnum): CAN_USE_BALANCE_FOR_MESSAGE_FEES = 1 -class _MemoryLimiterConsts(typing.NamedTuple): - TABLE_ENTRY: int = 64 - FILE_MAPPING: int = 256 - FD_ALLOCATION: int = 96 - RUNNER_LOAD_COST: int = 4096 - VM_SPAWN_COST: int = 134217728 - -memory_limiter_consts: typing.Final = _MemoryLimiterConsts() - - class _RootOffsets(typing.NamedTuple): MAJOR: int = 0 CONTRACT: int = 1 @@ -52,24 +41,39 @@ class _RootOffsets(typing.NamedTuple): root_offsets: typing.Final = _RootOffsets() -class _TopLimits(typing.NamedTuple): - NONDET_BLOCKS: int = 4096 - LOCKED_SLOTS: int = 256 - UPGRADERS: int = 32 - VM_RECURSION: int = 512 - WEB_REQUEST_MIN_SPACE: int = 65536 - WEB_RENDER_MIN_SPACE: int = 134217728 - MAX_FDS: int = 1024 - WASM_CALL_DEPTH: int = 1024 - WASM_STACK_VALUE_SLOTS: int = 65535 - -top_limits: typing.Final = _TopLimits() - - class SpecialMethod(StrEnum): GET_SCHEMA = '#get-schema' ERRORED_MESSAGE = '#error' +class _VmErrorLeaderFaultNondetOutput: + @staticmethod + def absent() -> 'VmError': + return VmError('leader_fault nondet_output absent') + @staticmethod + def malformed() -> 'VmError': + return VmError('leader_fault nondet_output malformed') + @staticmethod + def uses_this_error() -> '_VmErrorLeaderFaultNondetOutputUsesThisError': + return _VmErrorLeaderFaultNondetOutputUsesThisError() + @staticmethod + def extra() -> '_VmErrorLeaderFaultNondetOutputExtra': + return _VmErrorLeaderFaultNondetOutputExtra() + +class _VmErrorLeaderFaultNondetOutputUsesThisError: + @staticmethod + def val_str(v: str) -> 'VmError': + return VmError(f'leader_fault nondet_output uses_this_error {v}') + +class _VmErrorLeaderFaultNondetOutputExtra: + @staticmethod + def val_str(v: str) -> 'VmError': + return VmError(f'leader_fault nondet_output extra {v}') + +class _VmErrorLeaderFault: + @staticmethod + def nondet_output() -> '_VmErrorLeaderFaultNondetOutput': + return _VmErrorLeaderFaultNondetOutput() + class _VmErrorWasmTrap: @staticmethod def val() -> 'VmError': @@ -195,6 +199,14 @@ class _VmErrorEvm: def reverted() -> 'VmError': return VmError('evm reverted') +class _VmErrorInvalidContractRunner: + @staticmethod + def absent() -> 'VmError': + return VmError('invalid_contract runner absent') + @staticmethod + def malformed() -> 'VmError': + return VmError('invalid_contract runner malformed') + class _VmErrorInvalidContractWasm: @staticmethod def validating() -> 'VmError': @@ -211,18 +223,15 @@ class _VmErrorInvalidContract: def val() -> 'VmError': return VmError('invalid_contract') @staticmethod - def absent_runner_comment() -> 'VmError': - return VmError('invalid_contract absent_runner_comment') - @staticmethod def not_utf8_text() -> 'VmError': return VmError('invalid_contract not_utf8_text') @staticmethod - def malformed_runner() -> 'VmError': - return VmError('invalid_contract malformed_runner') - @staticmethod def major_mismatch() -> 'VmError': return VmError('invalid_contract major_mismatch') @staticmethod + def runner() -> '_VmErrorInvalidContractRunner': + return _VmErrorInvalidContractRunner() + @staticmethod def wasm() -> '_VmErrorInvalidContractWasm': return _VmErrorInvalidContractWasm() @@ -241,11 +250,14 @@ def __str__(self) -> str: def timeout() -> 'VmError': return VmError('timeout') @staticmethod - def absent_leader_nondet_output() -> 'VmError': - return VmError('absent_leader_nondet_output') + def malformed_entry() -> 'VmError': + return VmError('malformed_entry') + @staticmethod + def forbidden() -> 'VmError': + return VmError('forbidden') @staticmethod - def host_forbidden() -> 'VmError': - return VmError('host_forbidden') + def leader_fault() -> '_VmErrorLeaderFault': + return _VmErrorLeaderFault() @staticmethod def exit_code() -> '_VmErrorExitCode': return _VmErrorExitCode() @@ -264,6 +276,12 @@ def evm() -> '_VmErrorEvm': @staticmethod def invalid_contract() -> '_VmErrorInvalidContract': return _VmErrorInvalidContract() + def internal(self) -> 'VmError': + assert ' # ' not in self.value + return VmError(f'{self.value} # internal') + def external(self) -> 'VmError': + assert ' # ' not in self.value + return VmError(f'{self.value} # external') diff --git a/tests/system/cross-major-observability/assets/v0.2/caller.py b/tests/system/cross-major-observability/assets/v0.2/caller.py new file mode 100644 index 00000000..784eb1eb --- /dev/null +++ b/tests/system/cross-major-observability/assets/v0.2/caller.py @@ -0,0 +1,27 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.2_py-genlayer@" } +from genlayer import * + + +class Contract(gl.Contract): + def __init__(self): + pass + + @gl.public.view + def context(self, target: Address): + return gl.get_contract_at(target).view().context() + + @gl.public.view + def permissions(self, target: Address, helper: Address): + return gl.get_contract_at(target).view().permissions(helper) + + @gl.public.view + def debug_alias(self, target: Address): + return gl.get_contract_at(target).view().debug_alias() + + @gl.public.view + def read(self, target: Address) -> int: + return gl.get_contract_at(target).view().read() + + @gl.public.view + def answer(self, target: Address) -> int: + return gl.get_contract_at(target).view().answer() diff --git a/tests/system/cross-major-observability/assets/v0.2/chain.py b/tests/system/cross-major-observability/assets/v0.2/chain.py new file mode 100644 index 00000000..a3ab6c98 --- /dev/null +++ b/tests/system/cross-major-observability/assets/v0.2/chain.py @@ -0,0 +1,15 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.2_py-genlayer@" } +from genlayer import * + + +class Contract(gl.Contract): + def __init__(self): + pass + + @gl.public.view + def hop(self, depth: int, other: Address) -> int: + if depth <= 0: + return 2 + return 2 + gl.get_contract_at(other).view().hop( + depth - 1, gl.message.contract_address + ) diff --git a/tests/system/cross-major-observability/assets/v0.3/chain.py b/tests/system/cross-major-observability/assets/v0.3/chain.py new file mode 100644 index 00000000..44b83fc4 --- /dev/null +++ b/tests/system/cross-major-observability/assets/v0.3/chain.py @@ -0,0 +1,16 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.3_py-genlayer@" } +import genlayer as gl +from genlayer.types import Address + + +class Contract(gl.contract.Contract): + def __init__(self): + pass + + @gl.public.view + def hop(self, depth: int, other: Address) -> int: + if depth <= 0: + return 3 + return 3 + gl.contract.get_at(other).view().hop( + depth - 1, gl.message.contract_address + ) diff --git a/tests/system/cross-major-observability/assets/v0.3/helper.py b/tests/system/cross-major-observability/assets/v0.3/helper.py new file mode 100644 index 00000000..ee36e49c --- /dev/null +++ b/tests/system/cross-major-observability/assets/v0.3/helper.py @@ -0,0 +1,11 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.3_py-genlayer@" } +import genlayer as gl + + +class Contract(gl.contract.Contract): + def __init__(self): + pass + + @gl.public.view + def answer(self) -> int: + return 11 diff --git a/tests/system/cross-major-observability/assets/v0.3/observer.py b/tests/system/cross-major-observability/assets/v0.3/observer.py new file mode 100644 index 00000000..eb4fd657 --- /dev/null +++ b/tests/system/cross-major-observability/assets/v0.3/observer.py @@ -0,0 +1,60 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.3_py-genlayer@" } +import genlayer as gl +import _genlayer_wasi as wasi +from genlayer.types import Address, u32 + + +class Contract(gl.contract.Contract): + value: u32 + + def __init__(self): + self.value = 777 + + @gl.public.view + def context(self): + return { + 'contract': gl.message.contract_address.as_hex, + 'sender': gl.message.sender_address.as_hex, + 'origin': gl.message.origin_address.as_hex, + 'signer': gl.message.signer_address.as_hex, + 'stack': [address.as_hex for address in gl.message.stack], + 'value': int(gl.message.value), + 'is_init': gl.message.is_init, + } + + @gl.public.view + def read(self) -> int: + return self.value + + @gl.public.view + def permissions(self, helper: Address): + def attempt(action): + try: + value = action() + return {'kind': 'allowed', 'value': str(value)} + except OSError as exc: + return {'kind': 'oserror', 'errno': exc.errno} + except Exception as exc: + return {'kind': type(exc).__name__, 'value': str(exc)} + + write = attempt(lambda: wasi.storage_write(b'\x77' * 32, 0, b'forbidden')) + send = attempt(lambda: gl.contract.get_at(Address(b'\x66' * 20)).emit().ping()) + nondet = attempt(lambda: gl.vm.run_nondet(lambda: 1, lambda _result: True)) + + registered = gl.vm.register_runner( + b'# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.3_py-genlayer@" }\n' + b'print("registered")\n' + ) + called = gl.contract.get_at(helper).view().answer() + return { + 'write': write, + 'send': send, + 'nondet': nondet, + 'registered': registered, + 'called': called, + } + + @gl.public.view + def debug_alias(self) -> int: + result = gl.vm.spawn_sandbox(lambda: 1, runner='py-genlayer:test') + return gl.vm.unpack_result(result) diff --git a/tests/system/cross-major-observability/assets/v0.3/self_recursion.py b/tests/system/cross-major-observability/assets/v0.3/self_recursion.py new file mode 100644 index 00000000..8e1e2370 --- /dev/null +++ b/tests/system/cross-major-observability/assets/v0.3/self_recursion.py @@ -0,0 +1,20 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.3_py-genlayer@" } +import genlayer as gl + + +class Contract(gl.contract.Contract): + def __init__(self): + pass + + @gl.public.view + def recurse(self, depth: int) -> int: + if depth == 0: + return 1 + return 1 + gl.contract.get_at(self.address).view().recurse(depth - 1) + + @gl.public.view + def observe_recursion(self, depth: int) -> str: + try: + return 'ok:' + str(self.recurse(depth)) + except gl.vm.UserError as exc: + return 'caught:' + str(exc.data) diff --git a/tests/system/cross-major-observability/assets/v0.3/trap.py b/tests/system/cross-major-observability/assets/v0.3/trap.py new file mode 100644 index 00000000..f143796d --- /dev/null +++ b/tests/system/cross-major-observability/assets/v0.3/trap.py @@ -0,0 +1,11 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.3_py-genlayer@" } +import genlayer as gl + + +class Contract(gl.contract.Contract): + def __init__(self): + pass + + @gl.public.view + def answer(self) -> int: + raise RuntimeError('callee trap') diff --git a/tests/system/cross-major-observability/assets/v0.3/user_error.py b/tests/system/cross-major-observability/assets/v0.3/user_error.py new file mode 100644 index 00000000..e50f8d5a --- /dev/null +++ b/tests/system/cross-major-observability/assets/v0.3/user_error.py @@ -0,0 +1,11 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.3_py-genlayer@" } +import genlayer as gl + + +class Contract(gl.contract.Contract): + def __init__(self): + pass + + @gl.public.view + def answer(self) -> int: + gl.vm.UserError.immediate('nested user error') diff --git a/tests/system/cross-major-observability/test.py b/tests/system/cross-major-observability/test.py index 99df3864..0055fa12 100644 --- a/tests/system/cross-major-observability/test.py +++ b/tests/system/cross-major-observability/test.py @@ -1,9 +1,11 @@ -"""Cross-major CallContract observability and determinism integration tests. +""" +Cross-major CallContract observability and determinism integration tests. This case reuses the real-manager harness from ``tests/system/cross-major`` without adding more concerns to that already-large case. """ +import functools import importlib.util import json import pickle @@ -12,10 +14,11 @@ from dataclasses import dataclass from pathlib import Path +import genvm_tool.io as gvm_io import genvm_tool.tests import genvm_tool.tests.stage.collection from gvm_extra.mock_host import MockStorage -from origin import public_abi +from origin import host_fns, public_abi from origin.calldata import Address @@ -41,229 +44,45 @@ def _load_cross_major_harness(): ADDR_CHAIN_V02 = Address('0x' + '48' * 20) ABSENT = Address('0x' + '99' * 20) +# Mirrors `CROSS_MAJOR_RECURSION` in implementation/src/manager/run.rs: how many +# delegated hops one chain of contract calls may make. +CROSS_MAJOR_RECURSION = 6 -CALLER_V02 = base._contract_source( - 2, - """ - from genlayer import * - - - class Contract(gl.Contract): - def __init__(self): - pass - - @gl.public.view - def context(self, target: Address): - return gl.get_contract_at(target).view().context() - - @gl.public.view - def permissions(self, target: Address, helper: Address): - return gl.get_contract_at(target).view().permissions(helper) - - @gl.public.view - def debug_alias(self, target: Address): - return gl.get_contract_at(target).view().debug_alias() - - @gl.public.view - def read(self, target: Address) -> int: - return gl.get_contract_at(target).view().read() - - @gl.public.view - def answer(self, target: Address) -> int: - return gl.get_contract_at(target).view().answer() - """, -) - -OBSERVER_V03 = base._contract_source( - 3, - f""" - import genlayer as gl - import _genlayer_wasi as wasi - from genlayer.types import Address, u32 - - - class Contract(gl.contract.Contract): - value: u32 - - def __init__(self): - self.value = 777 - - @gl.public.view - def context(self): - return {{ - 'contract': gl.message.contract_address.as_hex, - 'sender': gl.message.sender_address.as_hex, - 'origin': gl.message.origin_address.as_hex, - 'signer': gl.message.signer_address.as_hex, - 'stack': [address.as_hex for address in gl.message.stack], - 'value': int(gl.message.value), - 'is_init': gl.message.is_init, - }} - - @gl.public.view - def read(self) -> int: - return self.value - - @gl.public.view - def permissions(self, helper: Address): - def attempt(action): - try: - value = action() - return {{'kind': 'allowed', 'value': str(value)}} - except OSError as exc: - return {{'kind': 'oserror', 'errno': exc.errno}} - except Exception as exc: - return {{'kind': type(exc).__name__, 'value': str(exc)}} - - write = attempt( - lambda: wasi.storage_write(b'\\x77' * 32, 0, b'forbidden') - ) - send = attempt( - lambda: gl.contract.get_at(Address(b'\\x66' * 20)).emit().ping() - ) - nondet = attempt( - lambda: gl.vm.run_nondet(lambda: 1, lambda _result: True) - ) - - registered = gl.vm.register_runner( - b'# {{ "Depends": "py-genlayer:{base.PY_GENLAYER_V03}" }}\\n' - b'print("registered")\\n' - ) - called = gl.contract.get_at(helper).view().answer() - return {{ - 'write': write, - 'send': send, - 'nondet': nondet, - 'registered': registered, - 'called': called, - }} - - @gl.public.view - def debug_alias(self) -> int: - result = gl.vm.spawn_sandbox(lambda: 1, runner='py-genlayer:test') - return gl.vm.unpack_result(result) - """, -) - -HELPER_V03 = base._contract_source( - 3, - """ - import genlayer as gl - - - class Contract(gl.contract.Contract): - def __init__(self): - pass - - @gl.public.view - def answer(self) -> int: - return 11 - """, -) - -SELF_V03 = base._contract_source( - 3, - """ - import genlayer as gl - - - class Contract(gl.contract.Contract): - def __init__(self): - pass - - @gl.public.view - def recurse(self, depth: int) -> int: - if depth == 0: - return 1 - return 1 + gl.contract.get_at(self.address).view().recurse(depth - 1) - - @gl.public.view - def observe_recursion(self, depth: int) -> str: - try: - return 'ok:' + str(self.recurse(depth)) - except gl.vm.UserError as exc: - return 'caught:' + str(exc.data) - """, -) - -TRAP_V03 = base._contract_source( - 3, - """ - import genlayer as gl - - - class Contract(gl.contract.Contract): - def __init__(self): - pass - @gl.public.view - def answer(self) -> int: - raise RuntimeError('callee trap') - """, +_contract_source = functools.partial( + base._contract_source, + assets_dir=Path(__file__).resolve().parent / 'assets', ) -USER_ERROR_V03 = base._contract_source( - 3, - """ - import genlayer as gl - - - class Contract(gl.contract.Contract): - def __init__(self): - pass - - @gl.public.view - def answer(self) -> int: - gl.vm.UserError.immediate('nested user error') - """, -) - -CHAIN_V03 = base._contract_source( - 3, - """ - import genlayer as gl - from genlayer.types import Address - - - class Contract(gl.contract.Contract): - def __init__(self): - pass - - @gl.public.view - def hop(self, depth: int, other: Address) -> int: - if depth <= 0: - return 3 - return 3 + gl.contract.get_at(other).view().hop( - depth - 1, gl.message.contract_address - ) - """, -) - -CHAIN_V02 = base._contract_source( - 2, - """ - from genlayer import * - - - class Contract(gl.Contract): - def __init__(self): - pass - - @gl.public.view - def hop(self, depth: int, other: Address) -> int: - if depth <= 0: - return 2 - return 2 + gl.get_contract_at(other).view().hop( - depth - 1, gl.message.contract_address - ) - """, -) +CALLER_V02 = _contract_source(2, 'caller') +OBSERVER_V03 = _contract_source(3, 'observer') +HELPER_V03 = _contract_source(3, 'helper') +SELF_V03 = _contract_source(3, 'self_recursion') +TRAP_V03 = _contract_source(3, 'trap') +USER_ERROR_V03 = _contract_source(3, 'user_error') +CHAIN_V03 = _contract_source(3, 'chain') +CHAIN_V02 = _contract_source(2, 'chain') + +FIXTURES = { + 'caller-v02': (2, ADDR_CALLER_V02, CALLER_V02), + 'observer-v03': (3, ADDR_OBSERVER_V03, OBSERVER_V03), + 'helper-v03': (3, ADDR_HELPER_V03, HELPER_V03), + 'self-v03': (3, ADDR_SELF_V03, SELF_V03), + 'trap-v03': (3, ADDR_TRAP_V03, TRAP_V03), + 'user-error-v03': (3, ADDR_USER_ERROR_V03, USER_ERROR_V03), + 'chain-v03': (3, ADDR_CHAIN_V03, CHAIN_V03), + 'chain-v02': (2, ADDR_CHAIN_V02, CHAIN_V02), +} @dataclass class ObservabilityCase(genvm_tool.tests.test.Case): description: genvm_tool.tests.test.Description shared: genvm_tool.tests.SharedContext + manager_service: genvm_tool.tests.stage.collection.Service + method: str + fixtures: tuple[str, ...] + arguments: tuple[typing.Any, ...] = () async def into_steps(self) -> list[genvm_tool.tests.exec.step.Step]: return [ObservabilityStep(self)] @@ -278,54 +97,21 @@ async def _run_all(self): 2: build_info['executor_versions']['v0.2'], 3: build_info['executor_versions']['v0.3'], } - work_dir = self.case.shared.artifacts_dir / 'cross-major-observability' + work_dir = self.case.shared.case_dir_for(self.case.description.name) self.storage_path = work_dir / 'storage.pickle' work_dir.mkdir(parents=True, exist_ok=True) - with open(self.storage_path, 'wb') as storage_file: - pickle.dump(MockStorage(), storage_file) + await gvm_io.write_file_bytes(self.storage_path, pickle.dumps(MockStorage())) - async with base.ManagerProc( - build_dir=self.build_dir, - work_dir=work_dir / 'manager', - ) as manager: - self.manager = manager + manager = self.case.manager_service.handle + assert manager is not None + self.manager = manager - self.phase = 'deploy observability fixtures' - for line, address, code in ( - (2, ADDR_CALLER_V02, CALLER_V02), - (3, ADDR_OBSERVER_V03, OBSERVER_V03), - (3, ADDR_HELPER_V03, HELPER_V03), - (3, ADDR_SELF_V03, SELF_V03), - (3, ADDR_TRAP_V03, TRAP_V03), - (3, ADDR_USER_ERROR_V03, USER_ERROR_V03), - (3, ADDR_CHAIN_V03, CHAIN_V03), - (2, ADDR_CHAIN_V02, CHAIN_V02), - ): - await self._deploy(line, address, code) + self.phase = 'deploy observability fixtures' + for line, address, code in (FIXTURES[name] for name in self.case.fixtures): + await self._deploy(line, address, code) - self.phase = 'leader and validator modes are genuine' - await self._assert_validator_mode() - - self.phase = 'callee observes the preserved nested message' - await self._assert_context() - - self.phase = 'nested permissions and disabled debug are observable' - await self._assert_permissions_and_debug() - - self.phase = 'read-only roots and nested storage reads agree' - await self._assert_read_only_storage() - - self.phase = 'self-call recursion budgets agree in lvs' - await self._assert_self_recursion() - - self.phase = 'deep alternating nesting agrees in lvs' - await self._assert_deep_nesting() - - self.phase = 'contract-controlled nested errors are not internal' - await self._assert_error_propagation() - - self.phase = 'imported deterministic fuel agrees in lvs' - await self._assert_fuel() + self.phase = self.case.method + await getattr(self, self.case.method)(*self.case.arguments) async def _execute( self, @@ -361,7 +147,10 @@ async def _execute( ), host_data='{"node_address":"test","tx_id":"cross-major-observe"}', host='unix://' + mock_host.path, - code=kwargs.get('code'), + code=base.resolve_runners( + typing.cast('bytes | None', kwargs.get('code')), + self.case.shared.root_dir, + ), calldata=typing.cast(bytes, kwargs['calldata']), timeout=kwargs.get('timeout', 30), debug_mode='unsafe', @@ -380,7 +169,7 @@ async def _execute( ) if ( kwargs.get('apply_changes', True) - and result.result_kind == public_abi.ResultCode.RETURN + and result.result_kind == host_fns.ResultCode.RETURN ): assert mock_host.storage is not None base._apply_storage_changes( @@ -425,7 +214,7 @@ async def one(suffix: str, **mode): ('validator', validator), ('sync', sync), ): - assert result.result_kind != public_abi.ResultCode.INTERNAL_ERROR, ( + assert result.result_kind != host_fns.ResultCode.INTERNAL_ERROR, ( name, label, result, @@ -465,7 +254,7 @@ async def _assert_validator_mode(self): is_sync=False, leader_nondet_results=[base.gvm_calldata.encode({})], ) - assert bogus.result_kind == public_abi.ResultCode.VM_ERROR, bogus + assert bogus.result_kind == host_fns.ResultCode.VM_ERROR, bogus async def _assert_context(self): routes: list[Address] = [] @@ -491,12 +280,12 @@ def resolve(address, state, major): 'is_init': False, } for result in (leader, validator, sync): - assert result.result_kind == public_abi.ResultCode.RETURN, result + assert result.result_kind == host_fns.ResultCode.RETURN, result assert result.result_data == expected, (result.result_data, expected) assert routes == [ADDR_OBSERVER_V03] * 3, routes self.notes.append(('nested context', expected)) - async def _assert_permissions_and_debug(self): + async def _assert_permissions(self): leader, validator, sync = await self._lvs_extended( name='permissions', line=2, @@ -506,7 +295,7 @@ async def _assert_permissions_and_debug(self): permissions='wscnu', ) for result in (leader, validator, sync): - assert result.result_kind == public_abi.ResultCode.RETURN, result + assert result.result_kind == host_fns.ResultCode.RETURN, result observed = result.result_data for denied in ('write', 'send', 'nondet'): assert observed[denied]['kind'] == 'SystemError', observed @@ -515,6 +304,7 @@ async def _assert_permissions_and_debug(self): assert observed['called'] == 11, observed self.notes.append(('nested permission observations', leader.result_data)) + async def _assert_debug_alias(self): top_level = await self._execute( name='debug-alias-top-level', line=3, @@ -525,12 +315,15 @@ async def _assert_permissions_and_debug(self): resolve_hook=self._route_v03, apply_changes=False, ) - # Unsafe mode resolves the alias and gets as far as running it. The - # deliberately mismatched sandbox payload is then an ordinary user-visible - # invalid-contract result, rather than the absent/malformed runner emitted - # before startup under disabled debug. - assert top_level.result_kind == public_abi.ResultCode.USER_ERROR, top_level - assert top_level.result_data == 'vm error: invalid_contract', top_level + # Unsafe mode resolves the alias and gets as far as running it, so the + # deliberately mismatched sandbox payload surfaces as a user error the + # contract can see. Under disabled debug the same runner fails before + # startup and is a vm error instead; the kind, not the code, is what + # separates the two. + assert top_level.result_kind == host_fns.ResultCode.USER_ERROR, top_level + assert top_level.result_data == 'vm error: ' + str( + public_abi.VmError.invalid_contract().runner().malformed() + ), top_level leader, validator, sync = await self._lvs_extended( name='debug-alias-nested', @@ -540,9 +333,9 @@ async def _assert_permissions_and_debug(self): resolve_hook=self._route_v03, ) for result in (leader, validator, sync): - assert result.result_kind == public_abi.ResultCode.VM_ERROR, result + assert result.result_kind == host_fns.ResultCode.VM_ERROR, result assert result.result_data == str( - public_abi.VmError.invalid_contract().malformed_runner() + public_abi.VmError.invalid_contract().runner().malformed() ), result self.notes.append( ( @@ -551,124 +344,213 @@ async def _assert_permissions_and_debug(self): ) ) - async def _assert_read_only_storage(self): - for permissions in ('c', 'wscn'): - reads: list[tuple[Address, public_abi.StorageType]] = [] - leader, validator, sync = await self._lvs_extended( - name=f'storage-{permissions}', - line=2, - address=ADDR_CALLER_V02, - calldata=base._calldata('read', ADDR_OBSERVER_V03), - resolve_hook=self._route_v03, - permissions=permissions, - read_log=reads, - ) - for result in (leader, validator, sync): - assert result.result_kind == public_abi.ResultCode.RETURN, result - assert result.result_data == 777, result - assert any(account == ADDR_OBSERVER_V03 for account, _mode in reads), reads - self.notes.append(('read-only nested storage', 'c and wscn both returned 777')) + async def _assert_read_only_storage(self, permissions: str): + reads: list[tuple[Address, public_abi.StorageType]] = [] + leader, validator, sync = await self._lvs_extended( + name=f'storage-{permissions}', + line=2, + address=ADDR_CALLER_V02, + calldata=base._calldata('read', ADDR_OBSERVER_V03), + resolve_hook=self._route_v03, + permissions=permissions, + read_log=reads, + ) + for result in (leader, validator, sync): + assert result.result_kind == host_fns.ResultCode.RETURN, result + assert result.result_data == 777, result + assert any(account == ADDR_OBSERVER_V03 for account, _mode in reads), reads + self.notes.append(('read-only nested storage', permissions)) - async def _assert_self_recursion(self): + async def _assert_self_recursion(self, budget: int): expected_error = str(public_abi.VmError.out_of().vm_recursion()) - outcomes = [] - for budget in (0, 1, 2, 4, 5, 6): - leader, validator, sync = await self._lvs_extended( - name=f'self-recursion-{budget}', - line=3, - address=ADDR_SELF_V03, - calldata=base._calldata('observe_recursion', 4), - resolve_hook=self._route_v03, - debug_initial_recursion=budget, - ) - for result in (leader, validator, sync): - if budget < 5: - assert result.result_kind == public_abi.ResultCode.VM_ERROR, result - assert result.result_data == expected_error, ( - budget, - result.result_data, - expected_error, - ) - else: - assert result.result_kind == public_abi.ResultCode.RETURN, result - assert result.result_data == 'ok:5', (budget, result) - outcomes.append( + leader, validator, sync = await self._lvs_extended( + name=f'self-recursion-{budget}', + line=3, + address=ADDR_SELF_V03, + calldata=base._calldata('observe_recursion', 4), + resolve_hook=self._route_v03, + debug_initial_recursion=budget, + ) + for result in (leader, validator, sync): + if budget < 5: + assert result.result_kind == host_fns.ResultCode.VM_ERROR, result + assert result.result_data == expected_error, ( + budget, + result.result_data, + expected_error, + ) + else: + assert result.result_kind == host_fns.ResultCode.RETURN, result + assert result.result_data == 'ok:5', (budget, result) + self.notes.append( + ( + 'self recursion outcome', ( budget, str(leader.result_kind), str(leader.result_data), leader.execution_hash.hex(), - ) - ) - self.notes.append(('self recursion outcomes', outcomes)) - - async def _assert_deep_nesting(self): - outcomes = [] - for depth in (1, 4, 8): - leader, validator, sync = await self._lvs_extended( - name=f'deep-{depth}', - line=3, - address=ADDR_CHAIN_V03, - calldata=base._calldata('hop', depth, ADDR_CHAIN_V02), - resolve_hook=self._route_chain, + ), ) + ) + + async def _assert_deep_nesting(self, depth: int): + # A chain deeper than the manager's cross-major bound is refused rather + # than served, and every node refuses it at the same place. + leader, validator, sync = await self._lvs_extended( + name=f'deep-{depth}', + line=3, + address=ADDR_CHAIN_V03, + calldata=base._calldata('hop', depth, ADDR_CHAIN_V02), + resolve_hook=self._route_chain, + ) + if depth > CROSS_MAJOR_RECURSION: + for result in (leader, validator, sync): + assert result.result_kind == host_fns.ResultCode.VM_ERROR, result + assert result.result_data == 'out_of vm_recursion', (depth, result) + outcome: int | str = 'out_of vm_recursion' + else: expected = sum(3 if index % 2 == 0 else 2 for index in range(depth + 1)) for result in (leader, validator, sync): - assert result.result_kind == public_abi.ResultCode.RETURN, result + assert result.result_kind == host_fns.ResultCode.RETURN, result assert result.result_data == expected, (depth, result, expected) - outcomes.append((depth, expected, leader.execution_hash.hex())) - self.notes.append(('deep alternating hashes', outcomes)) - - async def _assert_error_propagation(self): - cases = ( - ('undeployed', ABSENT), - ('non-contract', base.SENDER), - ('trap', ADDR_TRAP_V03), - ('user-error', ADDR_USER_ERROR_V03), + outcome = expected + self.notes.append( + ('deep alternating hash', (depth, outcome, leader.execution_hash.hex())) ) - observed = [] - for label, target in cases: - leader, validator, sync = await self._lvs_extended( - name=f'error-{label}', - line=2, - address=ADDR_CALLER_V02, - calldata=base._calldata('answer', target), - resolve_hook=lambda address, state, major, target=target: ( - self._route(3) - if address == target - else self._route_v03(address, state, major) - ), + + async def _assert_error(self, label: str, target: Address): + leader, validator, sync = await self._lvs_extended( + name=f'error-{label}', + line=2, + address=ADDR_CALLER_V02, + calldata=base._calldata('answer', target), + resolve_hook=lambda address, state, major: ( + self._route(3) if address == target else self._route_v03(address, state, major) + ), + ) + for result in (leader, validator, sync): + assert result.result_kind in { + host_fns.ResultCode.VM_ERROR, + host_fns.ResultCode.USER_ERROR, + }, (label, result) + self.notes.append( + ( + 'nested error outcome', + (label, str(leader.result_kind), str(leader.result_data)[:120]), ) - for result in (leader, validator, sync): - assert result.result_kind in { - public_abi.ResultCode.VM_ERROR, - public_abi.ResultCode.USER_ERROR, - }, (label, result) - observed.append((label, str(leader.result_kind), str(leader.result_data)[:120])) - self.notes.append(('nested error outcomes', observed)) - - async def _assert_fuel(self): - outcomes = [] - for fuel in (0, 1, 1000, 2**32): - leader, validator, sync = await self._lvs_extended( - name=f'fuel-{fuel}', - line=2, - address=ADDR_CALLER_V02, - calldata=base._calldata('read', ADDR_OBSERVER_V03), - resolve_hook=self._route_v03, - host_fuel=fuel, + ) + + async def _assert_undeployed_error(self): + await self._assert_error('undeployed', ABSENT) + + async def _assert_non_contract_error(self): + await self._assert_error('non-contract', base.SENDER) + + async def _assert_trap_error(self): + await self._assert_error('trap', ADDR_TRAP_V03) + + async def _assert_user_error(self): + await self._assert_error('user-error', ADDR_USER_ERROR_V03) + + async def _assert_fuel(self, fuel: int): + leader, validator, sync = await self._lvs_extended( + name=f'fuel-{fuel}', + line=2, + address=ADDR_CALLER_V02, + calldata=base._calldata('read', ADDR_OBSERVER_V03), + resolve_hook=self._route_v03, + host_fuel=fuel, + ) + for result in (leader, validator, sync): + assert result.result_kind == host_fns.ResultCode.RETURN, result + assert result.result_data == 777, result + self.notes.append( + ('nested deterministic fuel hash', (fuel, leader.execution_hash.hex())) + ) + + +def collect( + ctx: genvm_tool.tests.stage.collection.Context, + *, + manager_service: genvm_tool.tests.stage.collection.Service, +) -> None: + cases = [ + ('validator-mode', '_assert_validator_mode', ('chain-v03', 'chain-v02'), ()), + ('message-context', '_assert_context', ('caller-v02', 'observer-v03'), ()), + ( + 'permissions', + '_assert_permissions', + ('caller-v02', 'observer-v03', 'helper-v03'), + (), + ), + ('debug-alias', '_assert_debug_alias', ('caller-v02', 'observer-v03'), ()), + *[ + ( + f'read-only-storage-{permissions}', + '_assert_read_only_storage', + ('caller-v02', 'observer-v03'), + (permissions,), ) - for result in (leader, validator, sync): - assert result.result_kind == public_abi.ResultCode.RETURN, result - assert result.result_data == 777, result - outcomes.append((fuel, leader.execution_hash.hex())) - self.notes.append(('nested deterministic fuel hashes', outcomes)) - - -def collect(ctx: genvm_tool.tests.stage.collection.Context) -> None: - desc = genvm_tool.tests.test.Description( - name='tests/system/cross-major-observability', - tags=frozenset({'integration', 'stable', 'cross-major'}), - console_pool=True, - ) - ctx.add_case(ObservabilityCase(description=desc, shared=ctx.shared)) + for permissions in ('c', 'wscn') + ], + *[ + ( + f'self-recursion-{budget}', + '_assert_self_recursion', + ('self-v03',), + (budget,), + ) + for budget in (0, 1, 2, 4, 5, 6) + ], + *[ + ( + f'deep-nesting-{depth}', + '_assert_deep_nesting', + ('chain-v03', 'chain-v02'), + (depth,), + ) + for depth in (1, 4, 8) + ], + ('error-undeployed', '_assert_undeployed_error', ('caller-v02',), ()), + ('error-non-contract', '_assert_non_contract_error', ('caller-v02',), ()), + ('error-trap', '_assert_trap_error', ('caller-v02', 'trap-v03'), ()), + ( + 'error-user', + '_assert_user_error', + ('caller-v02', 'user-error-v03'), + (), + ), + *[ + ( + f'fuel-{fuel}', + '_assert_fuel', + ('caller-v02', 'observer-v03'), + (fuel,), + ) + for fuel in (0, 1, 1000, 2**32) + ], + ] + for slug, method, fixtures, arguments in cases: + desc = genvm_tool.tests.test.Description( + name=f'tests/system/cross-major-observability/{slug}', + needed_services=frozenset({manager_service}), + tags=frozenset( + { + 'integration', + 'stable', + 'feature-version-routing-cross-major', + 'feature-observability', + } + ), + ) + ctx.add_case( + ObservabilityCase( + description=desc, + shared=ctx.shared, + manager_service=manager_service, + method=method, + fixtures=fixtures, + arguments=arguments, + ) + ) diff --git a/tests/system/cross-major/assets/v0.2/blob_caller.py b/tests/system/cross-major/assets/v0.2/blob_caller.py new file mode 100644 index 00000000..7039b4a8 --- /dev/null +++ b/tests/system/cross-major/assets/v0.2/blob_caller.py @@ -0,0 +1,11 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.2_py-genlayer@" } +from genlayer import * + + +class Contract(gl.Contract): + def __init__(self): + pass + + @gl.public.view + def send(self, target: Address, size: int) -> int: + return gl.get_contract_at(target).view().sink('x' * size) diff --git a/tests/system/cross-major/assets/v0.2/busy.py b/tests/system/cross-major/assets/v0.2/busy.py new file mode 100644 index 00000000..7f866277 --- /dev/null +++ b/tests/system/cross-major/assets/v0.2/busy.py @@ -0,0 +1,12 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.2_py-genlayer@" } +from genlayer import * + + +class Contract(gl.Contract): + def __init__(self): + pass + + @gl.public.view + def answer(self) -> int: + while True: + pass diff --git a/tests/system/cross-major/assets/v0.2/callee.py b/tests/system/cross-major/assets/v0.2/callee.py new file mode 100644 index 00000000..0180656a --- /dev/null +++ b/tests/system/cross-major/assets/v0.2/callee.py @@ -0,0 +1,11 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.2_py-genlayer@" } +from genlayer import * + + +class Contract(gl.Contract): + def __init__(self): + pass + + @gl.public.view + def answer(self) -> int: + return 202 diff --git a/tests/system/cross-major/assets/v0.2/caller.py b/tests/system/cross-major/assets/v0.2/caller.py new file mode 100644 index 00000000..ec212a69 --- /dev/null +++ b/tests/system/cross-major/assets/v0.2/caller.py @@ -0,0 +1,11 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.2_py-genlayer@" } +from genlayer import * + + +class Contract(gl.Contract): + def __init__(self): + pass + + @gl.public.view + def call(self, target: Address) -> int: + return gl.get_contract_at(target).view().answer() diff --git a/tests/system/cross-major/assets/v0.2/chain.py b/tests/system/cross-major/assets/v0.2/chain.py new file mode 100644 index 00000000..7f0e6fd4 --- /dev/null +++ b/tests/system/cross-major/assets/v0.2/chain.py @@ -0,0 +1,14 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.2_py-genlayer@" } +from genlayer import * + + +class Contract(gl.Contract): + def __init__(self): + pass + + @gl.public.view + def hop(self, depth: int, other: Address) -> int: + if depth <= 0: + return 2 + me = gl.message.contract_address + return 2 + gl.get_contract_at(other).view().hop(depth - 1, me) diff --git a/tests/system/cross-major/assets/v0.2/loop.py b/tests/system/cross-major/assets/v0.2/loop.py new file mode 100644 index 00000000..e8e4fe59 --- /dev/null +++ b/tests/system/cross-major/assets/v0.2/loop.py @@ -0,0 +1,11 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.2_py-genlayer@" } +from genlayer import * + + +class Contract(gl.Contract): + def __init__(self): + pass + + @gl.public.view + def loop(self, first: Address, second: Address) -> int: + return gl.get_contract_at(first).view().loop(0, first, second) diff --git a/tests/system/cross-major/assets/v0.2/signer_caller.py b/tests/system/cross-major/assets/v0.2/signer_caller.py new file mode 100644 index 00000000..4d593747 --- /dev/null +++ b/tests/system/cross-major/assets/v0.2/signer_caller.py @@ -0,0 +1,11 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.2_py-genlayer@" } +from genlayer import * + + +class Contract(gl.Contract): + def __init__(self): + pass + + @gl.public.view + def signer(self, target: Address) -> str: + return gl.get_contract_at(target).view().signer() diff --git a/tests/system/cross-major/assets/v0.2/user_error.py b/tests/system/cross-major/assets/v0.2/user_error.py new file mode 100644 index 00000000..bac20cba --- /dev/null +++ b/tests/system/cross-major/assets/v0.2/user_error.py @@ -0,0 +1,11 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.2_py-genlayer@" } +from genlayer import * + + +class Contract(gl.Contract): + def __init__(self): + pass + + @gl.public.view + def answer(self) -> int: + raise gl.vm.UserError('boom') diff --git a/tests/system/cross-major/assets/v0.3/blob.py b/tests/system/cross-major/assets/v0.3/blob.py new file mode 100644 index 00000000..f06a1b0a --- /dev/null +++ b/tests/system/cross-major/assets/v0.3/blob.py @@ -0,0 +1,11 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.3_py-genlayer@" } +import genlayer as gl + + +class Contract(gl.contract.Contract): + def __init__(self): + pass + + @gl.public.view + def sink(self, blob: str) -> int: + return len(blob) diff --git a/tests/system/cross-major/assets/v0.3/callee.py b/tests/system/cross-major/assets/v0.3/callee.py new file mode 100644 index 00000000..1c2b2c1b --- /dev/null +++ b/tests/system/cross-major/assets/v0.3/callee.py @@ -0,0 +1,11 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.3_py-genlayer@" } +import genlayer as gl + + +class Contract(gl.contract.Contract): + def __init__(self): + pass + + @gl.public.view + def answer(self) -> int: + return 303 diff --git a/tests/system/cross-major/assets/v0.3/caller.py b/tests/system/cross-major/assets/v0.3/caller.py new file mode 100644 index 00000000..3e9e1f26 --- /dev/null +++ b/tests/system/cross-major/assets/v0.3/caller.py @@ -0,0 +1,12 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.3_py-genlayer@" } +import genlayer as gl +from genlayer.types import Address + + +class Contract(gl.contract.Contract): + def __init__(self): + pass + + @gl.public.view + def call(self, target: Address) -> int: + return gl.contract.get_at(target).view().answer() diff --git a/tests/system/cross-major/assets/v0.3/chain.py b/tests/system/cross-major/assets/v0.3/chain.py new file mode 100644 index 00000000..e166801f --- /dev/null +++ b/tests/system/cross-major/assets/v0.3/chain.py @@ -0,0 +1,15 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.3_py-genlayer@" } +import genlayer as gl +from genlayer.types import Address + + +class Contract(gl.contract.Contract): + def __init__(self): + pass + + @gl.public.view + def hop(self, depth: int, other: Address) -> int: + if depth <= 0: + return 3 + me = gl.message.contract_address + return 3 + gl.contract.get_at(other).view().hop(depth - 1, me) diff --git a/tests/system/cross-major/assets/v0.3/loop.py b/tests/system/cross-major/assets/v0.3/loop.py new file mode 100644 index 00000000..0c4514db --- /dev/null +++ b/tests/system/cross-major/assets/v0.3/loop.py @@ -0,0 +1,14 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.3_py-genlayer@" } +import genlayer as gl +from genlayer.types import Address + + +class Contract(gl.contract.Contract): + def __init__(self): + pass + + @gl.public.view + def loop(self, remaining: int, first: Address, second: Address) -> int: + if remaining > 0: + return gl.contract.get_at(first).view().loop(remaining - 1, first, second) + return gl.contract.get_at(second).view().loop(first, second) diff --git a/tests/system/cross-major/assets/v0.3/signer.py b/tests/system/cross-major/assets/v0.3/signer.py new file mode 100644 index 00000000..d8792643 --- /dev/null +++ b/tests/system/cross-major/assets/v0.3/signer.py @@ -0,0 +1,11 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.3_py-genlayer@" } +import genlayer as gl + + +class Contract(gl.contract.Contract): + def __init__(self): + pass + + @gl.public.view + def signer(self) -> str: + return gl.message.signer_address.as_hex diff --git a/tests/system/cross-major/assets/v0.3/state_caller.py b/tests/system/cross-major/assets/v0.3/state_caller.py new file mode 100644 index 00000000..c612dce2 --- /dev/null +++ b/tests/system/cross-major/assets/v0.3/state_caller.py @@ -0,0 +1,17 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.3_py-genlayer@" } +import genlayer as gl +from genlayer.types import Address + + +class Contract(gl.contract.Contract): + def __init__(self): + pass + + @gl.public.view + def call(self, target: Address, final: bool) -> int: + mode = ( + gl.vm.public_abi.StorageType.LATEST_FINAL + if final + else gl.vm.public_abi.StorageType.LATEST_NON_FINAL + ) + return gl.contract.get_at(target).view(state=mode).answer() diff --git a/tests/system/cross-major/assets/v0.3/structured_error.py b/tests/system/cross-major/assets/v0.3/structured_error.py new file mode 100644 index 00000000..4e2c26fa --- /dev/null +++ b/tests/system/cross-major/assets/v0.3/structured_error.py @@ -0,0 +1,11 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.3_py-genlayer@" } +import genlayer as gl + + +class Contract(gl.contract.Contract): + def __init__(self): + pass + + @gl.public.view + def answer(self) -> int: + gl.vm.UserError.immediate({'code': 7}) diff --git a/tests/system/cross-major/assets/v0.3/user_error.py b/tests/system/cross-major/assets/v0.3/user_error.py new file mode 100644 index 00000000..5cf9cdcb --- /dev/null +++ b/tests/system/cross-major/assets/v0.3/user_error.py @@ -0,0 +1,11 @@ +# { "Depends": "py-genlayer:@RUNNER_LATEST_v0.3_py-genlayer@" } +import genlayer as gl + + +class Contract(gl.contract.Contract): + def __init__(self): + pass + + @gl.public.view + def answer(self) -> int: + gl.vm.UserError.immediate('boom') diff --git a/tests/system/cross-major/cases/routing.jsonnet b/tests/system/cross-major/cases/routing.jsonnet new file mode 100644 index 00000000..b0f0c485 --- /dev/null +++ b/tests/system/cross-major/cases/routing.jsonnet @@ -0,0 +1,95 @@ +local util = import 'templates/util.jsonnet'; +local message = import 'templates/message.json'; + +local route02 = '${executorV02}'; +local route03 = '${executorV03}'; + +local deploy(slug, address, code) = { + slug: slug, + code: '${jsonnetDir}/../assets/' + code, + message: message + { + contract_address: address, + is_init: true, + }, + calldata: '{}', + modes: 'l', + stable_hash: false, + expected_semantics_components: [], + reroute_to: if std.startsWith(code, 'v0.2/') then route02 else route03, +}; + +local call(slug, caller, target, method, route, extra={}) = { + slug: slug, + code: null, + vars: { target: target }, + message: message + { contract_address: caller }, + calldata: '{"": "' + method + '", "args": [Address(target)]}', + executor_routes: if route == null then {} else { [target]: route }, + hook_cross_contract_calls: true, + stable_hash: false, + expected_semantics_components: ['return', 'kind'], +} + extra; + +local caller03 = '0x1111111111111111111111111111111111111111'; +local caller02 = '0x1212121212121212121212121212121212121212'; +local callee03 = '0x1313131313131313131313131313131313131313'; +local callee02 = '0x1414141414141414141414141414141414141414'; +local signer03 = '0x1717171717171717171717171717171717171717'; +local signerCaller02 = '0x1818181818181818181818181818181818181818'; +local structured03 = '0x1919191919191919191919191919191919191919'; +local userError03 = '0x2020202020202020202020202020202020202020'; +local userError02 = '0x2121212121212121212121212121212121212121'; + +local scenarios = [ + util.chain([ + deploy('v03-to-v02-caller', caller03, 'v0.3/caller.py'), + deploy('v03-to-v02-callee', callee02, 'v0.2/callee.py'), + call('v03-to-v02', caller03, callee02, 'call', route02), + ]), + util.chain([ + deploy('v02-to-v03-caller', caller02, 'v0.2/caller.py'), + deploy('v02-to-v03-callee', callee03, 'v0.3/callee.py'), + call('v02-to-v03', caller02, callee03, 'call', route03, { reroute_to: route02 }), + ]), + util.chain([ + deploy('signer-caller', signerCaller02, 'v0.2/signer_caller.py'), + deploy('signer-callee', signer03, 'v0.3/signer.py'), + call('signer', signerCaller02, signer03, 'signer', route03, { reroute_to: route02 }), + ]), + util.chain([ + deploy('structured-error-caller', caller02, 'v0.2/caller.py'), + deploy('structured-error-callee', structured03, 'v0.3/structured_error.py'), + call('structured-error', caller02, structured03, 'call', route03, { reroute_to: route02 }), + ]), + util.chain([ + deploy('plain-error-caller', caller02, 'v0.2/caller.py'), + deploy('plain-error-callee', userError03, 'v0.3/user_error.py'), + call('plain-error', caller02, userError03, 'call', route03, { reroute_to: route02 }), + ]), + util.chain([ + deploy('plain-error-reverse-caller', caller03, 'v0.3/caller.py'), + deploy('plain-error-reverse-callee', userError02, 'v0.2/user_error.py'), + call('plain-error-reverse', caller03, userError02, 'call', route02), + ]), + util.chain([ + deploy('null-same-caller', caller03, 'v0.3/caller.py'), + deploy('null-same-callee', callee03, 'v0.3/callee.py'), + call('null-same-major', caller03, callee03, 'call', null, { + expected_executor_route_requests: [{ + contract_address: callee03, + state_mode: 2, + advisory_major: 0, + }], + }), + ]), + util.chain([ + deploy('null-mismatch-caller', caller03, 'v0.3/caller.py'), + deploy('null-mismatch-callee', callee02, 'v0.2/callee.py'), + call('null-mismatch', caller03, callee02, 'call', null), + ]), +]; + +{ + tags: util.features([['version-routing', 'cross-major']], 'stable') + ['python'], + entry: util.addPaths(scenarios), +} diff --git a/tests/system/cross-major/cases/routing.null-mismatch-caller_null-mismatch-callee_null-mismatch.stdout b/tests/system/cross-major/cases/routing.null-mismatch-caller_null-mismatch-callee_null-mismatch.stdout new file mode 100644 index 00000000..07c2a520 --- /dev/null +++ b/tests/system/cross-major/cases/routing.null-mismatch-caller_null-mismatch-callee_null-mismatch.stdout @@ -0,0 +1,2 @@ +executed with `VMError("invalid_contract runner absent")` +VM_ERROR diff --git a/tests/system/cross-major/cases/routing.null-same-caller_null-same-callee_null-same-major.stdout b/tests/system/cross-major/cases/routing.null-same-caller_null-same-callee_null-same-major.stdout new file mode 100644 index 00000000..d95482b9 --- /dev/null +++ b/tests/system/cross-major/cases/routing.null-same-caller_null-same-callee_null-same-major.stdout @@ -0,0 +1,2 @@ +executed with `Return(303)` +RETURN diff --git a/tests/system/cross-major/cases/routing.plain-error-caller_plain-error-callee_plain-error.stdout b/tests/system/cross-major/cases/routing.plain-error-caller_plain-error-callee_plain-error.stdout new file mode 100644 index 00000000..90bfa685 --- /dev/null +++ b/tests/system/cross-major/cases/routing.plain-error-caller_plain-error-callee_plain-error.stdout @@ -0,0 +1,2 @@ +executed with `UserError("boom")` +USER_ERROR diff --git a/tests/system/cross-major/cases/routing.plain-error-reverse-caller_plain-error-reverse-callee_plain-error-reverse.stdout b/tests/system/cross-major/cases/routing.plain-error-reverse-caller_plain-error-reverse-callee_plain-error-reverse.stdout new file mode 100644 index 00000000..90bfa685 --- /dev/null +++ b/tests/system/cross-major/cases/routing.plain-error-reverse-caller_plain-error-reverse-callee_plain-error-reverse.stdout @@ -0,0 +1,2 @@ +executed with `UserError("boom")` +USER_ERROR diff --git a/tests/system/cross-major/cases/routing.signer-caller_signer-callee_signer.stdout b/tests/system/cross-major/cases/routing.signer-caller_signer-callee_signer.stdout new file mode 100644 index 00000000..4a9bc9ff --- /dev/null +++ b/tests/system/cross-major/cases/routing.signer-caller_signer-callee_signer.stdout @@ -0,0 +1,2 @@ +executed with `Return("0x0200000000000000000000000000000000000000")` +RETURN diff --git a/tests/system/cross-major/cases/routing.structured-error-caller_structured-error-callee_structured-error.stdout b/tests/system/cross-major/cases/routing.structured-error-caller_structured-error-callee_structured-error.stdout new file mode 100644 index 00000000..47776f49 --- /dev/null +++ b/tests/system/cross-major/cases/routing.structured-error-caller_structured-error-callee_structured-error.stdout @@ -0,0 +1,2 @@ +executed with `VMError("invalid_contract major_mismatch")` +VM_ERROR diff --git a/tests/system/cross-major/cases/routing.v02-to-v03-caller_v02-to-v03-callee_v02-to-v03.stdout b/tests/system/cross-major/cases/routing.v02-to-v03-caller_v02-to-v03-callee_v02-to-v03.stdout new file mode 100644 index 00000000..d95482b9 --- /dev/null +++ b/tests/system/cross-major/cases/routing.v02-to-v03-caller_v02-to-v03-callee_v02-to-v03.stdout @@ -0,0 +1,2 @@ +executed with `Return(303)` +RETURN diff --git a/tests/system/cross-major/cases/routing.v03-to-v02-caller_v03-to-v02-callee_v03-to-v02.stdout b/tests/system/cross-major/cases/routing.v03-to-v02-caller_v03-to-v02-callee_v03-to-v02.stdout new file mode 100644 index 00000000..ef72678b --- /dev/null +++ b/tests/system/cross-major/cases/routing.v03-to-v02-caller_v03-to-v02-callee_v03-to-v02.stdout @@ -0,0 +1,2 @@ +executed with `Return(202)` +RETURN diff --git a/tests/system/cross-major/test.py b/tests/system/cross-major/test.py index 5636ecbb..5f57b641 100644 --- a/tests/system/cross-major/test.py +++ b/tests/system/cross-major/test.py @@ -1,31 +1,28 @@ -"""Cross-major CallContract system test. - -The case owns its manager because it exercises manager cancellation and -deadlines while executor processes are nested beneath it. -""" +"""Cross-major CallContract assertions that need Python host inspection.""" import asyncio import contextlib import json import os import pickle -import socket -import textwrap import typing from dataclasses import dataclass from pathlib import Path -import aiohttp +import genvm_tool.io as gvm_io import genvm_tool.tests import genvm_tool.tests.stage.collection +import genvm_tool_plugins.runners as runners import origin.base_host as base_host import origin.calldata as gvm_calldata from gvm_extra.mock_host import MockHost, MockStorage -from origin import public_abi +from origin import host_fns, public_abi from origin.calldata import Address -PY_GENLAYER_V03 = '9b8kjyda2ycxyq4ea6g4yfpnydxhd52gqba5rb8dw7krkh5mn9p0' -PY_GENLAYER_V02 = '1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6' +# One directory per line, because a contract is written against its own sdk. +# Their `@RUNNER_LATEST_...@` tokens stand for the uids of the last build; +# `_execute` resolves them before any code reaches an executor. +ASSETS_DIR = Path(__file__).resolve().parent / 'assets' ADDR_CALLER_V03 = Address('0x' + '31' * 20) ADDR_CALLER_V02 = Address('0x' + '21' * 20) @@ -34,324 +31,65 @@ ADDR_BUSY_V02 = Address('0x' + '23' * 20) ADDR_LOOP_V03 = Address('0x' + '33' * 20) ADDR_LOOP_V02 = Address('0x' + '24' * 20) -ADDR_SIGNER_V03 = Address('0x' + '34' * 20) -ADDR_SIGNER_CALLER_V02 = Address('0x' + '25' * 20) -ADDR_STRUCTURED_V03 = Address('0x' + '35' * 20) ADDR_BLOB_V03 = Address('0x' + '36' * 20) ADDR_BLOB_CALLER_V02 = Address('0x' + '26' * 20) -ADDR_UERR_V03 = Address('0x' + '37' * 20) -ADDR_UERR_V02 = Address('0x' + '27' * 20) ADDR_STATE_CALLER_V03 = Address('0x' + '38' * 20) ADDR_CHAIN_V03 = Address('0x' + '39' * 20) ADDR_CHAIN_V02 = Address('0x' + '28' * 20) +ABSENT_CALLEE = Address('0x' + '99' * 20) SENDER = Address('0x' + '01' * 20) # Larger than the manager cap the test configures below, so the nested envelope # cannot fit through the socketpair. -"""Client frame cap for `/ws`; kept low so a nested envelope can exceed it.""" MANAGER_MAX_MESSAGE_BYTES = 1 * 1024 * 1024 BLOB_BYTES = 2 * 1024 * 1024 TIMESTAMP = '2024-11-26T06:42:42.424242Z' -def _contract_source(line: int, body: str) -> bytes: - runner = PY_GENLAYER_V03 if line == 3 else PY_GENLAYER_V02 - return ( - f'# {{ "Depends": "py-genlayer:{runner}" }}\n' + textwrap.dedent(body).lstrip() - ).encode() - - -CALLER_V03 = _contract_source( - 3, - """ - import genlayer as gl - from genlayer.types import Address - - - class Contract(gl.contract.Contract): - def __init__(self): - pass - - @gl.public.view - def call(self, target: Address) -> int: - return gl.contract.get_at(target).view().answer() - """, -) - -CALLER_V02 = _contract_source( - 2, - """ - from genlayer import * - - - class Contract(gl.Contract): - def __init__(self): - pass - - @gl.public.view - def call(self, target: Address) -> int: - return gl.get_contract_at(target).view().answer() - """, -) - -STATE_CALLER_V03 = _contract_source( - 3, - """ - import genlayer as gl - from genlayer.types import Address - - - class Contract(gl.contract.Contract): - def __init__(self): - pass - - @gl.public.view - def call(self, target: Address, final: bool) -> int: - mode = ( - gl.vm.public_abi.StorageType.LATEST_FINAL - if final - else gl.vm.public_abi.StorageType.LATEST_NON_FINAL - ) - return gl.contract.get_at(target).view(state=mode).answer() - """, -) - -CALLEE_V03 = _contract_source( - 3, - """ - import genlayer as gl - - - class Contract(gl.contract.Contract): - def __init__(self): - pass - - @gl.public.view - def answer(self) -> int: - return 303 - """, -) - -CALLEE_V02 = _contract_source( - 2, - """ - from genlayer import * - - - class Contract(gl.Contract): - def __init__(self): - pass - - @gl.public.view - def answer(self) -> int: - return 202 - """, -) - -SIGNER_V03 = _contract_source( - 3, - """ - import genlayer as gl - - - class Contract(gl.contract.Contract): - def __init__(self): - pass - - @gl.public.view - def signer(self) -> str: - return gl.message.signer_address.as_hex - """, -) - -SIGNER_CALLER_V02 = _contract_source( - 2, - """ - from genlayer import * - - - class Contract(gl.Contract): - def __init__(self): - pass - - @gl.public.view - def signer(self, target: Address) -> str: - return gl.get_contract_at(target).view().signer() - """, -) - -STRUCTURED_ERROR_V03 = _contract_source( - 3, - """ - import genlayer as gl - - - class Contract(gl.contract.Contract): - def __init__(self): - pass - - @gl.public.view - def answer(self) -> int: - gl.vm.UserError.immediate({'code': 7}) - """, -) - -BLOB_V03 = _contract_source( - 3, - """ - import genlayer as gl - - - class Contract(gl.contract.Contract): - def __init__(self): - pass - - @gl.public.view - def sink(self, blob: str) -> int: - return len(blob) - """, -) - -BLOB_CALLER_V02 = _contract_source( - 2, - """ - from genlayer import * - - - class Contract(gl.Contract): - def __init__(self): - pass - - @gl.public.view - def send(self, target: Address, size: int) -> int: - return gl.get_contract_at(target).view().sink('x' * size) - """, -) - -USER_ERROR_V03 = _contract_source( - 3, - """ - import genlayer as gl - - - class Contract(gl.contract.Contract): - def __init__(self): - pass - - @gl.public.view - def answer(self) -> int: - gl.vm.UserError.immediate('boom') - """, -) - -USER_ERROR_V02 = _contract_source( - 2, +def resolve_runners(code: bytes | None, root_dir: Path) -> bytes | None: """ - from genlayer import * - - - class Contract(gl.Contract): - def __init__(self): - pass - - @gl.public.view - def answer(self) -> int: - raise gl.vm.UserError('boom') - """, -) + Turns the `@RUNNER_LATEST_...@` tokens of a contract source into uids. -CHAIN_V03 = _contract_source( - 3, + Every comparison against a deployed contract's bytes has to go through this + too, because storage holds what the executor was given. """ - import genlayer as gl - from genlayer.types import Address + return None if code is None else runners.substitute(code, root_dir) - class Contract(gl.contract.Contract): - def __init__(self): - pass - - @gl.public.view - def hop(self, depth: int, other: Address) -> int: - if depth <= 0: - return 3 - me = gl.message.contract_address - return 3 + gl.contract.get_at(other).view().hop(depth - 1, me) - """, -) - -CHAIN_V02 = _contract_source( - 2, +def _contract_source(line: int, name: str, assets_dir: Path = ASSETS_DIR) -> bytes: """ - from genlayer import * - - - class Contract(gl.Contract): - def __init__(self): - pass - - @gl.public.view - def hop(self, depth: int, other: Address) -> int: - if depth <= 0: - return 2 - me = gl.message.contract_address - return 2 + gl.get_contract_at(other).view().hop(depth - 1, me) - """, -) - -BUSY_V02 = _contract_source( - 2, + Reads a contract asset written against `line`'s sdk. """ - from genlayer import * - - - class Contract(gl.Contract): - def __init__(self): - pass - - @gl.public.view - def answer(self) -> int: - while True: - pass - """, -) - -LOOP_V03 = _contract_source( - 3, - """ - import genlayer as gl - from genlayer.types import Address - - - class Contract(gl.contract.Contract): - def __init__(self): - pass - - @gl.public.view - def loop(self, remaining: int, first: Address, second: Address) -> int: - if remaining > 0: - return gl.contract.get_at(first).view().loop( - remaining - 1, first, second - ) - return gl.contract.get_at(second).view().loop(first, second) - """, -) - -LOOP_V02 = _contract_source( - 2, - """ - from genlayer import * - - - class Contract(gl.Contract): - def __init__(self): - pass - - @gl.public.view - def loop(self, first: Address, second: Address) -> int: - return gl.get_contract_at(first).view().loop(0, first, second) - """, -) + return (assets_dir / f'v0.{line}' / f'{name}.py').read_bytes() + + +CALLER_V03 = _contract_source(3, 'caller') +CALLER_V02 = _contract_source(2, 'caller') +STATE_CALLER_V03 = _contract_source(3, 'state_caller') +CALLEE_V03 = _contract_source(3, 'callee') +CALLEE_V02 = _contract_source(2, 'callee') +BLOB_V03 = _contract_source(3, 'blob') +BLOB_CALLER_V02 = _contract_source(2, 'blob_caller') +CHAIN_V03 = _contract_source(3, 'chain') +CHAIN_V02 = _contract_source(2, 'chain') +BUSY_V02 = _contract_source(2, 'busy') +LOOP_V03 = _contract_source(3, 'loop') +LOOP_V02 = _contract_source(2, 'loop') + +FIXTURES = { + 'caller-v03': (3, ADDR_CALLER_V03, CALLER_V03), + 'caller-v02': (2, ADDR_CALLER_V02, CALLER_V02), + 'callee-v03': (3, ADDR_CALLEE_V03, CALLEE_V03), + 'callee-v02': (2, ADDR_CALLEE_V02, CALLEE_V02), + 'busy-v02': (2, ADDR_BUSY_V02, BUSY_V02), + 'loop-v03': (3, ADDR_LOOP_V03, LOOP_V03), + 'loop-v02': (2, ADDR_LOOP_V02, LOOP_V02), + 'blob-v03': (3, ADDR_BLOB_V03, BLOB_V03), + 'blob-caller-v02': (2, ADDR_BLOB_CALLER_V02, BLOB_CALLER_V02), + 'state-caller-v03': (3, ADDR_STATE_CALLER_V03, STATE_CALLER_V03), + 'chain-v03': (3, ADDR_CHAIN_V03, CHAIN_V03), + 'chain-v02': (2, ADDR_CHAIN_V02, CHAIN_V02), +} def _wat_data(data: bytes) -> str: @@ -432,89 +170,6 @@ def add_stat(self, key: str, value: typing.Any, /): self.stats[key] = value -class ManagerProc: - def __init__(self, *, build_dir: Path, work_dir: Path): - self.build_dir = build_dir - self.work_dir = work_dir - self.process: asyncio.subprocess.Process | None = None - self.log_file = None - self.port = self._unused_port() - - @staticmethod - def _unused_port() -> int: - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: - sock.bind(('127.0.0.1', 0)) - return sock.getsockname()[1] - - @property - def uri(self) -> str: - return f'http://127.0.0.1:{self.port}' - - async def __aenter__(self): - self.work_dir.mkdir(parents=True, exist_ok=True) - config_path = self.work_dir / 'genvm-manager.yaml' - config_path.write_text( - '\n'.join( - [ - 'threads: 4', - 'blocking_threads: 48', - 'log_disable: tracing*,polling*,tungstenite*,tokio_tungstenite*', - 'log_level: info', - f'manifest_path: {self.build_dir / "out" / "data" / "manifest.yaml"}', - 'permits: 2', - 'execution_retention: 30s', - f'max_message_bytes: {MANAGER_MAX_MESSAGE_BYTES}', - '', - ] - ) - ) - self.log_file = open(self.work_dir / 'manager.log', 'wb') - self.process = await asyncio.subprocess.create_subprocess_exec( - str(self.build_dir / 'out' / 'bin' / 'genvm-modules'), - 'manager', - '--port', - str(self.port), - '--die-with-parent', - '--config', - str(config_path), - stdin=asyncio.subprocess.DEVNULL, - stdout=self.log_file, - stderr=self.log_file, - start_new_session=True, - ) - await self._wait_healthy() - return self - - async def __aexit__(self, *_args): - if self.process is not None: - try: - self.process.terminate() - await asyncio.wait_for(self.process.wait(), timeout=5) - except asyncio.TimeoutError: - self.process.kill() - await self.process.wait() - if self.log_file is not None: - self.log_file.close() - - async def _wait_healthy(self): - last_error: BaseException | None = None - for _ in range(80): - if self.process is not None and self.process.returncode is not None: - raise RuntimeError(f'manager exited early with {self.process.returncode}') - try: - async with aiohttp.request( - 'GET', - f'{self.uri}/status', - timeout=aiohttp.ClientTimeout(total=1), - ) as response: - if response.status == 200: - return - except BaseException as exc: - last_error = exc - await asyncio.sleep(0.1) - raise TimeoutError(f'manager did not become healthy: {last_error}') - - def _message(address: Address, *, is_init: bool) -> base_host.Message: return { 'contract_address': address, @@ -532,6 +187,17 @@ def _calldata(method: str, *args: typing.Any) -> bytes: return gvm_calldata.encode({'': method, 'args': list(args)}) +def _assert_hashes_agree(label: str, runs: list[tuple[str, typing.Any]]) -> None: + """ + A disagreement is only actionable once the failure says who disagreed. + """ + hashes = [(name, run.execution_hash.hex()) for name, run in runs] + assert len({digest for _name, digest in hashes}) == 1, '\n'.join( + [f'{label}: execution hashes disagree'] + + [f' {name}: {digest}' for name, digest in hashes] + ) + + def _apply_storage_changes( storage: MockStorage, address: Address, @@ -581,7 +247,7 @@ async def _wait_for_descendants( async def _wait_for_no_descendants(pid: int, timeout: float = 10) -> None: async with asyncio.timeout(timeout): - while _descendants(pid): + while _descendants(pid): # noqa: ASYNC110 — polls the OS process table, no event to await await asyncio.sleep(0.05) @@ -589,6 +255,10 @@ async def _wait_for_no_descendants(pid: int, timeout: float = 10) -> None: class CrossMajorCase(genvm_tool.tests.test.Case): description: genvm_tool.tests.test.Description shared: genvm_tool.tests.SharedContext + manager_service: genvm_tool.tests.stage.collection.Service + method: str + fixtures: tuple[str, ...] + arguments: tuple[typing.Any, ...] = () async def into_steps(self) -> list[genvm_tool.tests.exec.step.Step]: return [CrossMajorStep(self)] @@ -614,7 +284,7 @@ async def run( except BaseException as exc: return genvm_tool.tests.test.Result( passed=False, - context={'phase': self.phase, 'error': repr(exc)}, + context={'phase': self.phase, 'error': exc, 'notes': self.notes}, elapsed_seconds=0, ) @@ -626,36 +296,19 @@ async def _run_all(self): 2: build_info['executor_versions']['v0.2'], 3: build_info['executor_versions']['v0.3'], } - work_dir = self.case.shared.artifacts_dir / 'cross-major' + work_dir = self.case.shared.case_dir_for(self.case.description.name) self.storage_path = work_dir / 'storage.pickle' work_dir.mkdir(parents=True, exist_ok=True) - with open(self.storage_path, 'wb') as storage_file: - pickle.dump(MockStorage(), storage_file) - - async with ManagerProc( - build_dir=self.build_dir, - work_dir=work_dir / 'manager', - ) as manager: - self.manager = manager - - self.phase = 'deploy fixtures' - await self._deploy(3, ADDR_CALLER_V03, CALLER_V03) - await self._deploy(2, ADDR_CALLER_V02, CALLER_V02) - await self._deploy(3, ADDR_CALLEE_V03, CALLEE_V03) - await self._deploy(2, ADDR_CALLEE_V02, CALLEE_V02) - await self._deploy(2, ADDR_BUSY_V02, BUSY_V02) - await self._deploy(3, ADDR_LOOP_V03, LOOP_V03) - await self._deploy(2, ADDR_LOOP_V02, LOOP_V02) - await self._deploy(3, ADDR_SIGNER_V03, SIGNER_V03) - await self._deploy(2, ADDR_SIGNER_CALLER_V02, SIGNER_CALLER_V02) - await self._deploy(3, ADDR_STRUCTURED_V03, STRUCTURED_ERROR_V03) - await self._deploy(3, ADDR_BLOB_V03, BLOB_V03) - await self._deploy(2, ADDR_BLOB_CALLER_V02, BLOB_CALLER_V02) - await self._deploy(3, ADDR_UERR_V03, USER_ERROR_V03) - await self._deploy(2, ADDR_UERR_V02, USER_ERROR_V02) - await self._deploy(3, ADDR_STATE_CALLER_V03, STATE_CALLER_V03) - await self._deploy(3, ADDR_CHAIN_V03, CHAIN_V03) - await self._deploy(2, ADDR_CHAIN_V02, CHAIN_V02) + await gvm_io.write_file_bytes(self.storage_path, pickle.dumps(MockStorage())) + + manager = self.case.manager_service.handle + assert manager is not None + self.manager = manager + + self.phase = 'deploy fixtures' + for line, address, code in (FIXTURES[name] for name in self.case.fixtures): + await self._deploy(line, address, code) + if 'loop-v03' in self.case.fixtures: loop_v03 = await self._compile_wat( _loop_wat(ADDR_LOOP_V02), work_dir / 'loop-v03' ) @@ -665,111 +318,14 @@ async def _run_all(self): self._replace_code(ADDR_LOOP_V03, LOOP_V03, loop_v03) self._replace_code(ADDR_LOOP_V02, LOOP_V02, loop_v02) - self.phase = 'v0.3 to v0.2' - forward = await self._call( - 3, - ADDR_CALLER_V03, - ADDR_CALLEE_V02, - lambda address, _state, _major: ( - self._route(2) if address == ADDR_CALLEE_V02 else None - ), - ) - assert forward.result_kind == public_abi.ResultCode.RETURN, forward - assert forward.result_data == 202, forward - assert len(forward.execution_hash) == 32, forward.execution_hash - assert forward.execution_hash.hex() == ( - 'c0e5932da9b2e9bf79579079f1fec46f74b83f02114bcd2f711a6798ee20bdd6' - ), forward.execution_hash.hex() - - self.phase = 'v0.2 to v0.3' - backward = await self._call( - 2, - ADDR_CALLER_V02, - ADDR_CALLEE_V03, - lambda address, _state, _major: ( - self._route(3) if address == ADDR_CALLEE_V03 else None - ), - ) - assert backward.result_kind == public_abi.ResultCode.RETURN, backward - assert backward.result_data == 303, backward - assert len(backward.execution_hash) == 32, backward.execution_hash - assert backward.execution_hash.hex() == ( - '6aad898ed66c94e7bc9fc1f6bb7d615b9b4cf01d1e1205ca0c640712a8c6792d' - ), backward.execution_hash.hex() - - self.phase = 'v0.2 forwards the signer it never exposes' - await self._assert_signer_preserved() - - self.phase = 'a nested envelope is not bounded by the websocket cap' - await self._assert_envelope_ignores_websocket_cap() - - self.phase = 'a structured user error survives the boundary' - await self._assert_structured_user_error() - - self.phase = 'null preserves same-major behavior' - resolved: list[tuple[Address, int]] = [] - - def resolve_null(address, _state, advisory_major): - resolved.append((address, advisory_major)) - return None - - same_major = await self._call( - 3, - ADDR_CALLER_V03, - ADDR_CALLEE_V03, - resolve_null, - ) - assert same_major.result_kind == public_abi.ResultCode.RETURN, same_major - assert same_major.result_data == 303, same_major - assert resolved == [(ADDR_CALLEE_V03, 0)], resolved - - self.phase = 'null preserves mismatch behavior' - mismatch = await self._call( - 3, - ADDR_CALLER_V03, - ADDR_CALLEE_V02, - lambda _address, _state, _major: None, - ) - assert mismatch.result_kind == public_abi.ResultCode.VM_ERROR, mismatch - assert str(mismatch.result_data).startswith( - str(public_abi.VmError.invalid_contract().absent_runner_comment()) - ), mismatch.result_data - - self.phase = 'a host that does not hook is never asked' - await self._assert_unhooked_stays_in_process() - - self.phase = 'leader, validator and sync agree on the nested hash' - await self._assert_lvs_agrees() - - self.phase = 'the route a host picks does not change the hash' - await self._assert_route_is_hash_invariant() - - self.phase = 'a plain user error survives the boundary' - await self._assert_plain_user_error() - - self.phase = 'the state mode a caller picks crosses the boundary' - await self._assert_state_mode_crosses() + self.phase = self.case.method + await getattr(self, self.case.method)(*self.case.arguments) - self.phase = 'a deep alternating chain stays deterministic' - await self._assert_deep_chain() + async def _assert_cancel_stops_chain(self): + await self._assert_chain_stopped('cancel') - self.phase = 'a starved fuel budget never becomes an internal error' - await self._assert_starved_fuel() - - self.phase = 'a contract cannot manufacture an internal error' - await self._assert_child_failures_are_canonical() - - self.phase = 'cancel kills process chain' - await self._assert_chain_stopped('cancel') - - self.phase = 'deadline kills process chain' - await self._assert_chain_stopped('deadline') - - self.phase = 'a nested chain that runs out of time reports timeout' - await self._assert_nested_deadline_is_timeout() - - self.phase = 'resolve loop bottoms out on the recursion budget' - await self._assert_resolve_loop_recursion() + async def _assert_deadline_stops_chain(self): + await self._assert_chain_stopped('deadline') async def _new_host( self, @@ -847,7 +403,7 @@ async def _execute( message=_message(address, is_init=is_init), host_data='{"node_address":"test","tx_id":"cross-major"}', host='unix://' + mock_host.path, - code=code, + code=resolve_runners(code, self.case.shared.root_dir), calldata=calldata, timeout=timeout, debug_mode='unsafe', @@ -861,7 +417,7 @@ async def _execute( }, bucket_totals=[2**200] * 20, ) - if apply_changes and result.result_kind == public_abi.ResultCode.RETURN: + if apply_changes and result.result_kind == host_fns.ResultCode.RETURN: assert mock_host.storage is not None _apply_storage_changes( mock_host.storage, @@ -881,14 +437,14 @@ async def _deploy(self, line: int, address: Address, code: bytes): code=code, is_init=True, ) - assert result.result_kind == public_abi.ResultCode.RETURN, result + assert result.result_kind == host_fns.ResultCode.RETURN, result assert len(result.execution_hash) == 32, result.execution_hash async def _compile_wat(self, wat: str, path: Path) -> bytes: - path.mkdir(parents=True, exist_ok=True) + await gvm_io.make_dir(path) wat_path = path / 'contract.wat' wasm_path = path / 'contract.wasm' - wat_path.write_text(wat) + await gvm_io.write_file_text(wat_path, wat) process = await asyncio.create_subprocess_exec( 'wat2wasm', '--enable-annotations', @@ -900,9 +456,12 @@ async def _compile_wat(self, wat: str, path: Path) -> bytes: ) stdout, stderr = await process.communicate() assert process.returncode == 0, (stdout, stderr) - return wasm_path.read_bytes() + return await gvm_io.read_file_bytes(wasm_path) def _replace_code(self, address: Address, old_code: bytes, new_code: bytes) -> None: + root_dir = self.case.shared.root_dir + old_code = typing.cast(bytes, resolve_runners(old_code, root_dir)) + new_code = typing.cast(bytes, resolve_runners(new_code, root_dir)) with open(self.storage_path, 'rb') as storage_file: storage: MockStorage = pickle.load(storage_file) slots = storage._storages[address] @@ -923,7 +482,8 @@ def _replace_code(self, address: Address, old_code: bytes, new_code: bytes) -> N pickle.dump(storage, storage_file) def _route(self, line: int) -> bytes: - """Routing payload placing a callee on `line`'s executor. + """ + Routing payload placing a callee on `line`'s executor. It names the directory rather than the major, because a major cannot pick between the live lines: every manifest key is semver major 0, so @@ -931,17 +491,6 @@ def _route(self, line: int) -> bytes: """ return gvm_calldata.encode({'kind': 'version', 'version': self.versions[line]}) - async def _call(self, line: int, caller: Address, target: Address, resolve_hook): - return await self._execute( - name=f'call-{line}-{caller.as_bytes.hex()}-{target.as_bytes.hex()}', - line=line, - address=caller, - calldata=_calldata('call', target), - code=None, - is_init=False, - resolve_hook=resolve_hook, - ) - def _raw_request( self, *, @@ -1000,7 +549,7 @@ def resolve(address, _state, _major): line=3, address=ADDR_CALLER_V03, host_path=mock_host.path, - deadline='30s' if mode == 'cancel' else '3s', + deadline='30s' if mode == 'cancel' else '10s', ) ) await asyncio.wait_for(nested_resolved.wait(), timeout=10) @@ -1019,45 +568,9 @@ def resolve(address, _state, _major): await host_task await host.stop_connections() - async def _assert_signer_preserved(self): - """This line's contract-facing message has no signer, but the executor - still receives one and must hand it to a callee that does expose it.""" - result = await self._execute( - name='signer-v02-to-v03', - line=2, - address=ADDR_SIGNER_CALLER_V02, - calldata=_calldata('signer', ADDR_SIGNER_V03), - code=None, - is_init=False, - resolve_hook=lambda address, _state, _major: ( - self._route(3) if address == ADDR_SIGNER_V03 else None - ), - ) - assert result.result_kind == public_abi.ResultCode.RETURN, result - assert result.result_data == SENDER.as_hex, (result.result_data, SENDER.as_hex) - - async def _assert_structured_user_error(self): - """A callee's user error is contract data, so it must stay contract-visible - on the caller. v0.2 user errors are strings, so a structured payload cannot - be carried across as one and degrades to the vm error naming the boundary - that could not represent it — never an internal error.""" - result = await self._execute( - name='structured-error-v02-to-v03', - line=2, - address=ADDR_CALLER_V02, - calldata=_calldata('call', ADDR_STRUCTURED_V03), - code=None, - is_init=False, - resolve_hook=lambda address, _state, _major: ( - self._route(3) if address == ADDR_STRUCTURED_V03 else None - ), - ) - assert result.result_kind == public_abi.ResultCode.VM_ERROR, result - expected = str(public_abi.VmError.invalid_contract().major_mismatch()) - assert result.result_data == expected, (result.result_data, expected) - async def _assert_envelope_ignores_websocket_cap(self): - """A contract picks the calldata it forwards, so nothing an operator + """ + A contract picks the calldata it forwards, so nothing an operator configures may decide whether the call goes through. This manager runs with `max_message_bytes` deliberately below the envelope this builds: the cap bounds client frames on `/ws`, never the executor socketpair.""" @@ -1074,11 +587,12 @@ async def _assert_envelope_ignores_websocket_cap(self): ), timeout=60, ) - assert result.result_kind == public_abi.ResultCode.RETURN, result + assert result.result_kind == host_fns.ResultCode.RETURN, result assert result.result_data == BLOB_BYTES, result async def _assert_nested_deadline_is_timeout(self): - """The chain dies on a signal, so no executor reports anything. What the + """ + The chain dies on a signal, so no executor reports anything. What the caller must still observe is a timeout, not the internal error the dead boundary would otherwise produce.""" result = await self._execute( @@ -1093,13 +607,14 @@ async def _assert_nested_deadline_is_timeout(self): ), timeout=10, ) - assert result.result_kind == public_abi.ResultCode.VM_ERROR, result + assert result.result_kind == host_fns.ResultCode.VM_ERROR, result assert result.result_data == str(public_abi.VmError.timeout()), result async def _lvs( self, *, name: str, line: int, address: Address, calldata: bytes, resolve_hook ): - """Run the same step as leader, validator and sync run. + """ + Run the same step as leader, validator and sync run. The three must agree on the execution hash; anything else is a determinism violation an honest validator would see as a disagreement. @@ -1125,7 +640,7 @@ async def one(suffix: str, **kwargs): sync = await one('sync', is_sync=True) return leader, validator, sync - async def _assert_lvs_agrees(self): + async def _assert_lvs_validator_mode(self): # A leader/validator run that silently degraded to a sync one would make # the agreement below vacuous, so first pin that the validator mode is # real: handing it a leader result nothing consumes must be rejected. @@ -1143,38 +658,34 @@ async def _assert_lvs_agrees(self): is_sync=False, leader_nondet_results=[gvm_calldata.encode({})], ) - assert bogus.result_kind == public_abi.ResultCode.VM_ERROR, bogus - - for suffix, line, caller, callee, major in ( - ('fwd', 3, ADDR_CALLER_V03, ADDR_CALLEE_V02, 2), - ('bwd', 2, ADDR_CALLER_V02, ADDR_CALLEE_V03, 3), - ): - target = callee - leader, validator, sync = await self._lvs( - name=f'lvs-{suffix}', - line=line, - address=caller, - calldata=_calldata('call', callee), - resolve_hook=lambda address, _state, _major, target=target, major=major: ( - self._route(major) if address == target else None - ), - ) - for label, run in (('leader', leader), ('validator', validator), ('sync', sync)): - assert run.result_kind == public_abi.ResultCode.RETURN, (suffix, label, run) - assert len(run.execution_hash) == 32, (suffix, label, run.execution_hash) - assert leader.execution_hash == validator.execution_hash, ( - suffix, - leader.execution_hash.hex(), - validator.execution_hash.hex(), - ) - assert leader.execution_hash == sync.execution_hash, ( - suffix, - leader.execution_hash.hex(), - sync.execution_hash.hex(), - ) + assert bogus.result_kind == host_fns.ResultCode.VM_ERROR, bogus + + async def _assert_lvs_direction( + self, + suffix: str, + line: int, + caller: Address, + callee: Address, + major: int, + ): + leader, validator, sync = await self._lvs( + name=f'lvs-{suffix}', + line=line, + address=caller, + calldata=_calldata('call', callee), + resolve_hook=lambda address, _state, _major: ( + self._route(major) if address == callee else None + ), + ) + runs = [('leader', leader), ('validator', validator), ('sync', sync)] + for label, run in runs: + assert run.result_kind == host_fns.ResultCode.RETURN, (suffix, label, run) + assert len(run.execution_hash) == 32, (suffix, label, run.execution_hash) + _assert_hashes_agree(f'nested call, {suffix}', runs) async def _assert_unhooked_stays_in_process(self): - """Without `hook_cross_contract_calls` the manager answers the resolve + """ + Without `hook_cross_contract_calls` the manager answers the resolve method itself, so a host is never consulted even when the callee really does live on another major, and the call stays in-process.""" asked: list[Address] = [] @@ -1196,13 +707,14 @@ def resolve(address, _state, _major): ) assert asked == [], asked # The in-process outcome for a v0.2 callee, identical to answering null. - assert result.result_kind == public_abi.ResultCode.VM_ERROR, result + assert result.result_kind == host_fns.ResultCode.VM_ERROR, result assert str(result.result_data).startswith( - str(public_abi.VmError.invalid_contract().absent_runner_comment()) + str(public_abi.VmError.invalid_contract().runner().absent()) ), result.result_data async def _assert_route_is_hash_invariant(self): - """A host picks the route, a contract does not. A same-major call that a + """ + A host picks the route, a contract does not. A same-major call that a host chooses to send through the nested boundary must hash exactly as the in-process one, otherwise the route is consensus-visible.""" in_process = await self._execute( @@ -1227,81 +739,57 @@ async def _assert_route_is_hash_invariant(self): ), apply_changes=False, ) - assert in_process.result_kind == public_abi.ResultCode.RETURN, in_process - assert nested.result_kind == public_abi.ResultCode.RETURN, nested + assert in_process.result_kind == host_fns.ResultCode.RETURN, in_process + assert nested.result_kind == host_fns.ResultCode.RETURN, nested assert in_process.result_data == nested.result_data == 303, (in_process, nested) # The parent's own execution hash folds the callee's small hash, which # commits to the outcome and to nothing about where the callee ran. - assert in_process.execution_hash == nested.execution_hash, ( + _assert_hashes_agree( 'the route is consensus-visible', - in_process.execution_hash.hex(), - nested.execution_hash.hex(), + [('in process', in_process), ('nested', nested)], ) - async def _assert_plain_user_error(self): - """A string user error is representable on both lines, so it must reach - the caller as a user error in either direction.""" - for suffix, line, caller, callee, major in ( - ('v02-to-v03', 2, ADDR_CALLER_V02, ADDR_UERR_V03, 3), - ('v03-to-v02', 3, ADDR_CALLER_V03, ADDR_UERR_V02, 2), - ): - target = callee + async def _assert_state_mode_crosses( + self, + final: bool, + expected: public_abi.StorageType, + ): + """ + The caller's state mode selects which chain view the callee reads, so + the boundary must hand the callee exactly the mode the in-process route + would have used.""" + modes: dict[bool, set[public_abi.StorageType]] = {} + for nested in (False, True): + resolved: list[public_abi.StorageType] = [] + read_log: list[tuple[Address, public_abi.StorageType]] = [] + + def resolve(address, state, _major, nested=nested, resolved=resolved): + if address != ADDR_CALLEE_V03: + return None + resolved.append(state) + return self._route(3) if nested else None + result = await self._execute( - name=f'plain-error-{suffix}', - line=line, - address=caller, - calldata=_calldata('call', callee), + name=f'state-mode-{"final" if final else "nonfinal"}-{nested}', + line=3, + address=ADDR_STATE_CALLER_V03, + calldata=_calldata('call', ADDR_CALLEE_V03, final), code=None, is_init=False, - resolve_hook=lambda address, _state, _major, target=target, major=major: ( - self._route(major) if address == target else None - ), + resolve_hook=resolve, apply_changes=False, + read_log=read_log, ) - assert result.result_kind == public_abi.ResultCode.USER_ERROR, (suffix, result) - - async def _assert_state_mode_crosses(self): - """The caller's state mode selects which chain view the callee reads, so - the boundary must hand the callee exactly the mode the in-process route - would have used.""" - for final, expected in ( - (False, public_abi.StorageType.LATEST_NON_FINAL), - (True, public_abi.StorageType.LATEST_FINAL), - ): - modes: dict[bool, set[public_abi.StorageType]] = {} - for nested in (False, True): - resolved: list[public_abi.StorageType] = [] - read_log: list[tuple[Address, public_abi.StorageType]] = [] - - def resolve(address, state, _major, nested=nested, resolved=resolved): - if address != ADDR_CALLEE_V03: - return None - resolved.append(state) - return self._route(3) if nested else None - - result = await self._execute( - name=f'state-mode-{"final" if final else "nonfinal"}-{nested}', - line=3, - address=ADDR_STATE_CALLER_V03, - calldata=_calldata('call', ADDR_CALLEE_V03, final), - code=None, - is_init=False, - resolve_hook=resolve, - apply_changes=False, - read_log=read_log, - ) - assert result.result_kind == public_abi.ResultCode.RETURN, ( - final, - nested, - result, - ) - assert result.result_data == 303, (final, nested, result) - assert resolved == [expected], (final, nested, resolved) - modes[nested] = { - mode for account, mode in read_log if account == ADDR_CALLEE_V03 - } - assert modes[False] == modes[True], (final, modes) - assert modes[True] == {expected}, (final, modes) + assert result.result_kind == host_fns.ResultCode.RETURN, ( + final, + nested, + result, + ) + assert result.result_data == 303, (final, nested, result) + assert resolved == [expected], (final, nested, resolved) + modes[nested] = {mode for account, mode in read_log if account == ADDR_CALLEE_V03} + assert modes[False] == modes[True], (final, modes) + assert modes[True] == {expected}, (final, modes) def _chain_resolve(self, address, _state, _major): if address == ADDR_CHAIN_V03: @@ -1311,7 +799,8 @@ def _chain_resolve(self, address, _state, _major): return None async def _assert_deep_chain(self): - """Every hop of an alternating chain crosses the boundary, so the whole + """ + Every hop of an alternating chain crosses the boundary, so the whole chain is a stack of nested processes. Its answer and its hash must not depend on which of the three runs produced them.""" depth = 6 @@ -1325,7 +814,7 @@ async def _assert_deep_chain(self): # The chain alternates v0.3, v0.2, ..., so it sums 3 and 2 in turn. expected = sum(3 if index % 2 == 0 else 2 for index in range(depth + 1)) for label, run in (('leader', leader), ('validator', validator), ('sync', sync)): - assert run.result_kind == public_abi.ResultCode.RETURN, (label, run) + assert run.result_kind == host_fns.ResultCode.RETURN, (label, run) assert run.result_data == expected, (label, run.result_data, expected) assert leader.execution_hash == validator.execution_hash, ( leader.execution_hash.hex(), @@ -1336,79 +825,77 @@ async def _assert_deep_chain(self): sync.execution_hash.hex(), ) - async def _assert_starved_fuel(self): - """The caller hands the callee whatever fuel the host says is left. A + async def _assert_starved_fuel(self, fuel: int): + """ + The caller hands the callee whatever fuel the host says is left. A callee that cannot finish on it must report a canonical vm error, and two hosts reporting the same figure must agree on the outcome.""" - outcomes = [] - for fuel in (0, 1, 1000, 10**6): - result = await self._execute( - name=f'starved-fuel-{fuel}', - line=3, - address=ADDR_CALLER_V03, - calldata=_calldata('call', ADDR_CALLEE_V02), - code=None, - is_init=False, - resolve_hook=lambda address, _state, _major: ( - self._route(2) if address == ADDR_CALLEE_V02 else None - ), - apply_changes=False, - host_fuel=fuel, - ) - assert result.result_kind != public_abi.ResultCode.INTERNAL_ERROR, (fuel, result) - outcomes.append((fuel, result.result_kind, result.result_data)) - repeat = await self._execute( - name=f'starved-fuel-{fuel}-again', - line=3, - address=ADDR_CALLER_V03, - calldata=_calldata('call', ADDR_CALLEE_V02), - code=None, - is_init=False, - resolve_hook=lambda address, _state, _major: ( - self._route(2) if address == ADDR_CALLEE_V02 else None - ), - apply_changes=False, - host_fuel=fuel, - ) - assert repeat.execution_hash == result.execution_hash, ( - fuel, - result.execution_hash.hex(), - repeat.execution_hash.hex(), - ) - self.notes.append(('starved fuel outcomes', [str(entry) for entry in outcomes])) - - async def _assert_child_failures_are_canonical(self): - """A contract must not be able to manufacture an - internal error. Every failure a contract can pick the input for — a - method the callee lacks, an address nothing was ever deployed to, a - callee routed to a line its stored major disagrees with — must land on a - user or vm error instead.""" - absent = Address('0x' + '99' * 20) - cases = ( - # The callee has `sink`, not `answer`. - ('missing-method', 2, ADDR_CALLER_V02, ADDR_BLOB_V03, 3), - ('absent-callee', 3, ADDR_CALLER_V03, absent, 2), - # The callee's stored major is 2; the host routes it to v0.3 anyway. - ('routed-to-wrong-line', 3, ADDR_CALLER_V03, ADDR_CALLEE_V02, 3), + result = await self._execute( + name=f'starved-fuel-{fuel}', + line=3, + address=ADDR_CALLER_V03, + calldata=_calldata('call', ADDR_CALLEE_V02), + code=None, + is_init=False, + resolve_hook=lambda address, _state, _major: ( + self._route(2) if address == ADDR_CALLEE_V02 else None + ), + apply_changes=False, + host_fuel=fuel, ) - observed = [] - for label, line, caller, callee, major in cases: - target = callee - result = await self._execute( - name=f'canonical-{label}', - line=line, - address=caller, - calldata=_calldata('call', callee), - code=None, - is_init=False, - resolve_hook=lambda address, _state, _major, target=target, major=major: ( - self._route(major) if address == target else None - ), - apply_changes=False, + assert result.result_kind != host_fns.ResultCode.INTERNAL_ERROR, (fuel, result) + repeat = await self._execute( + name=f'starved-fuel-{fuel}-again', + line=3, + address=ADDR_CALLER_V03, + calldata=_calldata('call', ADDR_CALLEE_V02), + code=None, + is_init=False, + resolve_hook=lambda address, _state, _major: ( + self._route(2) if address == ADDR_CALLEE_V02 else None + ), + apply_changes=False, + host_fuel=fuel, + ) + assert repeat.execution_hash == result.execution_hash, ( + fuel, + result.execution_hash.hex(), + repeat.execution_hash.hex(), + ) + self.notes.append( + ('starved fuel outcome', (fuel, str(result.result_kind), str(result.result_data))) + ) + + async def _assert_child_failure_is_canonical( + self, + label: str, + line: int, + caller: Address, + callee: Address, + major: int, + ): + """ + A contract-controlled child failure must land on a user or VM error, + never an internal error.""" + result = await self._execute( + name=f'canonical-{label}', + line=line, + address=caller, + calldata=_calldata('call', callee), + code=None, + is_init=False, + resolve_hook=lambda address, _state, _major: ( + self._route(major) if address == callee else None + ), + apply_changes=False, + ) + assert result.result_kind != host_fns.ResultCode.INTERNAL_ERROR, (label, result) + self.notes.append( + ( + 'child failure outcome', + (label, str(result.result_kind), str(result.result_data)[:80]), ) - assert result.result_kind != public_abi.ResultCode.INTERNAL_ERROR, (label, result) - observed.append((label, str(result.result_kind), str(result.result_data)[:80])) - self.notes.append(('child failure outcomes', [str(entry) for entry in observed])) + ) async def _assert_resolve_loop_recursion(self): resolved: list[tuple[Address, int]] = [] @@ -1434,7 +921,7 @@ def resolve(address, _state, advisory_major): # cost 511 spawns to reach; this hits the same code path in two. debug_initial_recursion=2, ) - assert result.result_kind == public_abi.ResultCode.VM_ERROR, ( + assert result.result_kind == host_fns.ResultCode.VM_ERROR, ( result, len(resolved), resolved[-3:], @@ -1450,10 +937,140 @@ def resolve(address, _state, advisory_major): ], resolved -def collect(ctx: genvm_tool.tests.stage.collection.Context) -> None: - desc = genvm_tool.tests.test.Description( - name='tests/system/cross-major', - tags=frozenset({'integration', 'stable', 'cross-major'}), - console_pool=True, - ) - ctx.add_case(CrossMajorCase(description=desc, shared=ctx.shared)) +def collect( + ctx: genvm_tool.tests.stage.collection.Context, + *, + manager_service: genvm_tool.tests.stage.collection.Service, + limited_manager_service: genvm_tool.tests.stage.collection.Service | None, + managed_manager: bool, +) -> None: + cases = [ + ( + 'large-envelope', + '_assert_envelope_ignores_websocket_cap', + ('blob-caller-v02', 'blob-v03'), + (), + ), + ( + 'unhooked', + '_assert_unhooked_stays_in_process', + ('caller-v03', 'callee-v02'), + (), + ), + ( + 'lvs-validator-mode', + '_assert_lvs_validator_mode', + ('caller-v03', 'callee-v02'), + (), + ), + ( + 'lvs-v03-to-v02', + '_assert_lvs_direction', + ('caller-v03', 'callee-v02'), + ('v03-to-v02', 3, ADDR_CALLER_V03, ADDR_CALLEE_V02, 2), + ), + ( + 'lvs-v02-to-v03', + '_assert_lvs_direction', + ('caller-v02', 'callee-v03'), + ('v02-to-v03', 2, ADDR_CALLER_V02, ADDR_CALLEE_V03, 3), + ), + ( + 'route-hash', + '_assert_route_is_hash_invariant', + ('caller-v03', 'callee-v03'), + (), + ), + ( + 'state-mode-nonfinal', + '_assert_state_mode_crosses', + ('state-caller-v03', 'callee-v03'), + (False, public_abi.StorageType.LATEST_NON_FINAL), + ), + ( + 'state-mode-final', + '_assert_state_mode_crosses', + ('state-caller-v03', 'callee-v03'), + (True, public_abi.StorageType.LATEST_FINAL), + ), + ('deep-chain', '_assert_deep_chain', ('chain-v03', 'chain-v02'), ()), + *[ + ( + f'starved-fuel-{fuel}', + '_assert_starved_fuel', + ('caller-v03', 'callee-v02'), + (fuel,), + ) + for fuel in (0, 1, 1000, 10**6) + ], + ( + 'child-failure-missing-method', + '_assert_child_failure_is_canonical', + ('caller-v02', 'blob-v03'), + ('missing-method', 2, ADDR_CALLER_V02, ADDR_BLOB_V03, 3), + ), + ( + 'child-failure-absent-callee', + '_assert_child_failure_is_canonical', + ('caller-v03',), + ('absent-callee', 3, ADDR_CALLER_V03, ABSENT_CALLEE, 2), + ), + ( + 'child-failure-wrong-line', + '_assert_child_failure_is_canonical', + ('caller-v03', 'callee-v02'), + ('routed-to-wrong-line', 3, ADDR_CALLER_V03, ADDR_CALLEE_V02, 3), + ), + ( + 'cancel-process-tree', + '_assert_cancel_stops_chain', + ('caller-v03', 'busy-v02'), + (), + ), + ( + 'deadline-process-tree', + '_assert_deadline_stops_chain', + ('caller-v03', 'busy-v02'), + (), + ), + ( + 'nested-timeout', + '_assert_nested_deadline_is_timeout', + ('caller-v03', 'busy-v02'), + (), + ), + ( + 'resolve-recursion', + '_assert_resolve_loop_recursion', + ('loop-v03', 'loop-v02'), + (), + ), + ] + for slug, method, fixtures, arguments in cases: + if not managed_manager and slug in { + 'cancel-process-tree', + 'deadline-process-tree', + }: + continue + if slug == 'large-envelope': + if limited_manager_service is None: + continue + case_manager = limited_manager_service + else: + case_manager = manager_service + desc = genvm_tool.tests.test.Description( + name=f'tests/system/cross-major/{slug}', + needed_services=frozenset({case_manager}), + tags=frozenset({'integration', 'stable', 'feature-version-routing-cross-major'}), + console_pool=slug in {'cancel-process-tree', 'deadline-process-tree'}, + ) + ctx.add_case( + CrossMajorCase( + description=desc, + shared=ctx.shared, + manager_service=case_manager, + method=method, + fixtures=fixtures, + arguments=arguments, + ) + ) diff --git a/tests/system/manager-socket/test.py b/tests/system/manager-socket/test.py index a489cc41..f375043c 100644 --- a/tests/system/manager-socket/test.py +++ b/tests/system/manager-socket/test.py @@ -1,17 +1,17 @@ import asyncio import contextlib -import json import os import pickle -import socket import stat import typing from dataclasses import dataclass from pathlib import Path import aiohttp +import genvm_tool.io as gvm_io import genvm_tool.tests import genvm_tool.tests.stage.collection +import genvm_tool_plugins.genvm as genvm import origin.base_host as base_host import origin.calldata as gvm_calldata from gvm_extra.mock_host import MockHost, MockStorage @@ -126,120 +126,36 @@ async def close(self) -> None: self.session = None -class ManagerProc: - def __init__( - self, - *, - root: Path, - build_dir: Path, - artifacts_dir: Path, - name: str, - socket_path: Path, - max_message_bytes: int = 67108864, - execution_retention: str = '30s', - use_unix_listener: bool = False, - ): - self.root = root - self.build_dir = build_dir - self.work_dir = artifacts_dir / name - self.socket_path = socket_path - self.max_message_bytes = max_message_bytes - self.execution_retention = execution_retention - self.use_unix_listener = use_unix_listener - self.process: asyncio.subprocess.Process | None = None - self.port = self._unused_port() - self.log_file = None - - @staticmethod - def _unused_port() -> int: - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: - sock.bind(('127.0.0.1', 0)) - return sock.getsockname()[1] +class _ManagerFixture: + def __init__(self, handle: genvm.ManagerHandle, work_dir: Path): + self.handle = handle + self.work_dir = work_dir + self.work_dir.mkdir(parents=True, exist_ok=True) @property def uri(self) -> str: - if self.use_unix_listener: - return f'unix://{self.socket_path}' - return f'http://127.0.0.1:{self.port}' + return self.handle.uri + + @property + def socket_path(self) -> Path | None: + return self.handle.socket_path + + async def restart(self) -> None: + await self.handle.restart() async def __aenter__(self): - self.work_dir.mkdir(parents=True, exist_ok=True) - config_path = self.work_dir / 'genvm-manager.yaml' - config_path.write_text( - '\n'.join( - [ - 'threads: 4', - 'blocking_threads: 48', - 'log_disable: tracing*,polling*,tungstenite*,tokio_tungstenite*', - 'log_level: info', - f'manifest_path: {self.build_dir / "out" / "data" / "manifest.yaml"}', - 'permits: 2', - f'execution_retention: {self.execution_retention}', - f'max_message_bytes: {self.max_message_bytes}', - '', - ] - ) - ) - listener_args = ( - ['--socket', str(self.socket_path)] - if self.use_unix_listener - else ['--port', str(self.port)] - ) - self.log_file = open(self.work_dir / 'manager.log', 'wb') - self.process = await asyncio.subprocess.create_subprocess_exec( - str(self.build_dir / 'out' / 'bin' / 'genvm-modules'), - 'manager', - *listener_args, - '--die-with-parent', - '--config', - str(config_path), - stdin=asyncio.subprocess.DEVNULL, - stdout=self.log_file, - stderr=self.log_file, - start_new_session=True, - ) - await self._wait_healthy() return self async def __aexit__(self, *_args): - if self.process is not None: - try: - self.process.terminate() - await asyncio.wait_for(self.process.wait(), timeout=5) - except asyncio.TimeoutError: - self.process.kill() - await self.process.wait() - if self.log_file is not None: - self.log_file.close() - - async def _wait_healthy(self): - last_error: BaseException | None = None - for _ in range(80): - if self.process is not None and self.process.returncode is not None: - raise RuntimeError(f'manager exited early with {self.process.returncode}') - try: - if self.use_unix_listener: - async with aiohttp.ClientSession( - connector=aiohttp.UnixConnector(path=str(self.socket_path)) - ) as session: - async with session.get( - 'http://localhost/status', - timeout=aiohttp.ClientTimeout(total=1), - ) as resp: - if resp.status == 200: - return - else: - async with aiohttp.request( - 'GET', - f'{self.uri}/status', - timeout=aiohttp.ClientTimeout(total=1), - ) as resp: - if resp.status == 200: - return - except BaseException as exc: - last_error = exc - await asyncio.sleep(0.1) - raise TimeoutError(f'manager did not become healthy: {last_error}') + pass + + +class _StaleSocketManagerService(genvm.ManagerService): + async def _start_once(self) -> genvm.ManagerHandle: + assert self._socket_path is not None + self._socket_path.parent.mkdir(parents=True, exist_ok=True) + self._socket_path.write_text('stale') + return await super()._start_once() def _run_request( @@ -302,7 +218,8 @@ async def _wait_event(client: ManagerWsClient, variant: str, timeout: float = 10 async def _wait_terminal(client: ManagerWsClient, timeout: float = 10.0): - """Wait for whichever terminal event the run produces. + """ + Wait for whichever terminal event the run produces. Which one it is depends on how far the run got, and the point of the test is that *some* terminal event arrives without the host having to time out. @@ -371,7 +288,7 @@ async def _get_artifact(client: ManagerWsClient, genvm_id: int, field: str) -> b def _make_mock_host( - manager: ManagerProc, + manager: _ManagerFixture, name: str, ctx: _TestContext, running_address: Address | None = None, @@ -400,6 +317,8 @@ def _make_mock_host( class ManagerSocketCase(genvm_tool.tests.test.Case): description: genvm_tool.tests.test.Description shared: genvm_tool.tests.SharedContext + manager_service: genvm_tool.tests.stage.collection.Service + method: str async def into_steps(self) -> list[genvm_tool.tests.exec.step.Step]: return [ManagerSocketStep(self)] @@ -408,7 +327,7 @@ async def into_steps(self) -> list[genvm_tool.tests.exec.step.Step]: class ManagerSocketStep(genvm_tool.tests.exec.step.Python): def __init__(self, case: ManagerSocketCase): self.case = case - self.phase = 'start' + self.phase = case.method def to_str(self) -> str: return '' @@ -417,7 +336,7 @@ async def run( self, previous_results: list[typing.Any] ) -> genvm_tool.tests.test.Result: try: - await self._run_all() + await getattr(self, self.case.method)() return genvm_tool.tests.test.Result(passed=True, context={}, elapsed_seconds=0) except BaseException as exc: return genvm_tool.tests.test.Result( @@ -433,69 +352,17 @@ async def _manager( max_message_bytes: int = 67108864, use_unix_listener: bool = False, ): - artifacts = self.case.shared.artifacts_dir / 'manager_socket' - socket_path = Path('/tmp') / f'gvm-ms-{os.getpid()}' / f'{name}.sock' - return ManagerProc( - root=self.case.shared.root_dir, - build_dir=Path( - json.loads((self.case.shared.root_dir / 'build' / 'info.json').read_text())[ - 'build_dir' - ] - ), - artifacts_dir=artifacts, - name=name, - socket_path=socket_path, - max_message_bytes=max_message_bytes, - use_unix_listener=use_unix_listener, + del max_message_bytes, use_unix_listener + handle = self.case.manager_service.handle + assert isinstance(handle, genvm.ManagerHandle) + return _ManagerFixture( + handle, + self.case.shared.case_dir_for(self.case.description.name) / name, ) async def _manager_with_retention(self, name: str, retention: str): - artifacts = self.case.shared.artifacts_dir / 'manager_socket' - socket_path = Path('/tmp') / f'gvm-ms-{os.getpid()}' / f'{name}.sock' - return ManagerProc( - root=self.case.shared.root_dir, - build_dir=Path( - json.loads((self.case.shared.root_dir / 'build' / 'info.json').read_text())[ - 'build_dir' - ] - ), - artifacts_dir=artifacts, - name=name, - socket_path=socket_path, - execution_retention=retention, - ) - - async def _run_all(self): - self.phase = 'protocol errors' - await self._malformed_unknown_and_survival() - self.phase = 'oversized close' - await self._oversized_closes_connection() - self.phase = 'startup failures' - await self._startup_failure_events_and_permits() - self.phase = 'happy path' - await self._happy_path_artifact_ack_attach() - self.phase = 'reconnect mid-run' - await self._disconnect_mid_run_reconnect_attach() - self.phase = 'finish before ack reconnect' - await self._disconnect_after_finish_before_ack() - self.phase = 'multi attach' - await self._two_clients_receive_terminal() - self.phase = 'ack and ttl' - await self._ack_and_ttl_drop_results() - self.phase = 'boot mismatch' - await self._manager_restart_boot_mismatch() - self.phase = 'restart loses run' - await self._manager_restart_fails_waiter() - self.phase = 'cancel after start' - await self._cancel_after_start_single_terminal() - self.phase = 'deadline event' - await self._deadline_pushes_terminal() - self.phase = 'ttl drain' - await self._client_never_returns_ttl_drains() - self.phase = 'http socket parity' - await self._http_and_socket_same_fixture() - self.phase = 'unix stale' - await self._unix_parent_and_stale_socket() + del retention + return await self._manager(name) async def _malformed_unknown_and_survival(self): async with await self._manager('protocol-errors') as manager: @@ -577,9 +444,9 @@ async def _happy_path_artifact_ack_attach(self): tmp_dir = manager.work_dir / 'host' tmp_dir.mkdir(parents=True, exist_ok=True) storage_path = tmp_dir / 'storage.pickle' - with open(storage_path, 'wb') as f: - pickle.dump(MockStorage(), f) - host_path = tmp_dir / 'host.sock' + await gvm_io.write_file_bytes(storage_path, pickle.dumps(MockStorage())) + host_path = Path('/tmp') / f'gvm-ms-{os.getpid()}' / 'happy-host.sock' + host_path.parent.mkdir(parents=True, exist_ok=True) ctx = _TestContext(self.case.shared.logger) host = MockHost( path=str(host_path), @@ -797,6 +664,7 @@ async def _manager_restart_boot_mismatch(self): async with ManagerWsClient(manager.uri) as client: boot_id = await _read_hello(client) genvm_id = 1 + await manager.restart() async with manager: async with ManagerWsClient(manager.uri) as client: await _read_hello(client) @@ -828,8 +696,7 @@ async def _manager_restart_fails_waiter(self): # The manager that owns the run dies and a fresh one takes its # place, handing out the same ids again -- the run cannot be # re-attached, so the waiter has to fail rather than reconnect. - await manager.__aexit__() - await manager.__aenter__() + await manager.restart() try: terminal = await asyncio.wait_for(client.wait_terminal(state), timeout=15) except base_host.ManagerRunLost: @@ -948,7 +815,7 @@ async def _http_and_socket_same_fixture(self): assert http_res['result_kind'] == socket_res.result_kind assert http_res['result_data'] == socket_res.result_data - async def _run_fixture_over_http(self, manager: ManagerProc, name: str): + async def _run_fixture_over_http(self, manager: _ManagerFixture, name: str): ctx = _TestContext(self.case.shared.logger) host, host_path = _make_mock_host(manager, name, ctx) cancel_host = asyncio.Event() @@ -985,7 +852,7 @@ async def _run_fixture_over_http(self, manager: ManagerProc, name: str): 'result_data': consumed.result_data, } - async def _run_fixture_over_socket(self, manager: ManagerProc, name: str): + async def _run_fixture_over_socket(self, manager: _ManagerFixture, name: str): ctx = _TestContext(self.case.shared.logger) host, host_path = _make_mock_host(manager, name, ctx) with host as mock_host: @@ -1011,24 +878,141 @@ async def _run_fixture_over_socket(self, manager: ManagerProc, name: str): ) async def _unix_parent_and_stale_socket(self): - artifacts = Path('/tmp') / f'gvm-ms-{os.getpid()}' - socket_path = artifacts / 'unix-stale.sock' - socket_path.parent.mkdir(parents=True, exist_ok=True) - socket_path.write_text('stale') async with await self._manager('unix-stale', use_unix_listener=True) as manager: - assert manager.socket_path == socket_path + assert manager.socket_path is not None + socket_path = manager.socket_path mode = os.stat(socket_path).st_mode assert stat.S_ISSOCK(mode) -def collect(ctx: genvm_tool.tests.stage.collection.Context) -> None: - # console_pool: this case starts, restarts and kills managers of its own, and - # waits out retention sweeps. Sharing the runner with other cases makes their - # manager unreachable partway through, which they report as a connection - # refused far away from the cause. - desc = genvm_tool.tests.test.Description( - name='tests/system/manager-socket', - tags=frozenset({'integration', 'stable', 'manager-socket'}), - console_pool=True, - ) - ctx.add_case(ManagerSocketCase(description=desc, shared=ctx.shared)) +def collect( + ctx: genvm_tool.tests.stage.collection.Context, + *, + manager_semaphore: genvm_tool.tests.stage.collection.Semaphore, + build_dir: Path, + ci: bool, +) -> None: + service_root = ctx.shared.artifacts_dir / 'manager_socket' / 'services' + base_config = { + 'permits': {'total': 2}, + 'execution_retention': '30s', + } + + def service( + name: str, + *, + config: dict[str, typing.Any] | None = None, + socket_path: Path | None = None, + implementation: type[genvm.ManagerService] = genvm.ManagerService, + ): + merged_config = {**base_config, **(config or {})} + return ctx.new_service( + name=f'manager-socket-{name}', + manager=implementation( + bin_path=build_dir / 'out' / 'bin' / 'genvm-modules', + log_path=service_root / name / 'manager.log', + env=ctx.configuration, + ci=ci, + config=merged_config, + socket_path=socket_path, + ), + semaphores=[manager_semaphore], + ) + + cases = [ + ( + 'protocol-errors', + '_malformed_unknown_and_survival', + {}, + None, + genvm.ManagerService, + ), + ( + 'oversized-close', + '_oversized_closes_connection', + {'max_message_bytes': 32}, + None, + genvm.ManagerService, + ), + ( + 'startup-failures', + '_startup_failure_events_and_permits', + {}, + None, + genvm.ManagerService, + ), + ('happy-path', '_happy_path_artifact_ack_attach', {}, None, genvm.ManagerService), + ( + 'reconnect-mid-run', + '_disconnect_mid_run_reconnect_attach', + {}, + None, + genvm.ManagerService, + ), + ( + 'finish-before-ack', + '_disconnect_after_finish_before_ack', + {}, + None, + genvm.ManagerService, + ), + ( + 'multiple-attachments', + '_two_clients_receive_terminal', + {}, + None, + genvm.ManagerService, + ), + ( + 'ack-drops-result', + '_ack_and_ttl_drop_results', + {'execution_retention': '500ms'}, + None, + genvm.ManagerService, + ), + ('boot-mismatch', '_manager_restart_boot_mismatch', {}, None, genvm.ManagerService), + ( + 'restart-loses-run', + '_manager_restart_fails_waiter', + {}, + None, + genvm.ManagerService, + ), + ('cancel', '_cancel_after_start_single_terminal', {}, None, genvm.ManagerService), + ('deadline', '_deadline_pushes_terminal', {}, None, genvm.ManagerService), + ( + 'retention-drain', + '_client_never_returns_ttl_drains', + {'execution_retention': '500ms'}, + None, + genvm.ManagerService, + ), + ('http-parity', '_http_and_socket_same_fixture', {}, None, genvm.ManagerService), + ( + 'unix-stale-socket', + '_unix_parent_and_stale_socket', + {}, + Path('/tmp') / f'gvm-ms-{os.getpid()}' / 'unix-stale.sock', + _StaleSocketManagerService, + ), + ] + for slug, method, config, socket_path, implementation in cases: + manager_service = service( + slug, + config=config, + socket_path=socket_path, + implementation=implementation, + ) + desc = genvm_tool.tests.test.Description( + name=f'tests/system/manager-socket/{slug}', + needed_services=frozenset({manager_service}), + tags=frozenset({'integration', 'stable', 'feature-manager-socket'}), + ) + ctx.add_case( + ManagerSocketCase( + description=desc, + shared=ctx.shared, + manager_service=manager_service, + method=method, + ) + ) diff --git a/tests/system/parse_version/test.py b/tests/system/parse_version/test.py index 9cdbd943..cd887492 100644 --- a/tests/system/parse_version/test.py +++ b/tests/system/parse_version/test.py @@ -1,4 +1,5 @@ -"""parse-version-pattern system tests. +""" +parse-version-pattern system tests. Each ``*.wat`` here is compiled to wasm and piped into ``genvm parse-version-pattern``; its ``*.expected`` sibling holds the expected @@ -34,7 +35,7 @@ def _add_case( ) -> None: name = f'tests/system/parse_version/{wat_file.stem}' desc = genvm_tool.tests.test.Description(name).with_tags( - ['integration', 'parse_version'] + frozenset({'integration', 'feature-version-parse'}) ) test_env = _default_env() diff --git a/tests/system/permits/test.py b/tests/system/permits/test.py index b5ab128a..50885c0a 100644 --- a/tests/system/permits/test.py +++ b/tests/system/permits/test.py @@ -1,4 +1,5 @@ -"""Permits semaphore system test. +""" +Permits semaphore system test. Tests that the manager's permit semaphore correctly blocks new genvm executions when all permits are exhausted. Evaluated by ``collection.Context.collect_dir``; @@ -12,6 +13,7 @@ from pathlib import Path import aiohttp +import genvm_tool.io as gvm_io import genvm_tool.tests import genvm_tool.tests.stage.collection import origin.base_host as base_host @@ -49,6 +51,7 @@ class PermitsTestCase(genvm_tool.tests.test.Case): description: genvm_tool.tests.test.Description manager_service: genvm_tool.tests.stage.collection.Service shared: genvm_tool.tests.SharedContext + method: str async def into_steps(self) -> list[genvm_tool.tests.exec.step.Step]: return [PermitsTestStep(self)] @@ -70,8 +73,13 @@ async def run( shared = self._case.shared logger = shared.logger - N = 1 - num_permits = N * 2 # minimum enforced by manager is 2 + # the manager refuses to go below the most expensive run, so take that + # many permits and fill them with sync runs exactly + costs = (await self._get_status(manager_uri))['permits'] + sync_cost = costs['per_sync_run'] + min_permits = max(sync_cost, costs['per_nondet_run']) + N = -(-min_permits // sync_cost) + num_permits = N * sync_cost original_permits = await self._get_permits(manager_uri) genvm_ids: list[str] = [] @@ -80,23 +88,21 @@ async def run( shut_downer = asyncio.Event() async with base_host.ManagerClient(manager_uri) as manager_client: try: - # Set permits to N * 2 await self._set_permits(manager_uri, num_permits) logger.debug('permits set', permits=num_permits) - # Start N*2 background genvms (each sync, 1 permit) + # Start N background genvms, each sync tmp_dir = shared.artifacts_dir / 'permits_test' tmp_dir.mkdir(parents=True, exist_ok=True) code = BUSY_CONTRACT.read_bytes() - for i in range(num_permits): + for i in range(N): sock_path = f'/tmp/genvm-test-permits-{i}.sock' storage_path = tmp_dir / f'storage_{i}.pickle' # Create empty storage - with open(storage_path, 'wb') as f: - pickle.dump(MockStorage(), f) + await gvm_io.write_file_bytes(storage_path, pickle.dumps(MockStorage())) ctx = _TestContext(logger) host = MockHost( @@ -140,23 +146,22 @@ async def run( logger.debug('all permits consumed, testing blocking behavior') # Try to start another genvm; it should block on semaphore. - blocked = await self._assert_blocks(manager_uri, code) - if not blocked: - return genvm_tool.tests.test.Result( - passed=False, - context={'reason': 'POST /genvm/run did not block when permits exhausted'}, - elapsed_seconds=0, + if self._case.method == 'http-blocks': + passed = await self._assert_blocks(manager_uri, code) + reason = 'POST /genvm/run did not block when permits exhausted' + elif self._case.method == 'socket-cancel': + passed = await self._assert_socket_cancel_queued( + manager_uri, manager_client, code ) - - socket_cancelled = await self._assert_socket_cancel_queued( - manager_uri, manager_client, code - ) - if not socket_cancelled: + reason = ( + 'socket cancel while queued consumed a permit or missed terminal event' + ) + else: + raise ValueError(f'unknown permits test method: {self._case.method}') + if not passed: return genvm_tool.tests.test.Result( passed=False, - context={ - 'reason': 'socket cancel while queued consumed a permit or missed terminal event' - }, + context={'reason': reason}, elapsed_seconds=0, ) @@ -340,16 +345,18 @@ def collect( *, manager_service: genvm_tool.tests.stage.collection.Service, ) -> None: - desc = genvm_tool.tests.test.Description( - name='tests/system/permits', - needed_services=frozenset({manager_service}), - tags=frozenset({'integration', 'stable', 'permits'}), - console_pool=True, - ) - ctx.add_case( - PermitsTestCase( - description=desc, - manager_service=manager_service, - shared=ctx.shared, + for slug in ('http-blocks', 'socket-cancel'): + desc = genvm_tool.tests.test.Description( + name=f'tests/system/permits/{slug}', + needed_services=frozenset({manager_service}), + tags=frozenset({'integration', 'stable', 'feature-permit'}), + console_pool=True, + ) + ctx.add_case( + PermitsTestCase( + description=desc, + manager_service=manager_service, + shared=ctx.shared, + method=slug, + ) ) - ) diff --git a/tests/tags.json b/tests/tags.json new file mode 100644 index 00000000..525f7c29 --- /dev/null +++ b/tests/tags.json @@ -0,0 +1,148 @@ +{ + "general": { + "unit": "In-crate or single-file test of one component", + "integration": "Manager-driven case: a jsonnet case or a tests/system suite", + "example": "Compilation-only check of an example", + "fuzz": "Randomized or property test", + "bench": "Benchmark, measured rather than asserted", + "rust": "Rust code under test", + "python": "Python code under test", + "bash": "Shell code under test", + "wasm": "WebAssembly artifact under test", + "smoke": "Manually selected fast representative of a feature subtree", + "needs-llm": "Requires LLM provider keys in the environment", + "needs-web": "Requires outbound web access", + "needs-time": "Correctness relies on real clock progression, sleeps or timeouts", + "needs-fuzz": "Requires a fuzz engine, corpus or fuzz toolchain", + "slow": "Expensive to run, independently of real time", + "stable": "Deterministic, no retries", + "semi-stable": "Occasionally flaky", + "unstable": "Flaky, retried", + "octane": "Selected by the external Octane benchmark suite", + "phase-prepare": "Generated setup phase of a case", + "phase-leader": "Generated leader phase of a case", + "phase-validator": "Generated validator phase of a case", + "phase-sync": "Generated sync phase of a case" + }, + "features": { + "nondet": "Nondeterministic execution", + "nondet-consensus": "Consensus over nondeterministic execution", + "nondet-consensus-leader": "Leader behavior", + "nondet-consensus-leader-error": "Leader error handling", + "nondet-consensus-leader-malicious": "Malicious leader handling", + "nondet-consensus-validator": "Validator behavior", + "nondet-consensus-validator-rollback": "Validator rollback", + "nondet-consensus-validator-sync": "Validator synchronization", + + "nasty-determinism": "Deterministic within the tested runner and version, but not a cross-version compatibility promise", + "nasty-determinism-float": "Floating-point behavior, same constraint", + "nasty-determinism-hash": "Hash-derived behavior, same constraint", + "nasty-determinism-id": "Runtime identity values such as Python id, same constraint", + "nasty-determinism-order": "Collection or iteration order, same constraint", + "nasty-determinism-random": "Random output, same constraint", + + "runner": "Runner loading and composition", + "runner-custom": "Custom runner sections", + "runner-dependency": "Runner dependencies", + "runner-load": "Runner loading", + "runner-lock": "Runner locking", + "runner-malformed": "Malformed runner rejection", + "runner-map-vm": "Runner VM mapping", + "runner-multi-file": "Multi-file runners", + "runner-permission": "Runner permissions", + "runner-register": "Runner registration", + "runner-slot": "Runner slots", + "runner-zip": "Zipped runners", + + "message": "Message handling", + "message-deploy": "Contract deployment", + "message-deploy-salt": "Deployment salt", + "message-external": "External calls", + "message-external-view": "External view calls", + "message-send": "Value-carrying sends", + "message-send-eth": "Eth sends", + "message-view": "View calls", + "message-payable": "Payable methods", + "message-eth": "Eth messages", + + "storage": "Contract storage", + "storage-allocation": "Storage allocation", + "storage-bootstrap": "Storage bootstrap", + "storage-dynamic": "Dynamically sized storage", + "storage-dynamic-array": "Dynamic arrays", + "storage-float": "Floats in storage", + "storage-lock": "Storage locking", + "storage-nested": "Nested storage types", + "storage-persistence": "Persistence across runs", + "storage-root": "Storage root", + "storage-tree-map": "TreeMap", + "storage-vector-db": "Vector DB", + + "prompt": "Prompting, including tokenizers and mocks", + "prompt-text": "Text prompts", + "prompt-json": "JSON prompts", + "prompt-vision": "Vision prompts", + "prompt-embedding": "Embeddings", + "prompt-tokenizer": "Tokenizers", + "prompt-comparative": "Comparative prompts", + "prompt-non-comparative": "Non-comparative prompts", + + "web": "Web module", + "web-render": "Page rendering", + "web-render-screenshot": "Screenshots", + "web-render-wait-js": "Waiting on JS", + "web-request": "HTTP requests", + "web-request-body": "Request and response bodies", + "web-request-signed": "Signed requests", + "web-request-status": "Status handling", + + "sandbox": "Sandboxing", + "sandbox-det": "Deterministic sandbox", + "sandbox-non-det": "Nondeterministic sandbox", + + "schema": "Calldata and method schemas", + "schema-primitive": "Primitive types", + "schema-complex": "Complex types", + "schema-float": "Floats", + "schema-tuple": "Tuples", + + "wasi": "WASI surface", + "wasi-environment": "Arguments and environment", + "wasi-path-normalization": "Path normalization", + "wasi-fd-seek": "File descriptor seeking", + "wasi-fd-pread": "Positional file descriptor reads", + "wasi-fd-write": "Writes to standard streams", + "wasi-map-file": "Mapping runner files into the guest filesystem", + "wasi-clock": "Clocks", + "wasi-random": "Randomness", + + "balance": "Balances", + "fees": "Fees", + "fees-balance": "Fee effects on balances", + + "user-error": "Errors attributable to contract code", + "exploit": "Hostile contract behavior", + "exploit-close-stdio": "Closing stdio", + "exploit-deep-calldata": "Deeply nested calldata", + "exploit-disagreement": "Forced disagreement", + "exploit-fork-bomb": "Fork bombs", + "exploit-leader-fault": "Faulty leader", + "exploit-oom": "Memory exhaustion", + "exploit-recursion": "Unbounded recursion", + "exploit-storage-limit": "Storage limits", + "exploit-wasi-extra": "Undeclared WASI functions", + + "permission": "Permission checks", + "permission-method": "Method permissions", + "permission-module": "Module permissions", + "permission-runner": "Runner permissions", + "permit": "Permits", + + "manager-socket": "Manager socket protocol", + "version-parse": "Version parsing", + "version-routing": "Version routing", + "version-routing-cross-major": "Cross-major routing", + "observability": "Logs, metrics and traces", + "event": "Events" + } +} diff --git a/tests/templates/simple_deploy_then_write.jsonnet b/tests/templates/simple_deploy_then_write.jsonnet index ae6da9e6..ffe87ea6 100644 --- a/tests/templates/simple_deploy_then_write.jsonnet +++ b/tests/templates/simple_deploy_then_write.jsonnet @@ -1,13 +1,17 @@ local msg = import './message.json'; { - run(scriptfile, method, args=[]):: + // a deploy that errors persists nothing, so a contract whose constructor + // takes arguments must get them here or the `next` step has no contract + run(scriptfile, method, args=[], ctor_args=[]):: { "vars": {}, "code": scriptfile, "message": msg + { "is_init": true, }, - "calldata": "{}", + "calldata": if std.length(ctor_args) == 0 then "{}" else std.manifestJsonEx({ + "args": ctor_args, + }, " "), next: [ { "vars": {}, diff --git a/webdriver/src/prj/package.json b/webdriver/src/prj/package.json index 52706881..5bf4ff8e 100644 --- a/webdriver/src/prj/package.json +++ b/webdriver/src/prj/package.json @@ -7,7 +7,9 @@ "scripts": { "start": "node --loader ts-node/esm src/index.ts", "dev": "ts-node src/index.ts", - "build": "tsc" + "build": "tsc", + "test": "node --import ./ts-node-register.mjs --test src/**/*.test.ts", + "typecheck": "tsc --noEmit" }, "dependencies": { "puppeteer-core": "24.16.0", diff --git a/webdriver/src/prj/src/duration.test.ts b/webdriver/src/prj/src/duration.test.ts new file mode 100644 index 00000000..02f9ce03 --- /dev/null +++ b/webdriver/src/prj/src/duration.test.ts @@ -0,0 +1,40 @@ +import { describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import { parseSize } from './duration.js'; + +describe('parseSize', () => { + it('treats a bare number as octets', () => { + assert.equal(parseSize('512', undefined), 512); + }); + + it('reads decimal suffixes as powers of 1000', () => { + assert.equal(parseSize('1B', undefined), 1); + assert.equal(parseSize('2KB', undefined), 2000); + assert.equal(parseSize('3MB', undefined), 3_000_000); + assert.equal(parseSize('4GB', undefined), 4_000_000_000); + }); + + it('reads binary suffixes as powers of 1024', () => { + assert.equal(parseSize('2KiB', undefined), 2048); + assert.equal(parseSize('5MiB', undefined), 5 * 1024 * 1024); + assert.equal(parseSize('1GiB', undefined), 1024 ** 3); + }); + + it('accepts fractions, spacing and any casing', () => { + assert.equal(parseSize('1.5 mib', undefined), 1024 * 1024 * 1.5); + assert.equal(parseSize(' 2gIb ', undefined), 2 * 1024 ** 3); + }); + + it('falls back to the default only when nothing was given', () => { + assert.equal(parseSize(undefined, 7), 7); + assert.equal(parseSize('', 7), 7); + assert.equal(parseSize('0', 7), 0); + }); + + it('rejects garbage rather than guessing', () => { + for (const bad of ['MiB', '1 potato', '1KB2', '-1MiB', '1e3']) { + assert.throws(() => parseSize(bad, undefined), /invalid size/, bad); + } + }); +}); diff --git a/webdriver/src/prj/src/duration.ts b/webdriver/src/prj/src/duration.ts index ec7ddaad..7fc241c8 100644 --- a/webdriver/src/prj/src/duration.ts +++ b/webdriver/src/prj/src/duration.ts @@ -54,6 +54,56 @@ export function formatDurationMs(ms: number): string { return `${(ms / 3600000).toFixed(1)}h`; } +const SIZE_UNITS: Record = { + b: 1, + kb: 1000, + mb: 1000 ** 2, + gb: 1000 ** 3, + kib: 1024, + mib: 1024 ** 2, + gib: 1024 ** 3, +}; + +/** + * Parse a size string with optional suffix: "512", "32KB", "5MiB", "1GB". + * Decimal suffixes are powers of 1000, `i` ones powers of 1024, matching what + * the units mean everywhere else. Plain numbers are treated as octets. + * Returns the value in octets, or `dflt` if the input is empty/undefined. + */ +export function parseSize( + input: string | undefined, + dflt: D, +): number | D { + if (input === undefined || input === '') { + return dflt; + } + const match = input.trim().match(/^(\d+(?:\.\d+)?)\s*([a-zA-Z]+)?$/); + if (!match || !match[1]) { + throw new Error(`invalid size: "${input}"`); + } + const multiplier = SIZE_UNITS[(match[2] ?? 'b').toLowerCase()]; + if (multiplier === undefined) { + throw new Error(`invalid size suffix: "${match[2]}"`); + } + return Math.floor(parseFloat(match[1]) * multiplier); +} + +/** + * A size limit below one octet rejects everything it is supposed to bound, so + * it fails at startup rather than silently disabling what it guards. + */ +export function envSize(envName: string, dflt: number | string): number { + const raw = process.env[envName]; + const parsed = parseSize(raw, dflt); + const value = + typeof parsed === 'string' ? parseSize(parsed, undefined) : parsed; + if (value === undefined || value < 1) { + throw new Error(`env ${envName} must be a positive size, got "${raw}"`); + } + logger.log('info', 'env', { name: envName, raw: raw ?? null, value, dflt }); + return value; +} + export function envInt(envName: string, defaultValue: number): number { const raw = process.env[envName]; const value = raw !== undefined && raw !== '' ? parseInt(raw, 10) : NaN; @@ -67,6 +117,21 @@ export function envInt(envName: string, defaultValue: number): number { return result; } +/** + * Like `envInt`, but for limits where a non-positive value is nonsense rather + * than merely unusual — a zero response cap, for instance, would reject every + * page. Fails at startup instead of silently disabling the feature. + */ +export function envPositiveInt(envName: string, defaultValue: number): number { + const value = envInt(envName, defaultValue); + if (!Number.isInteger(value) || value < 1) { + throw new Error( + `env ${envName} must be a positive integer, got "${process.env[envName]}"`, + ); + } + return value; +} + export function envStr(envName: string, defaultValue: string): string { const raw = process.env[envName]; const value = raw !== undefined && raw !== '' ? raw : defaultValue; diff --git a/webdriver/src/prj/src/index.ts b/webdriver/src/prj/src/index.ts index d948c6ac..540faaba 100644 --- a/webdriver/src/prj/src/index.ts +++ b/webdriver/src/prj/src/index.ts @@ -5,7 +5,19 @@ import { Command } from 'commander'; import * as logger from './logging.js'; import * as chromeBrowser from './browser/chrome.js'; import * as ssrf from './ssrf.js'; -import { envDurationMs, envInt, formatDurationMs } from './duration.js'; +import { + envDurationMs, + envInt, + envPositiveInt, + envSize, + formatDurationMs, +} from './duration.js'; +import { + Semaphore, + SemaphoreAborted, + SemaphoreQueueFull, + SemaphoreTimeout, +} from './semaphore.js'; interface NavigationOptions { waitUntil?: pup.PuppeteerLifeCycleEvent; @@ -17,6 +29,7 @@ interface RenderOptions { waitAfterLoaded?: number; waitUntil?: pup.PuppeteerLifeCycleEvent; maxPageHeapMB?: number; + maxResponseChars?: number; } const program = new Command(); @@ -30,9 +43,43 @@ program const options = program.opts(); const STATUS_I_AM_A_TEAPOT = 418; +const STATUS_INSUFFICIENT_STORAGE = 507; +const STATUS_SERVICE_UNAVAILABLE = 503; const DEFAULT_MAX_PAGE_HEAP_MB = envInt('GVM_WEBDRIVER_MAX_PAGE_HEAP_MB', 1024); +// peak_mem ~= MAX_CONCURRENT_RENDERS * (page heap + extracted response) + browser baseline +// +// we deem that by default we are limited by manager permits, +// so this knob is for extra tuning and default 128 is essentially "unlimited" +const MAX_CONCURRENT_RENDERS = envPositiveInt( + 'GVM_WEBDRIVER_MAX_CONCURRENT_RENDERS', + 128, +); + +// Counted in characters, which is what bounds the string materialized in this +// process. One character encodes to at most 4 UTF-8 bytes on the wire, and +// occupies 2 bytes in V8 for the common (BMP) case. +const MAX_RESPONSE_CHARS = envSize('GVM_WEBDRIVER_MAX_RESPONSE', '5MiB'); + +// Waiting callers are cheap but not free: each holds a live connection. Past +// this depth the service is not going to work through the backlog before +// callers give up anyway, so refusing immediately beats refusing slowly. +const MAX_RENDER_QUEUE = envInt('GVM_WEBDRIVER_MAX_RENDER_QUEUE', 64); + +// Kept well below the caller's own transport timeout: a queue wait that +// outlives it converts a condition we can report cleanly into a transport +// failure, which callers treat far more harshly. +const RENDER_QUEUE_TIMEOUT_MS = envDurationMs( + 'GVM_WEBDRIVER_RENDER_QUEUE_TIMEOUT', + '120s', +); + +const renderSlots = new Semaphore({ + permits: MAX_CONCURRENT_RENDERS, + maxQueued: MAX_RENDER_QUEUE, +}); + const MAX_WAIT_AFTER_LOADED_MS = envDurationMs( 'GVM_WEBDRIVER_MAX_WAIT_AFTER_LOADED', '60s', @@ -119,22 +166,53 @@ async function navigateToPage( } } -async function asText(page: pup.Page) { - const bodyText = await page.evaluate(() => { - return document.body.innerText; - }); +/** + * Read `innerText` or `innerHTML`, rejecting oversized documents *in the page*. + * + * The size test has to happen on the browser side. Pulling the string across + * first and measuring it here would already have paid the memory cost we are + * trying to avoid — this process would hold the whole document no matter what + * any downstream limit says. + */ +async function extractBounded( + page: pup.Page, + kind: 'innerText' | 'innerHTML', + maxChars: number, +): Promise { + const extracted = await page.evaluate( + (k, limit) => { + const raw = + k === 'innerText' ? document.body.innerText : document.body.innerHTML; + return raw.length > limit + ? { tooLarge: true as const, length: raw.length } + : { tooLarge: false as const, content: raw }; + }, + kind, + maxChars, + ); + + if (extracted.tooLarge) { + throw new ResponseLimitExceeded(extracted.length, maxChars); + } + return extracted.content; +} - return normalizeWhitespace(bodyText); +async function asText(page: pup.Page, maxChars: number) { + return normalizeWhitespace(await extractBounded(page, 'innerText', maxChars)); } -async function asHTML(page: pup.Page) { - return await page.evaluate(() => { - return document.body.innerHTML; - }); +async function asHTML(page: pup.Page, maxChars: number) { + return await extractBounded(page, 'innerHTML', maxChars); } -async function asScreenshot(page: pup.Page) { - return await page.screenshot(); +async function asScreenshot(page: pup.Page, maxChars: number) { + // Screenshots are viewport-sized rather than full-page, so this is a + // backstop rather than a limit anyone should reach. + const image = await page.screenshot(); + if (image.length > maxChars) { + throw new ResponseLimitExceeded(image.length, maxChars); + } + return image; } class HeapLimitExceeded extends Error { @@ -143,6 +221,12 @@ class HeapLimitExceeded extends Error { } } +class ResponseLimitExceeded extends Error { + constructor(size: number, maxSize: number) { + super(`Rendered response ${size} exceeds limit ${maxSize}`); + } +} + const HEAP_CHECK_INTERVAL_MS = envInt( 'GVM_WEBDRIVER_HEAP_CHECK_INTERVAL_MS', 200, @@ -212,18 +296,49 @@ async function renderPage( targetUrl: string, mode: 'text' | 'html' | 'screenshot', options: RenderOptions = {}, + signal?: AbortSignal, ): Promise<{ status: number; body: any }> { - const browserManager = await chromeBrowser.INSTANCE; - const browserInstance = browserManager.getBrowser(); + // The slot is taken before the browser is touched, so a queued request costs + // nothing but the open connection. try { - return renderPageWithBrowser( - browserInstance.get(), - targetUrl, - mode, - options, - ); + await renderSlots.acquire(RENDER_QUEUE_TIMEOUT_MS, signal); + } catch (e) { + // Saturation escapes as a transport failure rather than a render result, + // and the distinction is deliberate. How busy this host happens to be is + // not a property of the page, so it must not reach the contract: two + // hosts under different load would otherwise return different answers + // for the same request and each would look legitimate. Failing at the + // transport level keeps the outcome an honest "this host could not run + // it" instead of a fabricated observation about the web. + if (e instanceof SemaphoreTimeout || e instanceof SemaphoreQueueFull) { + logger.log('warn', 'render rejected: saturated', { + url: targetUrl, + reason: e.name, + inFlight: renderSlots.inFlight, + queued: renderSlots.queued, + timeout: formatDurationMs(RENDER_QUEUE_TIMEOUT_MS), + }); + } else if (e instanceof SemaphoreAborted) { + logger.log('debug', 'render abandoned while queued', { url: targetUrl }); + } + throw e; + } + + try { + const browserManager = await chromeBrowser.INSTANCE; + const browserInstance = browserManager.getBrowser(); + try { + return await renderPageWithBrowser( + browserInstance.get(), + targetUrl, + mode, + options, + ); + } finally { + browserInstance.close(); + } } finally { - browserInstance.close(); + renderSlots.release(); } } @@ -238,13 +353,25 @@ async function renderPageWithBrowser( waitAfterLoaded = 0, waitUntil = 'domcontentloaded', maxPageHeapMB = DEFAULT_MAX_PAGE_HEAP_MB, + maxResponseChars = MAX_RESPONSE_CHARS, } = options; // Each render runs in its own browser context so cookies, localStorage, // IndexedDB, service workers and HSTS state never leak between tenants // sharing this long-lived browser. const context = await browserInstance.createBrowserContext(); - const page = await context.newPage(); + + // `newPage` fails when the shared browser is under pressure, and the cleanup + // below only runs once execution is inside the try. Without this the context + // survives for the browser's whole lifetime — and since pressure is exactly + // what makes `newPage` fail, the response to it would be to leak more. + let page: pup.Page; + try { + page = await context.newPage(); + } catch (e) { + await context.close().catch(() => {}); + throw e; + } try { await ssrf.installSsrfGuard(page); @@ -287,13 +414,13 @@ async function renderPageWithBrowser( let data; switch (mode) { case 'text': - data = await asText(page); + data = await asText(page, maxResponseChars); break; case 'html': - data = await asHTML(page); + data = await asHTML(page, maxResponseChars); break; case 'screenshot': - data = await asScreenshot(page); + data = await asScreenshot(page, maxResponseChars); break; default: data = 'Invalid mode'; @@ -302,14 +429,26 @@ async function renderPageWithBrowser( return { status: statusCode, body: data }; }); } catch (e) { + // Both limits are reported as render results, not transport failures: a + // transport failure aborts the caller's whole execution, and a page too + // big for this host is a thing the contract can reasonably be told about + // and handle, like any other page it could not load. if (e instanceof HeapLimitExceeded) { logger.log('warn', 'page heap limit exceeded', { url: targetUrl, error: e.message, }); - return { status: 507, body: e.message }; + } else if (e instanceof ResponseLimitExceeded) { + logger.log('warn', 'rendered response limit exceeded', { + url: targetUrl, + mode, + error: e.message, + }); + } else { + throw e; } - throw e; + + return { status: STATUS_INSUFFICIENT_STORAGE, body: e.message }; } finally { // Close the page and its context together; the context teardown is what // actually discards the per-request browsing state. @@ -317,6 +456,23 @@ async function renderPageWithBrowser( } } +/** + * Fires when the caller goes away before it has been answered, so a request + * nobody is waiting for stops occupying a queue slot. + */ +function disconnectSignal( + req: http.IncomingMessage, + res: http.ServerResponse, +): AbortSignal { + const controller = new AbortController(); + req.on('close', () => { + if (!res.writableEnded) { + controller.abort(); + } + }); + return controller.signal; +} + async function handleRenderRequest( parsedUrl: URL, req: http.IncomingMessage, @@ -355,7 +511,12 @@ async function handleRenderRequest( : {}), }; - const result = await renderPage(targetUrl, mode, options); + const result = await renderPage( + targetUrl, + mode, + options, + disconnectSignal(req, res), + ); if (statusIsGood(result.status)) { updateLastSuccessfulRenderTime(); @@ -370,6 +531,29 @@ async function handleRenderRequest( } res.end(result.body); } catch (error) { + if (error instanceof SemaphoreAborted) { + // The caller hung up while queued; there is nobody left to answer. + return; + } + // How loaded this host happens to be is not a property of the page, so it + // must not reach the contract: two hosts under different load would + // answer the same request differently, both answers looking legitimate. + // A transport failure says plainly that this host could not run it. + if ( + error instanceof SemaphoreTimeout || + error instanceof SemaphoreQueueFull + ) { + res.writeHead(STATUS_SERVICE_UNAVAILABLE, { + 'Content-Type': 'application/json', + }); + res.end( + JSON.stringify({ + error: 'Service unavailable', + message: error.message, + }), + ); + return; + } res.writeHead(500, { 'Content-Type': 'application/json' }); res.end( JSON.stringify({ @@ -380,7 +564,11 @@ async function handleRenderRequest( } } -async function handleHealthcheck(parsedUrl: URL, res: http.ServerResponse) { +async function handleHealthcheck( + parsedUrl: URL, + req: http.IncomingMessage, + res: http.ServerResponse, +) { const now = Date.now(); const sinceLastSuccessMs = now - lastSuccessfulRenderTime; if (sinceLastSuccessMs < HEALTHCHECK_CACHE_DURATION_MS) { @@ -415,7 +603,12 @@ async function handleHealthcheck(parsedUrl: URL, res: http.ServerResponse) { cacheDuration: formatDurationMs(HEALTHCHECK_CACHE_DURATION_MS), }); try { - const result = await renderPage(targetUrl, mode, {}); + const result = await renderPage( + targetUrl, + mode, + {}, + disconnectSignal(req, res), + ); if (statusIsGood(result.status)) { updateLastSuccessfulRenderTime(); logger.log('info', 'healthcheck ok', { status: result.status }); @@ -427,6 +620,13 @@ async function handleHealthcheck(parsedUrl: URL, res: http.ServerResponse) { res.end('unhealthy'); } } catch (error) { + if (error instanceof SemaphoreAborted) { + return; + } + // Saturation lands here too, and reporting unhealthy is right: the probe + // only renders when nothing has succeeded for the cache duration, so a + // host that is both saturated and has completed nothing in that window + // genuinely is not serving. logger.log('error', 'healthcheck error', { error: (error as Error).message, }); @@ -442,7 +642,7 @@ const server = http.createServer(async (req, res) => { if (pathname === '/render') { await handleRenderRequest(parsedUrl, req, res); } else if (pathname === '/healthcheck') { - await handleHealthcheck(parsedUrl, res); + await handleHealthcheck(parsedUrl, req, res); } else if (pathname === '/log-level') { if (req.method === 'GET') { res.writeHead(200, { 'Content-Type': 'text/plain' }); diff --git a/webdriver/src/prj/src/semaphore.test.ts b/webdriver/src/prj/src/semaphore.test.ts new file mode 100644 index 00000000..afc6d3fa --- /dev/null +++ b/webdriver/src/prj/src/semaphore.test.ts @@ -0,0 +1,270 @@ +import { describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import { + Semaphore, + SemaphoreAborted, + SemaphoreQueueFull, + SemaphoreTimeout, +} from './semaphore.js'; + +const NEVER = 60_000; + +/** Queue depth is irrelevant to most cases, so default it out of the way. */ +function sem(permits: number, maxQueued = 1024) { + return new Semaphore({ permits, maxQueued }); +} + +function deferred() { + let resolve!: (v: T) => void; + const promise = new Promise((r) => { + resolve = r; + }); + return { promise, resolve }; +} + +describe('Semaphore', () => { + it('rejects invalid construction', () => { + assert.throws(() => sem(0)); + assert.throws(() => sem(-1)); + assert.throws(() => sem(1.5)); + assert.throws(() => new Semaphore({ permits: 1, maxQueued: -1 })); + assert.throws(() => new Semaphore({ permits: 1, maxQueued: 1.5 })); + }); + + it('grants up to the permit count without waiting', async () => { + const s = sem(3); + await s.acquire(NEVER); + await s.acquire(NEVER); + await s.acquire(NEVER); + assert.equal(s.inFlight, 3); + assert.equal(s.queued, 0); + }); + + it('queues the caller past the limit until a permit is released', async () => { + const s = sem(1); + await s.acquire(NEVER); + + let granted = false; + const waiting = s.acquire(NEVER).then(() => { + granted = true; + }); + + await new Promise((r) => setTimeout(r, 10)); + assert.equal(granted, false, 'should still be queued'); + assert.equal(s.queued, 1); + + s.release(); + await waiting; + assert.equal(granted, true); + assert.equal(s.inFlight, 1, 'permit passed to the waiter, not returned'); + }); + + it('hands permits to waiters in FIFO order', async () => { + const s = sem(1); + await s.acquire(NEVER); + + const order: number[] = []; + const waiters = [1, 2, 3].map((n) => + s.acquire(NEVER).then(() => { + order.push(n); + }), + ); + + await new Promise((r) => setTimeout(r, 10)); + s.release(); + s.release(); + s.release(); + await Promise.all(waiters); + + assert.deepEqual(order, [1, 2, 3]); + }); + + it('times out a caller that waits too long, and stops queueing it', async () => { + const s = sem(1); + await s.acquire(NEVER); + + await assert.rejects(() => s.acquire(20), SemaphoreTimeout); + assert.equal(s.queued, 0, 'timed-out waiter must leave the queue'); + + s.release(); + await s.acquire(NEVER); + assert.equal(s.inFlight, 1); + }); + + it('does not grant a permit to a waiter that already timed out', async () => { + const s = sem(1); + await s.acquire(NEVER); + + const timedOut = assert.rejects(() => s.acquire(20), SemaphoreTimeout); + await new Promise((r) => setTimeout(r, 40)); + await timedOut; + + s.release(); + assert.equal(s.inFlight, 0, 'released permit must not be held by a ghost'); + }); + + it('never exceeds the permit count under concurrent load', async () => { + const permits = 4; + const s = sem(permits); + let active = 0; + let peak = 0; + + await Promise.all( + Array.from({ length: 50 }, () => + s.withPermit(NEVER, async () => { + active += 1; + peak = Math.max(peak, active); + await new Promise((r) => setTimeout(r, 1)); + active -= 1; + }), + ), + ); + + assert.equal(peak, permits, 'concurrency must saturate but not exceed'); + assert.equal(s.inFlight, 0); + assert.equal(s.queued, 0); + }); + + it('releases the permit when the guarded task throws', async () => { + const s = sem(1); + await assert.rejects( + () => + s.withPermit(NEVER, async () => { + throw new Error('boom'); + }), + /boom/, + ); + assert.equal(s.inFlight, 0, 'a failed task must not leak its permit'); + }); + + it('ignores a release with nothing outstanding', async () => { + const s = sem(2); + s.release(); + s.release(); + s.release(); + + // A leaked permit would let a third caller through here. + await s.acquire(NEVER); + await s.acquire(NEVER); + await assert.rejects(() => s.acquire(20), SemaphoreTimeout); + }); + + it('keeps a slow task from starving a queued one indefinitely', async () => { + const s = sem(1); + const slow = deferred(); + + const running = s.withPermit(NEVER, () => slow.promise); + const queued = s.acquire(NEVER); + + slow.resolve(); + await running; + await queued; + assert.equal(s.inFlight, 1); + }); + + describe('queue depth', () => { + it('refuses callers once the queue is full', async () => { + const s = new Semaphore({ permits: 1, maxQueued: 2 }); + await s.acquire(NEVER); + + const queued = [s.acquire(NEVER), s.acquire(NEVER)]; + assert.equal(s.queued, 2); + + await assert.rejects(() => s.acquire(NEVER), SemaphoreQueueFull); + assert.equal(s.queued, 2, 'a refused caller must not be queued'); + + s.release(); + s.release(); + await Promise.all(queued); + }); + + it('accepts again once the queue drains', async () => { + const s = new Semaphore({ permits: 1, maxQueued: 1 }); + await s.acquire(NEVER); + const first = s.acquire(NEVER); + await assert.rejects(() => s.acquire(NEVER), SemaphoreQueueFull); + + s.release(); + await first; + + // Slot freed: a new caller queues rather than being refused. + const second = s.acquire(NEVER); + assert.equal(s.queued, 1); + s.release(); + await second; + }); + + it('refuses immediately rather than waiting out the timeout', async () => { + const s = new Semaphore({ permits: 1, maxQueued: 0 }); + await s.acquire(NEVER); + + const started = Date.now(); + await assert.rejects(() => s.acquire(NEVER), SemaphoreQueueFull); + assert.ok( + Date.now() - started < 50, + 'a full queue must fail fast, not after the wait', + ); + }); + }); + + describe('abort', () => { + it('drops a waiter whose caller went away', async () => { + const s = sem(1); + await s.acquire(NEVER); + + const controller = new AbortController(); + const waiting = assert.rejects( + () => s.acquire(NEVER, controller.signal), + SemaphoreAborted, + ); + assert.equal(s.queued, 1); + + controller.abort(); + await waiting; + assert.equal(s.queued, 0, 'aborted waiter must leave the queue'); + + // The permit must go to a live caller, not the abandoned one. + s.release(); + assert.equal(s.inFlight, 0); + }); + + it('rejects at once when the signal is already aborted', async () => { + const s = sem(1); + await s.acquire(NEVER); + await assert.rejects( + () => s.acquire(NEVER, AbortSignal.abort()), + SemaphoreAborted, + ); + assert.equal(s.queued, 0); + }); + + it('does not reject a caller that already holds a permit', async () => { + const s = sem(1); + const controller = new AbortController(); + await s.acquire(NEVER, controller.signal); + controller.abort(); + // Aborting after the permit was granted is a no-op; release still works. + s.release(); + assert.equal(s.inFlight, 0); + }); + + it('frees the queue slot so a later caller is not refused', async () => { + const s = new Semaphore({ permits: 1, maxQueued: 1 }); + await s.acquire(NEVER); + + const controller = new AbortController(); + const abandoned = assert.rejects( + () => s.acquire(NEVER, controller.signal), + SemaphoreAborted, + ); + controller.abort(); + await abandoned; + + const queued = s.acquire(NEVER); + assert.equal(s.queued, 1, 'slot must have been reclaimed'); + s.release(); + await queued; + }); + }); +}); diff --git a/webdriver/src/prj/src/semaphore.ts b/webdriver/src/prj/src/semaphore.ts new file mode 100644 index 00000000..84197977 --- /dev/null +++ b/webdriver/src/prj/src/semaphore.ts @@ -0,0 +1,156 @@ +export interface SemaphoreOptions { + /** Concurrent holders. */ + permits: number; + /** Callers allowed to wait for a permit before further ones are refused. */ + maxQueued: number; +} + +/** + * Counting semaphore with FIFO waiters, a bounded queue and a bounded wait. + * + * Callers past the permit count queue rather than being refused outright: + * refusing on any contention would make the outcome depend on whatever else the + * host happened to be running at the time. + * + * The queue is still finite, and the wait is still bounded. Both exist because + * an unbounded queue only defers the problem — a caller parked indefinitely + * eventually trips its own transport timeout, which fails far more harshly than + * a refusal we issue ourselves, and until then it costs a live connection. + */ +export class Semaphore { + private readonly permits: number; + private readonly maxQueued: number; + private available: number; + private readonly waiters: Array<{ + resolve: () => void; + reject: (e: Error) => void; + timer: NodeJS.Timeout; + cleanup: () => void; + }> = []; + + constructor(options: SemaphoreOptions) { + const { permits, maxQueued } = options; + if (!Number.isInteger(permits) || permits < 1) { + throw new Error( + `semaphore permits must be a positive integer, got ${permits}`, + ); + } + if (!Number.isInteger(maxQueued) || maxQueued < 0) { + throw new Error( + `semaphore maxQueued must be a non-negative integer, got ${maxQueued}`, + ); + } + this.permits = permits; + this.maxQueued = maxQueued; + this.available = permits; + } + + get inFlight(): number { + return this.permits - this.available; + } + + get queued(): number { + return this.waiters.length; + } + + /** + * Acquire a permit. + * + * @param timeoutMs how long to wait before giving up. + * @param signal aborts the wait — pass the caller's disconnect signal so a + * vanished caller stops occupying a queue slot it will never use. + * @throws {SemaphoreQueueFull} if the queue is already at capacity. + * @throws {SemaphoreTimeout} if no permit became available in time. + * @throws {SemaphoreAborted} if `signal` fired while waiting. + */ + acquire(timeoutMs: number, signal?: AbortSignal): Promise { + if (this.available > 0) { + this.available -= 1; + return Promise.resolve(); + } + if (this.waiters.length >= this.maxQueued) { + return Promise.reject(new SemaphoreQueueFull(this.maxQueued)); + } + if (signal?.aborted) { + return Promise.reject(new SemaphoreAborted()); + } + + return new Promise((resolve, reject) => { + const remove = () => { + const idx = this.waiters.indexOf(entry); + if (idx !== -1) { + this.waiters.splice(idx, 1); + } + }; + const onAbort = () => { + remove(); + clearTimeout(entry.timer); + reject(new SemaphoreAborted()); + }; + const entry = { + resolve, + reject, + timer: setTimeout(() => { + remove(); + entry.cleanup(); + reject(new SemaphoreTimeout(timeoutMs)); + }, timeoutMs), + cleanup: () => signal?.removeEventListener('abort', onAbort), + }; + signal?.addEventListener('abort', onAbort, { once: true }); + this.waiters.push(entry); + }); + } + + release(): void { + const next = this.waiters.shift(); + if (next === undefined) { + // Guard against a double release leaking permits, which would silently + // raise the concurrency ceiling above the configured one. + if (this.available < this.permits) { + this.available += 1; + } + return; + } + clearTimeout(next.timer); + next.cleanup(); + // The permit passes straight to the waiter; `available` deliberately stays + // where it is. + next.resolve(); + } + + /** Run `fn` holding a permit, releasing it however `fn` settles. */ + async withPermit( + timeoutMs: number, + fn: () => Promise, + signal?: AbortSignal, + ): Promise { + await this.acquire(timeoutMs, signal); + try { + return await fn(); + } finally { + this.release(); + } + } +} + +export class SemaphoreTimeout extends Error { + constructor(timeoutMs: number) { + super(`timed out after ${timeoutMs}ms waiting for a render slot`); + this.name = 'SemaphoreTimeout'; + } +} + +export class SemaphoreQueueFull extends Error { + constructor(maxQueued: number) { + super(`render queue is full (${maxQueued} waiting)`); + this.name = 'SemaphoreQueueFull'; + } +} + +export class SemaphoreAborted extends Error { + constructor() { + super('caller went away while waiting for a render slot'); + this.name = 'SemaphoreAborted'; + } +} diff --git a/webdriver/src/prj/ts-node-register.mjs b/webdriver/src/prj/ts-node-register.mjs new file mode 100644 index 00000000..ef847107 --- /dev/null +++ b/webdriver/src/prj/ts-node-register.mjs @@ -0,0 +1,6 @@ +// `--loader ts-node/esm` is gone in current Node; registering the hook from +// inside the process is the supported spelling. +import { register } from 'node:module'; +import { pathToFileURL } from 'node:url'; + +register('ts-node/esm', pathToFileURL('./'));