diff --git a/defensive-coding/en-US/C/Libc.xml b/defensive-coding/en-US/C/Libc.xml
index 1f16fee..970f5bf 100644
--- a/defensive-coding/en-US/C/Libc.xml
+++ b/defensive-coding/en-US/C/Libc.xml
@@ -249,26 +249,103 @@
- strncpy and related functions
+ strncpy
- There are other functions which operator on NUL-terminated
- strings and take a length argument which affects the number of
- bytes written to the destination: strncpy,
- strncat, and stpncpy.
- These functions do not ensure that the result string is
- NUL-terminated. For strncpy,
- NUL termination can be added this way:
+ The strncpy function does not ensure that
+ the target buffer is NUL-terminated. A common idiom for
+ ensuring NUL termination is:
+
+ Another approach uses the strncat
+ function for this purpose:
+
+
+
+
+
+
+ strncat
+
+ The length argument of the strncat
+ function specifies the maximum number of characters copied
+ from the source buffer, excluding the terminating NUL
+ character. This means that the required number of bytes in
+ the destination buffer is the length of the original string,
+ plus the length argument in the strncat
+ call, plus one. Consequently, this function is rarely
+ appropriate for performing a length-checked string operation,
+ with the notable exception of the strcpy
+ emulation described in .
+
+
+ To implement a length-checked string append, you can use an
+ approach similar to :
+
+
+
+
+
+ In many cases, including this one, the string concatenation
+ can be avoided by combining everything into a single format
+ string:
+
+
+
+
+
+ But you should must not dynamically construct format strings
+ to avoid concatenation because this would prevent GCC from
+ type-checking the argument lists.
+
+
+ It is not possible to use format strings like
+ "%s%s" to implement concatenation, unless
+ you use separate buffers. snprintf does
+ not support overlapping source and target strings.
+
+
+
+ strlcpy and
+ strlcat
Some systems support strlcpy and
strlcat functions which behave this way,
- but these functions are not part of GNU libc. Using
- snprintf with a suitable format string is a
- simple (albeit slightly slower) replacement.
+ but these functions are not part of GNU libc.
+ strlcpy is often replaced with
+ snprintf with a "%s"
+ format string. See for a caveat
+ related to the snprintf return value.
+
+
+ To emulate strlcat, use the approach
+ described in .
+
+
+
+ ISO C11 Annex K *_s functions
+
+ ISO C11 adds another set of length-checking functions, but GNU
+ libc currently does not implement them.
+
+
+
+ Other strn* and
+ stpn* functions
+
+ GNU libc contains additional functions with different variants
+ of length checking. Consult the documentation before using
+ them to find out what the length actually means.
diff --git a/defensive-coding/en-US/C/snippets/String-Functions-strncat-as-strncpy.xml b/defensive-coding/en-US/C/snippets/String-Functions-strncat-as-strncpy.xml
new file mode 100644
index 0000000..0895eaf
--- /dev/null
+++ b/defensive-coding/en-US/C/snippets/String-Functions-strncat-as-strncpy.xml
@@ -0,0 +1,8 @@
+
+
+
+
+buf[0] = '\0';
+strncpy(buf, data, sizeof(buf) - 1);
+
diff --git a/defensive-coding/en-US/C/snippets/String-Functions-strncat-emulation.xml b/defensive-coding/en-US/C/snippets/String-Functions-strncat-emulation.xml
new file mode 100644
index 0000000..12f5437
--- /dev/null
+++ b/defensive-coding/en-US/C/snippets/String-Functions-strncat-emulation.xml
@@ -0,0 +1,9 @@
+
+
+
+
+char buf[10];
+snprintf(buf, sizeof(buf), "%s", prefix);
+snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s", data);
+
diff --git a/defensive-coding/en-US/C/snippets/String-Functions-strncat-merged.xml b/defensive-coding/en-US/C/snippets/String-Functions-strncat-merged.xml
new file mode 100644
index 0000000..3deaa94
--- /dev/null
+++ b/defensive-coding/en-US/C/snippets/String-Functions-strncat-merged.xml
@@ -0,0 +1,7 @@
+
+
+
+
+snprintf(buf, sizeof(buf), "%s%s", prefix, data);
+
diff --git a/defensive-coding/src/C-String-Functions.c b/defensive-coding/src/C-String-Functions.c
index 3522eaa..34d9c31 100644
--- a/defensive-coding/src/C-String-Functions.c
+++ b/defensive-coding/src/C-String-Functions.c
@@ -68,5 +68,24 @@ main(void)
//-
assert(strlen(buf) == 9);
assert(strncmp(buf, data, 9) == 0);
+ //+ C String-Functions-strncat-as-strncpy
+ buf[0] = '\0';
+ strncpy(buf, data, sizeof(buf) - 1);
+ //-
+ }
+ {
+ const char *const prefix = "prefix";
+ const char *const data = " suffix";
+
+ //+ C String-Functions-strncat-emulation
+ char buf[10];
+ snprintf(buf, sizeof(buf), "%s", prefix);
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s", data);
+ //-
+ puts(buf);
+ //+ C String-Functions-strncat-merged
+ snprintf(buf, sizeof(buf), "%s%s", prefix, data);
+ //-
+ puts(buf);
}
}