conf parsing: Fix memory leaks and clean up code a bit.
Charybdis currently leaks about 45-50k per configuration parse, including every rehash. This change plugs these leaks by properly iterating through all conf_parm_t structures to seek all strings that should be freed and also by freeing the conf_parm_t structures themselves. These leaks have been present since the original rewrite of the configuration parsing system in ircd-ratbox r11953. Additionally, this change also cleans up and documents the parsing code a bit.
This commit is contained in:
parent
e8cfec47c6
commit
dceac3e4fb
3 changed files with 37 additions and 30 deletions
|
@ -25,19 +25,27 @@ struct TopConf
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#define CF_QSTRING 0x01
|
#define CF_QSTRING 0x01 /* quoted string */
|
||||||
#define CF_INT 0x02
|
#define CF_INT 0x02
|
||||||
#define CF_STRING 0x03
|
#define CF_STRING 0x03 /* unquoted string */
|
||||||
#define CF_TIME 0x04
|
#define CF_TIME 0x04
|
||||||
#define CF_YESNO 0x05
|
#define CF_YESNO 0x05
|
||||||
#define CF_LIST 0x06
|
|
||||||
#define CF_ONE 0x07
|
|
||||||
|
|
||||||
#define CF_MTYPE 0xFF
|
#define CF_MTYPE 0xFF /* mask for type */
|
||||||
|
|
||||||
#define CF_FLIST 0x1000
|
/* CF_FLIST is used to allow specifying that an option accepts a list of (type)
|
||||||
#define CF_MFLAG 0xFF00
|
* values. conf_parm_t.type will never actually have another type & CF_FLIST;
|
||||||
|
* it's only used as a true flag in newconf.c (which only consumes conf_parm_t
|
||||||
|
* structures and doesn't create them itself).
|
||||||
|
*/
|
||||||
|
#define CF_FLIST 0x0100 /* flag for list */
|
||||||
|
#define CF_MFLAG 0xFF00 /* mask for flags */
|
||||||
|
|
||||||
|
/* conf_parm_t.type must be either one type OR one flag. this is pretty easy to
|
||||||
|
* enforce because lists always contain nested conf_parm_t structures whose
|
||||||
|
* .type is the real type, so it doesn't need to be stored in the top-level one
|
||||||
|
* anyway.
|
||||||
|
*/
|
||||||
typedef struct conf_parm_t_stru
|
typedef struct conf_parm_t_stru
|
||||||
{
|
{
|
||||||
struct conf_parm_t_stru *next;
|
struct conf_parm_t_stru *next;
|
||||||
|
@ -59,7 +67,7 @@ extern char *current_file;
|
||||||
int read_config(char *);
|
int read_config(char *);
|
||||||
int conf_start_block(char *, char *);
|
int conf_start_block(char *, char *);
|
||||||
int conf_end_block(struct TopConf *);
|
int conf_end_block(struct TopConf *);
|
||||||
int conf_call_set(struct TopConf *, char *, conf_parm_t *, int);
|
int conf_call_set(struct TopConf *, char *, conf_parm_t *);
|
||||||
void conf_report_error(const char *, ...);
|
void conf_report_error(const char *, ...);
|
||||||
void newconf_init(void);
|
void newconf_init(void);
|
||||||
int add_conf_item(const char *topconf, const char *name, int type, void (*func) (void *));
|
int add_conf_item(const char *topconf, const char *name, int type, void (*func) (void *));
|
||||||
|
|
|
@ -101,22 +101,22 @@ static int conf_get_yesno_value(char *str)
|
||||||
|
|
||||||
static void free_cur_list(conf_parm_t* list)
|
static void free_cur_list(conf_parm_t* list)
|
||||||
{
|
{
|
||||||
switch (list->type & CF_MTYPE)
|
if (list->type == CF_STRING || list->type == CF_QSTRING) {
|
||||||
{
|
|
||||||
case CF_STRING:
|
|
||||||
case CF_QSTRING:
|
|
||||||
rb_free(list->v.string);
|
rb_free(list->v.string);
|
||||||
break;
|
} else if (list->type == CF_FLIST) {
|
||||||
case CF_LIST:
|
/* Even though CF_FLIST is a flag, comparing with == is valid
|
||||||
|
* because conf_parm_t.type must be either a type or one flag.
|
||||||
|
*/
|
||||||
free_cur_list(list->v.list);
|
free_cur_list(list->v.list);
|
||||||
break;
|
|
||||||
default: break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (list->next)
|
if (list->next) {
|
||||||
free_cur_list(list->next);
|
free_cur_list(list->next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rb_free(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
conf_parm_t * cur_list = NULL;
|
conf_parm_t * cur_list = NULL;
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ static void add_cur_list_cpt(conf_parm_t *new)
|
||||||
if (cur_list == NULL)
|
if (cur_list == NULL)
|
||||||
{
|
{
|
||||||
cur_list = rb_malloc(sizeof(conf_parm_t));
|
cur_list = rb_malloc(sizeof(conf_parm_t));
|
||||||
cur_list->type |= CF_FLIST;
|
cur_list->type = CF_FLIST;
|
||||||
cur_list->v.list = new;
|
cur_list->v.list = new;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -216,7 +216,7 @@ block_items: block_items block_item
|
||||||
|
|
||||||
block_item: string '=' itemlist ';'
|
block_item: string '=' itemlist ';'
|
||||||
{
|
{
|
||||||
conf_call_set(conf_cur_block, $1, cur_list, CF_LIST);
|
conf_call_set(conf_cur_block, $1, cur_list);
|
||||||
free_cur_list(cur_list);
|
free_cur_list(cur_list);
|
||||||
cur_list = NULL;
|
cur_list = NULL;
|
||||||
}
|
}
|
||||||
|
@ -233,8 +233,7 @@ single: oneitem
|
||||||
| oneitem TWODOTS oneitem
|
| oneitem TWODOTS oneitem
|
||||||
{
|
{
|
||||||
/* "1 .. 5" meaning 1,2,3,4,5 - only valid for integers */
|
/* "1 .. 5" meaning 1,2,3,4,5 - only valid for integers */
|
||||||
if (($1->type & CF_MTYPE) != CF_INT ||
|
if ($1->type != CF_INT || $3->type != CF_INT)
|
||||||
($3->type & CF_MTYPE) != CF_INT)
|
|
||||||
{
|
{
|
||||||
conf_report_error("Both arguments in '..' notation must be integers.");
|
conf_report_error("Both arguments in '..' notation must be integers.");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -65,7 +65,7 @@ static char *yy_privset_extends = NULL;
|
||||||
static const char *
|
static const char *
|
||||||
conf_strtype(int type)
|
conf_strtype(int type)
|
||||||
{
|
{
|
||||||
switch (type & CF_MTYPE)
|
switch (CF_TYPE(type))
|
||||||
{
|
{
|
||||||
case CF_INT:
|
case CF_INT:
|
||||||
return "integer value";
|
return "integer value";
|
||||||
|
@ -424,7 +424,7 @@ set_modes_from_table(int *modes, const char *whatis, struct mode_table *tab, con
|
||||||
int dir = 1;
|
int dir = 1;
|
||||||
int mode;
|
int mode;
|
||||||
|
|
||||||
if((args->type & CF_MTYPE) != CF_STRING)
|
if(CF_TYPE(args->type) != CF_STRING)
|
||||||
{
|
{
|
||||||
conf_report_error("Warning -- %s is not a string; ignoring.", whatis);
|
conf_report_error("Warning -- %s is not a string; ignoring.", whatis);
|
||||||
continue;
|
continue;
|
||||||
|
@ -857,7 +857,7 @@ conf_set_listen_port_both(void *data, int ssl)
|
||||||
conf_parm_t *args = data;
|
conf_parm_t *args = data;
|
||||||
for (; args; args = args->next)
|
for (; args; args = args->next)
|
||||||
{
|
{
|
||||||
if((args->type & CF_MTYPE) != CF_INT)
|
if(CF_TYPE(args->type) != CF_INT)
|
||||||
{
|
{
|
||||||
conf_report_error
|
conf_report_error
|
||||||
("listener::port argument is not an integer " "-- ignoring.");
|
("listener::port argument is not an integer " "-- ignoring.");
|
||||||
|
@ -1179,7 +1179,7 @@ conf_set_shared_oper(void *data)
|
||||||
|
|
||||||
if(args->next != NULL)
|
if(args->next != NULL)
|
||||||
{
|
{
|
||||||
if((args->type & CF_MTYPE) != CF_QSTRING)
|
if(CF_TYPE(args->type) != CF_QSTRING)
|
||||||
{
|
{
|
||||||
conf_report_error("Ignoring shared::oper -- server is not a qstring");
|
conf_report_error("Ignoring shared::oper -- server is not a qstring");
|
||||||
return;
|
return;
|
||||||
|
@ -1191,7 +1191,7 @@ conf_set_shared_oper(void *data)
|
||||||
else
|
else
|
||||||
yy_shared->server = rb_strdup("*");
|
yy_shared->server = rb_strdup("*");
|
||||||
|
|
||||||
if((args->type & CF_MTYPE) != CF_QSTRING)
|
if(CF_TYPE(args->type) != CF_QSTRING)
|
||||||
{
|
{
|
||||||
conf_report_error("Ignoring shared::oper -- oper is not a qstring");
|
conf_report_error("Ignoring shared::oper -- oper is not a qstring");
|
||||||
return;
|
return;
|
||||||
|
@ -2037,7 +2037,7 @@ conf_set_generic_string(void *data, int len, void *location)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
conf_call_set(struct TopConf *tc, char *item, conf_parm_t * value, int type)
|
conf_call_set(struct TopConf *tc, char *item, conf_parm_t * value)
|
||||||
{
|
{
|
||||||
struct ConfEntry *cf;
|
struct ConfEntry *cf;
|
||||||
conf_parm_t *cp;
|
conf_parm_t *cp;
|
||||||
|
|
Loading…
Reference in a new issue