Merged revisions 176216 via svnmerge from
authorKevin P. Fleming <kpfleming@digium.com>
Mon, 16 Feb 2009 21:45:54 +0000 (21:45 +0000)
committerKevin P. Fleming <kpfleming@digium.com>
Mon, 16 Feb 2009 21:45:54 +0000 (21:45 +0000)
https://origsvn.digium.com/svn/asterisk/branches/1.4

........
  r176216 | kpfleming | 2009-02-16 15:10:38 -0600 (Mon, 16 Feb 2009) | 3 lines

  fix a flaw in the ast_string_field_build() family of API calls; these functions made no attempt to reuse the space already allocated to a field, so every time the field was written it would allocate new space, leading to what appeared to be a memory leak.
........
  r176254 | kpfleming | 2009-02-16 15:41:46 -0600 (Mon, 16 Feb 2009) | 3 lines

  correct a logic error in the last stringfields commit... don't mark additional space as allocated if the string was built using already-allocated space
........

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@176255 65c4cc65-6c06-0410-ace0-fbb531ad65f3

include/asterisk/stringfields.h
main/utils.c

index ded54a4..9c48bfd 100644 (file)
@@ -183,7 +183,7 @@ ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr
 */
 void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr,
                                  struct ast_string_field_pool **pool_head,
-                                 const ast_string_field *ptr, const char *format, ...) __attribute__((format(printf, 4, 5)));
+                                 ast_string_field *ptr, const char *format, ...) __attribute__((format(printf, 4, 5)));
 
 /*!
   \internal
@@ -198,7 +198,7 @@ void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr,
 */
 void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
                                     struct ast_string_field_pool **pool_head,
-                                    const ast_string_field *ptr, const char *format, va_list a1, va_list a2) __attribute__((format(printf, 4, 0)));
+                                    ast_string_field *ptr, const char *format, va_list a1, va_list a2) __attribute__((format(printf, 4, 0)));
 
 /*!
   \brief Declare a string field
@@ -287,7 +287,7 @@ int __ast_string_field_init(struct ast_string_field_mgr *mgr,
   \return nothing
 */
 #define ast_string_field_ptr_build(x, ptr, fmt, args...) \
-       __ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, ptr, fmt, args)
+       __ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) ptr, fmt, args)
 
 /*!
   \brief Set a field to a complex (built) value
@@ -298,7 +298,7 @@ int __ast_string_field_init(struct ast_string_field_mgr *mgr,
   \return nothing
 */
 #define ast_string_field_build(x, field, fmt, args...) \
-       __ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, &(x)->field, fmt, args)
+       __ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) &(x)->field, fmt, args)
 
 /*!
   \brief Set a field to a complex (built) value with prebuilt va_lists.
@@ -310,7 +310,7 @@ int __ast_string_field_init(struct ast_string_field_mgr *mgr,
   \return nothing
 */
 #define ast_string_field_ptr_build_va(x, ptr, fmt, args1, args2) \
-       __ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, ptr, fmt, args1, args2)
+       __ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) ptr, fmt, args1, args2)
 
 /*!
   \brief Set a field to a complex (built) value
@@ -322,6 +322,6 @@ int __ast_string_field_init(struct ast_string_field_mgr *mgr,
   \return nothing
 */
 #define ast_string_field_build_va(x, field, fmt, args1, args2) \
-       __ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, &(x)->field, fmt, args1, args2)
+       __ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) &(x)->field, fmt, args1, args2)
 
 #endif /* _ASTERISK_STRINGFIELDS_H */
index 61638f9..3a50289 100644 (file)
@@ -1587,38 +1587,58 @@ int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr, size_t needed,
 
 void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
                                     struct ast_string_field_pool **pool_head,
-                                    const ast_string_field *ptr, const char *format, va_list ap1, va_list ap2)
+                                    ast_string_field *ptr, const char *format, va_list ap1, va_list ap2)
 {
        size_t needed;
-       char *dst = (*pool_head)->base + mgr->used;
-       const char **p = (const char **) ptr;
+       size_t available;
        size_t space = mgr->size - mgr->used;
+       char *target;
 
-       /* try to write using available space */
-       needed = vsnprintf(dst, space, format, ap1) + 1;
-
-       va_end(ap1);
+       /* if the field already has space allocated, try to reuse it;
+          otherwise, use the empty space at the end of the current
+          pool
+       */
+       if ((*ptr)[0] != '0') {
+               target = (char *) *ptr;
+               available = strlen(target);
+       } else {
+               target = (*pool_head)->base + mgr->used;
+               available = space;
+       }
 
-       if (needed > space) {   /* if it fails, reallocate */
-               size_t new_size = mgr->size * 2;
+       needed = vsnprintf(target, available, format, ap1) + 1;
 
-               while (new_size < needed)
-                       new_size *= 2;
+       va_end(ap1);
 
-               if (add_string_pool(mgr, pool_head, new_size))
-                       return;
+       if (needed > available) {
+               /* if the space needed can be satisfied by using the current
+                  pool (which could only occur if we tried to use the field's
+                  allocated space and failed), then use that space; otherwise
+                  allocate a new pool
+               */
+               if (needed > space) {
+                       size_t new_size = mgr->size * 2;
+
+                       while (new_size < needed)
+                               new_size *= 2;
+                       
+                       if (add_string_pool(mgr, pool_head, new_size))
+                               return;
+               }
 
-               dst = (*pool_head)->base + mgr->used;
-               vsprintf(dst, format, ap2);
+               target = (*pool_head)->base + mgr->used;
+               vsprintf(target, format, ap2);
        }
 
-       mgr->last_alloc = *p = dst;
-       mgr->used += needed;
+       if (*ptr != target) {
+               mgr->last_alloc = *ptr = target;
+               mgr->used += needed;
+       }
 }
 
 void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr,
                                  struct ast_string_field_pool **pool_head,
-                                 const ast_string_field *ptr, const char *format, ...)
+                                 ast_string_field *ptr, const char *format, ...)
 {
        va_list ap1, ap2;