From: Stefan Fritsch Date: Tue, 10 Jul 2012 20:19:03 +0000 (+0000) Subject: make varbuf functions treat AP_VARBUF_UNKNOWN consistently, improve docs X-Git-Tag: 2.5.0-alpha~6663 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0d77ab651bb66085fcda2a111f38ad8a008f5149;p=apache make varbuf functions treat AP_VARBUF_UNKNOWN consistently, improve docs ap_varbuf_pdup(): copying the whole buffer in case strlen == AP_VARBUF_UNKNOWN does not make sense as the caller can not set the exact buffer size, only a minimum. No API change as previously the behavior with AP_VARBUF_UNKNOWN was undocumented. regsub_core(): Checking for vb->buf is useless, it cannot be NULL unless ap_varbuf_init has not been called. ap_varbuf_cfg_getline(): Initially, allocate enough memory to hold an empty line. If strlen == AP_VARBUF_UNKNOWN, use strlen(buf) instead of undefined behavior. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1359884 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/include/util_varbuf.h b/include/util_varbuf.h index 1ae99f911e..cf4bc7ffe3 100644 --- a/include/util_varbuf.h +++ b/include/util_varbuf.h @@ -17,6 +17,14 @@ /** * @file util_varbuf.h * @brief Apache resizable variable length buffer library + * + * This set of functions provides resizable buffers. While the primary + * usage is with NUL-terminated strings, most functions also work with + * arbitrary binary data. + * + * @defgroup APACHE_CORE_VARBUF + * @ingroup APACHE_CORE + * @{ */ #ifndef AP_VARBUF_H @@ -36,7 +44,8 @@ struct ap_varbuf_info; /** A resizable buffer */ struct ap_varbuf { - /** the actual buffer; will point to a const '\0' if avail == 0 */ + /** the actual buffer; will point to a const '\0' if avail == 0 and + * to memory of the same lifetime as the pool otherwise */ char *buf; /** allocated size of the buffer (minus one for the final \0); @@ -49,7 +58,7 @@ struct ap_varbuf { apr_size_t strlen; /** the pool for memory allocations and for registering the cleanup; - * the buffer memory will be released when this pool is destroyed */ + * the buffer memory will be released when this pool is cleared */ apr_pool_t *pool; /** opaque info for memory allocation */ @@ -58,7 +67,8 @@ struct ap_varbuf { /** initialize a resizable buffer. It is safe to re-initialize a prevously * used ap_varbuf. The old buffer will be released when the corresponding - * pool is destroyed. + * pool is cleared. The buffer remains usable until the pool is cleared, + * even if the ap_varbuf was located on the stack and has gone out of scope. * @param pool the pool to allocate small buffers from and to register the * cleanup with * @param vb pointer to the ap_varbuf struct @@ -68,8 +78,8 @@ AP_DECLARE(void) ap_varbuf_init(apr_pool_t *pool, struct ap_varbuf *vb, apr_size_t init_size); /** grow a resizable buffer. If the vb->buf cannot be grown in place, it will - * be reallocated and up to vb->strlen + 1 bytes of memory will be copied to - * the new location. If vb->strlen == AP_VARBUF_UNKNOWN, the whole buffer + * be reallocated and the first vb->strlen + 1 bytes of memory will be copied + * to the new location. If vb->strlen == AP_VARBUF_UNKNOWN, the whole buffer * is copied. * @param vb pointer to the ap_varbuf struct * @param new_size the minimum new size of the buffer @@ -83,19 +93,22 @@ AP_DECLARE(void) ap_varbuf_grow(struct ap_varbuf *vb, apr_size_t new_size); /** Release memory from a ap_varbuf immediately, if possible. * This allows to free large buffers before the corresponding pool is - * destroyed. Only larger allocations using mem nodes will be freed. + * cleared. Only larger allocations using mem nodes will be freed. * @param vb pointer to the ap_varbuf struct * @note After ap_varbuf_free(), vb must not be used unless ap_varbuf_init() * is called again. */ AP_DECLARE(void) ap_varbuf_free(struct ap_varbuf *vb); -/** Concatenate a string to an ap_varbuf +/** Concatenate a string to an ap_varbuf. vb->strlen determines where + * the string is appended in the buffer. If vb->strlen == AP_VARBUF_UNKNOWN, + * the string will be appended at the first NUL byte in the buffer. + * If len == 0, ap_varbuf_strmemcat() does nothing. * @param vb pointer to the ap_varbuf struct * @param str the string to append; must be at least len bytes long * @param len the number of characters of *str to concatenate to the buf * @note vb->strlen will be set to the length of the new string - * @note vb->buf will be null-terminated + * @note if len != 0, vb->buf will always be NUL-terminated */ AP_DECLARE(void) ap_varbuf_strmemcat(struct ap_varbuf *vb, const char *str, int len); @@ -112,7 +125,9 @@ AP_DECLARE(void) ap_varbuf_strmemcat(struct ap_varbuf *vb, const char *str, * @return the new string * @note ap_varbuf_pdup() uses vb->strlen to determine how much memory to * copy. It works even if 0-bytes are embedded in vb->buf, prepend, or - * append + * append. + * @note If vb->strlen equals AP_VARBUF_UNKNOWN, it will be set to + * strlen(vb->buf). */ AP_DECLARE(char *) ap_varbuf_pdup(apr_pool_t *p, struct ap_varbuf *vb, const char *prepend, apr_size_t prepend_len, @@ -141,6 +156,8 @@ AP_DECLARE(char *) ap_varbuf_pdup(apr_pool_t *p, struct ap_varbuf *vb, * @note Just like ap_pregsub(), this function does not copy the part of * *source before the matching part (i.e. the first pmatch[0].rm_so * characters). + * @note If vb->strlen equals AP_VARBUF_UNKNOWN, it will be set to + * strlen(vb->buf) first. */ AP_DECLARE(apr_status_t) ap_varbuf_regsub(struct ap_varbuf *vb, const char *input, @@ -149,12 +166,14 @@ AP_DECLARE(apr_status_t) ap_varbuf_regsub(struct ap_varbuf *vb, ap_regmatch_t pmatch[], apr_size_t maxlen); -/** Read a line from an ap_configfile_t into an ap_varbuf. +/** Read a line from an ap_configfile_t and append it to an ap_varbuf. * @param vb pointer to the ap_varbuf struct * @param cfg pointer to the ap_configfile_t * @param max_len maximum line length, including leading/trailing whitespace * @return see ap_cfg_getline() * @note vb->strlen will be set to the length of the line + * @note If vb->strlen equals AP_VARBUF_UNKNOWN, it will be set to + * strlen(vb->buf) first. */ AP_DECLARE(apr_status_t) ap_varbuf_cfg_getline(struct ap_varbuf *vb, ap_configfile_t *cfp, @@ -165,3 +184,4 @@ AP_DECLARE(apr_status_t) ap_varbuf_cfg_getline(struct ap_varbuf *vb, #endif #endif /* !AP_VARBUF_H */ +/** @} */ diff --git a/server/util.c b/server/util.c index 5e2f107106..fd9425c789 100644 --- a/server/util.c +++ b/server/util.c @@ -427,7 +427,7 @@ static apr_status_t regsub_core(apr_pool_t *p, char **result, *result = dst = apr_palloc(p, len + 1); } else { - if (vb->buf && vb->strlen == AP_VARBUF_UNKNOWN) + if (vb->strlen == AP_VARBUF_UNKNOWN) vb->strlen = strlen(vb->buf); ap_varbuf_grow(vb, vb->strlen + len); dst = vb->buf + vb->strlen; @@ -1095,11 +1095,22 @@ AP_DECLARE(apr_status_t) ap_varbuf_cfg_getline(struct ap_varbuf *vb, apr_size_t max_len) { apr_status_t rc; + apr_size_t new_len; vb->strlen = 0; *vb->buf = '\0'; + if (vb->strlen == AP_VARBUF_UNKNOWN) + vb->strlen = strlen(vb->buf); + if (vb->avail - vb->strlen < 3) { + new_len = vb->avail * 2; + if (new_len > max_len) + new_len = max_len; + else if (new_len < 3) + new_len = 3; + ap_varbuf_grow(vb, new_len); + } + for (;;) { - apr_size_t new_len; rc = ap_cfg_getline_core(vb->buf + vb->strlen, vb->avail - vb->strlen, cfp); if (rc == APR_ENOSPC || rc == APR_SUCCESS) vb->strlen += strlen(vb->buf + vb->strlen); @@ -2585,6 +2596,8 @@ AP_DECLARE(void) ap_varbuf_grow(struct ap_varbuf *vb, apr_size_t new_len) struct ap_varbuf_info *new_info; char *new; + AP_DEBUG_ASSERT(vb->strlen == AP_VARBUF_UNKNOWN || vb->avail >= vb->strlen); + if (new_len <= vb->avail) return; @@ -2704,9 +2717,10 @@ AP_DECLARE(char *) ap_varbuf_pdup(apr_pool_t *p, struct ap_varbuf *buf, i++; } if (buf->avail && buf->strlen) { + if (buf->strlen == AP_VARBUF_UNKNOWN) + buf->strlen = strlen(buf->buf); vec[i].iov_base = (void *)buf->buf; - vec[i].iov_len = (buf->strlen == AP_VARBUF_UNKNOWN) ? buf->avail - : buf->strlen; + vec[i].iov_len = buf->strlen; i++; } if (append) {