From nobody Mon Feb 9 01:16:39 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1532097878693115.99140752343408; Fri, 20 Jul 2018 07:44:38 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 454DA37E7B; Fri, 20 Jul 2018 14:44:37 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id EA19210021B1; Fri, 20 Jul 2018 14:44:36 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 846A24A464; Fri, 20 Jul 2018 14:44:36 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w6KEiMln021017 for ; Fri, 20 Jul 2018 10:44:22 -0400 Received: by smtp.corp.redhat.com (Postfix) id 7E7C92026D6B; Fri, 20 Jul 2018 14:44:22 +0000 (UTC) Received: from inaba.usersys.redhat.com (unknown [10.43.2.44]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 1FC772026D69 for ; Fri, 20 Jul 2018 14:44:21 +0000 (UTC) From: Andrea Bolognani To: libvir-list@redhat.com Date: Fri, 20 Jul 2018 16:44:13 +0200 Message-Id: <20180720144413.28226-9-abologna@redhat.com> In-Reply-To: <20180720144413.28226-1-abologna@redhat.com> References: <20180720144413.28226-1-abologna@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-loop: libvir-list@redhat.com Subject: [libvirt] [PATCH v2 8/8] util: Improve virStrncpy() implementation X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Fri, 20 Jul 2018 14:44:37 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" 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 --- docs/hacking.html.in | 29 ++++++++++----------- src/util/virstring.c | 62 ++++++++++++++++++++++++++++++-------------- 2 files changed, 55 insertions(+), 36 deletions(-) diff --git a/docs/hacking.html.in b/docs/hacking.html.in index 6c1a5121a4..f99d143b7b 100644 --- a/docs/hacking.html.in +++ b/docs/hacking.html.in @@ -1121,22 +1121,22 @@

Do not use the strncpy function. According to the man page, it does not 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:

=20
   virStrncpy(char *dest, const char *src, size_t n, size_t destbytes)
 

- 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 <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 <0 is returned instead.

=20
@@ -1144,10 +1144,8 @@
 

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) -

+ string into dest. +

=20
   virStrcpyStatic(char *dest, const char *src)
@@ -1157,8 +1155,7 @@
       string into dest and 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.
     

=20
diff --git a/src/util/virstring.c b/src/util/virstring.c
index 3e2f85465f..93fda69d7f 100644
--- a/src/util/virstring.c
+++ b/src/util/virstring.c
@@ -769,44 +769,66 @@ virAsprintfInternal(bool report,
 }
=20
 /**
- * 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 =3D 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 =3D=3D -1)
+        n =3D src_len;
+
+    if (n <=3D 0 || n > src_len || n > (destbytes - 1))
         return -1;
=20
-    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] =3D '\0';
=20
     return 0;
 }
=20
 /**
- * virStrcpy
+ * virStrcpy:
+ *
+ * @dest: destination buffer
+ * @src: source buffer
+ * @destbytes: number of bytes the destination can accomodate
+ *
+ * Copies @src to @dest.
+ *
+ * See virStrncpy() for more information.
  *
- * 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.
+ * 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);
 }
=20
 /**
--=20
2.17.1

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list