]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
[master] Add isc_buffer_printf()
authorMichał Kępień <michal@isc.org>
Mon, 9 Oct 2017 09:43:07 +0000 (11:43 +0200)
committerMichał Kępień <michal@isc.org>
Mon, 9 Oct 2017 09:43:07 +0000 (11:43 +0200)
4767. [func] Add a new function, isc_buffer_printf(), which can be
used to append a formatted string to the used region of
a buffer. [RT #46201]

CHANGES
bin/named/unix/os.c
lib/dns/dst_api.c
lib/isc/buffer.c
lib/isc/httpd.c
lib/isc/include/isc/buffer.h
lib/isc/tests/buffer_test.c

diff --git a/CHANGES b/CHANGES
index 28e7a721e4178b6f94565b83974adbd18101f0b0..d6d9913315320bc318723a551032fec0ef1a548c 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,7 @@
+4767.  [func]          Add a new function, isc_buffer_printf(), which can be
+                       used to append a formatted string to the used region of
+                       a buffer. [RT #46201]
+
 4766.  [cleanup]       Addresss Coverity warnings. [RT #46150]
 
 4765.  [bug]           Address potential INSIST in dnssec-cds. [RT #46150]
index 7b2ae1e9f21e9a0d12b7c383db4ab998be2de3ed..56f52c44bcea345f2aff98ab24d2e906570b6066 100644 (file)
@@ -1036,12 +1036,7 @@ named_os_shutdownmsg(char *command, isc_buffer_t *text) {
        pid = getpid();
 #endif
 
-       n = snprintf((char *)isc_buffer_used(text),
-                    isc_buffer_availablelength(text),
-                    "pid: %ld", (long)pid);
-       /* Only send a message if it is complete. */
-       if (n > 0 && n < isc_buffer_availablelength(text))
-               isc_buffer_add(text, n);
+       (void)isc_buffer_printf(text, "pid: %ld", (long)pid);
 }
 
 void
index 76212bf5aad18e5f8b6c3e19033a1d211d5164b3..3a5de99b90e3f47e0c1ff66d6d5bdb694847ec22 100644 (file)
@@ -1875,15 +1875,8 @@ buildfilename(dns_name_t *name, dns_keytag_t id,
        result = dns_name_tofilenametext(name, ISC_FALSE, out);
        if (result != ISC_R_SUCCESS)
                return (result);
-       len = 1 + 3 + 1 + 5 + strlen(suffix) + 1;
-       if (isc_buffer_availablelength(out) < len)
-               return (ISC_R_NOSPACE);
-       snprintf((char *) isc_buffer_used(out),
-                (int)isc_buffer_availablelength(out),
-                "+%03d+%05d%s", alg, id, suffix);
-       isc_buffer_add(out, len);
 
-       return (ISC_R_SUCCESS);
+       return (isc_buffer_printf(out, "+%03d+%05d%s", alg, id, suffix));
 }
 
 static isc_result_t
index 95b5c5ec28f6d0967804c3cf623ad97b2ded24e2..8c635da7855cb1260d89d2948e4969a18c685e15 100644 (file)
@@ -17,6 +17,8 @@
 #include <isc/string.h>
 #include <isc/util.h>
 
+#include <stdarg.h>
+
 void
 isc__buffer_init(isc_buffer_t *b, void *base, unsigned int length) {
        /*
@@ -633,3 +635,37 @@ isc_buffer_free(isc_buffer_t **dynbuffer) {
        isc_buffer_invalidate(dbuf);
        isc_mem_put(mctx, dbuf, sizeof(isc_buffer_t));
 }
+
+isc_result_t
+isc_buffer_printf(isc_buffer_t *b, const char *format, ...) {
+       va_list ap;
+       int n;
+       isc_result_t result;
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+
+       va_start(ap, format);
+       n = vsnprintf(NULL, 0, format, ap);
+       va_end(ap);
+
+       if (n < 0) {
+               return (ISC_R_FAILURE);
+       }
+
+       result = isc_buffer_reserve(&b, n + 1);
+       if (result != ISC_R_SUCCESS) {
+               return (result);
+       }
+
+       va_start(ap, format);
+       n = vsnprintf(isc_buffer_used(b), n + 1, format, ap);
+       va_end(ap);
+
+       if (n < 0) {
+               return (ISC_R_FAILURE);
+       }
+
+       b->used += n;
+
+       return (ISC_R_SUCCESS);
+}
index 9cb33889732cfc50d9c4fb672930bf741497802f..b8971a4a5744b6a87739c1530f4d849509eed3e3 100644 (file)
@@ -1046,13 +1046,9 @@ isc_httpd_response(isc_httpd_t *httpd) {
                        return (result);
        }
 
-       snprintf(isc_buffer_used(&httpd->headerbuffer),
-                (int)isc_buffer_availablelength(&httpd->headerbuffer),
-                "%s %03u %s\r\n", httpd->protocol, httpd->retcode,
-                httpd->retmsg);
-       isc_buffer_add(&httpd->headerbuffer, needlen);
-
-       return (ISC_R_SUCCESS);
+       return (isc_buffer_printf(&httpd->headerbuffer, "%s %03u %s\r\n",
+                                  httpd->protocol, httpd->retcode,
+                                  httpd->retmsg));
 }
 
 isc_result_t
@@ -1073,18 +1069,13 @@ isc_httpd_addheader(isc_httpd_t *httpd, const char *name,
                        return (result);
        }
 
-       if (val != NULL)
-               snprintf(isc_buffer_used(&httpd->headerbuffer),
-                        isc_buffer_availablelength(&httpd->headerbuffer),
-                        "%s: %s\r\n", name, val);
-       else
-               snprintf(isc_buffer_used(&httpd->headerbuffer),
-                        isc_buffer_availablelength(&httpd->headerbuffer),
-                        "%s\r\n", name);
-
-       isc_buffer_add(&httpd->headerbuffer, needlen);
-
-       return (ISC_R_SUCCESS);
+       if (val != NULL) {
+               return (isc_buffer_printf(&httpd->headerbuffer, "%s: %s\r\n",
+                                          name, val));
+       } else {
+               return (isc_buffer_printf(&httpd->headerbuffer, "%s\r\n",
+                                          name));
+       }
 }
 
 isc_result_t
@@ -1097,11 +1088,7 @@ isc_httpd_endheaders(isc_httpd_t *httpd) {
                        return (result);
        }
 
-       snprintf(isc_buffer_used(&httpd->headerbuffer),
-                isc_buffer_availablelength(&httpd->headerbuffer), "\r\n");
-       isc_buffer_add(&httpd->headerbuffer, 2);
-
-       return (ISC_R_SUCCESS);
+       return (isc_buffer_printf(&httpd->headerbuffer, "\r\n"));
 }
 
 isc_result_t
@@ -1122,13 +1109,8 @@ isc_httpd_addheaderuint(isc_httpd_t *httpd, const char *name, int val) {
                        return (result);
        }
 
-       snprintf(isc_buffer_used(&httpd->headerbuffer),
-                isc_buffer_availablelength(&httpd->headerbuffer),
-                "%s: %s\r\n", name, buf);
-
-       isc_buffer_add(&httpd->headerbuffer, needlen);
-
-       return (ISC_R_SUCCESS);
+       return (isc_buffer_printf(&httpd->headerbuffer, "%s: %s\r\n", name,
+                                  buf));
 }
 
 static void
index 3ed8f204d9564faa1b222ea8c6a4189c36670025..ae9fc412b83a9f4c0160b796310dbb49744cc6e1 100644 (file)
@@ -741,6 +741,38 @@ isc_buffer_dup(isc_mem_t *mctx, isc_buffer_t **dstp, const isc_buffer_t *src);
  *                                     big enough.
  */
 
+isc_result_t
+isc_buffer_printf(isc_buffer_t *b, const char *format, ...)
+       ISC_FORMAT_PRINTF(2, 3);
+/*!<
+ * \brief Append a formatted string to the used region of 'b'.
+ *
+ * Notes:
+ *
+ *\li  The 'format' argument is a printf(3) string, with additional arguments
+ *     as necessary.
+ *
+ *\li  If 'b' has autoreallocation enabled, and the formatted string
+ *     would overrun the buffer, the buffer is reallocated.
+ *
+ * Requires:
+ *
+ *\li  'b' is a valid buffer.
+ *
+ * Ensures:
+ *
+ *\li  The used pointer in 'b' is advanced by the number of bytes appended
+ *     (excluding the terminating NULL byte).
+ *
+ * Returns:
+ *
+ *\li  #ISC_R_SUCCESS  Operation succeeded.
+ *\li  #ISC_R_NOSPACE  'b' does not allow reallocation and appending the
+ *                     formatted string to it would cause it to overflow.
+ *\li  #ISC_R_NOMEMORY Reallocation failed.
+ *\li  #ISC_R_FAILURE  Other error occurred.
+ */
+
 ISC_LANG_ENDDECLS
 
 /*
index c9c36abc8bc0e6407a4a1a7258a40e135bf5e814..0b3156ff876d701b55e72158986c2eea6827cd06 100644 (file)
@@ -189,6 +189,125 @@ ATF_TC_BODY(isc_buffer_dynamic, tc) {
        isc_test_end();
 }
 
+ATF_TC(isc_buffer_printf);
+ATF_TC_HEAD(isc_buffer_printf, tc) {
+       atf_tc_set_md_var(tc, "descr", "printf() into a buffer");
+}
+
+ATF_TC_BODY(isc_buffer_printf, tc) {
+       const char *bad_fmt, *empty_fmt;
+       unsigned int used, prev_used;
+       isc_result_t result;
+       isc_buffer_t *b, sb;
+       char buf[8];
+
+       result = isc_test_begin(NULL, ISC_TRUE);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       /*
+        * Prepare a buffer with auto-reallocation enabled.
+        */
+       b = NULL;
+       result = isc_buffer_allocate(mctx, &b, 0);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+       isc_buffer_setautorealloc(b, ISC_TRUE);
+
+       /*
+        * Sanity check.
+        */
+       result = isc_buffer_printf(b, "foo");
+       ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+       used = isc_buffer_usedlength(b);
+       ATF_CHECK_EQ(used, 3);
+
+       result = isc_buffer_printf(b, "bar");
+       ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+       used = isc_buffer_usedlength(b);
+       ATF_CHECK_EQ(used, 3 + 3);
+
+       /*
+        * Also check the terminating NULL byte is there, even though it is not
+        * part of the buffer's used region.
+        */
+       ATF_CHECK_EQ(memcmp(isc_buffer_current(b), "foobar", 7), 0);
+
+       /*
+        * Skip over data from previous check to prevent failures in previous
+        * check from affecting this one.
+        */
+       prev_used = used;
+       isc_buffer_forward(b, prev_used);
+
+       /*
+        * Some standard usage checks.
+        */
+       isc_buffer_printf(b, "%d", 42);
+       used = isc_buffer_usedlength(b);
+       ATF_CHECK_EQ(used - prev_used, 2);
+
+       isc_buffer_printf(b, "baz%1X", 42);
+       used = isc_buffer_usedlength(b);
+       ATF_CHECK_EQ(used - prev_used, 2 + 5);
+
+       isc_buffer_printf(b, "%6.1f", 42.42f);
+       used = isc_buffer_usedlength(b);
+       ATF_CHECK_EQ(used - prev_used, 2 + 5 + 6);
+
+       /*
+        * Also check the terminating NULL byte is there, even though it is not
+        * part of the buffer's used region.
+        */
+       ATF_CHECK_EQ(memcmp(isc_buffer_current(b), "42baz2A  42.4", 14), 0);
+
+       /*
+        * Check an empty format string is properly handled.
+        */
+       prev_used = used;
+       empty_fmt = "";
+       result = isc_buffer_printf(b, empty_fmt, NULL);
+       ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+       used = isc_buffer_usedlength(b);
+       ATF_CHECK_EQ(prev_used, used);
+
+       /*
+        * Ensure vsnprintf() errors do not cause the buffer to be modified.
+        */
+       prev_used = used;
+       bad_fmt = "%";
+       result = isc_buffer_printf(b, bad_fmt, NULL);
+       ATF_CHECK_EQ(result, ISC_R_FAILURE);
+       used = isc_buffer_usedlength(b);
+       ATF_CHECK_EQ(prev_used, used);
+
+       isc_buffer_free(&b);
+
+       /*
+        * Check overflow on a static buffer.
+        */
+       isc_buffer_init(&sb, buf, sizeof(buf));
+       result = isc_buffer_printf(&sb, "123456");
+       ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+       used = isc_buffer_usedlength(&sb);
+       ATF_CHECK_EQ(used, 6);
+
+       result = isc_buffer_printf(&sb, "789");
+       ATF_CHECK_EQ(result, ISC_R_NOSPACE);
+       used = isc_buffer_usedlength(&sb);
+       ATF_CHECK_EQ(used, 6);
+
+       result = isc_buffer_printf(&sb, "78");
+       ATF_CHECK_EQ(result, ISC_R_NOSPACE);
+       used = isc_buffer_usedlength(&sb);
+       ATF_CHECK_EQ(used, 6);
+
+       result = isc_buffer_printf(&sb, "7");
+       ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+       used = isc_buffer_usedlength(&sb);
+       ATF_CHECK_EQ(used, 7);
+
+       isc_test_end();
+}
+
 /*
  * Main
  */
@@ -196,5 +315,6 @@ ATF_TP_ADD_TCS(tp) {
        ATF_TP_ADD_TC(tp, isc_buffer_reserve);
        ATF_TP_ADD_TC(tp, isc_buffer_reallocate);
        ATF_TP_ADD_TC(tp, isc_buffer_dynamic);
+       ATF_TP_ADD_TC(tp, isc_buffer_printf);
        return (atf_no_error());
 }