aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authorjumpnbrownweasel <49791153+jumpnbrownweasel@users.noreply.github.com>2021-04-25 16:16:24 -0700
committerGitHub <noreply@github.com>2021-04-25 19:16:24 -0400
commitbf67a3fdc9efea7126058b21e687c24868bc1268 (patch)
treeb1f5f2d6be676d0435024d464b3af7facdd617c3 /lib/std
parentc420eb60ad17599f035594ba877df66b7705fb25 (diff)
downloadzig-bf67a3fdc9efea7126058b21e687c24868bc1268.tar.gz
zig-bf67a3fdc9efea7126058b21e687c24868bc1268.zip
#8454 Fix for std.mem.replacementSize adjacent matches bug. (#8455)
* #8454 Fix for std.mem.replacementSize adjacent matches bug. When two 'needle' values are adjacent in the 'input' slice, the size is not counted correctly. The 2nd 'needle' value is not matched because the index is incremented by one after changing the index to account for the first value. The impact is the the size returned is incorrect, and could cause UB when this amount is used to size of the buffer passed to std.mem.replace. * Apply changes from PR review: - Add assert checking that the needle is non-empty and doc for this. - Add minimal test that an empty input works. - Use testing.expectEqualStrings.
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/mem.zig44
1 files changed, 40 insertions, 4 deletions
diff --git a/lib/std/mem.zig b/lib/std/mem.zig
index 66505f5d29..274da3b8f1 100644
--- a/lib/std/mem.zig
+++ b/lib/std/mem.zig
@@ -1876,7 +1876,11 @@ test "rotate" {
/// Replace needle with replacement as many times as possible, writing to an output buffer which is assumed to be of
/// appropriate size. Use replacementSize to calculate an appropriate buffer size.
+/// The needle must not be empty.
pub fn replace(comptime T: type, input: []const T, needle: []const T, replacement: []const T, output: []T) usize {
+ // Empty needle will loop until output buffer overflows.
+ assert(needle.len > 0);
+
var i: usize = 0;
var slide: usize = 0;
var replacements: usize = 0;
@@ -1899,22 +1903,48 @@ pub fn replace(comptime T: type, input: []const T, needle: []const T, replacemen
test "replace" {
var output: [29]u8 = undefined;
var replacements = replace(u8, "All your base are belong to us", "base", "Zig", output[0..]);
+ var expected: []const u8 = "All your Zig are belong to us";
testing.expect(replacements == 1);
- testing.expect(eql(u8, output[0..], "All your Zig are belong to us"));
+ testing.expectEqualStrings(expected, output[0..expected.len]);
replacements = replace(u8, "Favor reading code over writing code.", "code", "", output[0..]);
+ expected = "Favor reading over writing .";
testing.expect(replacements == 2);
- testing.expect(eql(u8, output[0..], "Favor reading over writing ."));
+ testing.expectEqualStrings(expected, output[0..expected.len]);
+
+ // Empty needle is not allowed but input may be empty.
+ replacements = replace(u8, "", "x", "y", output[0..0]);
+ expected = "";
+ testing.expect(replacements == 0);
+ testing.expectEqualStrings(expected, output[0..expected.len]);
+
+ // Adjacent replacements.
+
+ replacements = replace(u8, "\\n\\n", "\\n", "\n", output[0..]);
+ expected = "\n\n";
+ testing.expect(replacements == 2);
+ testing.expectEqualStrings(expected, output[0..expected.len]);
+
+ replacements = replace(u8, "abbba", "b", "cd", output[0..]);
+ expected = "acdcdcda";
+ testing.expect(replacements == 3);
+ testing.expectEqualStrings(expected, output[0..expected.len]);
}
/// Calculate the size needed in an output buffer to perform a replacement.
+/// The needle must not be empty.
pub fn replacementSize(comptime T: type, input: []const T, needle: []const T, replacement: []const T) usize {
+ // Empty needle will loop forever.
+ assert(needle.len > 0);
+
var i: usize = 0;
var size: usize = input.len;
- while (i < input.len) : (i += 1) {
+ while (i < input.len) {
if (mem.indexOf(T, input[i..], needle) == @as(usize, 0)) {
size = size - needle.len + replacement.len;
i += needle.len;
+ } else {
+ i += 1;
}
}
@@ -1923,9 +1953,15 @@ pub fn replacementSize(comptime T: type, input: []const T, needle: []const T, re
test "replacementSize" {
testing.expect(replacementSize(u8, "All your base are belong to us", "base", "Zig") == 29);
- testing.expect(replacementSize(u8, "", "", "") == 0);
testing.expect(replacementSize(u8, "Favor reading code over writing code.", "code", "") == 29);
testing.expect(replacementSize(u8, "Only one obvious way to do things.", "things.", "things in Zig.") == 41);
+
+ // Empty needle is not allowed but input may be empty.
+ testing.expect(replacementSize(u8, "", "x", "y") == 0);
+
+ // Adjacent replacements.
+ testing.expect(replacementSize(u8, "\\n\\n", "\\n", "\n") == 2);
+ testing.expect(replacementSize(u8, "abbba", "b", "cd") == 8);
}
/// Perform a replacement on an allocated buffer of pre-determined size. Caller must free returned memory.