Skip to content

Commit

Permalink
mem/q_malloc: add support for debug history
Browse files Browse the repository at this point in the history
By setting a size via the QM_DBG_MALLOC_HIST define, we now keep a
history of the file, func, line debug information in each fragment.

(cherry picked from commit bc3e62f)
  • Loading branch information
rvlad-patrascu committed Sep 6, 2022
1 parent c2da73f commit 691c96e
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 23 deletions.
4 changes: 2 additions & 2 deletions mem/q_malloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ static void qm_debug_frag(struct qm_block *qm, struct qm_frag *f)
(PREV_FRAG_END(f)->check2!=END_CHECK_PATTERN2) ) ){
LM_CRIT(" qm_*: prev. fragm. tail overwritten(%lx, %lx)[%p:%p] (%s, %s:%ld)!\n",
PREV_FRAG_END(f)->check1, PREV_FRAG_END(f)->check2, f,
(char*)f+sizeof(struct qm_frag), FRAG_PREV(f)->func,
FRAG_PREV(f)->file,FRAG_PREV(f)->line);
(char*)f+sizeof(struct qm_frag),
qm_dbg_coords(FRAG_PREV(f)));
abort();
}
}
Expand Down
52 changes: 46 additions & 6 deletions mem/q_malloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,56 @@
* QM_ROUNDTO from bucket to bucket
* +1 .... end - size = 2^k, big buckets */

#ifdef DBG_MALLOC
#ifndef QM_DBG_MALLOC_HIST
#define QM_DBG_MALLOC_HIST 1
#endif
struct qm_frag_dbg {
const char* file;
const char* func;
unsigned long line;
};

#define qm_dbg_coords(_frag) \
(_frag)->dbg[0].file, (_frag)->dbg[0].func, (_frag)->dbg[0].line
#else
#define qm_dbg_coords(_frag)
#endif

#ifdef DBG_MALLOC
#if QM_DBG_MALLOC_HIST > 1
#define qm_dbg_move(_frag) \
memmove(&(_frag)->dbg[1], &(_frag)->dbg[0], \
(QM_DBG_MALLOC_HIST - 1) * sizeof(struct qm_frag_dbg))
#define qm_dbg_clear(_frag) \
memset(&(_frag)->dbg[1], 0, \
(QM_DBG_MALLOC_HIST - 1) * sizeof(struct qm_frag_dbg))
#else /* QM_DBG_MALLOC_HIST */
#define qm_dbg_move(_frag)
#define qm_dbg_clear(_frag)
#endif /* QM_DBG_MALLOC_HIST */
#define qm_dbg_fill(_frag, _file, _func, _line) \
do { \
qm_dbg_move(_frag); \
(_frag)->dbg[0].file = _file; \
(_frag)->dbg[0].func = _func; \
(_frag)->dbg[0].line = _line; \
} while(0)

#else /* DBG_MALLOC */
#define qm_dbg_fill(_frag, _file, _func, _line)
#define qm_dbg_clear(_frag)
#endif /* DBG_MALLOC */


struct qm_frag {
unsigned long size;
union {
struct qm_frag *nxt_free;
long is_free;
} u;
#ifdef DBG_MALLOC
const char *file;
const char *func;
unsigned long line;
struct qm_frag_dbg dbg[QM_DBG_MALLOC_HIST];
unsigned long check;
#endif
#ifdef SHM_EXTRA_STATS
Expand Down Expand Up @@ -158,9 +198,9 @@ unsigned long qm_stats_get_index(void *ptr);
void qm_stats_set_index(void *ptr, unsigned long idx);

#ifdef DBG_MALLOC
static inline const char *qm_frag_file(void *p) { return QM_FRAG(p)->file; }
static inline const char *qm_frag_func(void *p) { return QM_FRAG(p)->func; }
static inline unsigned long qm_frag_line(void *p) { return QM_FRAG(p)->line; }
static inline const char *qm_frag_file(void *p) { return QM_FRAG(p)->dbg[0].file; }
static inline const char *qm_frag_func(void *p) { return QM_FRAG(p)->dbg[0].func; }
static inline unsigned long qm_frag_line(void *p) { return QM_FRAG(p)->dbg[0].line; }
#else
static inline const char *qm_frag_file(void *p) { return NULL; }
static inline const char *qm_frag_func(void *p) { return NULL; }
Expand Down
25 changes: 10 additions & 15 deletions mem/q_malloc_dyn.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,9 @@ int qm_split_frag(struct qm_block *qm, struct qm_frag *f,
end->check1=END_CHECK_PATTERN1;
end->check2=END_CHECK_PATTERN2;
/* frag created by malloc, mark it*/
n->file=file;
n->func=func;
n->line=line;
n->check=ST_CHECK_PATTERN;
qm_dbg_clear(n);
qm_dbg_fill(n, file, func, line);
#endif
/* reinsert n in free list*/
qm_insert_free(qm, n);
Expand Down Expand Up @@ -141,9 +140,7 @@ void *qm_malloc(struct qm_block *qm, unsigned long size,
qm->max_real_used=qm->real_used;

#ifdef DBG_MALLOC
f->file=file;
f->func=func;
f->line=line;
qm_dbg_fill(f, file, func, line);
f->check=ST_CHECK_PATTERN;
/* FRAG_END(f)->check1=END_CHECK_PATTERN1;
FRAG_END(f)->check2=END_CHECK_PATTERN2;*/
Expand Down Expand Up @@ -200,11 +197,11 @@ void qm_free(struct qm_block *qm, void *p,
if (f->u.is_free){
LM_CRIT("freeing already freed pointer,"
" first free: %s: %s(%ld) - aborting\n",
f->file, f->func, f->line);
qm_dbg_coords(f));
abort();
}
LM_GEN1( memlog, "freeing frag. %p alloc'ed from %s: %s(%ld)\n",
f, f->file, f->func, f->line);
f, qm_dbg_coords(f));
#endif

size=f->size;
Expand Down Expand Up @@ -245,9 +242,7 @@ void qm_free(struct qm_block *qm, void *p,
f->size=size;
FRAG_END(f)->size=f->size;
#ifdef DBG_MALLOC
f->file=file;
f->func=func;
f->line=line;
qm_dbg_fill(f, file, func, line);
#endif
qm_insert_free(qm, f);
qm->fragments -= 1;
Expand Down Expand Up @@ -308,7 +303,7 @@ void *qm_realloc(struct qm_block *qm, void *p, unsigned long size,
#ifdef DBG_MALLOC
qm_debug_frag(qm, f);
LM_GEN1( memlog, "realloc'ing frag %p alloc'ed from %s: %s(%ld)\n",
f, f->file, f->func, f->line);
f, qm_dbg_coords(f));
if (f->u.is_free) {
LM_CRIT("trying to realloc an already freed "
"pointer %p , fragment %p -- aborting\n", p, f);
Expand Down Expand Up @@ -434,8 +429,8 @@ void qm_status(struct qm_block *qm)

for (f = qm->first_frag; f >= qm->first_frag &&
(void *)f < (void *)qm->last_frag_end; f = FRAG_NEXT(f)) {
if (!f->u.is_free && f->file)
if (dbg_ht_update(allocd, f->file, f->func, f->line, f->size) < 0) {
if (!f->u.is_free && f->dbg[0].file)
if (dbg_ht_update(allocd, qm_dbg_coords(f), f->size) < 0) {
LM_ERR("Unable to update alloc'ed. memory summary\n");
dbg_ht_free(allocd);
return;
Expand Down Expand Up @@ -474,7 +469,7 @@ void qm_status(struct qm_block *qm)
LM_GEN1(memdump, "unused fragm.: hash = %3d, fragment %p,"
" address %p size %lu, created from %s: %s(%lu)\n",
h, f, (char*)f+sizeof(struct qm_frag), f->size,
f->file, f->func, f->line);
qm_dbg_coords(f));
#endif
}
}
Expand Down

0 comments on commit 691c96e

Please sign in to comment.