+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]
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
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
#include <isc/string.h>
#include <isc/util.h>
+#include <stdarg.h>
+
void
isc__buffer_init(isc_buffer_t *b, void *base, unsigned int length) {
/*
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);
+}
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
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
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
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
* 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
/*
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
*/
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());
}