authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2021-09-15 17:31:40-07:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2021-09-16 11:43:07+02:00
logdb940a2c8131c52fb6e1f2e40af9c68d2228e656
treee5dda363b6556ce35e3d00211e509e5890651552
parente1bf350b4d66a682c8fc5f151563dd1725e8eaf1

std.unicode: cleanup allocations on error in allocating functions

Fixes leaks when `utf16leToUtf8Alloc`/`utf16leToUtf8AllocZ`/`utf8ToUtf16LeWithNull` return an error and adds relevant test cases

1 files changed, 21 insertions(+), 3 deletions(-)

lib/std/unicode.zig+21-3
...@@ -553,8 +553,9 @@ fn testDecode(bytes: []const u8) !u21 {...@@ -553,8 +553,9 @@ fn testDecode(bytes: []const u8) !u21 {
553/// Caller must free returned memory.553/// Caller must free returned memory.
554pub fn utf16leToUtf8Alloc(allocator: *mem.Allocator, utf16le: []const u16) ![]u8 {554pub fn utf16leToUtf8Alloc(allocator: *mem.Allocator, utf16le: []const u16) ![]u8 {
555 var result = std.ArrayList(u8).init(allocator);555 var result = std.ArrayList(u8).init(allocator);
556 errdefer result.deinit();
556 // optimistically guess that it will all be ascii.557 // optimistically guess that it will all be ascii.
557 try result.ensureCapacity(utf16le.len);558 try result.ensureTotalCapacity(utf16le.len);
558 var out_index: usize = 0;559 var out_index: usize = 0;
559 var it = Utf16LeIterator.init(utf16le);560 var it = Utf16LeIterator.init(utf16le);
560 while (try it.nextCodepoint()) |codepoint| {561 while (try it.nextCodepoint()) |codepoint| {
...@@ -569,9 +570,10 @@ pub fn utf16leToUtf8Alloc(allocator: *mem.Allocator, utf16le: []const u16) ![]u8...@@ -569,9 +570,10 @@ pub fn utf16leToUtf8Alloc(allocator: *mem.Allocator, utf16le: []const u16) ![]u8
569570
570/// Caller must free returned memory.571/// Caller must free returned memory.
571pub fn utf16leToUtf8AllocZ(allocator: *mem.Allocator, utf16le: []const u16) ![:0]u8 {572pub fn utf16leToUtf8AllocZ(allocator: *mem.Allocator, utf16le: []const u16) ![:0]u8 {
572 var result = try std.ArrayList(u8).initCapacity(allocator, utf16le.len);573 var result = std.ArrayList(u8).init(allocator);
574 errdefer result.deinit();
573 // optimistically guess that it will all be ascii.575 // optimistically guess that it will all be ascii.
574 try result.ensureCapacity(utf16le.len);576 try result.ensureTotalCapacity(utf16le.len);
575 var out_index: usize = 0;577 var out_index: usize = 0;
576 var it = Utf16LeIterator.init(utf16le);578 var it = Utf16LeIterator.init(utf16le);
577 while (try it.nextCodepoint()) |codepoint| {579 while (try it.nextCodepoint()) |codepoint| {
...@@ -653,10 +655,18 @@ test "utf16leToUtf8" {...@@ -653,10 +655,18 @@ test "utf16leToUtf8" {
653 defer std.testing.allocator.free(utf8);655 defer std.testing.allocator.free(utf8);
654 try testing.expect(mem.eql(u8, utf8, "\xf4\x8f\xb0\x80"));656 try testing.expect(mem.eql(u8, utf8, "\xf4\x8f\xb0\x80"));
655 }657 }
658
659 {
660 mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xdcdc);
661 mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdcdc);
662 const result = utf16leToUtf8Alloc(std.testing.allocator, &utf16le);
663 try std.testing.expectError(error.UnexpectedSecondSurrogateHalf, result);
664 }
656}665}
657666
658pub fn utf8ToUtf16LeWithNull(allocator: *mem.Allocator, utf8: []const u8) ![:0]u16 {667pub fn utf8ToUtf16LeWithNull(allocator: *mem.Allocator, utf8: []const u8) ![:0]u16 {
659 var result = std.ArrayList(u16).init(allocator);668 var result = std.ArrayList(u16).init(allocator);
669 errdefer result.deinit();
660 // optimistically guess that it will not require surrogate pairs670 // optimistically guess that it will not require surrogate pairs
661 try result.ensureCapacity(utf8.len + 1);671 try result.ensureCapacity(utf8.len + 1);
662672
...@@ -718,6 +728,10 @@ test "utf8ToUtf16Le" {...@@ -718,6 +728,10 @@ test "utf8ToUtf16Le" {
718 try testing.expectEqual(@as(usize, 2), length);728 try testing.expectEqual(@as(usize, 2), length);
719 try testing.expectEqualSlices(u8, "\xff\xdb\xff\xdf", mem.sliceAsBytes(utf16le[0..]));729 try testing.expectEqualSlices(u8, "\xff\xdb\xff\xdf", mem.sliceAsBytes(utf16le[0..]));
720 }730 }
731 {
732 const result = utf8ToUtf16Le(utf16le[0..], "\xf4\x90\x80\x80");
733 try testing.expectError(error.InvalidUtf8, result);
734 }
721}735}
722736
723test "utf8ToUtf16LeWithNull" {737test "utf8ToUtf16LeWithNull" {
...@@ -733,6 +747,10 @@ test "utf8ToUtf16LeWithNull" {...@@ -733,6 +747,10 @@ test "utf8ToUtf16LeWithNull" {
733 try testing.expectEqualSlices(u8, "\xff\xdb\xff\xdf", mem.sliceAsBytes(utf16[0..]));747 try testing.expectEqualSlices(u8, "\xff\xdb\xff\xdf", mem.sliceAsBytes(utf16[0..]));
734 try testing.expect(utf16[2] == 0);748 try testing.expect(utf16[2] == 0);
735 }749 }
750 {
751 const result = utf8ToUtf16LeWithNull(testing.allocator, "\xf4\x90\x80\x80");
752 try testing.expectError(error.InvalidUtf8, result);
753 }
736}754}
737755
738/// Converts a UTF-8 string literal into a UTF-16LE string literal.756/// Converts a UTF-8 string literal into a UTF-16LE string literal.