add zero-termination guarantees

Tue, 04 Oct 2022 18:49:14 +0200

author
Mike Becker <universe@uap-core.de>
date
Tue, 04 Oct 2022 18:49:14 +0200
changeset 589
c290f8fd979e
parent 588
6a3cd8f0a2cf
child 590
02a56701a5cb

add zero-termination guarantees

src/cx/string.h file | annotate | diff | comparison | revisions
test/test_string.cpp file | annotate | diff | comparison | revisions
--- a/src/cx/string.h	Tue Sep 20 10:37:29 2022 +0200
+++ b/src/cx/string.h	Tue Oct 04 18:49:14 2022 +0200
@@ -241,6 +241,7 @@
   * So developers \em must pass the return value to cx_strfree() eventually.
   *
   * \note It is guaranteed that there is only one allocation.
+  * It is also guaranteed that the returned string is zero-terminated.
  *
  * @param alloc the allocator to use
  * @param count   the total number of strings to concatenate
@@ -260,6 +261,9 @@
  * The resulting string will be allocated by standard \c malloc().
  * So developers \em must pass the return value to cx_strfree() eventually.
  *
+ * \note It is guaranteed that there is only one allocation.
+ * It is also guaranteed that the returned string is zero-terminated.
+ *
  * @param count   the total number of strings to concatenate
  * @param ...     all strings
  * @return the concatenated string
@@ -608,8 +612,7 @@
  *
  * The new string will contain a copy allocated by \p allocator.
  *
- * \note The returned string is guaranteed to be zero-terminated and can safely
- * be passed to other APIs.
+ * \note The returned string is guaranteed to be zero-terminated.
  *
  * @param allocator the allocator to use
  * @param string the string to duplicate
@@ -628,8 +631,7 @@
  * The new string will contain a copy allocated by standard
  * \c malloc(). So developers \em must pass the return value to cx_strfree().
  *
- * \note The returned string is guaranteed to be zero-terminated and can safely
- * be passed to other APIs.
+ * \note The returned string is guaranteed to be zero-terminated.
  *
  * @param string the string to duplicate
  * @return a duplicate of the string
@@ -743,7 +745,8 @@
  * The pattern is taken literally and is no regular expression.
  * Replaces at most \p replmax occurrences.
  *
- * The returned string will be allocated by \p allocator.
+ * The returned string will be allocated by \p allocator and is guaranteed
+ * to be zero-terminated.
  *
  * If allocation fails, or the input string is empty,
  * the returned string will be empty.
@@ -770,8 +773,8 @@
  * The pattern is taken literally and is no regular expression.
  * Replaces at most \p replmax occurrences.
  *
- * The returned string will be allocated by \c malloc() and \em must be passed
- * to cx_strfree() eventually.
+ * The returned string will be allocated by \c malloc() and is guaranteed
+ * to be zero-terminated.
  *
  * If allocation fails, or the input string is empty,
  * the returned string will be empty.
@@ -790,7 +793,8 @@
  *
  * The pattern is taken literally and is no regular expression.
  *
- * The returned string will be allocated by \p allocator.
+ * The returned string will be allocated by \p allocator and is guaranteed
+ * to be zero-terminated.
  *
  * If allocation fails, or the input string is empty,
  * the returned string will be empty.
@@ -810,8 +814,8 @@
  * The pattern is taken literally and is no regular expression.
  * Replaces at most \p replmax occurrences.
  *
- * The returned string will be allocated by \c malloc() and \em must be passed
- * to cx_strfree() eventually.
+ * The returned string will be allocated by \c malloc() and is guaranteed
+ * to be zero-terminated.
  *
  * If allocation fails, or the input string is empty,
  * the returned string will be empty.
--- a/test/test_string.cpp	Tue Sep 20 10:37:29 2022 +0200
+++ b/test/test_string.cpp	Tue Oct 04 18:49:14 2022 +0200
@@ -31,6 +31,8 @@
 
 #include <gtest/gtest.h>
 
+#define EXPECT_ZERO_TERMINATED(str) EXPECT_EQ((str).ptr[(str).length], '\0')
+
 TEST(String, construct) {
     cxstring s1 = cx_str("1234");
     cxstring s2 = cx_strn("abcd", 2);
@@ -55,6 +57,22 @@
     EXPECT_TRUE(alloc.verify());
 }
 
+TEST(String, strdup) {
+    cxstring str = CX_STR("test");
+    cxmutstr dup = cx_strdup(str);
+    ASSERT_EQ(dup.length, str.length);
+    EXPECT_STREQ(dup.ptr, str.ptr);
+    EXPECT_ZERO_TERMINATED(dup);
+    cx_strfree(&dup);
+
+    str.length = 2;
+    dup = cx_strdup(str);
+    ASSERT_EQ(dup.length, str.length);
+    EXPECT_STREQ(dup.ptr, "te");
+    EXPECT_ZERO_TERMINATED(dup);
+    cx_strfree(&dup);
+}
+
 TEST(String, strlen) {
     cxstring s1 = CX_STR("1234");
     cxstring s2 = CX_STR(".:.:.");
@@ -210,7 +228,6 @@
     EXPECT_GT(cx_strcasecmp(str, cx_str("compare")), 0);
 }
 
-
 TEST(String, strcat) {
     cxstring s1 = CX_STR("12");
     cxstring s2 = CX_STR("34");
@@ -221,18 +238,22 @@
 
     cxmutstr t1 = cx_strcat_a(&alloc, 2, s1, s2);
     EXPECT_EQ(cx_strcmp(cx_strcast(t1), cx_str("1234")), 0);
+    EXPECT_ZERO_TERMINATED(t1);
     cx_strfree_a(&alloc, &t1);
 
     cxmutstr t2 = cx_strcat_a(&alloc, 3, s1, s2, s3);
     EXPECT_EQ(cx_strcmp(cx_strcast(t2), cx_str("123456")), 0);
+    EXPECT_ZERO_TERMINATED(t2);
     cx_strfree_a(&alloc, &t2);
 
     cxmutstr t3 = cx_strcat_a(&alloc, 6, s1, sn, s2, sn, s3, sn);
     EXPECT_EQ(cx_strcmp(cx_strcast(t3), cx_str("123456")), 0);
+    EXPECT_ZERO_TERMINATED(t3);
     cx_strfree_a(&alloc, &t3);
 
     cxmutstr t4 = cx_strcat_a(&alloc, 2, sn, sn);
     EXPECT_EQ(cx_strcmp(cx_strcast(t4), cx_str("")), 0);
+    EXPECT_ZERO_TERMINATED(t4);
     cx_strfree_a(&alloc, &t4);
 
     EXPECT_TRUE(alloc.verify());
@@ -524,63 +545,75 @@
     cxstring csstr = CX_STR("test AB ab TEST xyz");
 
     cxmutstr repl = cx_strreplace(str, cx_str("abab"), cx_str("muchlonger"));
-    cxstring expected = CX_STR("test muchlongerab string aba");
+    auto expected = "test muchlongerab string aba";
 
     cxmutstr repln = cx_strreplacen(str, cx_str("ab"), cx_str("c"), 2);
-    cxstring expectedn = CX_STR("test ccab string aba");
+    auto expectedn = "test ccab string aba";
 
     cxmutstr longrepl = cx_strreplace(longstr, cx_str("a"), cx_str("z"));
-    cxstring longexpect = CX_STR(
-            "xyzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzcd");
+    auto longexpect = "xyzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzcd";
 
     cxmutstr replnotrail = cx_strreplace(notrail, cx_str("ab"), cx_str("z"));
-    cxstring notrailexpect = CX_STR("test zz");
+    auto notrailexpect = "test zz";
 
     cxmutstr repleq = cx_strreplace(str, str, cx_str("hello"));
-    cxstring eqexpect = CX_STR("hello");
+    auto eqexpect = "hello";
 
     cxmutstr replempty1 = cx_strreplace(empty, cx_str("ab"), cx_str("c")); // expect: empty
     cxmutstr replempty2 = cx_strreplace(str, cx_str("abab"), empty);
-    cxstring emptyexpect2 = CX_STR("test ab string aba");
+    auto emptyexpect2 = "test ab string aba";
 
     cxmutstr replpre = cx_strreplace(str, cx_str("test "), cx_str("TEST "));
-    cxstring preexpected = CX_STR("TEST ababab string aba");
+    auto preexpected = "TEST ababab string aba";
 
     cxmutstr replan1 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 1);
-    cxstring an1expected = CX_STR("xaaaaaaaaa");
+    auto an1expected = "xaaaaaaaaa";
 
     cxmutstr replan4 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 4);
-    cxstring an4expected = CX_STR("xxxxaaaaaa");
+    auto an4expected = "xxxxaaaaaa";
 
     cxmutstr replan9 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 9);
-    cxstring an9expected = CX_STR("xxxxxxxxxa");
+    auto an9expected = "xxxxxxxxxa";
 
     cxmutstr replan10 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 10);
-    cxstring an10expected = CX_STR("xxxxxxxxxx");
+    auto an10expected = "xxxxxxxxxx";
 
     cxmutstr replcs1 = cx_strreplace(csstr, cx_str("AB"), cx_str("*"));
-    cxstring cs1expected = CX_STR("test * ab TEST xyz");
+    auto cs1expected = "test * ab TEST xyz";
 
     cxmutstr replcs2 = cx_strreplace(csstr, cx_str("test"), cx_str("TEST"));
-    cxstring cs2expected = CX_STR("TEST AB ab TEST xyz");
+    auto cs2expected = "TEST AB ab TEST xyz";
 
 
     EXPECT_NE(repl.ptr, str.ptr);
-    EXPECT_EQ(cx_strcmp(cx_strcast(repl), expected), 0);
-    EXPECT_NE(repln.ptr, str.ptr);
-    EXPECT_EQ(cx_strcmp(cx_strcast(repln), expectedn), 0);
-    EXPECT_EQ(cx_strcmp(cx_strcast(longrepl), longexpect), 0);
-    EXPECT_EQ(cx_strcmp(cx_strcast(replnotrail), notrailexpect), 0);
-    EXPECT_EQ(cx_strcmp(cx_strcast(repleq), eqexpect), 0);
-    EXPECT_EQ(cx_strcmp(cx_strcast(replempty1), empty), 0);
-    EXPECT_EQ(cx_strcmp(cx_strcast(replempty2), emptyexpect2), 0);
-    EXPECT_EQ(cx_strcmp(cx_strcast(replpre), preexpected), 0);
-    EXPECT_EQ(cx_strcmp(cx_strcast(replan1), an1expected), 0);
-    EXPECT_EQ(cx_strcmp(cx_strcast(replan4), an4expected), 0);
-    EXPECT_EQ(cx_strcmp(cx_strcast(replan9), an9expected), 0);
-    EXPECT_EQ(cx_strcmp(cx_strcast(replan10), an10expected), 0);
-    EXPECT_EQ(cx_strcmp(cx_strcast(replcs1), cs1expected), 0);
-    EXPECT_EQ(cx_strcmp(cx_strcast(replcs2), cs2expected), 0);
+    EXPECT_ZERO_TERMINATED(repl);
+    EXPECT_STREQ(repl.ptr, expected);
+    EXPECT_ZERO_TERMINATED(repln);
+    EXPECT_STREQ(repln.ptr, expectedn);
+    EXPECT_ZERO_TERMINATED(longrepl);
+    EXPECT_STREQ(longrepl.ptr, longexpect);
+    EXPECT_ZERO_TERMINATED(replnotrail);
+    EXPECT_STREQ(replnotrail.ptr, notrailexpect);
+    EXPECT_ZERO_TERMINATED(repleq);
+    EXPECT_STREQ(repleq.ptr, eqexpect);
+    EXPECT_ZERO_TERMINATED(replempty1);
+    EXPECT_STREQ(replempty1.ptr, "");
+    EXPECT_ZERO_TERMINATED(replempty2);
+    EXPECT_STREQ(replempty2.ptr, emptyexpect2);
+    EXPECT_ZERO_TERMINATED(replpre);
+    EXPECT_STREQ(replpre.ptr, preexpected);
+    EXPECT_ZERO_TERMINATED(replan1);
+    EXPECT_STREQ(replan1.ptr, an1expected);
+    EXPECT_ZERO_TERMINATED(replan4);
+    EXPECT_STREQ(replan4.ptr, an4expected);
+    EXPECT_ZERO_TERMINATED(replan9);
+    EXPECT_STREQ(replan9.ptr, an9expected);
+    EXPECT_ZERO_TERMINATED(replan10);
+    EXPECT_STREQ(replan10.ptr, an10expected);
+    EXPECT_ZERO_TERMINATED(replcs1);
+    EXPECT_STREQ(replcs1.ptr, cs1expected);
+    EXPECT_ZERO_TERMINATED(replcs2);
+    EXPECT_STREQ(replcs2.ptr, cs2expected);
 
     cx_strfree(&repl);
     cx_strfree(&repln);

mercurial