util: Improve virStrncpy() implementation

We finally get rid of the strncpy()-like semantics
and implement our own, more sensible ones instead.

As a bonus, this also fixes compilation on MinGW.

Signed-off-by: Andrea Bolognani <abologna@redhat.com>
This commit is contained in:
Andrea Bolognani 2018-07-20 13:00:44 +02:00
parent 19136bbf10
commit 7d70a63b94
2 changed files with 55 additions and 36 deletions

View File

@ -1121,22 +1121,22 @@
<p>
Do not use the strncpy function. According to the man page, it
does <b>not</b> guarantee a NULL-terminated buffer, which makes
it extremely dangerous to use. Instead, use one of the
functionally equivalent functions:
it extremely dangerous to use. Instead, use one of the replacement
functions provided by libvirt:
</p>
<pre>
virStrncpy(char *dest, const char *src, size_t n, size_t destbytes)
</pre>
<p>
The first three arguments have the same meaning as for strncpy;
namely the destination, source, and number of bytes to copy,
respectively. The last argument is the number of bytes
available in the destination string; if a copy of the source
string (including a \0) will not fit into the destination, no
bytes are copied and the routine returns &lt;0. Otherwise, n
bytes from the source are copied into the destination and a
trailing \0 is appended.
The first two arguments have the same meaning as for strncpy,
namely the destination and source of the copy operation. Unlike
strncpy, the function will always copy exactly the number of bytes
requested and make sure the destination is NULL-terminated, as the
source is required to be; sanity checks are performed to ensure the
size of the destination, as specified by the last argument, is
sufficient for the operation to succeed. On success, 0 is returned;
on failure, a value &lt;0 is returned instead.
</p>
<pre>
@ -1144,10 +1144,8 @@
</pre>
<p>
Use this variant if you know you want to copy the entire src
string into dest. Note that this is a macro, so arguments could
be evaluated more than once. This is equivalent to
virStrncpy(dest, src, strlen(src), destbytes)
</p>
string into dest.
</p>
<pre>
virStrcpyStatic(char *dest, const char *src)
@ -1157,8 +1155,7 @@
string into dest <b>and</b> you know that your destination string is
a static string (i.e. that sizeof(dest) returns something
meaningful). Note that this is a macro, so arguments could be
evaluated more than once. This is equivalent to
virStrncpy(dest, src, strlen(src), sizeof(dest)).
evaluated more than once.
</p>
<pre>

View File

@ -769,44 +769,66 @@ virAsprintfInternal(bool report,
}
/**
* virStrncpy
* virStrncpy:
*
* A safe version of strncpy. The last parameter is the number of bytes
* available in the destination string, *not* the number of bytes you want
* to copy. If the destination is not large enough to hold all n of the
* src string bytes plus a \0, <0 is returned and no data is copied.
* If the destination is large enough to hold the n bytes plus \0, then the
* string is copied and 0 is returned.
* @dest: destination buffer
* @src: source buffer
* @n: number of bytes to copy
* @destbytes: number of bytes the destination can accomodate
*
* Copies the first @n bytes of @src to @dest.
*
* @src must be NULL-terminated; if successful, @dest is guaranteed to
* be NULL-terminated as well.
*
* @n must be a reasonable value, that is, it must not exceed either
* the length of @src or the size of @dest. For the latter constraint,
* the fact that @dest needs to accomodate a NULL byte in addition to
* the bytes copied from @src must be taken into account.
*
* If you want to copy *all* of @src to @dest, use virStrcpy() or
* virStrcpyStatic() instead.
*
* Returns: 0 on success, <0 on failure.
*/
int
virStrncpy(char *dest, const char *src, size_t n, size_t destbytes)
{
if (n > (destbytes - 1))
size_t src_len = strlen(src);
/* As a special case, -1 means "copy the entire string".
*
* This is to avoid calling strlen() twice, once in the virStrcpy()
* wrapper and once here for bound checking purposes. */
if (n == -1)
n = src_len;
if (n <= 0 || n > src_len || n > (destbytes - 1))
return -1;
strncpy(dest, src, n);
/* strncpy NULL terminates iff the last character is \0. Therefore
* force the last byte to be \0
*/
memcpy(dest, src, n);
dest[n] = '\0';
return 0;
}
/**
* virStrcpy
* virStrcpy:
*
* A safe version of strcpy. The last parameter is the number of bytes
* available in the destination string, *not* the number of bytes you want
* to copy. If the destination is not large enough to hold all n of the
* src string bytes plus a \0, <0 is returned and no data is copied.
* If the destination is large enough to hold the source plus \0, then the
* string is copied and 0 is returned.
* @dest: destination buffer
* @src: source buffer
* @destbytes: number of bytes the destination can accomodate
*
* Copies @src to @dest.
*
* See virStrncpy() for more information.
*
* Returns: 0 on success, <0 on failure.
*/
int
virStrcpy(char *dest, const char *src, size_t destbytes)
{
return virStrncpy(dest, src, strlen(src), destbytes);
return virStrncpy(dest, src, -1, destbytes);
}
/**