From: Simon Kelley Date: Thu, 29 May 2025 21:44:15 +0000 (+0100) Subject: Rewrite chunks of inotify.c to remove a memory leak. X-Git-Tag: v2.92test11~1 X-Git-Url: https://thekelleys.org.uk/gitweb/?a=commitdiff_plain;h=5846f749e5d878b6b5f7c20f6975bc96b95e4aae;p=dnsmasq.git Rewrite chunks of inotify.c to remove a memory leak. The code is much easier to follow now, this shouldn't happen again. --- diff --git a/src/inotify.c b/src/inotify.c index 8f07a98..e2f2fb3 100644 --- a/src/inotify.c +++ b/src/inotify.c @@ -133,29 +133,44 @@ void inotify_dnsmasq_init() } } -static struct hostsfile *dyndir_addhosts(struct dyndir *dd, char *path) +static struct hostsfile *dyndir_addhosts(struct dyndir *dd, char *file) { /* Check if this file is already known in dd->files */ - struct hostsfile *ah = NULL; - for(ah = dd->files; ah; ah = ah->next) - if(ah && ah->fname && strcmp(path, ah->fname) == 0) + struct hostsfile *ah; + size_t dirlen = sizeof(dd->dname); + + /* ah->fname always starts with the string in dd->dname */ + for (ah = dd->files; ah; ah = ah->next) + if (ah->fname[dirlen+2] == '/' && + strcmp(&ah->fname[dirlen+3], file) == 0) return ah; - + /* Not known, create new hostsfile record for this dyndir */ - struct hostsfile *newah = NULL; - if(!(newah = whine_malloc(sizeof(struct hostsfile)))) - return NULL; - - /* Add this file to the tip of the linked list */ - newah->next = dd->files; - dd->files = newah; - - /* Copy flags, set index and the full file path */ - newah->flags = dd->flags; - newah->index = daemon->host_index++; - newah->fname = path; + if ((ah = whine_malloc(sizeof(struct hostsfile)))) + { + char *path; - return newah; + if (!(path = whine_malloc(dirlen + strlen(file) + 2))) + { + free(ah); + return NULL; + } + + strcpy(path, dd->dname); + strcat(path, "/"); + strcat(path, file); + + /* Add this file to the tip of the linked list */ + ah->next = dd->files; + dd->files = ah; + + /* Copy flags, set index and the full file path */ + ah->flags = dd->flags; + ah->index = daemon->host_index++; + ah->fname = path; + } + + return ah; } @@ -204,10 +219,8 @@ void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revh while ((ent = readdir(dir_stream))) { - size_t lendir = strlen(dd->dname); size_t lenfile = strlen(ent->d_name); - char *path; - + /* ignore emacs backups and dotfiles */ if (lenfile == 0 || ent->d_name[lenfile - 1] == '~' || @@ -215,33 +228,36 @@ void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revh ent->d_name[0] == '.') continue; - if ((path = whine_malloc(lendir + lenfile + 2))) + if (dd->flags & AH_HOSTS) { struct hostsfile *ah; - strcpy(path, dd->dname); - strcat(path, "/"); - strcat(path, ent->d_name); - - if (!(ah = dyndir_addhosts(dd, path))) - { - free(path); - continue; - } - /* ignore non-regular files */ - if (stat(path, &buf) != -1 && S_ISREG(buf.st_mode)) - { - if (dd->flags & AH_HOSTS) - total_size = read_hostsfile(path, ah->index, total_size, rhash, revhashsz); + if ((ah = dyndir_addhosts(dd, ent->d_name)) && + stat(ah->fname, &buf) != -1 && S_ISREG(buf.st_mode)) + total_size = read_hostsfile(ah->fname, ah->index, total_size, rhash, revhashsz); + } #ifdef HAVE_DHCP - else if (dd->flags & (AH_DHCP_HST | AH_DHCP_OPT)) + else if (dd->flags & (AH_DHCP_HST | AH_DHCP_OPT)) + { + char *path; + + if ((path = whine_malloc(strlen(dd->dname) + lenfile + 2))) + { + strcpy(path, dd->dname); + strcat(path, "/"); + strcat(path, ent->d_name); + + /* ignore non-regular files */ + if (stat(path, &buf) != -1 && S_ISREG(buf.st_mode)) option_read_dynfile(path, dd->flags); -#endif + + free(path); } } +#endif } - + closedir(dir_stream); } } @@ -285,50 +301,51 @@ int inotify_check(time_t now) for (dd = daemon->dynamic_dirs; dd; dd = dd->next) if (dd->wd == in->wd) { - size_t lendir = strlen(dd->dname); - char *path; - - if ((path = whine_malloc(lendir + in->len + 2))) + if (dd->flags & AH_HOSTS) { - struct hostsfile *ah = NULL; - - strcpy(path, dd->dname); - strcat(path, "/"); - strcat(path, in->name); - - /* Is this is a deletion event? */ - if (in->mask & IN_DELETE) - my_syslog(LOG_INFO, _("inotify: %s removed"), path); - else - my_syslog(LOG_INFO, _("inotify: %s new or modified"), path); - - if (dd->flags & AH_HOSTS) + struct hostsfile *ah; + if ((ah = dyndir_addhosts(dd, in->name))) { - if ((ah = dyndir_addhosts(dd, path))) - { - const unsigned int removed = cache_remove_uid(ah->index); - if (removed > 0) - my_syslog(LOG_INFO, _("inotify: flushed %u names read from %s"), removed, path); - - /* (Re-)load hostsfile only if this event isn't triggered by deletion */ - if (!(in->mask & IN_DELETE)) - read_hostsfile(path, ah->index, 0, NULL, 0); + const unsigned int removed = cache_remove_uid(ah->index); + + /* Is this is a deletion event? */ + if (in->mask & IN_DELETE) + my_syslog(LOG_INFO, _("inotify: %s removed"), ah->fname); + else + my_syslog(LOG_INFO, _("inotify: %s new or modified"), ah->fname); + + if (removed > 0) + my_syslog(LOG_INFO, _("inotify: flushed %u names read from %s"), removed, ah->fname); + + /* (Re-)load hostsfile only if this event isn't triggered by deletion */ + if (!(in->mask & IN_DELETE)) + read_hostsfile(ah->fname, ah->index, 0, NULL, 0); #ifdef HAVE_DHCP - if (daemon->dhcp || daemon->doing_dhcp6) - { - /* Propagate the consequences of loading a new dhcp-host */ - dhcp_update_configs(daemon->dhcp_conf); - lease_update_from_configs(); - lease_update_file(now); - lease_update_dns(1); - } -#endif + if (daemon->dhcp || daemon->doing_dhcp6) + { + /* Propagate the consequences of loading a new dhcp-host */ + dhcp_update_configs(daemon->dhcp_conf); + lease_update_from_configs(); + lease_update_file(now); + lease_update_dns(1); } +#endif } + } #ifdef HAVE_DHCP - else if (dd->flags & AH_DHCP_HST) + else if (!(in->mask & IN_DELETE)) + { + char *path; + + if ((path = whine_malloc(strlen(dd->dname) + in->len + 2))) { - if (option_read_dynfile(path, AH_DHCP_HST)) + strcpy(path, dd->dname); + strcat(path, "/"); + strcat(path, in->name); + + my_syslog(LOG_INFO, _("inotify: %s new or modified"), path); + + if ((dd->flags & AH_DHCP_HST) && option_read_dynfile(path, AH_DHCP_HST)) { /* Propagate the consequences of loading a new dhcp-host */ dhcp_update_configs(daemon->dhcp_conf); @@ -336,17 +353,19 @@ int inotify_check(time_t now) lease_update_file(now); lease_update_dns(1); } - } - else if (dd->flags & AH_DHCP_OPT) - option_read_dynfile(path, AH_DHCP_OPT); -#endif + + if (dd->flags & AH_DHCP_OPT) + option_read_dynfile(path, AH_DHCP_OPT); - if (!ah) - free(path); + free(path); + } } +#endif + } } } + return hit; }