(command.CommandList children: [ (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name left:<Id.Lit_VarLike 'test_description='> name:test_description) op: assign_op.Equal rhs: {(SQ <'bounds-checking of access to mmapped on-disk file formats'>)} spids: [4] ) ] redirects: [] ) (C {<.>} {<'./test-lib.sh'>}) (command.ShFunction name: clear_base body: (BraceGroup left: <Id.Lit_LBrace '{'> children: [ (command.AndOr ops: [Id.Op_DAmp] children: [ (C {<test_when_finished>} {(SQ <restore_base>)}) (C {<rm>} {<-f>} {($ Id.VSub_DollarName base)}) ] ) ] redirects: [] right: <Id.Lit_RBrace '}'> ) ) (command.ShFunction name: restore_base body: (BraceGroup left: <Id.Lit_LBrace '{'> children: [(C {<cp>} {<'base-backup/'> <Id.Lit_Star '*'>} {<'.git/objects/pack/'>})] redirects: [] right: <Id.Lit_RBrace '}'> ) ) (command.ShFunction name: do_pack body: (BraceGroup left: <Id.Lit_LBrace '{'> children: [ (command.Sentence child: (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name left:<Id.Lit_VarLike 'pack_objects='> name:pack_objects) op: assign_op.Equal rhs: {($ Id.VSub_Number 1)} spids: [66] ) ] redirects: [] ) 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 left:<Id.Lit_VarLike 'sha1='> name:sha1) op: assign_op.Equal rhs: { (command_sub left_token: <Id.Left_DollarParen '$('> child: (command.Pipeline children: [ (command.ForEach iter_names: [i] iterable: (for_iter.Words words: [{($ Id.VSub_DollarName pack_objects)}] ) body: (command.DoGroup children: [(C {<echo>} {($ Id.VSub_DollarName i)})] ) redirects: [] ) (C {<git>} {<pack-objects>} {(DQ ($ Id.VSub_At '@'))} {<'.git/objects/pack/pack'>} ) ] negated: F stderr_indices: [] ) right: <Id.Eof_RParen _> ) } spids: [73] ) ] redirects: [] ) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name left:<Id.Lit_VarLike 'pack='> name:pack) op: assign_op.Equal rhs: {<'.git/objects/pack/pack-'> ($ Id.VSub_DollarName sha1) <.pack>} spids: [114] ) ] redirects: [] ) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name left:<Id.Lit_VarLike 'idx='> name:idx) op: assign_op.Equal rhs: {<'.git/objects/pack/pack-'> ($ Id.VSub_DollarName sha1) <.idx>} spids: [122] ) ] redirects: [] ) (C {<chmod>} {<Id.Lit_Other '+'> <w>} {($ Id.VSub_DollarName pack)} {($ Id.VSub_DollarName idx)} ) (C {<test_when_finished>} {(SQ <'rm -f "$pack" "$idx"'>)}) ] ) ] redirects: [] right: <Id.Lit_RBrace '}'> ) ) (command.ShFunction name: munge body: (BraceGroup left: <Id.Lit_LBrace '{'> 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 stderr_indices: [] ) ] redirects: [] right: <Id.Lit_RBrace '}'> ) ) (command.ShFunction name: ofs_table body: (BraceGroup left: <Id.Lit_LBrace '{'> 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)} ) ) ) } ) ] redirects: [] right: <Id.Lit_RBrace '}'> ) ) (command.ShFunction name: extended_table body: (BraceGroup left: <Id.Lit_LBrace '{'> 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: <Id.Eof_RParen _> ) } right: (arith_expr.Binary op_id: Id.Arith_Star left: {<Id.Lit_Digits 4>} right: {($ Id.VSub_Number 1)} ) ) ) } ) ] redirects: [] right: <Id.Lit_RBrace '}'> ) ) (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>}) ] )