DHowett / go-plist

A pure Go Apple Property List transcoder
Other
410 stars 96 forks source link

bplist: teach the parser about unusual OffsetIntSize values #78

Closed MarSoft closed 1 year ago

MarSoft commented 1 year ago

Fixes #77. Notice that this is only a partial fix which works for the value of 3 and for any value < 8, but won't help in other cases. Supporting values < 16 should also be possible, but I didn't bother with it. Also this doesn't touch bplist_generator and hence won't make use of non-standard values for generating plists (while those values could probably give a benefit of slightly reduced plist size).

DHowett commented 1 year ago

WOW, excellent find!

This might be annoying (and I am totally okay if you tell me "no" -- I'll happily do it myself), but would you be able to write a bplist deserialization test for this case?

I quickly cross-referenced the behavior in CoreFoundation and it looks like offset int sizes that aren't powers of two are considered legal. Neat!

DHowett commented 1 year ago

(Also, thanks so much!)

DHowett commented 1 year ago

Okay, I got too excited about this and ended up writing a test

bplist_test.go

func TestBplistNonPowerOfTwoOffsetIntSizes(t *testing.T) {
    bplist := []byte{
        'b', 'p', 'l', 'i', 's', 't', '0', '0',

        // Array (2 entries)
        0xA2,
        0x01, 0x02,

        // 0xFFFFFFFFFFFFFF80 (MinInt8, sign extended)
        0x13, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80,

        // 0x7F (MaxInt8)
        0x10, 0x7f,

        // Offset table (each entry is 3 bytes)
        0x00, 0x00, 0x08,
        0x00, 0x00, 0x0b,
        0x00, 0x00, 0x14,

        // Trailer
        0x00, 0x00, 0x00, 0x00, 0x00,
        0x00,
        0x03, // Offset Int Size 3 (not a power of 2)
        0x01,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
    }

    buf := bytes.NewReader(bplist)
    d := newBplistParser(buf)
    _, err := d.parseDocument()
    if err != nil {
        t.Error("Unexpected error", err)
    }
}
DHowett commented 1 year ago

Thanks again for the fix! I added the test case from my most recent comment and squashed.