(command.CommandList
  children: [
    (command.ShAssignment
      pairs: [
        (assign_pair
          lhs: (sh_lhs_expr.Name name:test_description)
          op: assign_op.Equal
          rhs: {(SQ <'bounds-checking of access to mmapped on-disk file formats'>)}
          spids: [4]
        )
      ]
    )
    (C {<.>} {<'./test-lib.sh'>})
    (command.ShFunction
      name: clear_base
      body: 
        (BraceGroup
          children: [
            (command.AndOr
              ops: [Id.Op_DAmp]
              children: [
                (C {<test_when_finished>} {(SQ <restore_base>)})
                (C {<rm>} {<-f>} {($ Id.VSub_DollarName '$base')})
              ]
            )
          ]
        )
    )
    (command.ShFunction
      name: restore_base
      body: 
        (BraceGroup
          children: [(C {<cp>} {<'base-backup/'> <Id.Lit_Star '*'>} {<'.git/objects/pack/'>})]
        )
    )
    (command.ShFunction
      name: do_pack
      body: 
        (BraceGroup
          children: [
            (command.Sentence
              child: 
                (command.ShAssignment
                  pairs: [
                    (assign_pair
                      lhs: (sh_lhs_expr.Name name:pack_objects)
                      op: assign_op.Equal
                      rhs: {($ Id.VSub_Number '$1')}
                      spids: [66]
                    )
                  ]
                )
              terminator: <Id.Op_Semi _>
            )
            (C {<shift>})
            (command.AndOr
              ops: [Id.Op_DAmp Id.Op_DAmp Id.Op_DAmp Id.Op_DAmp]
              children: [
                (command.ShAssignment
                  pairs: [
                    (assign_pair
                      lhs: (sh_lhs_expr.Name name:sha1)
                      op: assign_op.Equal
                      rhs: 
                        {
                          (command_sub
                            left_token: <Id.Left_DollarParen '$('>
                            child: 
                              (command.Pipeline
                                children: [
                                  (command.ForEach
                                    iter_name: i
                                    iter_words: [{($ Id.VSub_DollarName '$pack_objects')}]
                                    do_arg_iter: F
                                    body: 
                                      (command.DoGroup
                                        children: [(C {<echo>} {($ Id.VSub_DollarName '$i')})]
                                      )
                                  )
                                  (C {<git>} {<pack-objects>} {(DQ ($ Id.VSub_At '$@'))} 
                                    {<'.git/objects/pack/pack'>}
                                  )
                                ]
                                negated: F
                              )
                          )
                        }
                      spids: [73]
                    )
                  ]
                )
                (command.ShAssignment
                  pairs: [
                    (assign_pair
                      lhs: (sh_lhs_expr.Name name:pack)
                      op: assign_op.Equal
                      rhs: {<'.git/objects/pack/pack-'> ($ Id.VSub_DollarName '$sha1') <.pack>}
                      spids: [114]
                    )
                  ]
                )
                (command.ShAssignment
                  pairs: [
                    (assign_pair
                      lhs: (sh_lhs_expr.Name name:idx)
                      op: assign_op.Equal
                      rhs: {<'.git/objects/pack/pack-'> ($ Id.VSub_DollarName '$sha1') <.idx>}
                      spids: [122]
                    )
                  ]
                )
                (C {<chmod>} {<Id.Lit_Other '+'> <w>} {($ Id.VSub_DollarName '$pack')} 
                  {($ Id.VSub_DollarName '$idx')}
                )
                (C {<test_when_finished>} {(SQ <'rm -f "$pack" "$idx"'>)})
              ]
            )
          ]
        )
    )
    (command.ShFunction
      name: munge
      body: 
        (BraceGroup
          children: [
            (command.Pipeline
              children: [
                (C {<printf>} {(DQ ($ Id.VSub_Number '$3'))})
                (C {<dd>} {<Id.Lit_VarLike 'of='> (DQ ($ Id.VSub_Number '$1'))} 
                  {<Id.Lit_VarLike 'bs='> <1>} {<Id.Lit_VarLike 'conv='> <notrunc>} {<Id.Lit_VarLike 'seek='> ($ Id.VSub_Number '$2')}
                )
              ]
              negated: F
            )
          ]
        )
    )
    (command.ShFunction
      name: ofs_table
      body: 
        (BraceGroup
          children: [
            (C {<echo>} 
              {
                (word_part.ArithSub
                  anode: 
                    (arith_expr.Binary
                      op_id: Id.Arith_Plus
                      left: 
                        (arith_expr.Binary
                          op_id: Id.Arith_Plus
                          left: 
                            (arith_expr.Binary
                              op_id: Id.Arith_Plus
                              left: 
                                (arith_expr.Binary
                                  op_id: Id.Arith_Plus
                                  left: {<Id.Lit_Digits 4>}
                                  right: {<Id.Lit_Digits 4>}
                                )
                              right: 
                                (arith_expr.Binary
                                  op_id: Id.Arith_Star
                                  left: {<Id.Lit_Digits 4>}
                                  right: {<Id.Lit_Digits 256>}
                                )
                            )
                          right: 
                            (arith_expr.Binary
                              op_id: Id.Arith_Star
                              left: {<Id.Lit_Digits 20>}
                              right: {($ Id.VSub_Number '$1')}
                            )
                        )
                      right: 
                        (arith_expr.Binary
                          op_id: Id.Arith_Star
                          left: {<Id.Lit_Digits 4>}
                          right: {($ Id.VSub_Number '$1')}
                        )
                    )
                )
              }
            )
          ]
        )
    )
    (command.ShFunction
      name: extended_table
      body: 
        (BraceGroup
          children: [
            (C {<echo>} 
              {
                (word_part.ArithSub
                  anode: 
                    (arith_expr.Binary
                      op_id: Id.Arith_Plus
                      left: 
                        {
                          (command_sub
                            left_token: <Id.Left_DollarParen '$('>
                            child: (C {<ofs_table>} {(DQ ($ Id.VSub_Number '$1'))})
                          )
                        }
                      right: 
                        (arith_expr.Binary
                          op_id: Id.Arith_Star
                          left: {<Id.Lit_Digits 4>}
                          right: {($ Id.VSub_Number '$1')}
                        )
                    )
                )
              }
            )
          ]
        )
    )
    (C {<test_expect_success>} {(SQ <'set up base packfile and variables'>)} 
      {
        (SQ <'\n'> <'\t# the hash of this content starts with ff, which\n'> 
          <'\t# makes some later computations much simpler\n'> <'\techo 74 >file &&\n'> <'\tgit add file &&\n'> <'\tgit commit -m base &&\n'> <'\tgit repack -ad &&\n'> 
          <'\tbase=$(echo .git/objects/pack/*) &&\n'> <'\tchmod +w $base &&\n'> <'\tmkdir base-backup &&\n'> <'\tcp $base base-backup/ &&\n'> 
          <'\tobject=$(git rev-parse HEAD:file)\n'>
        )
      }
    )
    (C {<test_expect_success>} {(SQ <'pack/index object count mismatch'>)} 
      {
        (SQ <'\n'> <'\tdo_pack $object &&\n'> <'\tmunge $pack 8 "\\377\\0\\0\\0" &&\n'> 
          <'\tclear_base &&\n'> <'\n'> <'\t# We enumerate the objects from the completely-fine\n'> 
          <'\t# .idx, but notice later that the .pack is bogus\n'> <'\t# and fail to show any data.\n'> <'\techo "$object missing" >expect &&\n'> 
          <'\tgit cat-file --batch-all-objects --batch-check >actual &&\n'> <'\ttest_cmp expect actual &&\n'> <'\n'> 
          <'\t# ...and here fail to load the object (without segfaulting),\n'> <'\t# but fallback to a good copy if available.\n'> 
          <'\ttest_must_fail git cat-file blob $object &&\n'> <'\trestore_base &&\n'> <'\tgit cat-file blob $object >actual &&\n'> <'\ttest_cmp file actual &&\n'> 
          <'\n'> <'\t# ...and make sure that index-pack --verify, which has its\n'> 
          <'\t# own reading routines, does not segfault.\n'> <'\ttest_must_fail git index-pack --verify $pack\n'>
        )
      }
    )
    (C {<test_expect_success>} {(SQ <'matched bogus object count'>)} 
      {
        (SQ <'\n'> <'\tdo_pack $object &&\n'> <'\tmunge $pack 8 "\\377\\0\\0\\0" &&\n'> 
          <'\tmunge $idx $((255 * 4)) "\\377\\0\\0\\0" &&\n'> <'\tclear_base &&\n'> <'\n'> <'\t# Unlike above, we should notice early that the .idx is totally\n'> 
          <'\t# bogus, and not even enumerate its contents.\n'> <'\t>expect &&\n'> <'\tgit cat-file --batch-all-objects --batch-check >actual &&\n'> 
          <'\ttest_cmp expect actual &&\n'> <'\n'> <'\t# But as before, we can do the same object-access checks.\n'> 
          <'\ttest_must_fail git cat-file blob $object &&\n'> <'\trestore_base &&\n'> <'\tgit cat-file blob $object >actual &&\n'> <'\ttest_cmp file actual &&\n'> 
          <'\n'> <'\ttest_must_fail git index-pack --verify $pack\n'>
        )
      }
    )
    (C {<test_expect_success>} {(SQ <'bogus object offset (v1)'>)} 
      {
        (SQ <'\n'> <'\tdo_pack $object --index-version=1 &&\n'> 
          <'\tmunge $idx $((4 * 256)) "\\377\\0\\0\\0" &&\n'> <'\tclear_base &&\n'> <'\ttest_must_fail git cat-file blob $object &&\n'> 
          <'\ttest_must_fail git index-pack --verify $pack\n'>
        )
      }
    )
    (C {<test_expect_success>} {(SQ <'bogus object offset (v2, no msb)'>)} 
      {
        (SQ <'\n'> <'\tdo_pack $object --index-version=2 &&\n'> 
          <'\tmunge $idx $(ofs_table 1) "\\0\\377\\0\\0" &&\n'> <'\tclear_base &&\n'> <'\ttest_must_fail git cat-file blob $object &&\n'> 
          <'\ttest_must_fail git index-pack --verify $pack\n'>
        )
      }
    )
    (C {<test_expect_success>} {(SQ <'bogus offset into v2 extended table'>)} 
      {
        (SQ <'\n'> <'\tdo_pack $object --index-version=2 &&\n'> 
          <'\tmunge $idx $(ofs_table 1) "\\377\\0\\0\\0" &&\n'> <'\tclear_base &&\n'> <'\ttest_must_fail git cat-file blob $object &&\n'> 
          <'\ttest_must_fail git index-pack --verify $pack\n'>
        )
      }
    )
    (C {<test_expect_success>} {(SQ <'bogus offset inside v2 extended table'>)} 
      {
        (SQ <'\n'> <'\t# We need two objects here, so we can plausibly require\n'> 
          <'\t# an extended table (if the first object were larger than 2^31).\n'> <'\tdo_pack "$object $(git rev-parse HEAD)" --index-version=2 &&\n'> <'\n'> 
          <'\t# We have to make extra room for the table, so we cannot\n'> <'\t# just munge in place as usual.\n'> <'\t{\n'> 
          <'\t\tdd if=$idx bs=1 count=$(($(ofs_table 2) + 4)) &&\n'> <'\t\tprintf "\\200\\0\\0\\0" &&\n'> <'\t\tprintf "\\377\\0\\0\\0\\0\\0\\0\\0" &&\n'> 
          <'\t\tdd if=$idx bs=1 skip=$(extended_table 2)\n'> <'\t} >tmp &&\n'> <'\tmv tmp "$idx" &&\n'> <'\tclear_base &&\n'> 
          <'\ttest_must_fail git cat-file blob $object &&\n'> <'\ttest_must_fail git index-pack --verify $pack\n'>
        )
      }
    )
    (C {<test_expect_success>} {(SQ <'bogus OFS_DELTA in packfile'>)} 
      {
        (SQ <'\n'> <'\t# Generate a pack with a delta in it.\n'> 
          <'\tbase=$(test-genrandom foo 3000 | git hash-object --stdin -w) &&\n'> <'\tdelta=$(test-genrandom foo 2000 | git hash-object --stdin -w) &&\n'> 
          <'\tdo_pack "$base $delta" --delta-base-offset &&\n'> <'\trm -f .git/objects/??/* &&\n'> <'\n'> <'\t# Double check that we have the delta we expect.\n'> 
          <'\techo $base >expect &&\n'> <'\techo $delta | git cat-file --batch-check="%(deltabase)" >actual &&\n'> 
          <'\ttest_cmp expect actual &&\n'> <'\n'> <'\t# Now corrupt it. We assume the varint size for the delta is small\n'> 
          <'\t# enough to fit in the first byte (which it should be, since it\n'> <'\t# is a pure deletion from the base), and that original ofs_delta\n'> 
          <'\t# takes 2 bytes (which it should, as it should be ~3000).\n'> <'\tofs=$(git show-index <$idx | grep $delta | cut -d" " -f1) &&\n'> 
          <'\tmunge $pack $(($ofs + 1)) "\\177\\377" &&\n'> <'\ttest_must_fail git cat-file blob $delta >/dev/null\n'>
        )
      }
    )
    (C {<test_done>})
  ]
)