Fix memory leaks and bad references detected by valgrind

* add free_font_cache()
* add css_free_colors()
* add unload_ligatures()
* add --free-all cmd line option to free memory upon exit for valgrind
* tty.c: fix off by 3 size in qe_realloc. Should be typed
* qe.c: fix invalid pointer reference upon destroying transient buffer
This commit is contained in:
Charlie Gordon 2014-01-24 00:46:26 +00:00
commit c5f56a0d5b
9 changed files with 118 additions and 8 deletions

View file

@ -579,6 +579,7 @@ void eb_free(EditBuffer **bp)
eb_free_style_buffer(b);
qe_free(&b->saved_data);
qe_free(bp);
}
}

View file

@ -249,6 +249,14 @@ static QEFont dummy_font;
static QEFont *font_cache[FONT_CACHE_SIZE];
static int font_cache_timestamp = 0;
void free_font_cache(QEditScreen *s)
{
int i;
for (i = 0; i < FONT_CACHE_SIZE; i++) {
close_font(s, &font_cache[i]);
}
}
QEFont *select_font(QEditScreen *s, int style, int size)
{
QEFont *fc;

View file

@ -248,8 +248,8 @@ void fill_rectangle(QEditScreen *s,
void set_clip_rectangle(QEditScreen *s, CSSRect *r);
void push_clip_rectangle(QEditScreen *s, CSSRect *or, CSSRect *r);
void free_font_cache(QEditScreen *s);
QEFont *select_font(QEditScreen *s, int style, int size);
static inline QEFont *lock_font(__unused__ QEditScreen *s, QEFont *font) {
if (font && font->refcount)
font->refcount++;

84
qe.c
View file

@ -72,6 +72,9 @@ static QEditScreen global_screen;
static int screen_width = 0;
static int screen_height = 0;
static int no_init_file;
#ifndef CONFIG_TINY
static int free_everything;
#endif
static const char *user_option;
/* mode handling */
@ -80,7 +83,6 @@ void qe_register_mode(ModeDef *m)
{
QEmacsState *qs = &qe_state;
ModeDef **p;
CmdDef *def;
/* register mode in mode list (at end) */
p = &qs->first_mode;
@ -107,6 +109,7 @@ void qe_register_mode(ModeDef *m)
if (!(m->mode_flags & MODEF_NOCMD)) {
char buf[64];
int size;
CmdDef *def;
/* lower case convert for C mode, Perl... */
qe_strtolower(buf, sizeof(buf) - 10, m->name);
@ -121,6 +124,7 @@ void qe_register_mode(ModeDef *m)
def->sig = CMD_ESs;
def->val = 0;
def->action.ESs = do_set_mode;
def[1].val = 1; /* flag as allocated for free-all */
qe_register_cmd_table(def, NULL);
}
}
@ -4155,7 +4159,7 @@ void do_define_kbd_macro(EditState *s, const char *name, const char *keys,
def->sig = CMD_ESs;
def->val = 0;
def->action.ESs = do_execute_macro_keys;
def[1].val = 1; /* flag as allocated for free-all */
qe_register_cmd_table(def, NULL);
do_set_key(s, key_bind, name, 0);
}
@ -4549,6 +4553,7 @@ void switch_to_buffer(EditState *s, EditBuffer *b)
EditBuffer *b1;
EditState *e;
ModeSavedData *saved_data, **psaved_data;
int saved_data_allocated = 0;
ModeDef *mode;
/* remove region hilite */
@ -4572,14 +4577,16 @@ void switch_to_buffer(EditState *s, EditBuffer *b)
* - otherwise, save the mode data in the buffer.
* CG: Should free previous such data ?
*/
if (b1->flags & BF_TRANSIENT) {
eb_free(&b1);
} else {
if (!(b1->flags & BF_TRANSIENT)) {
qe_free(&b1->saved_data);
b1->saved_data = s->mode->mode_save_data(s);
}
}
/* now we can close the mode */
edit_set_mode(s, NULL);
if (b1->flags & BF_TRANSIENT) {
eb_free(&b1);
}
}
/* now we can switch ! */
@ -4595,6 +4602,7 @@ void switch_to_buffer(EditState *s, EditBuffer *b)
if (e) {
psaved_data = NULL;
saved_data = e->mode->mode_save_data(e);
saved_data_allocated = 1;
} else {
psaved_data = &b->saved_data;
saved_data = *psaved_data;
@ -4608,6 +4616,8 @@ void switch_to_buffer(EditState *s, EditBuffer *b)
/* open it ! */
edit_set_mode_full(s, mode, saved_data, NULL);
if (saved_data_allocated)
qe_free(&saved_data);
}
}
@ -4732,6 +4742,7 @@ void edit_close(EditState *s)
if (qs->active_window == s)
qs->active_window = qs->first_window;
qe_free(&s->mode_data);
qe_free(&s->prompt);
qe_free(&s->line_shadow);
qe_free(&s);
@ -5853,6 +5864,7 @@ static void quit_examine_buffers(QuitState *is)
edit_display(&qe_state);
dpy_flush(&global_screen);
} else {
qe_free(&is);
url_exit();
}
}
@ -7719,6 +7731,10 @@ static CmdOptionDef cmd_options[] = {
{ .func_arg = set_user_option }},
{ "version", "V", NULL, 0, "display version information and exit",
{ .func_noarg = show_version }},
#ifndef CONFIG_TINY
{ "free-all", NULL, NULL, CMD_OPT_BOOL, "free all structures upon exit",
{ .int_ptr = &free_everything }},
#endif
{ NULL, NULL, NULL, 0, NULL, { NULL }},
};
@ -8040,7 +8056,65 @@ int main(int argc, char **argv)
#ifdef CONFIG_ALL_KMAPS
unload_input_methods();
#endif
#ifdef CONFIG_UNICODE_JOIN
unload_ligatures();
#endif
#ifndef CONFIG_TINY
if (free_everything) {
/* free all structures for valgrind */
QEmacsState *qs = &qe_state;
while (qs->input_methods) {
InputMethod *p = qs->input_methods;
qs->input_methods = p->next;
if (p->data)
qe_free(&p);
}
while (qs->first_window) {
EditState *e = qs->first_window;
edit_close(e);
}
while (qs->first_buffer) {
EditBuffer *b = qs->first_buffer;
eb_free(&b);
}
while (qs->first_cmd) {
CmdDef *d = qs->first_cmd;
CmdDef *d1 = d;
while (d1->name)
d1++;
qs->first_cmd = d1->action.next;
/* free xxx-mode commands and macros */
if (d->name && !d[1].name && d[1].val) {
qe_free((char **)&d->name);
qe_free(&d);
}
}
while (qs->first_key) {
KeyDef *p = qs->first_key;
qs->first_key = p->next;
qe_free(&p);
}
while (qs->first_mode) {
ModeDef *m = qs->first_mode;
qs->first_mode = m->next;
while (m->first_key) {
KeyDef *p = m->first_key;
m->first_key = p->next;
qe_free(&p);
}
}
while (qs->first_completion) {
CompletionEntry *cp = qs->first_completion;
qs->first_completion = cp->next;
qe_free(&cp);
}
css_free_colors();
free_font_cache(&global_screen);
}
#endif
dpy_close(&global_screen);
return 0;
}

2
qe.h
View file

@ -315,6 +315,7 @@ int to_hex(int key);
void color_completion(CompleteState *cp);
int css_define_color(const char *name, const char *value);
int css_get_color(QEColor *color_ptr, const char *p);
void css_free_colors(void);
int css_get_font_family(const char *str);
void css_union_rect(CSSRect *a, const CSSRect *b);
static inline int css_is_null_rect(const CSSRect *a) {
@ -561,6 +562,7 @@ int unicode_to_glyphs(unsigned int *dst, unsigned int *char_to_glyph_pos,
int dst_size, unsigned int *src, int src_size,
int reverse);
int load_ligatures(void);
void unload_ligatures(void);
/* qe event handling */

View file

@ -1328,6 +1328,7 @@ static void shell_close(EditBuffer *b)
while (waitpid(s->pid, &status, 0) != s->pid)
continue;
}
set_pid_handler(s->pid, NULL, NULL);
s->pid = -1;
}
if (s->pty_fd >= 0) {

9
tty.c
View file

@ -241,6 +241,8 @@ static int tty_term_init(QEditScreen *s,
static void tty_term_close(QEditScreen *s)
{
TTYState *ts = s->priv_data;
fcntl(fileno(s->STDIN), F_SETFL, 0);
#if 0
/* go to the last line */
@ -258,6 +260,9 @@ static void tty_term_close(QEditScreen *s)
);
#endif
fflush(s->STDOUT);
qe_free(&ts->screen);
qe_free(&ts->line_updated);
}
static void tty_term_exit(void)
@ -290,12 +295,12 @@ static void tty_resize(__unused__ int sig)
count = s->width * s->height;
size = count * sizeof(TTYChar);
/* screen buffer + shadow buffer + extra slot for loop guard */
qe_realloc(&ts->screen, size * 2 + 1);
qe_realloc(&ts->screen, size * 2 + sizeof(TTYChar));
qe_realloc(&ts->line_updated, s->height);
ts->screen_size = count;
/* Erase shadow buffer to impossible value */
memset(ts->screen + count, 0xFF, size);
memset(ts->screen + count, 0xFF, size + sizeof(TTYChar));
/* Fill screen buffer with black spaces */
tc = TTYCHAR_DEFAULT;
for (i = 0; i < count; i++) {

View file

@ -93,6 +93,13 @@ int load_ligatures(void)
return -1;
}
void unload_ligatures(void)
{
qe_free(&subst1);
qe_free(&ligature2);
qe_free(&ligature_long);
}
static int find_ligature(int l1, int l2)
{
int a, b, m, v1, v2;

12
util.c
View file

@ -1152,6 +1152,18 @@ int css_define_color(const char *name, const char *value)
return 0;
}
void css_free_colors(void)
{
if (qe_colors != default_colors) {
while (nb_qe_colors > nb_default_colors) {
nb_qe_colors--;
qe_free((char **)&qe_colors[nb_qe_colors].name);
}
qe_free(&qe_colors);
qe_colors = (ColorDef *)default_colors;
}
}
/* XXX: make HTML parsing optional ? */
int css_get_color(QEColor *color_ptr, const char *p)
{