-
Notifications
You must be signed in to change notification settings - Fork 30
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
fix: memory leak when decoding Lists of Bytes #68
Conversation
Messages that include a `repeated` field of type `bytes` are not properly freed due to a missing condition `deinit_field()` which only cares for list of other message types or strings, but not bytes. This commit introduces a new unit test that fails if decoding a message with a list of bytes leaks and fix, that makes the unit test pass.
Thanks! I'll look into the details ASAP. It seems I introduced this bug myself recently with bytes. Seems OK at first glance, but I will look at it properly soon. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a slight little change to enforce switch (which would have prevented the mistake in the first place).
But apart from that this is great, thanks for the catch!
src/protobuf.zig
Outdated
@@ -586,7 +586,7 @@ fn deinit_field(result: anytype, comptime field_name: []const u8, comptime ftype | |||
} | |||
}, | |||
.List => |list_type| { | |||
if (list_type == .SubMessage or list_type == .String) { | |||
if (list_type == .SubMessage or list_type == .String or list_type == .Bytes) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use switch here so we have the exhaustive check at compile time and avoid this kind of error in the future.
diff --git a/src/protobuf.zig b/src/protobuf.zig
index dbe0c48..ac7e811 100644
--- a/src/protobuf.zig
+++ b/src/protobuf.zig
@@ -586,10 +586,13 @@ fn deinit_field(result: anytype, comptime field_name: []const u8, comptime ftype
}
},
.List => |list_type| {
- if (list_type == .SubMessage or list_type == .String or list_type == .Bytes) {
- for (@field(result, field_name).items) |item| {
- item.deinit();
- }
+ switch (list_type) {
+ .SubMessage, .String, .Bytes => {
+ for (@field(result, field_name).items) |item| {
+ item.deinit();
+ }
+ },
+ .Varint, .FixedInt => {},
}
@field(result, field_name).deinit();
},
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I'll change it. Thanks for the improvement. I'm currently taking my first baby steps with zig, so I'm grateful for each learning along the way :)
In `deinit_field()` we previously used an if condition that checked for different types within a list, but unfortunately this check was not exhaustive. By replacing this check with an switch statement, we now make sure that we have to handle all possible cases, otherwise we'll get a compiler error.
I changed the check to use |
Thanks a lot for your contribution ! |
Messages that include a
repeated
field of typebytes
are not properly freed due to a missing condition indeinit_field()
which only cares for list of other message types or strings, but not bytes.This commit introduces a new unit test that fails if decoding a message with a list of bytes leaks and fix, that makes the unit test pass.