refactor: introduce XFREE_CLEAR()

Unfortunately we cannot indiscriminately replace xfree() with
XFREE_CLEAR(), because comparing pointers after freeing them is a common
pattern. Example in `tv_list_remove_items()`:

    xfree(li);
    if (li == item2) {
      break;
    }

Instead we can do it selectively/explicitly.

ref #1375
This commit is contained in:
Justin M. Keyes 2019-05-22 00:10:35 +02:00
parent 4769deb36a
commit a9d7ec4587
8 changed files with 33 additions and 20 deletions

View File

@ -72,7 +72,7 @@
*top++ = (b)->root; \
while (top != stack) { \
x = *--top; \
if (x->is_internal == 0) { xfree(x); continue; } \
if (x->is_internal == 0) { XFREE_CLEAR(x); continue; } \
for (i = 0; i <= x->n; ++i) \
if (__KB_PTR(b, x)[i]) { \
if (top - stack == (int)max) { \
@ -82,10 +82,10 @@
} \
*top++ = __KB_PTR(b, x)[i]; \
} \
xfree(x); \
XFREE_CLEAR(x); \
} \
} \
xfree(stack); \
XFREE_CLEAR(stack); \
} while (0)
#define __KB_GET_AUX1(name, key_t, kbnode_t, __cmp) \
@ -253,7 +253,7 @@
memmove(&__KB_KEY(key_t, x)[i], &__KB_KEY(key_t, x)[i + 1], (unsigned int)(x->n - i - 1) * sizeof(key_t)); \
memmove(&__KB_PTR(b, x)[i + 1], &__KB_PTR(b, x)[i + 2], (unsigned int)(x->n - i - 1) * sizeof(void*)); \
--x->n; \
xfree(z); \
XFREE_CLEAR(z); \
return __kb_delp_aux_##name(b, y, k, s); \
} \
} \
@ -281,7 +281,7 @@
memmove(&__KB_KEY(key_t, x)[i - 1], &__KB_KEY(key_t, x)[i], (unsigned int)(x->n - i) * sizeof(key_t)); \
memmove(&__KB_PTR(b, x)[i], &__KB_PTR(b, x)[i + 1], (unsigned int)(x->n - i) * sizeof(void*)); \
--x->n; \
xfree(xp); \
XFREE_CLEAR(xp); \
xp = y; \
} else if (i < x->n && (y = __KB_PTR(b, x)[i + 1])->n == T - 1) { \
__KB_KEY(key_t, xp)[xp->n++] = __KB_KEY(key_t, x)[i]; \
@ -291,7 +291,7 @@
memmove(&__KB_KEY(key_t, x)[i], &__KB_KEY(key_t, x)[i + 1], (unsigned int)(x->n - i - 1) * sizeof(key_t)); \
memmove(&__KB_PTR(b, x)[i + 1], &__KB_PTR(b, x)[i + 2], (unsigned int)(x->n - i - 1) * sizeof(void*)); \
--x->n; \
xfree(y); \
XFREE_CLEAR(y); \
} \
} \
return __kb_delp_aux_##name(b, xp, k, s); \
@ -306,7 +306,7 @@
--b->n_nodes; \
x = b->root; \
b->root = __KB_PTR(b, x)[0]; \
xfree(x); \
XFREE_CLEAR(x); \
} \
return ret; \
} \

View File

@ -181,7 +181,7 @@ typedef khint_t khiter_t;
#define krealloc(P,Z) xrealloc(P,Z)
#endif
#ifndef kfree
#define kfree(P) xfree(P)
#define kfree(P) XFREE_CLEAR(P)
#endif
#define __ac_HASH_UPPER 0.77

View File

@ -46,9 +46,9 @@
static inline void kmp_destroy_##name(kmp_##name##_t *mp) { \
size_t k; \
for (k = 0; k < mp->n; k++) { \
kmpfree_f(mp->buf[k]); xfree(mp->buf[k]); \
kmpfree_f(mp->buf[k]); XFREE_CLEAR(mp->buf[k]); \
} \
xfree(mp->buf); xfree(mp); \
XFREE_CLEAR(mp->buf); XFREE_CLEAR(mp); \
} \
static inline kmptype_t *kmp_alloc_##name(kmp_##name##_t *mp) { \
mp->cnt++; \
@ -100,7 +100,7 @@
} \
kmp_free(name, kl->mp, p); \
kmp_destroy(name, kl->mp); \
xfree(kl); \
XFREE_CLEAR(kl); \
} \
static inline void kl_push_##name(kl_##name##_t *kl, kltype_t d) { \
kl1_##name *q, *p = kmp_alloc(name, kl->mp); \

View File

@ -58,7 +58,7 @@
}
#define kv_init(v) ((v).size = (v).capacity = 0, (v).items = 0)
#define kv_destroy(v) xfree((v).items)
#define kv_destroy(v) XFREE_CLEAR((v).items)
#define kv_A(v, i) ((v).items[(i)])
#define kv_pop(v) ((v).items[--(v).size])
#define kv_size(v) ((v).size)
@ -138,7 +138,7 @@ static inline void *_memcpy_free(void *const restrict dest,
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET FUNC_ATTR_ALWAYS_INLINE
{
memcpy(dest, src, size);
xfree(src);
XFREE_CLEAR(src);
return dest;
}
@ -201,7 +201,7 @@ static inline void *_memcpy_free(void *const restrict dest,
#define kvi_destroy(v) \
do { \
if ((v).items != (v).init_array) { \
xfree((v).items); \
XFREE_CLEAR((v).items); \
} \
} while (0)

View File

@ -136,14 +136,14 @@ static inline void funcprefix##_rb_free(TypeName##RingBuffer *const rb) \
RINGBUF_FORALL(rb, RBType, rbitem) { \
rbfree(rbitem); \
} \
xfree(rb->buf); \
XFREE_CLEAR(rb->buf); \
} \
\
static inline void funcprefix##_rb_dealloc(TypeName##RingBuffer *const rb) \
REAL_FATTR_UNUSED; \
static inline void funcprefix##_rb_dealloc(TypeName##RingBuffer *const rb) \
{ \
xfree(rb->buf); \
XFREE_CLEAR(rb->buf); \
} \
\
static inline void funcprefix##_rb_push(TypeName##RingBuffer *const rb, \

View File

@ -110,6 +110,8 @@ void *xmalloc(size_t size)
}
/// free() wrapper that delegates to the backing memory manager
///
/// @note Use XFREE_CLEAR() instead, if possible.
void xfree(void *ptr)
{
free(ptr);

View File

@ -40,4 +40,15 @@ extern bool entered_free_all_mem;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "memory.h.generated.h"
#endif
#define XFREE_CLEAR(ptr) \
do { \
/* Take the address to avoid double evaluation. #1375 */ \
void **ptr_ = (void **)&(ptr); \
xfree(*ptr_); \
/* coverity[dead-store] */ \
*ptr_ = NULL; \
(void)(*ptr_); \
} while (0)
#endif // NVIM_MEMORY_H

View File

@ -148,10 +148,10 @@ describe('autocmd', function()
funcs.execute('autocmd Tabnew'))
end)
it('window works', function()
-- Nvim uses a special window to execute certain actions for an invisible buffer,
-- internally called autcmd_win and mentioned in the docs at :help E813
-- Do some safety checks for redrawing and api accesses to this window.
it('internal `aucmd_win` window', function()
-- Nvim uses a special internal window `aucmd_win` to execute certain
-- actions for an invisible buffer (:help E813).
-- Check redrawing and API accesses to this window.
local screen = Screen.new(50, 10)
screen:attach()