Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash when parsing packed repeated uint64 field with length 0 in Swift #3043

Closed
sashaweiss-signal opened this issue Jul 23, 2024 · 5 comments

Comments

@sashaweiss-signal
Copy link
Contributor

sashaweiss-signal commented Jul 23, 2024

Hi! Thanks for maintaining Wire – I'm loving using it.

I'm using Wire to generate Swift code for proto types and parsing, and am running into a crash when deserializing that I think is a bug in the Swift ProtoReader.

Specifically, I'm using my in-code Wire-generated Swift models to assemble a type that has a [UInt64] field on it, which I'm setting to [], and serialize it. When I later try and deserialize that serialized proto, I'm hitting this fatalError:

image

Digging into it a little, I'm seeing just before the crash that Wire is trying to decode a repeated uint64 field:

image image

Poking around at those breakpoints, it looks like length is 0:

image

There's a comment in that method that suggests that when we actually go to decode a T: UInt64 for this array, we'll set state to .tag (the original fatalError was because state was not being set to .tag). However, since length is 0 (which makes sense, since this array is empty) we'll never actually decode a UInt64, and state remains .lengthDelimited rather than getting reset to .tag.


I'm able to reproduce this minimally by adding the following to ProtoReaderTests.swift:

func testDecodePackedRepeatedFixedUInt64Empty() throws {
    let data = Foundation.Data(hexEncoded: """
        0A       // (Tag 1 | Length Delimited)
        00       // Length 0
    """)!

    try test(data: data) { reader in
        var values: [UInt64] = []
        try reader.decode(tag: 1) {
            try reader.decode(into: &values, encoding: .fixed)
        }

        XCTAssertEqual(values, [])
    }
}

However, if I add the following shim to ProtoReader.swift locally, it works:

image

So perhaps this method sould check for length == 0 and manually reset state = .tag and early-return?

Please let me know if there's more information I can provide. Thanks!

@dnkoutso
Copy link
Collaborator

thanks a lot for this report! Would it be possible to ask you to attempt something similar in Wire 4.5 or Wire 4.6 so we can see if this regressed at some point or it was always an issue? I will attempt to do it myself using the test you provided too but I can do so a little bit later in the week.

@lickel
Copy link
Collaborator

lickel commented Jul 24, 2024

Also feel free to open a PR!

@sashaweiss-signal
Copy link
Contributor Author

For sure – I just replayed these changes on top of the 4.5.0 and 4.5.6 tags, and the issue's there. Happy to open a PR if the change I suggested seems reasonable. (I'll plan to do that – if nothing else, I'm gonna make a fork to unblock myself for the time being.)

@lickel
Copy link
Collaborator

lickel commented Jul 24, 2024

There's a number of additional lengthDelimited cases that might be impacted too?
But this fix seems reasonable.

@sashaweiss-signal
Copy link
Contributor Author

Great! I searched through ProtoReader.swift for lengthDelimted, and the only thing I found was:

image

which already has its own length == 0 check.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants