<p>George Joseph has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/10612">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">vector:  Add options for alternate memory management<br><br>The vector implementation has been using the ast_calloc, ast_free,<br>and ast_malloc functions for memory management but there are<br>situations where the vector may be used to process error or<br>backtrace information where an error in the ast_ MM functions<br>could cause a recursive error situation.<br><br>* Added an ast_calloc_ptr function that, regardless of MALLOC_DEBUG,<br>  always points to a real function and not a macro.<br><br>* Added an ast_std_strdup function that always calls the libc strdup<br>  function regardless of MALLOC_DEBUG.  Will be needed for a<br>  follow-on commit.<br><br>* Added 3 virtual function pointers for calloc, free and element<br>  cleanup to the vector structures.  AST_VECTOR_INIT defaults these<br>  to ast_calloc_ptr, ast_free_ptr and NULL respectively.  This<br>  preserves existing behavior.<br><br>* All places in vector.h that had called the ast_ functions<br>  directly now use the virtual function pointers instead.<br><br>* A new macro AST_VECTOR_INIT_MM_FN() allows the caller to specify<br>  the 3 new functions.  The element cleanup function is optional.<br><br>* Two new macros AST_VECTOR_CLEANUP and AST_VECTOR_PTR_CLEANUP will<br>  use the 3 virtual functions to...<br>    1. Cleanup all elements in the vector (provided the element<br>       cleanup function was specified in AST_VECTOR_INIT_MM_FN)<br>    2. Use the free virtual function to free the internal "elems"<br>       array.<br>    3. For AST_VECTOR_PTR_CLEANUP, use the free virtual function to<br>       free the externally allocated vector structure itself.<br><br>* cli.c was using a calloc'd vector without having called<br>  AST_VECTOR_INIT() which used to be effectively safe but was never<br>  technically correct.  It now calls AST_VECTOR_INIT.<br><br>* optional_api.c was using a vector without having called<br>  AST_VECTOR_INIT() on it.  Needed to add init() and atexit()<br>  routines to do the work.<br><br>Example where a function must return a vector that doesn't use the<br>ast_ memory management functions.  Error checking omitted for<br>brevity.<br><br>struct ast_vector_string *get_somevector()<br>{<br> struct ast_vector_string *strings = ast_std_malloc(sizeof(*strings));<br> AST_VECTOR_INIT_MM_FN(strings, 0, ast_std_calloc, ast_std_free,<br>          ast_std_free);<br>     AST_VECTOR_APPEND(strings, ast_std_strdup(somestring1);<br>       AST_VECTOR_APPEND(strings, ast_std_strdup(somestring2);<br>       AST_VECTOR_APPEND(strings, ast_std_strdup(somestring3);<br>       return strings;<br>}<br><br>In this case, the ast_std_calloc function will be used to allocate<br>the vector's elements array.<br><br>void myfunc()<br>{<br>        int i;<br>        struct ast_vector_string *strings = get_somevector();<br> for (i = 0; i < AST_VECTOR_SIZE(strings); i++) {<br>           AST_LOG(LOG_ERROR, "%s\n", AST_VECTOR_GET(strings, i));<br>     }<br>     AST_VECTOR_PTR_CLEANUP(strings);<br>}<br><br>Notice that myfunc() doesn't have to worry about how either<br>the vector itself or the elements were allocated.  It just<br>calls AST_VECTOR_PTR_CLEANUP() and that macro uses ast_std_free<br>to free the elements, the internal "elems" array, and the vector<br>structure itself.<br><br>Change-Id: I0d871dfed9ce215fd11aa03e7d6cfaf385b55597<br>---<br>M include/asterisk/_private.h<br>M include/asterisk/astmm.h<br>M include/asterisk/vector.h<br>M main/asterisk.c<br>M main/astmm.c<br>M main/cli.c<br>M main/optional_api.c<br>7 files changed, 145 insertions(+), 11 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/12/10612/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/asterisk/_private.h b/include/asterisk/_private.h</span><br><span>index d954768..71f5a5b 100644</span><br><span>--- a/include/asterisk/_private.h</span><br><span>+++ b/include/asterisk/_private.h</span><br><span>@@ -56,6 +56,7 @@</span><br><span> void ast_msg_shutdown(void);        /*!< Provided by message.c */</span><br><span> int aco_init(void);             /*!< Provided by config_options.c */</span><br><span> int dns_core_init(void);        /*!< Provided by dns_core.c */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_optional_api_init(void);        /*!< Provided by optional_api.c */</span><br><span> </span><br><span> /*!</span><br><span>  * \brief Initialize malloc debug phase 1.</span><br><span>diff --git a/include/asterisk/astmm.h b/include/asterisk/astmm.h</span><br><span>index e1f91dd..8b66fca 100644</span><br><span>--- a/include/asterisk/astmm.h</span><br><span>+++ b/include/asterisk/astmm.h</span><br><span>@@ -34,6 +34,7 @@</span><br><span> void *ast_std_malloc(size_t size) attribute_malloc;</span><br><span> void *ast_std_calloc(size_t nmemb, size_t size) attribute_malloc;</span><br><span> void *ast_std_realloc(void *ptr, size_t size);</span><br><span style="color: hsl(120, 100%, 40%);">+char *ast_std_strdup(const char *ptr);</span><br><span> void ast_std_free(void *ptr);</span><br><span> </span><br><span> /*!</span><br><span>@@ -44,6 +45,14 @@</span><br><span>  */</span><br><span> void ast_free_ptr(void *ptr);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief calloc() wrapper</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * ast_calloc_ptr should be used when a function pointer for calloc() needs to be passed</span><br><span style="color: hsl(120, 100%, 40%);">+ * as the argument to a function. Otherwise, astmm will cause seg faults.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void *ast_calloc_ptr(size_t nmemb, size_t size);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> void *__ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func) attribute_malloc;</span><br><span> void *__ast_calloc_cache(size_t nmemb, size_t size, const char *file, int lineno, const char *func) attribute_malloc;</span><br><span> void *__ast_malloc(size_t size, const char *file, int lineno, const char *func) attribute_malloc;</span><br><span>diff --git a/include/asterisk/vector.h b/include/asterisk/vector.h</span><br><span>index d1b2973..61ddcc3 100644</span><br><span>--- a/include/asterisk/vector.h</span><br><span>+++ b/include/asterisk/vector.h</span><br><span>@@ -35,6 +35,9 @@</span><br><span>  * \since 12</span><br><span>  */</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+typedef void *(*_calloc_fn)(size_t count, size_t len);</span><br><span style="color: hsl(120, 100%, 40%);">+typedef void (*_free_fn)(void *ptr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*!</span><br><span>  * \brief Define a vector structure</span><br><span>  *</span><br><span>@@ -46,6 +49,9 @@</span><br><span>          type *elems;                    \</span><br><span>            size_t max;                     \</span><br><span>            size_t current;                 \</span><br><span style="color: hsl(120, 100%, 40%);">+             _calloc_fn calloc_fn; \</span><br><span style="color: hsl(120, 100%, 40%);">+               _free_fn free_fn; \</span><br><span style="color: hsl(120, 100%, 40%);">+           _free_fn elem_cleanup_fn; \</span><br><span>  }</span><br><span> </span><br><span> /*! \brief Integer vector definition */</span><br><span>@@ -96,6 +102,9 @@</span><br><span>                size_t max;          \</span><br><span>               size_t current;      \</span><br><span>               ast_rwlock_t lock;   \</span><br><span style="color: hsl(120, 100%, 40%);">+                _calloc_fn calloc_fn; \</span><br><span style="color: hsl(120, 100%, 40%);">+               _free_fn free_fn; \</span><br><span style="color: hsl(120, 100%, 40%);">+           _free_fn elem_cleanup_fn; \</span><br><span>  }</span><br><span> </span><br><span> /*!</span><br><span>@@ -113,7 +122,44 @@</span><br><span> #define AST_VECTOR_INIT(vec, size) ({                                    \</span><br><span>    size_t __size = (size);                                         \</span><br><span>    size_t alloc_size = __size * sizeof(*((vec)->elems));                \</span><br><span style="color: hsl(0, 100%, 40%);">-       (vec)->elems = alloc_size ? ast_calloc(1, alloc_size) : NULL;        \</span><br><span style="color: hsl(120, 100%, 40%);">+     (vec)->calloc_fn = (ast_calloc_ptr); \</span><br><span style="color: hsl(120, 100%, 40%);">+     (vec)->free_fn = (ast_free_ptr); \</span><br><span style="color: hsl(120, 100%, 40%);">+ (vec)->elem_cleanup_fn = NULL; \</span><br><span style="color: hsl(120, 100%, 40%);">+   (vec)->elems = alloc_size ? (vec)->calloc_fn(1, alloc_size) : NULL;       \</span><br><span style="color: hsl(120, 100%, 40%);">+     (vec)->current = 0;                                          \</span><br><span style="color: hsl(120, 100%, 40%);">+     if ((vec)->elems) {                                          \</span><br><span style="color: hsl(120, 100%, 40%);">+             (vec)->max = __size;                                 \</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {                                                        \</span><br><span style="color: hsl(120, 100%, 40%);">+             (vec)->max = 0;                                              \</span><br><span style="color: hsl(120, 100%, 40%);">+     }                                                               \</span><br><span style="color: hsl(120, 100%, 40%);">+     (alloc_size == 0 || (vec)->elems != NULL) ? 0 : -1;          \</span><br><span style="color: hsl(120, 100%, 40%);">+})</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Initialize a vector with specified memory management functions</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * If \a size is 0, then no space will be allocated until the vector is</span><br><span style="color: hsl(120, 100%, 40%);">+ * appended to.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This macro is primarily intended for use by functions that return vectors.</span><br><span style="color: hsl(120, 100%, 40%);">+ * It enables them to hide the details of memory management and element cleanup.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param vec Vector to initialize.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param size Initial size of the vector.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param calloc_fn The zero-fill allocation function.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param free_fn The free function.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param elem_cleanup_fn An optional element cleanup function.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return 0 on success.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return Non-zero on failure.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#define AST_VECTOR_INIT_MM_FN(vec, size, __calloc_fn, __free_fn, __elem_cleanup_fn) ({                                       \</span><br><span style="color: hsl(120, 100%, 40%);">+     size_t __size = (size);                                         \</span><br><span style="color: hsl(120, 100%, 40%);">+     size_t alloc_size = __size * sizeof(*((vec)->elems));                \</span><br><span style="color: hsl(120, 100%, 40%);">+     (vec)->calloc_fn = (__calloc_fn); \</span><br><span style="color: hsl(120, 100%, 40%);">+        (vec)->free_fn = (__free_fn); \</span><br><span style="color: hsl(120, 100%, 40%);">+    (vec)->elem_cleanup_fn = (__elem_cleanup_fn); \</span><br><span style="color: hsl(120, 100%, 40%);">+    (vec)->elems = alloc_size ? (vec)->calloc_fn(1, alloc_size) : NULL;       \</span><br><span>    (vec)->current = 0;                                          \</span><br><span>    if ((vec)->elems) {                                          \</span><br><span>            (vec)->max = __size;                                 \</span><br><span>@@ -172,7 +218,9 @@</span><br><span>  * \param vec Vector to deallocate.</span><br><span>  */</span><br><span> #define AST_VECTOR_FREE(vec) do {              \</span><br><span style="color: hsl(0, 100%, 40%);">-       ast_free((vec)->elems);                      \</span><br><span style="color: hsl(120, 100%, 40%);">+     if ((vec)->free_fn) { \</span><br><span style="color: hsl(120, 100%, 40%);">+            (vec)->free_fn((vec)->elems); \</span><br><span style="color: hsl(120, 100%, 40%);">+ } \</span><br><span>  (vec)->elems = NULL;                 \</span><br><span>    (vec)->max = 0;                              \</span><br><span>    (vec)->current = 0;                  \</span><br><span>@@ -187,8 +235,45 @@</span><br><span>  * \param vec Pointer to a malloc'd vector structure.</span><br><span>  */</span><br><span> #define AST_VECTOR_PTR_FREE(vec) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+       _free_fn ff = (vec)->free_fn; \</span><br><span>   AST_VECTOR_FREE(vec); \</span><br><span style="color: hsl(0, 100%, 40%);">- ast_free(vec); \</span><br><span style="color: hsl(120, 100%, 40%);">+      if (ff) { \</span><br><span style="color: hsl(120, 100%, 40%);">+           ff(vec); \</span><br><span style="color: hsl(120, 100%, 40%);">+    } \</span><br><span style="color: hsl(120, 100%, 40%);">+} while (0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Completely deallocates this vector using the element cleanup function.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * If no element_cleanup_fn was supplied when this vector was initialized, a simple</span><br><span style="color: hsl(120, 100%, 40%);">+ * AST_VECTOR_FREE is done.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param vec Pointer to a vector structure.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#define AST_VECTOR_CLEANUP(vec) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+        size_t __idx; \</span><br><span style="color: hsl(120, 100%, 40%);">+       if ((vec)->elem_cleanup_fn) { \</span><br><span style="color: hsl(120, 100%, 40%);">+            for (__idx = 0; __idx < (vec)->current; __idx++) { \</span><br><span style="color: hsl(120, 100%, 40%);">+                    (vec)->elem_cleanup_fn((vec)->elems[__idx]); \</span><br><span style="color: hsl(120, 100%, 40%);">+          } \</span><br><span style="color: hsl(120, 100%, 40%);">+   } \</span><br><span style="color: hsl(120, 100%, 40%);">+   AST_VECTOR_FREE(vec); \</span><br><span style="color: hsl(120, 100%, 40%);">+} while (0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Completely deallocates this malloc'd vector using the element cleanup function.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * If no element_cleanup_fn was supplied when this vector was initialized, a simple</span><br><span style="color: hsl(120, 100%, 40%);">+ * AST_VECTOR_PTR_FREE is done.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param vec Pointer to a malloc'd vector structure.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#define AST_VECTOR_PTR_CLEANUP(vec) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+  _free_fn ff = (vec)->free_fn; \</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_VECTOR_CLEANUP(vec); \</span><br><span style="color: hsl(120, 100%, 40%);">+    if (ff) { \</span><br><span style="color: hsl(120, 100%, 40%);">+           ff(vec); \</span><br><span style="color: hsl(120, 100%, 40%);">+    } \</span><br><span> } while (0)</span><br><span> </span><br><span> /*!</span><br><span>@@ -213,8 +298,11 @@</span><br><span>  * \param vec Pointer to a malloc'd vector structure.</span><br><span>  */</span><br><span> #define AST_VECTOR_RW_PTR_FREE(vec) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+        _free_fn ff = (vec)->free_fn; \</span><br><span>   AST_VECTOR_RW_FREE(vec); \</span><br><span style="color: hsl(0, 100%, 40%);">-      ast_free(vec); \</span><br><span style="color: hsl(120, 100%, 40%);">+      if (ff) { \</span><br><span style="color: hsl(120, 100%, 40%);">+           ff(vec); \</span><br><span style="color: hsl(120, 100%, 40%);">+    } \</span><br><span> } while(0)</span><br><span> </span><br><span> /*!</span><br><span>@@ -225,7 +313,7 @@</span><br><span>   do {                                                                                                            \</span><br><span>            if ((idx) >= (vec)->max) {                                                                \</span><br><span>                    size_t new_max = ((idx) + 1) * 2;                               \</span><br><span style="color: hsl(0, 100%, 40%);">-                       typeof((vec)->elems) new_elems = ast_calloc(1,               \</span><br><span style="color: hsl(120, 100%, 40%);">+                     typeof((vec)->elems) new_elems = (vec)->calloc_fn(1,              \</span><br><span>                            new_max * sizeof(*new_elems));                                  \</span><br><span>                    if (new_elems) {                                                                        \</span><br><span>                            if ((vec)->elems) {                                                          \</span><br><span>@@ -744,6 +832,8 @@</span><br><span>  * elements in a new vector</span><br><span>  *</span><br><span>  * This macro basically provides a filtered clone.</span><br><span style="color: hsl(120, 100%, 40%);">+ * The memory management functions used for the clone will be the same as the</span><br><span style="color: hsl(120, 100%, 40%);">+ * source vector.</span><br><span>  *</span><br><span>  * \param vec Vector to operate on.</span><br><span>  * \param callback A callback that takes at least 1 argument (the element)</span><br><span>@@ -791,12 +881,13 @@</span><br><span>      size_t idx; \</span><br><span>        typeof((vec)) new_vec; \</span><br><span>     do { \</span><br><span style="color: hsl(0, 100%, 40%);">-          new_vec = ast_malloc(sizeof(*new_vec)); \</span><br><span style="color: hsl(120, 100%, 40%);">+             new_vec = (vec)->calloc_fn(1, sizeof(*new_vec)); \</span><br><span>                if (!new_vec) { \</span><br><span>                    break; \</span><br><span>             } \</span><br><span style="color: hsl(0, 100%, 40%);">-             if (AST_VECTOR_INIT(new_vec, AST_VECTOR_SIZE((vec))) != 0) { \</span><br><span style="color: hsl(0, 100%, 40%);">-                  ast_free(new_vec); \</span><br><span style="color: hsl(120, 100%, 40%);">+          if (AST_VECTOR_INIT_MM_FN(new_vec, AST_VECTOR_SIZE((vec)), (vec)->calloc_fn, \</span><br><span style="color: hsl(120, 100%, 40%);">+                     (vec)->free_fn, (vec)->elem_cleanup_fn) != 0) { \</span><br><span style="color: hsl(120, 100%, 40%);">+                       (vec)->free_fn(new_vec); \</span><br><span>                        new_vec = NULL; \</span><br><span>                    break; \</span><br><span>             } \</span><br><span>diff --git a/main/asterisk.c b/main/asterisk.c</span><br><span>index 3354724..28c6321 100644</span><br><span>--- a/main/asterisk.c</span><br><span>+++ b/main/asterisk.c</span><br><span>@@ -4108,6 +4108,7 @@</span><br><span> </span><br><span>     ast_autoservice_init();</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+   check_init(ast_optional_api_init(), "Optional API");</span><br><span>       check_init(ast_timing_init(), "Timing");</span><br><span>   check_init(ast_ssl_init(), "SSL");</span><br><span>         read_pjproject_startup_options();</span><br><span>diff --git a/main/astmm.c b/main/astmm.c</span><br><span>index c845ee7..76c1a5f 100644</span><br><span>--- a/main/astmm.c</span><br><span>+++ b/main/astmm.c</span><br><span>@@ -1752,6 +1752,11 @@</span><br><span>      return realloc(ptr, size);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+char *ast_std_strdup(const char *ptr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return strdup(ptr);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> void ast_std_free(void *ptr)</span><br><span> {</span><br><span>        free(ptr);</span><br><span>@@ -1761,3 +1766,8 @@</span><br><span> {</span><br><span>      ast_free(ptr);</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void *ast_calloc_ptr(size_t nmemb, size_t size)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     return ast_calloc(nmemb, size);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/main/cli.c b/main/cli.c</span><br><span>index cf51d0d..1331dea 100644</span><br><span>--- a/main/cli.c</span><br><span>+++ b/main/cli.c</span><br><span>@@ -2534,7 +2534,7 @@</span><br><span>      char *retstr, *prevstr;</span><br><span>      size_t max_equal;</span><br><span>    size_t which = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-       struct ast_vector_string *vec = ast_calloc(1, sizeof(*vec));</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_vector_string *vec = ast_malloc(sizeof(*vec));</span><br><span> </span><br><span>        /* Recursion into this function is a coding error. */</span><br><span>        ast_assert(!ast_threadstorage_get_ptr(&completion_storage));</span><br><span>@@ -2543,6 +2543,8 @@</span><br><span>             return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_INIT(vec, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>   if (ast_threadstorage_set_ptr(&completion_storage, vec)) {</span><br><span>               ast_log(LOG_ERROR, "Failed to initialize threadstorage for completion.\n");</span><br><span>                ast_free(vec);</span><br><span>@@ -2607,8 +2609,7 @@</span><br><span>       return vec;</span><br><span> </span><br><span> vector_cleanup:</span><br><span style="color: hsl(0, 100%, 40%);">-      AST_VECTOR_CALLBACK_VOID(vec, ast_free);</span><br><span style="color: hsl(0, 100%, 40%);">-        AST_VECTOR_PTR_FREE(vec);</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_VECTOR_PTR_CLEANUP(vec);</span><br><span> </span><br><span>     return NULL;</span><br><span> }</span><br><span>diff --git a/main/optional_api.c b/main/optional_api.c</span><br><span>index d63129c..75e0b22 100644</span><br><span>--- a/main/optional_api.c</span><br><span>+++ b/main/optional_api.c</span><br><span>@@ -18,6 +18,7 @@</span><br><span> </span><br><span> #include "asterisk.h"</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/_private.h"</span><br><span> #include "asterisk/optional_api.h"</span><br><span> #include "asterisk/utils.h"</span><br><span> #include "asterisk/vector.h"</span><br><span>@@ -143,6 +144,7 @@</span><br><span>                 return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_INIT(&api->users, 0);</span><br><span>      strcpy(api->symname, symname); /* SAFE */</span><br><span> </span><br><span>     return api;</span><br><span>@@ -267,4 +269,23 @@</span><br><span>           }</span><br><span>    }</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #endif /* defined(OPTIONAL_API) */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void optional_api_shutdown(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef OPTIONAL_API</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_VECTOR_CLEANUP(&apis);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_optional_api_init(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef OPTIONAL_API</span><br><span style="color: hsl(120, 100%, 40%);">+  AST_VECTOR_INIT(&apis, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_register_cleanup(optional_api_shutdown);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/10612">change 10612</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/10612"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 16 </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I0d871dfed9ce215fd11aa03e7d6cfaf385b55597 </div>
<div style="display:none"> Gerrit-Change-Number: 10612 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: George Joseph <gjoseph@digium.com> </div>