test: add script_tests cases covering interpreter mutants #36291

pull ViniciusCestarii wants to merge 6 commits into bitcoin:master from ViniciusCestarii:kill-interpreter-mutants changing 1 files +13 −0
  1. ViniciusCestarii commented at 7:37 PM on September 17, 2026: contributor

    Kills some live mutants on interpreter.cpp found by https://bitcoincore.space. They are:

    interpreter.cpp#5168: IsCompressedOrUncompressedPubKey: pubkey with neither compressed nor uncompressed prefix returns true

    -    } else if (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03) {
    +    } else if (1==1) {
    

    interpreter.cpp#5191: IsValidSignatureEncoding: 73-byte upper bound returns true

         if (sig.size() < 9) return false;
    -    if (sig.size() > 73) return false;
    

    interpreter.cpp#5200: IsValidSignatureEncoding: total-length byte check returns true

         // Make sure the length covers the entire signature.
    -    if (sig[1] != sig.size() - 3) return false;
    

    interpreter.cpp#5232: IsValidSignatureEncoding: null R byte check lenR > 1 -> lenR >=1

         // Null bytes at the start of R are not allowed, unless R would
         // otherwise be interpreted as a negative number.
    -    if (lenR > 1 && (sig[4] == 0x00) && !(sig[5] & 0x80)) return false;
    +    if (lenR >= 1 && (sig[4] == 0x00) && !(sig[5] & 0x80)) return false;
    

    interpreter.cpp#5259: IsValidSignatureEncoding: null S byte check lenS > 1 -> lenS >= 1

         // Null bytes at the start of S are not allowed, unless S would otherwise be
         // interpreted as a negative number.
    -    if (lenS > 1 && (sig[lenR + 6] == 0x00) && !(sig[lenR + 7] & 0x80)) return false;
    +    if (lenS >= 1 && (sig[lenR + 6] == 0x00) && !(sig[lenR + 7] & 0x80)) return false;
    

    interpreter.cpp#5186: IsValidSignatureEncoding: 9-byte lower bound returns true

         // Minimum and maximum size constraints.
    -    if (sig.size() < 9) return false;
    

    The first affects policy only, the next four affect consensus, and the last covers the lower bound and lets ASan catch UB: a 3-byte signature reaches the sig[3] read that the sig.size() < 9 guard protects.

    Recommend reviewing per commit.

  2. DrahtBot added the label Tests on Sep 17, 2026
  3. DrahtBot commented at 7:37 PM on September 17, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--006a51241073e994b41acfe9ec718e94-->

    External sites

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline and AI policy for information on the review process.

    Type Reviewers
    ACK brunoerg, fametrano, sedited

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  4. ViniciusCestarii renamed this:
    test: add script_tests cases covering interpreter mutants Tests
    test: add script_tests cases covering interpreter mutants
    on Sep 21, 2026
  5. ViniciusCestarii commented at 4:48 PM on September 28, 2026: contributor
  6. in src/test/data/script_tests.json:731 in d34cd78bd5
     727 | @@ -728,6 +728,8 @@
     728 |  ["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701", "0 CHECKSIG NOT", "", "OK", "Negative S is correctly encoded"],
     729 |  ["0x4a 0x3047022201010101010101010101010101010101010101010101010101010101010101010101022101010101010101010101010101010101010101010101010101010101010101010101", "0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 CHECKSIG NOT", "", "OK", "74-byte signature is correctly encoded"],
     730 |  ["0x47 0x3043022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501", "0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 CHECKSIG NOT", "", "OK", "Total-length byte not covering the entire signature is correctly encoded"],
     731 | +["0x08 0x3005020101020101", "0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 CHECKSIG NOT", "", "OK", "8-byte signature is correctly encoded"],
    


    brunoerg commented at 5:53 PM on September 28, 2026:

    d34cd78bd5ed887f136e0f09a98b519c71470516: do we really need this 8-byte vector test? As far as I verified, the mutant is killed with the other test here (3-byte one).


    ViniciusCestarii commented at 6:45 PM on September 28, 2026:

    It is not necessary for killing the mutant. My reasoning was to add case that directly tests the lower bound. But thinking back no signature under 9 bytes is valid and the 3 byte case is only worth it because it causes UB. I will drop the 8 byte cases and keep the 3 byte one. Thanks for spotting this.


    ViniciusCestarii commented at 6:50 PM on September 28, 2026:

    Done on a0ce5b2629394af8e5d5fde6459e27d2c935d43e.

  7. ViniciusCestarii force-pushed on Sep 28, 2026
  8. ViniciusCestarii commented at 6:50 PM on September 28, 2026: contributor

    Thanks @brunoerg for the review! Forced push a0ce5b2629394af8e5d5fde6459e27d2c935d43e addressing comment #36291 (review)

  9. in src/test/data/script_tests.json:1303 in a0ce5b2629
    1299 | @@ -1293,6 +1300,12 @@
    1300 |  ["0x17 0x3014021077777777777777777777777777777777020001", "0 CHECKSIG NOT", "DERSIG", "SIG_DER", "Zero-length S is incorrectly encoded for DERSIG"],
    1301 |  ["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "SIG_DER", "Negative S is incorrectly encoded for DERSIG"],
    1302 |  ["0x27 0x312402107777777777777777777777777777777702107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "SIG_DER", "Non-compound type is incorrectly encoded for DERSIG"],
    1303 | +["0x4a 0x3047022201010101010101010101010101010101010101010101010101010101010101010101022101010101010101010101010101010101010101010101010101010101010101010101", "0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 CHECKSIG NOT", "DERSIG", "SIG_DER", "74-byte signature is incorrectly encoded for DERSIG"],
    


    brunoerg commented at 11:41 PM on September 28, 2026:

    nit: do these new DERSIG test cases really need a real pubkey? I think an empty pubkey would work, e.g. "0 CHECKSIG NOT"


    ViniciusCestarii commented at 6:21 PM on September 29, 2026:

    True, it is better to simplify these tests. I noticed this also applies for the sigs on cases of STRICTENC, so I simplified both DERSIG and STRICTENC added tests on efe0dfcf1e5c431c62dc9ac4fd2c2d97a62814fe

  10. brunoerg approved
  11. brunoerg commented at 11:42 PM on September 28, 2026: contributor

    ACK a0ce5b2629394af8e5d5fde6459e27d2c935d43e

    just left a nit, happy to re-ack if you decide to address it.

  12. ViniciusCestarii force-pushed on Sep 29, 2026
  13. test: cover STRICTENC rejects bad 33-byte pubkey prefix
    https://bitcoincore.space/src/script/interpreter.cpp#5168
    2c0f69a047
  14. test: cover DERSIG 73-byte signature upper bound
    https://bitcoincore.space/src/script/interpreter.cpp#5191
    3d04ed8ac7
  15. test: cover DERSIG total-length byte check
    https://bitcoincore.space/src/script/interpreter.cpp#5200
    a1deba78c5
  16. test: cover DERSIG null R byte only when R is multi-byte
    https://bitcoincore.space/src/script/interpreter.cpp#5232
    fd2cf04502
  17. test: cover DERSIG null S byte only when S is multi-byte
    https://bitcoincore.space/src/script/interpreter.cpp#5259
    bbc4bdf909
  18. test: cover DERSIG 9-byte signature lower bound
    https://bitcoincore.space/src/script/interpreter.cpp#5186
    
    A 3-byte signature reaches the sig[3] read so ASan catches a weakened size guard.
    efe0dfcf1e
  19. ViniciusCestarii force-pushed on Sep 29, 2026
  20. DrahtBot added the label CI failed on Sep 29, 2026
  21. ViniciusCestarii commented at 6:26 PM on September 29, 2026: contributor

    Thanks @brunoerg. Forced push efe0dfcf1e5c431c62dc9ac4fd2c2d97a62814fe addressing #36291 (review). See DERSIG cases diff and STRICTENC cases diff

  22. DrahtBot removed the label CI failed on Sep 29, 2026
  23. brunoerg approved
  24. brunoerg commented at 7:23 PM on September 29, 2026: contributor

    reACK efe0dfcf1e5c431c62dc9ac4fd2c2d97a62814fe

  25. fametrano commented at 9:48 PM on October 1, 2026: contributor

    ACK efe0dfcf1e5c431c62dc9ac4fd2c2d97a62814fe

    I ran the 11 new rows through btclib's script interpreter and each gives the expected result and error code.

  26. sedited commented at 9:21 AM on October 5, 2026: contributor

    @ViniciusCestarii can you re-write the pull request descriptions of your mutations without having to nest html in it? Maybe just give every mutation as its minimized diff? The pull request description gets added to every merge commit and all the formatting makes it harder to render the same everywhere and a bit harder to read.

  27. ViniciusCestarii commented at 12:15 PM on October 5, 2026: contributor

    Updated the pr description.

  28. sedited approved
  29. sedited commented at 7:46 AM on October 7, 2026: contributor

    ACK efe0dfcf1e5c431c62dc9ac4fd2c2d97a62814fe

  30. sedited merged this on Oct 7, 2026
  31. sedited closed this on Oct 7, 2026


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-10-21 19:51 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me