This is an automated email from the git hooks/post-receive script.
sparks pushed a commit to branch master
in repository defensive-coding-guide.
commit 78ee39cce1085890bdf65c4adf809643c98573f6
Author: Florian Weimer <fweimer(a)redhat.com>
Date: Thu Apr 11 15:39:38 2013 +0200
C: Split out snprintf into its own section and document return value
---
defensive-coding/en-US/C/Libc.xml | 154 ++++++++++++++-------
.../String-Functions-snprintf-incremental.xml | 14 ++
defensive-coding/src/C-String-Functions.c | 23 +++
3 files changed, 138 insertions(+), 53 deletions(-)
diff --git a/defensive-coding/en-US/C/Libc.xml b/defensive-coding/en-US/C/Libc.xml
index 6173bf0..1f16fee 100644
--- a/defensive-coding/en-US/C/Libc.xml
+++ b/defensive-coding/en-US/C/Libc.xml
@@ -169,59 +169,107 @@
<section id="sect-Defensive_Coding-C-String-Functions-Length">
<title>String Functions With Explicit Length Arguments</title>
<para>
- The <function>snprintf</function> function provides a way to
- construct a string in a statically-sized buffer. (If the buffer
- size is dynamic, use <function>asprintf</function> instead.)
- </para>
- <informalexample>
- <xi:include href="snippets/String-Functions-snprintf.xml"
-
xmlns:xi="http://www.w3.org/2001/XInclude" />
- </informalexample>
- <para>
- The second argument to the <function>snprintf</function> should
- always be the size of the buffer in the first argument (which
- should be a character array). Complex pointer and length
- arithmetic can introduce errors and nullify the security
- benefits of <function>snprintf</function>. If you need to
- construct a string iteratively, by repeatedly appending
- fragments, consider constructing the string on the heap,
- increasing the buffer with <function>realloc</function> as
- needed. (<function>snprintf</function> does not support
- overlapping the result buffer with argument strings.)
- </para>
- <para>
- If you use <function>vsnprintf</function> (or
- <function>snprintf</function>) with a format string which is not
- a constant, but a function argument, it is important to annotate
- the function with a <literal>format</literal> function
- attribute, so that GCC can warn about misuse of your function
- (see <xref
- linkend="ex-Defensive_Coding-C-String-Functions-format-Attribute"/>).
- </para>
- <example
id="ex-Defensive_Coding-C-String-Functions-format-Attribute">
- <title>The <literal>format</literal> function
attribute</title>
- <xi:include href="snippets/String-Functions-format.xml"
-
xmlns:xi="http://www.w3.org/2001/XInclude" />
- </example>
- <para>
- 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: <function>strncpy</function>,
- <function>strncat</function>, and
<function>stpncpy</function>.
- These functions do not ensure that the result string is
- NUL-terminated. For <function>strncpy</function>,
- NUL termination can be added this way:
- </para>
- <informalexample>
- <xi:include href="snippets/String-Functions-strncpy.xml"
-
xmlns:xi="http://www.w3.org/2001/XInclude" />
- </informalexample>
- <para>
- Some systems support <function>strlcpy</function> and
- <function>strlcat</function> functions which behave this way,
- but these functions are not part of GNU libc. Using
- <function>snprintf</function> with a suitable format string is a
- simple (albeit slightly slower) replacement.
+ The C run-time library provides string manipulation functions
+ which not just look for NUL characters for string termination,
+ but also honor explicit lengths provided by the caller.
+ However, these functions evolved over a long period of time, and
+ the lengths mean different things depending on the function.
</para>
+ <section id="sect-Defensive_Coding-C-Libc-snprintf">
+ <title><literal>snprintf</literal></title>
+ <para>
+ The <function>snprintf</function> function provides a way to
+ construct a string in a statically-sized buffer. (If the buffer
+ size is allocated on the heap, consider use
+ <function>asprintf</function> instead.)
+ </para>
+ <informalexample>
+ <xi:include href="snippets/String-Functions-snprintf.xml"
+
xmlns:xi="http://www.w3.org/2001/XInclude" />
+ </informalexample>
+ <para>
+ The second argument to the <function>snprintf</function> call
+ should always be the size of the buffer in the first argument
+ (which should be a character array). Elaborate pointer and
+ length arithmetic can introduce errors and nullify the
+ security benefits of <function>snprintf</function>.
+ </para>
+ <para>
+ In particular, <literal>snprintf</literal> is not well-suited
+ to constructing a string iteratively, by appending to an
+ existing buffer. <function>snprintf</function> returns one of
+ two values, <literal>-1</literal> on errors, or the number of
+ characters which <emphasis>would have been written to the
+ buffer if the buffer were large enough</emphasis>. This means
+ that adding the result of <function>snprintf</function> to the
+ buffer pointer to skip over the characters just written is
+ incorrect and risky. However, as long as the length argument
+ is not zero, the buffer will remain NUL-terminated. <xref
+ linkend="ex-Defensive_Coding-C-String-Functions-snprintf-incremental"/>
+ works because <literal>end -current > 0</literal> is a loop
+ invariant. After the loop, the result string is in the
+ <varname>buf</varname> variable.
+ </para>
+ <example
id="ex-Defensive_Coding-C-String-Functions-snprintf-incremental">
+ <title>Repeatedly writing to a buffer using
<function>snprintf</function></title>
+ <xi:include href="snippets/String-Functions-snprintf-incremental.xml"
+
xmlns:xi="http://www.w3.org/2001/XInclude" />
+ </example>
+ <para>
+ If you want to avoid the call to <function>strlen</function>
+ for performance reasons, you have to check for a negative
+ return value from <function>snprintf</function> and also check
+ if the return value is equal to the specified buffer length or
+ larger. Only if neither condition applies, you may advance
+ the pointer to the start of the write buffer by the number
+ return by <function>snprintf</function>. However, this
+ optimization is rarely worthwhile.
+ </para>
+ <para>
+ Note that it is not permitted to use the same buffer both as
+ the destination and as a source argument.
+ </para>
+ </section>
+ <section id="sect-Defensive_Coding-C-Libc-vsnprintf">
+ <title><literal>vsnprintf</literal> and format
strings</title>
+ <para>
+ If you use <function>vsnprintf</function> (or
+ <function>vasprintf</function> or even
+ <function>snprintf</function>) with a format string which is
+ not a constant, but a function argument, it is important to
+ annotate the function with a <literal>format</literal>
+ function attribute, so that GCC can warn about misuse of your
+ function (see <xref
+ linkend="ex-Defensive_Coding-C-String-Functions-format-Attribute"/>).
+ </para>
+ <example
id="ex-Defensive_Coding-C-String-Functions-format-Attribute">
+ <title>The <literal>format</literal> function attribute</title>
+ <xi:include href="snippets/String-Functions-format.xml"
+
xmlns:xi="http://www.w3.org/2001/XInclude" />
+ </example>
+ </section>
+ <section id="sect-Defensive_Coding-C-Libc-strncpy">
+ <title><function>strncpy</function> and related
functions</title>
+ <para>
+ 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: <function>strncpy</function>,
+ <function>strncat</function>, and <function>stpncpy</function>.
+ These functions do not ensure that the result string is
+ NUL-terminated. For <function>strncpy</function>,
+ NUL termination can be added this way:
+ </para>
+ <informalexample>
+ <xi:include href="snippets/String-Functions-strncpy.xml"
+
xmlns:xi="http://www.w3.org/2001/XInclude" />
+ </informalexample>
+ <para>
+ Some systems support <function>strlcpy</function> and
+ <function>strlcat</function> functions which behave this way,
+ but these functions are not part of GNU libc. Using
+ <function>snprintf</function> with a suitable format string is a
+ simple (albeit slightly slower) replacement.
+ </para>
+ </section>
</section>
</section>
diff --git a/defensive-coding/en-US/C/snippets/String-Functions-snprintf-incremental.xml
b/defensive-coding/en-US/C/snippets/String-Functions-snprintf-incremental.xml
new file mode 100644
index 0000000..5978684
--- /dev/null
+++ b/defensive-coding/en-US/C/snippets/String-Functions-snprintf-incremental.xml
@@ -0,0 +1,14 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE programlisting PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+]>
+<!-- Automatically generated file. Do not edit. -->
+<programlisting language="C">
+char buf[512];
+char *current = buf;
+const char *const end = buf + sizeof(buf);
+for (struct item *it = data; it->key; ++it) {
+ snprintf(current, end - current, "%s%s=%d",
+ current == buf ? "" : ", ", it->key,
it->value);
+ current += strlen(current);
+}
+</programlisting>
diff --git a/defensive-coding/src/C-String-Functions.c
b/defensive-coding/src/C-String-Functions.c
index b2139ac..3522eaa 100644
--- a/defensive-coding/src/C-String-Functions.c
+++ b/defensive-coding/src/C-String-Functions.c
@@ -2,6 +2,7 @@
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
+#include <stdbool.h>
static void
log_string(const char *s)
@@ -28,6 +29,28 @@ int
main(void)
{
{
+ struct item {
+ const char *key;
+ int value;
+ } data[] = {
+ {"key1", 17},
+ {"key2", 29},
+ {NULL, 0}
+ };
+
+ //+ C String-Functions-snprintf-incremental
+ char buf[512];
+ char *current = buf;
+ const char *const end = buf + sizeof(buf);
+ for (struct item *it = data; it->key; ++it) {
+ snprintf(current, end - current, "%s%s=%d",
+ current == buf ? "" : ", ", it->key, it->value);
+ current += strlen(current);
+ }
+ //-
+ puts(buf);
+ }
+ {
int numerator = 3, denominator = 4;
//+ C String-Functions-snprintf
char fraction[30];
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.