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
     1.1 --- a/src/cx/string.h	Tue Sep 20 10:37:29 2022 +0200
     1.2 +++ b/src/cx/string.h	Tue Oct 04 18:49:14 2022 +0200
     1.3 @@ -241,6 +241,7 @@
     1.4    * So developers \em must pass the return value to cx_strfree() eventually.
     1.5    *
     1.6    * \note It is guaranteed that there is only one allocation.
     1.7 +  * It is also guaranteed that the returned string is zero-terminated.
     1.8   *
     1.9   * @param alloc the allocator to use
    1.10   * @param count   the total number of strings to concatenate
    1.11 @@ -260,6 +261,9 @@
    1.12   * The resulting string will be allocated by standard \c malloc().
    1.13   * So developers \em must pass the return value to cx_strfree() eventually.
    1.14   *
    1.15 + * \note It is guaranteed that there is only one allocation.
    1.16 + * It is also guaranteed that the returned string is zero-terminated.
    1.17 + *
    1.18   * @param count   the total number of strings to concatenate
    1.19   * @param ...     all strings
    1.20   * @return the concatenated string
    1.21 @@ -608,8 +612,7 @@
    1.22   *
    1.23   * The new string will contain a copy allocated by \p allocator.
    1.24   *
    1.25 - * \note The returned string is guaranteed to be zero-terminated and can safely
    1.26 - * be passed to other APIs.
    1.27 + * \note The returned string is guaranteed to be zero-terminated.
    1.28   *
    1.29   * @param allocator the allocator to use
    1.30   * @param string the string to duplicate
    1.31 @@ -628,8 +631,7 @@
    1.32   * The new string will contain a copy allocated by standard
    1.33   * \c malloc(). So developers \em must pass the return value to cx_strfree().
    1.34   *
    1.35 - * \note The returned string is guaranteed to be zero-terminated and can safely
    1.36 - * be passed to other APIs.
    1.37 + * \note The returned string is guaranteed to be zero-terminated.
    1.38   *
    1.39   * @param string the string to duplicate
    1.40   * @return a duplicate of the string
    1.41 @@ -743,7 +745,8 @@
    1.42   * The pattern is taken literally and is no regular expression.
    1.43   * Replaces at most \p replmax occurrences.
    1.44   *
    1.45 - * The returned string will be allocated by \p allocator.
    1.46 + * The returned string will be allocated by \p allocator and is guaranteed
    1.47 + * to be zero-terminated.
    1.48   *
    1.49   * If allocation fails, or the input string is empty,
    1.50   * the returned string will be empty.
    1.51 @@ -770,8 +773,8 @@
    1.52   * The pattern is taken literally and is no regular expression.
    1.53   * Replaces at most \p replmax occurrences.
    1.54   *
    1.55 - * The returned string will be allocated by \c malloc() and \em must be passed
    1.56 - * to cx_strfree() eventually.
    1.57 + * The returned string will be allocated by \c malloc() and is guaranteed
    1.58 + * to be zero-terminated.
    1.59   *
    1.60   * If allocation fails, or the input string is empty,
    1.61   * the returned string will be empty.
    1.62 @@ -790,7 +793,8 @@
    1.63   *
    1.64   * The pattern is taken literally and is no regular expression.
    1.65   *
    1.66 - * The returned string will be allocated by \p allocator.
    1.67 + * The returned string will be allocated by \p allocator and is guaranteed
    1.68 + * to be zero-terminated.
    1.69   *
    1.70   * If allocation fails, or the input string is empty,
    1.71   * the returned string will be empty.
    1.72 @@ -810,8 +814,8 @@
    1.73   * The pattern is taken literally and is no regular expression.
    1.74   * Replaces at most \p replmax occurrences.
    1.75   *
    1.76 - * The returned string will be allocated by \c malloc() and \em must be passed
    1.77 - * to cx_strfree() eventually.
    1.78 + * The returned string will be allocated by \c malloc() and is guaranteed
    1.79 + * to be zero-terminated.
    1.80   *
    1.81   * If allocation fails, or the input string is empty,
    1.82   * the returned string will be empty.
     2.1 --- a/test/test_string.cpp	Tue Sep 20 10:37:29 2022 +0200
     2.2 +++ b/test/test_string.cpp	Tue Oct 04 18:49:14 2022 +0200
     2.3 @@ -31,6 +31,8 @@
     2.4  
     2.5  #include <gtest/gtest.h>
     2.6  
     2.7 +#define EXPECT_ZERO_TERMINATED(str) EXPECT_EQ((str).ptr[(str).length], '\0')
     2.8 +
     2.9  TEST(String, construct) {
    2.10      cxstring s1 = cx_str("1234");
    2.11      cxstring s2 = cx_strn("abcd", 2);
    2.12 @@ -55,6 +57,22 @@
    2.13      EXPECT_TRUE(alloc.verify());
    2.14  }
    2.15  
    2.16 +TEST(String, strdup) {
    2.17 +    cxstring str = CX_STR("test");
    2.18 +    cxmutstr dup = cx_strdup(str);
    2.19 +    ASSERT_EQ(dup.length, str.length);
    2.20 +    EXPECT_STREQ(dup.ptr, str.ptr);
    2.21 +    EXPECT_ZERO_TERMINATED(dup);
    2.22 +    cx_strfree(&dup);
    2.23 +
    2.24 +    str.length = 2;
    2.25 +    dup = cx_strdup(str);
    2.26 +    ASSERT_EQ(dup.length, str.length);
    2.27 +    EXPECT_STREQ(dup.ptr, "te");
    2.28 +    EXPECT_ZERO_TERMINATED(dup);
    2.29 +    cx_strfree(&dup);
    2.30 +}
    2.31 +
    2.32  TEST(String, strlen) {
    2.33      cxstring s1 = CX_STR("1234");
    2.34      cxstring s2 = CX_STR(".:.:.");
    2.35 @@ -210,7 +228,6 @@
    2.36      EXPECT_GT(cx_strcasecmp(str, cx_str("compare")), 0);
    2.37  }
    2.38  
    2.39 -
    2.40  TEST(String, strcat) {
    2.41      cxstring s1 = CX_STR("12");
    2.42      cxstring s2 = CX_STR("34");
    2.43 @@ -221,18 +238,22 @@
    2.44  
    2.45      cxmutstr t1 = cx_strcat_a(&alloc, 2, s1, s2);
    2.46      EXPECT_EQ(cx_strcmp(cx_strcast(t1), cx_str("1234")), 0);
    2.47 +    EXPECT_ZERO_TERMINATED(t1);
    2.48      cx_strfree_a(&alloc, &t1);
    2.49  
    2.50      cxmutstr t2 = cx_strcat_a(&alloc, 3, s1, s2, s3);
    2.51      EXPECT_EQ(cx_strcmp(cx_strcast(t2), cx_str("123456")), 0);
    2.52 +    EXPECT_ZERO_TERMINATED(t2);
    2.53      cx_strfree_a(&alloc, &t2);
    2.54  
    2.55      cxmutstr t3 = cx_strcat_a(&alloc, 6, s1, sn, s2, sn, s3, sn);
    2.56      EXPECT_EQ(cx_strcmp(cx_strcast(t3), cx_str("123456")), 0);
    2.57 +    EXPECT_ZERO_TERMINATED(t3);
    2.58      cx_strfree_a(&alloc, &t3);
    2.59  
    2.60      cxmutstr t4 = cx_strcat_a(&alloc, 2, sn, sn);
    2.61      EXPECT_EQ(cx_strcmp(cx_strcast(t4), cx_str("")), 0);
    2.62 +    EXPECT_ZERO_TERMINATED(t4);
    2.63      cx_strfree_a(&alloc, &t4);
    2.64  
    2.65      EXPECT_TRUE(alloc.verify());
    2.66 @@ -524,63 +545,75 @@
    2.67      cxstring csstr = CX_STR("test AB ab TEST xyz");
    2.68  
    2.69      cxmutstr repl = cx_strreplace(str, cx_str("abab"), cx_str("muchlonger"));
    2.70 -    cxstring expected = CX_STR("test muchlongerab string aba");
    2.71 +    auto expected = "test muchlongerab string aba";
    2.72  
    2.73      cxmutstr repln = cx_strreplacen(str, cx_str("ab"), cx_str("c"), 2);
    2.74 -    cxstring expectedn = CX_STR("test ccab string aba");
    2.75 +    auto expectedn = "test ccab string aba";
    2.76  
    2.77      cxmutstr longrepl = cx_strreplace(longstr, cx_str("a"), cx_str("z"));
    2.78 -    cxstring longexpect = CX_STR(
    2.79 -            "xyzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzcd");
    2.80 +    auto longexpect = "xyzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzcd";
    2.81  
    2.82      cxmutstr replnotrail = cx_strreplace(notrail, cx_str("ab"), cx_str("z"));
    2.83 -    cxstring notrailexpect = CX_STR("test zz");
    2.84 +    auto notrailexpect = "test zz";
    2.85  
    2.86      cxmutstr repleq = cx_strreplace(str, str, cx_str("hello"));
    2.87 -    cxstring eqexpect = CX_STR("hello");
    2.88 +    auto eqexpect = "hello";
    2.89  
    2.90      cxmutstr replempty1 = cx_strreplace(empty, cx_str("ab"), cx_str("c")); // expect: empty
    2.91      cxmutstr replempty2 = cx_strreplace(str, cx_str("abab"), empty);
    2.92 -    cxstring emptyexpect2 = CX_STR("test ab string aba");
    2.93 +    auto emptyexpect2 = "test ab string aba";
    2.94  
    2.95      cxmutstr replpre = cx_strreplace(str, cx_str("test "), cx_str("TEST "));
    2.96 -    cxstring preexpected = CX_STR("TEST ababab string aba");
    2.97 +    auto preexpected = "TEST ababab string aba";
    2.98  
    2.99      cxmutstr replan1 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 1);
   2.100 -    cxstring an1expected = CX_STR("xaaaaaaaaa");
   2.101 +    auto an1expected = "xaaaaaaaaa";
   2.102  
   2.103      cxmutstr replan4 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 4);
   2.104 -    cxstring an4expected = CX_STR("xxxxaaaaaa");
   2.105 +    auto an4expected = "xxxxaaaaaa";
   2.106  
   2.107      cxmutstr replan9 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 9);
   2.108 -    cxstring an9expected = CX_STR("xxxxxxxxxa");
   2.109 +    auto an9expected = "xxxxxxxxxa";
   2.110  
   2.111      cxmutstr replan10 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 10);
   2.112 -    cxstring an10expected = CX_STR("xxxxxxxxxx");
   2.113 +    auto an10expected = "xxxxxxxxxx";
   2.114  
   2.115      cxmutstr replcs1 = cx_strreplace(csstr, cx_str("AB"), cx_str("*"));
   2.116 -    cxstring cs1expected = CX_STR("test * ab TEST xyz");
   2.117 +    auto cs1expected = "test * ab TEST xyz";
   2.118  
   2.119      cxmutstr replcs2 = cx_strreplace(csstr, cx_str("test"), cx_str("TEST"));
   2.120 -    cxstring cs2expected = CX_STR("TEST AB ab TEST xyz");
   2.121 +    auto cs2expected = "TEST AB ab TEST xyz";
   2.122  
   2.123  
   2.124      EXPECT_NE(repl.ptr, str.ptr);
   2.125 -    EXPECT_EQ(cx_strcmp(cx_strcast(repl), expected), 0);
   2.126 -    EXPECT_NE(repln.ptr, str.ptr);
   2.127 -    EXPECT_EQ(cx_strcmp(cx_strcast(repln), expectedn), 0);
   2.128 -    EXPECT_EQ(cx_strcmp(cx_strcast(longrepl), longexpect), 0);
   2.129 -    EXPECT_EQ(cx_strcmp(cx_strcast(replnotrail), notrailexpect), 0);
   2.130 -    EXPECT_EQ(cx_strcmp(cx_strcast(repleq), eqexpect), 0);
   2.131 -    EXPECT_EQ(cx_strcmp(cx_strcast(replempty1), empty), 0);
   2.132 -    EXPECT_EQ(cx_strcmp(cx_strcast(replempty2), emptyexpect2), 0);
   2.133 -    EXPECT_EQ(cx_strcmp(cx_strcast(replpre), preexpected), 0);
   2.134 -    EXPECT_EQ(cx_strcmp(cx_strcast(replan1), an1expected), 0);
   2.135 -    EXPECT_EQ(cx_strcmp(cx_strcast(replan4), an4expected), 0);
   2.136 -    EXPECT_EQ(cx_strcmp(cx_strcast(replan9), an9expected), 0);
   2.137 -    EXPECT_EQ(cx_strcmp(cx_strcast(replan10), an10expected), 0);
   2.138 -    EXPECT_EQ(cx_strcmp(cx_strcast(replcs1), cs1expected), 0);
   2.139 -    EXPECT_EQ(cx_strcmp(cx_strcast(replcs2), cs2expected), 0);
   2.140 +    EXPECT_ZERO_TERMINATED(repl);
   2.141 +    EXPECT_STREQ(repl.ptr, expected);
   2.142 +    EXPECT_ZERO_TERMINATED(repln);
   2.143 +    EXPECT_STREQ(repln.ptr, expectedn);
   2.144 +    EXPECT_ZERO_TERMINATED(longrepl);
   2.145 +    EXPECT_STREQ(longrepl.ptr, longexpect);
   2.146 +    EXPECT_ZERO_TERMINATED(replnotrail);
   2.147 +    EXPECT_STREQ(replnotrail.ptr, notrailexpect);
   2.148 +    EXPECT_ZERO_TERMINATED(repleq);
   2.149 +    EXPECT_STREQ(repleq.ptr, eqexpect);
   2.150 +    EXPECT_ZERO_TERMINATED(replempty1);
   2.151 +    EXPECT_STREQ(replempty1.ptr, "");
   2.152 +    EXPECT_ZERO_TERMINATED(replempty2);
   2.153 +    EXPECT_STREQ(replempty2.ptr, emptyexpect2);
   2.154 +    EXPECT_ZERO_TERMINATED(replpre);
   2.155 +    EXPECT_STREQ(replpre.ptr, preexpected);
   2.156 +    EXPECT_ZERO_TERMINATED(replan1);
   2.157 +    EXPECT_STREQ(replan1.ptr, an1expected);
   2.158 +    EXPECT_ZERO_TERMINATED(replan4);
   2.159 +    EXPECT_STREQ(replan4.ptr, an4expected);
   2.160 +    EXPECT_ZERO_TERMINATED(replan9);
   2.161 +    EXPECT_STREQ(replan9.ptr, an9expected);
   2.162 +    EXPECT_ZERO_TERMINATED(replan10);
   2.163 +    EXPECT_STREQ(replan10.ptr, an10expected);
   2.164 +    EXPECT_ZERO_TERMINATED(replcs1);
   2.165 +    EXPECT_STREQ(replcs1.ptr, cs1expected);
   2.166 +    EXPECT_ZERO_TERMINATED(replcs2);
   2.167 +    EXPECT_STREQ(replcs2.ptr, cs2expected);
   2.168  
   2.169      cx_strfree(&repl);
   2.170      cx_strfree(&repln);

mercurial