diff --git a/doc/developer/memtypes.rst b/doc/developer/memtypes.rst index e04049001d..952b316ea0 100644 --- a/doc/developer/memtypes.rst +++ b/doc/developer/memtypes.rst @@ -131,3 +131,10 @@ Usage - if ptr is NULL, no operation is performed (as is guaranteed by system implementations.) Do not surround XFREE with ``if (ptr != NULL)`` checks. + +.. c:function:: void XCOUNTFREE(struct memtype *mtype, void *ptr) + + This macro is used to count the ``ptr`` as freed without actually freeing + it. This may be needed in some very specific cases, for example, when the + ``ptr`` was allocated using any of the above wrappers and will be freed + by some external library using simple ``free()``. diff --git a/lib/memory.c b/lib/memory.c index f715044ea3..a377d3b945 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -127,6 +127,12 @@ void *qstrdup(struct memtype *mt, const char *str) return str ? mt_checkalloc(mt, strdup(str), strlen(str) + 1) : NULL; } +void qcountfree(struct memtype *mt, void *ptr) +{ + if (ptr) + mt_count_free(mt, ptr); +} + void qfree(struct memtype *mt, void *ptr) { if (ptr) diff --git a/lib/memory.h b/lib/memory.h index 13f2f9b11a..e9db12fce2 100644 --- a/lib/memory.h +++ b/lib/memory.h @@ -162,12 +162,15 @@ extern void *qrealloc(struct memtype *mt, void *ptr, size_t size) __attribute__((_ALLOC_SIZE(3), nonnull(1) _RET_NONNULL)); extern void *qstrdup(struct memtype *mt, const char *str) __attribute__((malloc, nonnull(1) _RET_NONNULL)); +extern void qcountfree(struct memtype *mt, void *ptr) + __attribute__((nonnull(1))); extern void qfree(struct memtype *mt, void *ptr) __attribute__((nonnull(1))); #define XMALLOC(mtype, size) qmalloc(mtype, size) #define XCALLOC(mtype, size) qcalloc(mtype, size) #define XREALLOC(mtype, ptr, size) qrealloc(mtype, ptr, size) #define XSTRDUP(mtype, str) qstrdup(mtype, str) +#define XCOUNTFREE(mtype, ptr) qcountfree(mtype, ptr) #define XFREE(mtype, ptr) \ do { \ qfree(mtype, ptr); \ diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index ace4139551..ef0dfccba9 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1144,12 +1144,10 @@ static char *command_generator(const char *text, int state) cmd_free_strvec(vline); } - if (matched && matched[index]) - /* - * this is free()'d by readline, but we leak 1 count of - * MTYPE_COMPLETION - */ + if (matched && matched[index]) { + XCOUNTFREE(MTYPE_COMPLETION, matched[index]); return matched[index++]; + } XFREE(MTYPE_TMP, matched); diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 7dcf019888..f35a8af4b9 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -485,8 +485,10 @@ void vtysh_config_dump(void) * are not under the VRF node. */ if (config->index == INTERFACE_NODE - && list_isempty(config->line)) + && list_isempty(config->line)) { + config_del(config); continue; + } vty_out(vty, "%s\n", config->name);