From 6bc76386f6d9ad333603fc81fd9d669e2457b1ec Mon Sep 17 00:00:00 2001 From: Xuan Sang LE Date: Fri, 2 Mar 2018 19:04:00 +0100 Subject: [PATCH] fix memory leak --- http_server.c | 109 +++++++++++++++++++++++++++++++++++---------- httpd.c | 24 +++++----- libs/dbhelper.c | 39 +++++++++++++--- libs/dbhelper.h | 2 + libs/dictionary.c | 26 ++++++++++- libs/handle.c | 23 +++++++--- libs/list.c | 12 ++++- libs/plugin.c | 9 ++++ libs/plugin.h | 2 +- libs/utils.c | 8 +++- libs/ws.c | 2 +- libs/wterm/wterm.c | 6 +++ plugin_manager.c | 27 ++++++++--- 13 files changed, 231 insertions(+), 58 deletions(-) diff --git a/http_server.c b/http_server.c index 2c49204..91b68e3 100644 --- a/http_server.c +++ b/http_server.c @@ -130,7 +130,24 @@ void accept_request(void* client) } end: if(oldurl) free(oldurl); - if(rq) free(rq); + if(rq) + { + dictionary subdict; + subdict = (dictionary)dvalue(rq, "__xheader__"); + if(subdict) + { + freedict(subdict); + dput(rq, "__xheader__", NULL); + } + + subdict = (dictionary)dvalue(rq, "cookie"); + if(subdict) + { + freedict(subdict); + dput(rq, "cookie", NULL); + } + freedict(rq); + } antd_close(client); } @@ -155,7 +172,12 @@ int rule_check(const char*k, const char* v, const char* host, const char* _url, else target = host; - if(!ret) return 0; + if(!ret) + { + free(url); + free(query); + return 0; + } tmp = (char*) v; char * search = "<([a-zA-Z0-9]+)>"; //printf("match again %s\n",tmp); @@ -519,9 +541,10 @@ dictionary decode_request(void* client,const char* method, char* url) } //if(line) free(line); query = apply_rules(host, url); + if(host) free(host); if(strcmp(method,"GET") == 0) - { - if(host) free(host); + { + if(ctype) free(ctype); if(query) { LOG("Query: %s\n", query); @@ -536,15 +559,21 @@ dictionary decode_request(void* client,const char* method, char* url) // plugin should handle this ugraded connection // not the server if(!request) request = dict(); - dput(request,"__web_socket__","1"); + dput(request,"__web_socket__",strdup("1")); } } else { + if(query) + free(query); + if(ws_key) + free(ws_key); if(ctype == NULL || clen == -1) { LOG("Bad request\n"); if(ctype) free(ctype); + if(cookie) freedict(cookie); + free(xheader); return NULL; } LOG("ContentType %s\n", ctype); @@ -575,8 +604,8 @@ dictionary decode_request(void* client,const char* method, char* url) //if(cookie->key == NULL) {free(cookie);cookie= NULL;} if(!request) request = dict(); - - dput(request,"cookie",cookie); + if(cookie) + dput(request,"cookie",cookie); dput(request,"__xheader__",xheader); return request; } @@ -635,10 +664,11 @@ dictionary decode_cookie(const char* line) { char *token,*token1; char *cpstr = strdup(line); + char *orgcpy = cpstr; trim(cpstr,' '); trim(cpstr,'\n'); trim(cpstr,'\r'); - //printf("FUCKIT %s\n",cpstr ); + dictionary dic = NULL; while((token = strsep(&cpstr,";"))) { @@ -648,13 +678,12 @@ dictionary decode_cookie(const char* line) { if(dic == NULL) dic = dict(); - //LOG("Found cookie : %s = %s\n",token1,token); dput(dic,token1,strdup(token)); } } //} + free(orgcpy); return dic; - //free(cpstr); } /** * Decode the multi-part form data from the POST request @@ -670,7 +699,9 @@ dictionary decode_multi_part_request(void* client,const char* ctype) char * boundary; char * boundend; char * line; + char * orgline; char * str_copy = strdup(ctype); + char* orgcpy = str_copy; char* token; char* keytoken ; char* valtoken ; @@ -689,13 +720,29 @@ dictionary decode_multi_part_request(void* client,const char* ctype) trim(boundary,' '); boundend = __s("%s--",boundary); //find first boundary - while((line = read_line(client))&&strstr(line,boundary) <= 0); + while((line = read_line(client))&&strstr(line,boundary) <= 0) + { + if(line) free(line); + } // loop through each part separated by the boundary while(line && strstr(line,boundary) > 0){ + free(line); // search for content disposition: while((line = read_line(client)) && - strstr(line,"Content-Disposition:") <= 0); - if(strstr(line,"Content-Disposition:") <= 0) return NULL; + strstr(line,"Content-Disposition:") <= 0) + { + free(line); + line = NULL; + } + if(!line || strstr(line,"Content-Disposition:") <= 0) + { + if(line) + free(line); + free(orgcpy); + free(boundend); + return NULL; + } + orgline = line; // extract parameters from header part_name = NULL; part_file = NULL; @@ -714,19 +761,24 @@ dictionary decode_multi_part_request(void* client,const char* ctype) trim(valtoken,'\"'); if(strcmp(keytoken,"name") == 0) { - part_name = valtoken; + part_name = strdup(valtoken); } else if(strcmp(keytoken,"filename") == 0) { - part_file = valtoken; + part_file = strdup(valtoken); } } } } + free(orgline); // get the binary data if(part_name != NULL) { // go to the beginer of data bock - while((line = read_line(client)) && strcmp(line,"\r\n") != 0); + while((line = read_line(client)) && strcmp(line,"\r\n") != 0) + { + free(line); + } + if(line) free(line); if(part_file == NULL) { /** @@ -740,7 +792,10 @@ dictionary decode_multi_part_request(void* client,const char* ctype) trim(line,' '); dput(dic,part_name,line); // find the next boundary - while((line = read_line(client)) && strstr(line,boundary) <= 0); + while((line = read_line(client)) && strstr(line,boundary) <= 0) + { + free(line); + } } else { @@ -762,11 +817,14 @@ dictionary decode_multi_part_request(void* client,const char* ctype) line = buf; field = __s("%s.file",part_name); - dput(dic,field,part_file); + dput(dic,field, strdup(part_file)); + free(field); field = __s("%s.tmp",part_name); dput(dic,field,strdup(file_path)); + free(field); field = __s("%s.size",part_name); dput(dic,field,__s("%d",totalsize)); + free(field); field = __s("%s.ext",part_name); dput(dic,field,ext(part_file)); free(field); @@ -777,7 +835,9 @@ dictionary decode_multi_part_request(void* client,const char* ctype) LOG("Cannot wirte file to :%s\n", file_path ); } free(file_path); + free(part_file); } + free(part_name); } //printf("[Lines]:%s\n",line); // check if end of request @@ -786,9 +846,10 @@ dictionary decode_multi_part_request(void* client,const char* ctype) LOG("End request %s\n", boundend); break; } - } + } + free(boundend); } - free(str_copy); + free(orgcpy); return dic; } /** @@ -800,10 +861,11 @@ dictionary decode_multi_part_request(void* client,const char* ctype) dictionary decode_url_request(const char* query) { if(query == NULL) return NULL; - char* str_copy = strdup(query); //str_copy = ; char* token; if(strlen(query) == 0) return NULL; + char* str_copy = strdup(query); + char* org_copy = str_copy; dictionary dic = dict(); while ((token = strsep(&str_copy, "&"))) { @@ -819,7 +881,7 @@ dictionary decode_url_request(const char* query) } } } - free(str_copy); + free(org_copy); return dic; } /** @@ -859,6 +921,7 @@ int execute_plugin(void* client, const char *path, const char *method, dictionar struct plugin_entry *plugin ; int plen = strlen(path); char * rpath = (char*) malloc((plen+1)*sizeof(char)); + char* orgs = rpath; char *error; memcpy(rpath,path+1,plen); rpath[plen] = '\0'; @@ -900,7 +963,7 @@ int execute_plugin(void* client, const char *path, const char *method, dictionar //dictionary dic = decode_request(client,method,query_string); (*fn)(client,method,pfunc,dic); //free(dic); - free(rpath); + free(orgs); return 1; } diff --git a/httpd.c b/httpd.c index 70d5df6..2ebffc6 100644 --- a/httpd.c +++ b/httpd.c @@ -4,9 +4,10 @@ #include "libs/ini.h" #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0 - +int server_sock = -1; #ifdef USE_OPENSSL static int ssl_session_ctx_id = 1; +SSL_CTX *ctx; void init_openssl() { SSL_load_error_strings(); @@ -98,12 +99,12 @@ static int config_handler(void* conf, const char* section, const char* name, #endif else if (strcmp(section, "RULES") == 0) { - list_put_s(&pconfig->rules, strdup(name)); - list_put_s(&pconfig->rules, strdup(value)); + list_put_s(&pconfig->rules, name); + list_put_s(&pconfig->rules, value); } else if (strcmp(section, "FILEHANDLER") == 0) { - dput( pconfig->handlers, strdup(name),strdup(value)); + dput( pconfig->handlers, name ,strdup(value)); } else if(strcmp(section,"AUTOSTART")==0){ // The server section must be added before the autostart section @@ -162,9 +163,13 @@ void load_config(const char* file) init_file_system(); } void stop_serve(int dummy) { - list_free(&server_config.rules); - free(server_config.handlers); + list_free(&(server_config.rules)); + freedict(server_config.handlers); unload_all_plugin(); +#ifdef USE_OPENSSL + SSL_CTX_free(ctx); +#endif + close(server_sock); } int main(int argc, char* argv[]) { @@ -173,8 +178,6 @@ int main(int argc, char* argv[]) load_config(CONFIG); else load_config(argv[1]); - - int server_sock = -1; unsigned port = server_config.port; int client_sock = -1; struct sockaddr_in client_name; @@ -188,7 +191,6 @@ int main(int argc, char* argv[]) signal(SIGINT, stop_serve); #ifdef USE_OPENSSL - SSL_CTX *ctx; if( server_config.usessl == 1 ) { init_openssl(); @@ -236,9 +238,7 @@ int main(int argc, char* argv[]) } //accept_request(&client); } -#ifdef USE_OPENSSL - SSL_CTX_free(ctx); -#endif + close(server_sock); return(0); diff --git a/libs/dbhelper.c b/libs/dbhelper.c index 6d8a5b4..bf86c0f 100644 --- a/libs/dbhelper.c +++ b/libs/dbhelper.c @@ -81,7 +81,10 @@ void add_record(dbrecord* r,dbfield f) new_r->idx = 1; new_r->next = NULL; if((*r)->idx == 0) + { + freerecord(&(*r)); *r = new_r; + } else { dbrecord* temp; @@ -157,8 +160,8 @@ dbrecord dbselect(sqlite3* db, const char* table,const char* fstring,...) dbfield fields = __field(); for(int col = 0; col < cols; col++) { - char *value = (char*)sqlite3_column_text(statement, col); - char *name = (char*)sqlite3_column_name(statement, col); + const char *value = sqlite3_column_text(statement, col); + const char *name = sqlite3_column_name(statement, col); add_field(&fields,name,(value!=0)?value:""); } add_record(&records,fields); @@ -180,8 +183,12 @@ int hastable(sqlite3* db,const char* table) dbrecord rc = dbselect(db,"sqlite_master","type='table' and name='%s'", table); //free(prefix); if(!rc) return 0; - if(!rc->fields) return 0; - free(rc); + if(!rc->fields) + { + freerecord(&rc); + return 0; + } + freerecord(&rc); return 1; } int dbupdate(sqlite3* db,const char* table,const dbfield field,const char* fstring,...) @@ -228,4 +235,26 @@ int dbdelete(sqlite3* db,const char* table,const char* fstring,...) free(cond); free(sql); return ret; -} \ No newline at end of file +} + +void freerecord(dbrecord * r) +{ + dbrecord curr; + while ((curr = (*r)) != NULL) { + (*r) = (*r)->next; + if(curr->fields) + freefield(&(curr->fields)); + free (curr); + } +} +void freefield(dbfield *f) +{ + dbfield curr; + while( (curr = (*f)) != NULL ) + { + (*f) = (*f)->next; + if(curr->name) free(curr->name); + if(curr->value) free(curr->value); + free(curr); + } +} \ No newline at end of file diff --git a/libs/dbhelper.h b/libs/dbhelper.h index 9b13cd8..d5b1610 100644 --- a/libs/dbhelper.h +++ b/libs/dbhelper.h @@ -34,4 +34,6 @@ char* value_of(const dbfield,const char*); void add_field(dbfield*,const char*, const char*); void add_record(dbrecord*,dbfield); void dbclose(sqlite3*); +void freerecord(dbrecord *); +void freefield(dbfield *); #endif \ No newline at end of file diff --git a/libs/dictionary.c b/libs/dictionary.c index 29f3260..a77dcb1 100644 --- a/libs/dictionary.c +++ b/libs/dictionary.c @@ -93,5 +93,29 @@ void* dvalue(dictionary dic, const char* key) return as->value; } -void freedict(dictionary dic){free(dic);} +void free_association(association * asoc) +{ + + while( (*asoc) != NULL ) + { + association a = *asoc; + (* asoc) = (*asoc) ->next; + + if(a->key) + { + free(a->key); + if(a->value) free(a->value); + } + free(a); + } + +} + +void freedict(dictionary dic){ + for(int i = 0; i < HASHSIZE; i++) + free_association(&(dic[i])); + free(dic); + +} + diff --git a/libs/handle.c b/libs/handle.c index 14d4037..1dfd20b 100644 --- a/libs/handle.c +++ b/libs/handle.c @@ -9,8 +9,12 @@ int usessl() void set_status(void* client,int code,const char* msg) { - response(client, __s("HTTP/1.1 %d %s", code, msg)); - response(client, __s("Server: %s ", SERVER_NAME)); + char *s = __s("HTTP/1.1 %d %s", code, msg); + response(client, s); + free(s); + s = __s("Server: %s ", SERVER_NAME); + response(client, s); + free(s); } void redirect(void* client,const char*path) { @@ -67,7 +71,7 @@ int response(void* client, const char* data) } int antd_send(const void *src, const void* data, int len) { - if(!src) return -1; + if(!src || !data) return -1; antd_client_t * source = (antd_client_t *) src; #ifdef USE_OPENSSL if(usessl()) @@ -146,7 +150,11 @@ int __t(void* client, const char* fstring,...) va_end(arguments); if(dlen < BUFFLEN) - return response(client,data); + { + int ret = response(client,data); + free(data); + return ret; + } else { while(sent < dlen - 1) @@ -163,7 +171,12 @@ int __t(void* client, const char* fstring,...) sent += buflen; nbytes = antd_send(client, chunk, buflen); free(chunk); - if(nbytes == -1) return 0; + if(nbytes == -1) + { + //free(data); + //return 0; + break; + } } chunk = "\r\n"; antd_send(client, chunk, strlen(chunk)); diff --git a/libs/list.c b/libs/list.c index a023506..d501838 100644 --- a/libs/list.c +++ b/libs/list.c @@ -34,6 +34,7 @@ void list_put(list* l, item it) { if(*l == NULL || (*l)->type == RPC_TYPE_NIL) { + free(*l); *l = it; return ; } @@ -167,6 +168,7 @@ list split(const char* str, const char* delim) { if(str == NULL || delim == NULL) return NULL; char* str_cpy = strdup(str); + char* org_str = str_cpy; char* token; list l = list_init(); while((token = strsep(&str_cpy,delim))) @@ -176,7 +178,7 @@ list split(const char* str, const char* delim) list_put_special(&l,token); } } - free(str_cpy); + free(org_str); if(l->type== RPC_TYPE_NIL) return NULL; return l; @@ -227,9 +229,15 @@ void list_free(list *l) { item curr; while ((curr = (*l)) != NULL) { - (*l) = (*l)->next; + (*l) = (*l)->next; if(curr->type == RPC_TYPE_ARRAY) list_free(&curr->value.array); + else if(curr->type == RPC_TYPE_STRING) + free(curr->value.s); + else if(curr->type == RPC_TYPE_DATE) + free(curr->value.date); + else if(curr->type == RPC_TYPE_BASE64) + free(curr->value.b64); free (curr); } } diff --git a/libs/plugin.c b/libs/plugin.c index e1b01ae..24b38dc 100644 --- a/libs/plugin.c +++ b/libs/plugin.c @@ -73,4 +73,13 @@ char* config_dir() if (stat(path, &st) == -1) mkdir(path, 0755); return path; +} + +void __release() +{ + printf("Releasing plugin\n"); + if(__plugin__.name) free(__plugin__.name); + if(__plugin__.dbpath) free(__plugin__.dbpath); + if(__plugin__.htdocs) free(__plugin__.htdocs); + if(__plugin__.pdir) free(__plugin__.pdir); } \ No newline at end of file diff --git a/libs/plugin.h b/libs/plugin.h index d8d2258..969eb23 100644 --- a/libs/plugin.h +++ b/libs/plugin.h @@ -37,5 +37,5 @@ char* htdocs(const char*); char* config_dir(); /*Default function for plugin*/ void handler(void*, const char*,const char*,dictionary); - +void __release(); #endif diff --git a/libs/utils.c b/libs/utils.c index 6c47d82..ca266ee 100644 --- a/libs/utils.c +++ b/libs/utils.c @@ -143,13 +143,15 @@ char* ext(const char* file) char* token,*ltoken = ""; if(file == NULL) return NULL; char* str_cpy = strdup(file); + char* str_org = str_cpy; if(strstr(str_cpy,".")<= 0) return ""; if(*file == '.') trim(str_cpy,'.'); while((token = strsep(&str_cpy,".")) && strlen(token)>0) {ltoken = token;} - free(str_cpy); - return ltoken; + char* ext = strdup(ltoken); + free(str_org); + return ext; } /*get mime file info from extension*/ @@ -182,6 +184,7 @@ char* mime(const char* file) { char * ex = ext(file); mime_t m = mime_from_ext(ex); + free(ex); return m.type; } @@ -189,6 +192,7 @@ int is_bin(const char* file) { char * ex = ext(file); mime_t m = mime_from_ext(ex); + free(ex); return m.bin; } diff --git a/libs/ws.c b/libs/ws.c index d64aaf7..6988edc 100644 --- a/libs/ws.c +++ b/libs/ws.c @@ -15,7 +15,7 @@ static void ws_gen_mask_key(ws_msg_header_t * header) ws_msg_header_t * ws_read_header(void* client) { - uint8_t byte; + uint8_t byte = 0; uint8_t bytes[8]; ws_msg_header_t* header = (ws_msg_header_t*) malloc(sizeof(*header)); diff --git a/libs/wterm/wterm.c b/libs/wterm/wterm.c index 737974f..afdf9a4 100644 --- a/libs/wterm/wterm.c +++ b/libs/wterm/wterm.c @@ -89,12 +89,14 @@ void handler(void* cl, const char* m, const char* rqp, dictionary rq) { LOG("%s\n","Data is not mask"); write(fdm, "exit\n", 5); + free(h); return; } if(h->opcode == WS_CLOSE) { LOG("%s\n","Websocket: connection closed"); write(fdm, "exit\n", 5); + free(h); return; } else if(h->opcode == WS_TEXT) @@ -102,6 +104,7 @@ void handler(void* cl, const char* m, const char* rqp, dictionary rq) int l; char * tok = NULL; char* tok1 = NULL; + char* orgs = NULL; while((l = ws_read_data(cl,h,sizeof(buff),buff)) > 0) { char c = buff[0]; @@ -114,6 +117,7 @@ void handler(void* cl, const char* m, const char* rqp, dictionary rq) case 's': // terminal resize event buff[l] = '\0'; tok = strdup(buff+1); + orgs = tok; tok1 = strsep(&tok,":"); if(tok != NULL && tok1 != NULL) { @@ -136,6 +140,8 @@ void handler(void* cl, const char* m, const char* rqp, dictionary rq) if (ioctl(fdm, TIOCSWINSZ, (char *) &win) != 0) printf("Cannot set winsize\n"); + + free(orgs); } break; diff --git a/plugin_manager.c b/plugin_manager.c index 261ba67..a0ee0d6 100644 --- a/plugin_manager.c +++ b/plugin_manager.c @@ -60,6 +60,8 @@ void * plugin_from_file(char* name) if (!lib_handle) { LOG("Cannot load plugin '%s' : '%s'\n",name,dlerror()); + if(path) + free(path); return NULL; } // set database path @@ -87,7 +89,16 @@ void unload_plugin(struct plugin_entry* np) { // execute it (*fn)(); - } + } + fn = (void(*)()) dlsym(np->handle, "__release"); + if ((error = dlerror()) != NULL) + { + LOG("Cant not release plugin %s : %s \n", np->pname,error); + } + if(fn) + { + (*fn)(); + } dlclose(np->handle); //free((void *) np->handle); free((void *) np->pname); @@ -124,11 +135,15 @@ void unload_all_plugin() LOG("Unload all plugins\n"); for(int i=0;inext) - { - unload_plugin(np); - } + struct plugin_entry **np, *curr; + np = &plugin_table[i]; + + while((curr = *np) != NULL) + { + (*np) = (*np)->next; + unload_plugin(curr); + free(curr); + } plugin_table[i] = NULL; } exit(0);