summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/string.h14
-rw-r--r--include/wchar.h14
-rw-r--r--tests/Makefile10
-rw-r--r--tests/test_mbsnrtowcs_dynamic.c4
-rw-r--r--tests/test_strncat_dynamic_write.c2
-rw-r--r--tests/test_strncat_n_eq_buf.c18
-rw-r--r--tests/test_strncat_n_gt_buf.c17
-rw-r--r--tests/test_strncat_n_lt_buf.c18
-rw-r--r--tests/test_strncat_n_one.c18
-rw-r--r--tests/test_strncat_safe.c34
-rw-r--r--tests/test_strncat_static_write.c10
-rw-r--r--tests/test_wcsncat_n_eq_buf.c18
-rw-r--r--tests/test_wcsncat_n_gt_buf.c17
-rw-r--r--tests/test_wcsncat_n_lt_buf.c18
-rw-r--r--tests/test_wcsncat_n_one.c18
-rw-r--r--tests/test_wcsncat_safe.c34
-rw-r--r--tests/test_wcsnrtombs_dynamic.c4
17 files changed, 239 insertions, 29 deletions
diff --git a/include/string.h b/include/string.h
index 23f598c..44206f0 100644
--- a/include/string.h
+++ b/include/string.h
@@ -140,14 +140,12 @@ _FORTIFY_FN(strncat) char *strncat(char * _FORTIFY_POS0 __d, const char *__s,
140 size_t __b = __bos(__d, 0); 140 size_t __b = __bos(__d, 0);
141 size_t __sl, __dl; 141 size_t __sl, __dl;
142 142
143 if (__n > __b) { 143 __sl = strlen(__s);
144 __sl = strlen(__s); 144 __dl = strlen(__d);
145 __dl = strlen(__d); 145 if (__sl > __n)
146 if (__sl > __n) 146 __sl = __n;
147 __sl = __n; 147 if (__sl + __dl + 1 > __b)
148 if (__sl + __dl + 1 > __b) 148 __builtin_trap();
149 __builtin_trap();
150 }
151 return __orig_strncat(__d, __s, __n); 149 return __orig_strncat(__d, __s, __n);
152} 150}
153 151
diff --git a/include/wchar.h b/include/wchar.h
index 2036245..4346023 100644
--- a/include/wchar.h
+++ b/include/wchar.h
@@ -153,14 +153,12 @@ _FORTIFY_FN(wcsncat) wchar_t *wcsncat(wchar_t * _FORTIFY_POS0 __d,
153 size_t __b = __bos(__d, 0); 153 size_t __b = __bos(__d, 0);
154 size_t __sl, __dl; 154 size_t __sl, __dl;
155 155
156 if (__n > __b / sizeof(wchar_t)) { 156 __sl = wcslen(__s);
157 __sl = wcslen(__s); 157 __dl = wcslen(__d);
158 __dl = wcslen(__d); 158 if (__sl > __n)
159 if (__sl > __n) 159 __sl = __n;
160 __sl = __n; 160 if (__sl + __dl + 1 > __b / sizeof(wchar_t))
161 if (__sl + __dl + 1 > __b / sizeof(wchar_t)) 161 __builtin_trap();
162 __builtin_trap();
163 }
164 return __orig_wcsncat(__d, __s, __n); 162 return __orig_wcsncat(__d, __s, __n);
165} 163}
166 164
diff --git a/tests/Makefile b/tests/Makefile
index 6904b2d..9bedd16 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -84,6 +84,11 @@ RUNTIME_TARGETS= \
84 test_strlcpy_dynamic_write \ 84 test_strlcpy_dynamic_write \
85 test_strlcpy_static_write \ 85 test_strlcpy_static_write \
86 test_strncat_dynamic_write \ 86 test_strncat_dynamic_write \
87 test_strncat_n_eq_buf \
88 test_strncat_n_gt_buf \
89 test_strncat_n_lt_buf \
90 test_strncat_n_one \
91 test_strncat_safe \
87 test_strncat_static_write \ 92 test_strncat_static_write \
88 test_strncpy_dynamic_write \ 93 test_strncpy_dynamic_write \
89 test_strncpy_static_write \ 94 test_strncpy_static_write \
@@ -101,6 +106,11 @@ RUNTIME_TARGETS= \
101 test_wcsnrtombs_static \ 106 test_wcsnrtombs_static \
102 test_wcscat_static_write \ 107 test_wcscat_static_write \
103 test_wcscpy_static_write \ 108 test_wcscpy_static_write \
109 test_wcsncat_n_eq_buf \
110 test_wcsncat_n_gt_buf \
111 test_wcsncat_n_lt_buf \
112 test_wcsncat_n_one \
113 test_wcsncat_safe \
104 test_wcsncat_static_write \ 114 test_wcsncat_static_write \
105 test_wcsncpy_static_write \ 115 test_wcsncpy_static_write \
106 test_wmemcpy_dynamic_read \ 116 test_wmemcpy_dynamic_read \
diff --git a/tests/test_mbsnrtowcs_dynamic.c b/tests/test_mbsnrtowcs_dynamic.c
index 77b9082..58575d3 100644
--- a/tests/test_mbsnrtowcs_dynamic.c
+++ b/tests/test_mbsnrtowcs_dynamic.c
@@ -14,9 +14,7 @@ int main(int argc, char** argv) {
14 srcp = src; 14 srcp = src;
15 mbsnrtowcs(buffer, &srcp, 2, 2, &st); 15 mbsnrtowcs(buffer, &srcp, 2, 2, &st);
16 16
17 /* Unsafe: ask to write argc (10) wide chars into 4-element buffer. 17 /* Unsafe: ask to write argc (10) wide chars into 4-element buffer. */
18 * Before the fix, the else branch clamped source bytes instead of
19 * the output wide-char count, allowing destination overflow. */
20 CHK_FAIL_START 18 CHK_FAIL_START
21 srcp = src; 19 srcp = src;
22 memset(&st, 0, sizeof(st)); 20 memset(&st, 0, sizeof(st));
diff --git a/tests/test_strncat_dynamic_write.c b/tests/test_strncat_dynamic_write.c
index d5c5a94..c538339 100644
--- a/tests/test_strncat_dynamic_write.c
+++ b/tests/test_strncat_dynamic_write.c
@@ -7,11 +7,9 @@ int main(int argc, char** argv) {
7 strncat(buffer, "1234567", 5); 7 strncat(buffer, "1234567", 5);
8 puts(buffer); 8 puts(buffer);
9 9
10#if 0
11 CHK_FAIL_START 10 CHK_FAIL_START
12 strncat(buffer, argv[1], argc); 11 strncat(buffer, argv[1], argc);
13 CHK_FAIL_END 12 CHK_FAIL_END
14#endif
15 13
16 puts(buffer); 14 puts(buffer);
17 return ret; 15 return ret;
diff --git a/tests/test_strncat_n_eq_buf.c b/tests/test_strncat_n_eq_buf.c
new file mode 100644
index 0000000..bbc39d2
--- /dev/null
+++ b/tests/test_strncat_n_eq_buf.c
@@ -0,0 +1,18 @@
1#include "common.h"
2
3#include <string.h>
4
5int main(int argc, char** argv) {
6 char buffer[8] = {0};
7 strncat(buffer, "12345", 5);
8 puts(buffer);
9
10 /* n == buffer size but overflow due to existing content.
11 * buffer has 5 chars, src "ABC" (len 3): 5+3+1 = 9 > 8 → overflow. */
12 CHK_FAIL_START
13 strncat(buffer, "ABC", 8);
14 CHK_FAIL_END
15
16 puts(buffer);
17 return ret;
18}
diff --git a/tests/test_strncat_n_gt_buf.c b/tests/test_strncat_n_gt_buf.c
new file mode 100644
index 0000000..cca226b
--- /dev/null
+++ b/tests/test_strncat_n_gt_buf.c
@@ -0,0 +1,17 @@
1#include "common.h"
2
3#include <string.h>
4
5int main(int argc, char** argv) {
6 char buffer[8] = {0};
7 strncat(buffer, "12345", 5);
8 puts(buffer);
9
10 /* n > buffer size and overflow: n=10, buffer has 5 chars. */
11 CHK_FAIL_START
12 strncat(buffer, "1234567890", 10);
13 CHK_FAIL_END
14
15 puts(buffer);
16 return ret;
17}
diff --git a/tests/test_strncat_n_lt_buf.c b/tests/test_strncat_n_lt_buf.c
new file mode 100644
index 0000000..35a0ba1
--- /dev/null
+++ b/tests/test_strncat_n_lt_buf.c
@@ -0,0 +1,18 @@
1#include "common.h"
2
3#include <string.h>
4
5int main(int argc, char** argv) {
6 char buffer[8] = {0};
7 strncat(buffer, "12345", 5);
8 puts(buffer);
9
10 /* n < buffer size but overflow due to existing content.
11 * buffer has 5 chars, src "ABCD" (len 4), min(4,3)=3: 5+3+1 = 9 > 8. */
12 CHK_FAIL_START
13 strncat(buffer, "ABCD", 3);
14 CHK_FAIL_END
15
16 puts(buffer);
17 return ret;
18}
diff --git a/tests/test_strncat_n_one.c b/tests/test_strncat_n_one.c
new file mode 100644
index 0000000..fce46bd
--- /dev/null
+++ b/tests/test_strncat_n_one.c
@@ -0,0 +1,18 @@
1#include "common.h"
2
3#include <string.h>
4
5int main(int argc, char** argv) {
6 char buffer[8] = {0};
7 strncat(buffer, "1234567", 7);
8 puts(buffer);
9
10 /* n=1, buffer has 7 chars ("1234567").
11 * 7+1+1 = 9 > 8 → overflow. Even n=1 can overflow a nearly-full buffer. */
12 CHK_FAIL_START
13 strncat(buffer, "X", 1);
14 CHK_FAIL_END
15
16 puts(buffer);
17 return ret;
18}
diff --git a/tests/test_strncat_safe.c b/tests/test_strncat_safe.c
new file mode 100644
index 0000000..ff8cadd
--- /dev/null
+++ b/tests/test_strncat_safe.c
@@ -0,0 +1,34 @@
1#include "common.h"
2
3#include <string.h>
4
5int main(int argc, char** argv) {
6 char buffer[8] = {0};
7
8 /* Safe: empty buffer, append 7 chars with n=7 → "1234567\0" = exactly 8 bytes */
9 strncat(buffer, "1234567", 7);
10 puts(buffer);
11
12 /* Safe: reset and append with n larger than source.
13 * src is "AB" (len 2), n=100 → only 2 chars copied + NUL = 3 bytes */
14 buffer[0] = '\0';
15 strncat(buffer, "AB", 100);
16 puts(buffer);
17
18 /* Safe: partially filled, append fits exactly.
19 * buffer = "ABCD" (4 chars), append "EFG" with n=3 → 4+3+1 = 8 = exact fit */
20 buffer[0] = '\0';
21 strncat(buffer, "ABCD", 4);
22 strncat(buffer, "EFG", 3);
23 puts(buffer);
24
25 /* Safe: n limits copy to fit.
26 * buffer = "ABCDE" (5 chars), src = "FGHIJKLM" (8 chars), n=2 → 5+2+1 = 8 */
27 buffer[0] = '\0';
28 strncat(buffer, "ABCDE", 5);
29 strncat(buffer, "FGHIJKLM", 2);
30 puts(buffer);
31
32 /* All safe operations passed without trapping */
33 return 0;
34}
diff --git a/tests/test_strncat_static_write.c b/tests/test_strncat_static_write.c
index 7fe89ff..53d1532 100644
--- a/tests/test_strncat_static_write.c
+++ b/tests/test_strncat_static_write.c
@@ -4,15 +4,15 @@
4 4
5int main(int argc, char** argv) { 5int main(int argc, char** argv) {
6 char buffer[8] = {0}; 6 char buffer[8] = {0};
7 char src[] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'}; 7 strncat(buffer, "12345", 5);
8 strncat(buffer, src, 5);
9 puts(buffer); 8 puts(buffer);
10 9
11#if 0 10 /* n=4 is less than buffer size (8), but buffer already has 5 chars,
11 * so appending 4 more + NUL = 10 bytes total, overflowing the buffer.
12 */
12 CHK_FAIL_START 13 CHK_FAIL_START
13 strncat(buffer, src, 10); 14 strncat(buffer, "ABCD", 4);
14 CHK_FAIL_END 15 CHK_FAIL_END
15#endif
16 16
17 puts(buffer); 17 puts(buffer);
18 return ret; 18 return ret;
diff --git a/tests/test_wcsncat_n_eq_buf.c b/tests/test_wcsncat_n_eq_buf.c
new file mode 100644
index 0000000..e516842
--- /dev/null
+++ b/tests/test_wcsncat_n_eq_buf.c
@@ -0,0 +1,18 @@
1#include "common.h"
2
3#include <wchar.h>
4
5int main(int argc, char** argv) {
6 wchar_t buffer[8] = {0};
7 wcsncat(buffer, L"12345", 5);
8 printf("%ls\n", buffer);
9
10 /* n == buffer capacity but overflow due to existing content.
11 * buffer has 5 wchars, src L"ABC" (len 3): 5+3+1 = 9 > 8 → overflow. */
12 CHK_FAIL_START
13 wcsncat(buffer, L"ABC", 8);
14 CHK_FAIL_END
15
16 printf("%ls\n", buffer);
17 return ret;
18}
diff --git a/tests/test_wcsncat_n_gt_buf.c b/tests/test_wcsncat_n_gt_buf.c
new file mode 100644
index 0000000..186b8c0
--- /dev/null
+++ b/tests/test_wcsncat_n_gt_buf.c
@@ -0,0 +1,17 @@
1#include "common.h"
2
3#include <wchar.h>
4
5int main(int argc, char** argv) {
6 wchar_t buffer[8] = {0};
7 wcsncat(buffer, L"12345", 5);
8 printf("%ls\n", buffer);
9
10 /* n > buffer capacity and overflow: n=10, buffer has 5 wchars. */
11 CHK_FAIL_START
12 wcsncat(buffer, L"1234567890", 10);
13 CHK_FAIL_END
14
15 printf("%ls\n", buffer);
16 return ret;
17}
diff --git a/tests/test_wcsncat_n_lt_buf.c b/tests/test_wcsncat_n_lt_buf.c
new file mode 100644
index 0000000..99a42de
--- /dev/null
+++ b/tests/test_wcsncat_n_lt_buf.c
@@ -0,0 +1,18 @@
1#include "common.h"
2
3#include <wchar.h>
4
5int main(int argc, char** argv) {
6 wchar_t buffer[8] = {0};
7 wcsncat(buffer, L"12345", 5);
8 printf("%ls\n", buffer);
9
10 /* n < buffer capacity but overflow due to existing content.
11 * buffer has 5 wchars, src L"ABCD" (len 4), min(4,3)=3: 5+3+1 = 9 > 8. */
12 CHK_FAIL_START
13 wcsncat(buffer, L"ABCD", 3);
14 CHK_FAIL_END
15
16 printf("%ls\n", buffer);
17 return ret;
18}
diff --git a/tests/test_wcsncat_n_one.c b/tests/test_wcsncat_n_one.c
new file mode 100644
index 0000000..23de28e
--- /dev/null
+++ b/tests/test_wcsncat_n_one.c
@@ -0,0 +1,18 @@
1#include "common.h"
2
3#include <wchar.h>
4
5int main(int argc, char** argv) {
6 wchar_t buffer[8] = {0};
7 wcsncat(buffer, L"1234567", 7);
8 printf("%ls\n", buffer);
9
10 /* n=1, buffer has 7 wchars.
11 * 7+1+1 = 9 > 8 → overflow. Even n=1 can overflow a nearly-full buffer. */
12 CHK_FAIL_START
13 wcsncat(buffer, L"X", 1);
14 CHK_FAIL_END
15
16 printf("%ls\n", buffer);
17 return ret;
18}
diff --git a/tests/test_wcsncat_safe.c b/tests/test_wcsncat_safe.c
new file mode 100644
index 0000000..00fc8e6
--- /dev/null
+++ b/tests/test_wcsncat_safe.c
@@ -0,0 +1,34 @@
1#include "common.h"
2
3#include <wchar.h>
4
5int main(int argc, char** argv) {
6 wchar_t buffer[8] = {0};
7
8 /* Safe: empty buffer, append 7 wide chars → exactly fills buffer */
9 wcsncat(buffer, L"ABCDEFG", 7);
10 printf("%ls\n", buffer);
11
12 /* Safe: reset, append with n larger than source.
13 * src is L"AB" (len 2), n=100 → only 2 wchars copied */
14 buffer[0] = L'\0';
15 wcsncat(buffer, L"AB", 100);
16 printf("%ls\n", buffer);
17
18 /* Safe: partially filled, append fits exactly.
19 * buffer = L"ABCD" (4 wchars), append L"EFG" n=3 → 4+3+1 = 8 = exact fit */
20 buffer[0] = L'\0';
21 wcsncat(buffer, L"ABCD", 4);
22 wcsncat(buffer, L"EFG", 3);
23 printf("%ls\n", buffer);
24
25 /* Safe: n limits copy to fit.
26 * buffer = L"ABCDE" (5 wchars), src long, n=2 → 5+2+1 = 8 = exact fit */
27 buffer[0] = L'\0';
28 wcsncat(buffer, L"ABCDE", 5);
29 wcsncat(buffer, L"FGHIJKLM", 2);
30 printf("%ls\n", buffer);
31
32 /* All safe operations passed without trapping */
33 return 0;
34}
diff --git a/tests/test_wcsnrtombs_dynamic.c b/tests/test_wcsnrtombs_dynamic.c
index 808c9c8..28b03bf 100644
--- a/tests/test_wcsnrtombs_dynamic.c
+++ b/tests/test_wcsnrtombs_dynamic.c
@@ -14,9 +14,7 @@ int main(int argc, char** argv) {
14 srcp = src; 14 srcp = src;
15 wcsnrtombs(buffer, &srcp, 4, 4, &st); 15 wcsnrtombs(buffer, &srcp, 4, 4, &st);
16 16
17 /* Unsafe: ask to write argc (10) bytes into 8-byte buffer. 17 /* Unsafe: ask to write argc (10) bytes into 8-byte buffer. */
18 * Before the fix, the first branch incorrectly divided the byte-sized
19 * buffer capacity by sizeof(wchar_t), making the check too permissive. */
20 CHK_FAIL_START 18 CHK_FAIL_START
21 srcp = src; 19 srcp = src;
22 memset(&st, 0, sizeof(st)); 20 memset(&st, 0, sizeof(st));