Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Commit 5d5b951

Browse files
authored
Merge pull request #731 from jfontan/fix/crash-with-delta-cycles
plumbing: format/packfile, fix crash with cycle deltas
2 parents 8c24b1b + d5f74d2 commit 5d5b951

File tree

4 files changed

+56
-2
lines changed

4 files changed

+56
-2
lines changed

plumbing/format/packfile/delta_selector.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,8 @@ func (dw *deltaSelector) restoreOriginal(otp *ObjectToPack) error {
196196
return err
197197
}
198198

199-
otp.Original = obj
199+
otp.SetOriginal(obj)
200+
200201
return nil
201202
}
202203

plumbing/format/packfile/encoder.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ func (e *Encoder) entry(o *ObjectToPack) error {
8787
// (for example due to a concurrent repack) and a different base
8888
// was chosen, forcing a cycle. Select something other than a
8989
// delta, and write this object.
90+
e.selector.restoreOriginal(o)
9091
o.BackToOriginal()
9192
}
9293

plumbing/format/packfile/encoder_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,15 @@ func (s *EncoderSuite) deltaOverDeltaCyclicTest(c *C) {
202202
o3 := newObject(plumbing.BlobObject, []byte("011111"))
203203
o4 := newObject(plumbing.BlobObject, []byte("01111100000"))
204204

205+
_, err := s.store.SetEncodedObject(o1)
206+
c.Assert(err, IsNil)
207+
_, err = s.store.SetEncodedObject(o2)
208+
c.Assert(err, IsNil)
209+
_, err = s.store.SetEncodedObject(o3)
210+
c.Assert(err, IsNil)
211+
_, err = s.store.SetEncodedObject(o4)
212+
c.Assert(err, IsNil)
213+
205214
d2, err := GetDelta(o1, o2)
206215
c.Assert(err, IsNil)
207216

@@ -219,6 +228,18 @@ func (s *EncoderSuite) deltaOverDeltaCyclicTest(c *C) {
219228
pd3.SetDelta(pd4, d3)
220229
pd4.SetDelta(pd3, d4)
221230

231+
// SetOriginal is used by delta selector when generating ObjectToPack.
232+
// It also fills type, hash and size values to be used when Original
233+
// is nil.
234+
po1.SetOriginal(po1.Original)
235+
pd2.SetOriginal(pd2.Original)
236+
pd2.SetOriginal(nil)
237+
238+
pd3.SetOriginal(pd3.Original)
239+
pd3.SetOriginal(nil)
240+
241+
pd4.SetOriginal(pd4.Original)
242+
222243
encHash, err := s.enc.encode([]*ObjectToPack{
223244
po1,
224245
pd2,

plumbing/format/packfile/object_pack.go

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ type ObjectToPack struct {
2323
// offset in pack when object has been already written, or 0 if it
2424
// has not been written yet
2525
Offset int64
26+
27+
// Information from the original object
28+
resolvedOriginal bool
29+
originalType plumbing.ObjectType
30+
originalSize int64
31+
originalHash plumbing.Hash
2632
}
2733

2834
// newObjectToPack creates a correct ObjectToPack based on a non-delta object
@@ -47,7 +53,7 @@ func newDeltaObjectToPack(base *ObjectToPack, original, delta plumbing.EncodedOb
4753

4854
// BackToOriginal converts that ObjectToPack to a non-deltified object if it was one
4955
func (o *ObjectToPack) BackToOriginal() {
50-
if o.IsDelta() {
56+
if o.IsDelta() && o.Original != nil {
5157
o.Object = o.Original
5258
o.Base = nil
5359
o.Depth = 0
@@ -71,11 +77,28 @@ func (o *ObjectToPack) WantWrite() bool {
7177
return o.Offset == 1
7278
}
7379

80+
// SetOriginal sets both Original and saves size, type and hash. If object
81+
// is nil Original is set but previous resolved values are kept
82+
func (o *ObjectToPack) SetOriginal(obj plumbing.EncodedObject) {
83+
o.Original = obj
84+
85+
if obj != nil {
86+
o.originalSize = obj.Size()
87+
o.originalType = obj.Type()
88+
o.originalHash = obj.Hash()
89+
o.resolvedOriginal = true
90+
}
91+
}
92+
7493
func (o *ObjectToPack) Type() plumbing.ObjectType {
7594
if o.Original != nil {
7695
return o.Original.Type()
7796
}
7897

98+
if o.resolvedOriginal {
99+
return o.originalType
100+
}
101+
79102
if o.Base != nil {
80103
return o.Base.Type()
81104
}
@@ -92,6 +115,10 @@ func (o *ObjectToPack) Hash() plumbing.Hash {
92115
return o.Original.Hash()
93116
}
94117

118+
if o.resolvedOriginal {
119+
return o.originalHash
120+
}
121+
95122
do, ok := o.Object.(plumbing.DeltaObject)
96123
if ok {
97124
return do.ActualHash()
@@ -105,6 +132,10 @@ func (o *ObjectToPack) Size() int64 {
105132
return o.Original.Size()
106133
}
107134

135+
if o.resolvedOriginal {
136+
return o.originalSize
137+
}
138+
108139
do, ok := o.Object.(plumbing.DeltaObject)
109140
if ok {
110141
return do.ActualSize()

0 commit comments

Comments
 (0)