[Rsync-patches] [PATCH] Properly free filters loaded during a parent_dirscan to avoid a crash when they define another per-dir merge file.
Matt McCutchen <matt at mattmccutchen.net>
Sun Aug 17 08:36:58 PDT 2008
---
This patch, which is available in branch wip/perdir-merge of my rsync
repository ( http://mattmccutchen.net/rsync/rsync.git/ ), should fix the
crash but could use some additional testing.
exclude.c | 39 +++++++++++++++++++++++++++++----------
rsync.h | 1 +
2 files changed, 30 insertions(+), 10 deletions(-)
diff --git a/exclude.c b/exclude.c
index 6eb83cb..cf93629 100644
--- a/exclude.c
+++ b/exclude.c
@@ -40,9 +40,9 @@ extern char curr_dir[MAXPATHLEN];
extern unsigned int curr_dir_len;
extern unsigned int module_dirlen;
-struct filter_list_struct filter_list = { 0, 0, "" };
-struct filter_list_struct cvs_filter_list = { 0, 0, " [global CVS]" };
-struct filter_list_struct daemon_filter_list = { 0, 0, " [daemon]" };
+struct filter_list_struct filter_list = { 0, 0, 0, "" };
+struct filter_list_struct cvs_filter_list = { 0, 0, 0, " [global CVS]" };
+struct filter_list_struct daemon_filter_list = { 0, 0, 0, " [daemon]" };
/* Need room enough for ":MODS " prefix plus some room to grow. */
#define MAX_RULE_PREFIX (16)
@@ -102,9 +102,15 @@ static int mergelist_size = 0;
* values (so we can pop back to them later) and set the tail to NULL.
*/
+static void free_filters(struct filter_struct *head);
+
static void free_filter(struct filter_struct *ex)
{
if (ex->match_flags & MATCHFLG_PERDIR_MERGE) {
+ /* Free the parent_dirscan list to clean up any per-dir
+ * mergelists it defined. Otherwise pop_local_filters may crash
+ * trying to restore nonexistent state for those mergelists. */
+ free_filters(ex->u.mergelist->parent_dirscan_head);
free(ex->u.mergelist->debug_type);
free(ex->u.mergelist);
mergelist_cnt--;
@@ -113,6 +119,15 @@ static void free_filter(struct filter_struct *ex)
free(ex);
}
+static void free_filters(struct filter_struct *head)
+{
+ while (head) {
+ struct filter_struct *next = head->next;
+ free_filter(head);
+ head = next;
+ }
+}
+
/* Build a filter structure given a filter pattern. The value in "pat"
* is not null-terminated. */
static void add_rule(struct filter_list_struct *listp, const char *pat,
@@ -237,7 +252,7 @@ static void add_rule(struct filter_list_struct *listp, const char *pat,
if (!(lp = new_array(struct filter_list_struct, 1)))
out_of_memory("add_rule");
- lp->head = lp->tail = NULL;
+ lp->head = lp->tail = lp->parent_dirscan_head = NULL;
if (asprintf(&lp->debug_type, " [per-dir %s]", cp) < 0)
out_of_memory("add_rule");
ret->u.mergelist = lp;
@@ -269,14 +284,10 @@ static void add_rule(struct filter_list_struct *listp, const char *pat,
static void clear_filter_list(struct filter_list_struct *listp)
{
if (listp->tail) {
- struct filter_struct *ent, *next;
/* Truncate any inherited items from the local list. */
listp->tail->next = NULL;
/* Now free everything that is left. */
- for (ent = listp->head; ent; ent = next) {
- next = ent->next;
- free_filter(ent);
- }
+ free_filters(listp->head);
}
listp->head = listp->tail = NULL;
@@ -414,12 +425,20 @@ static BOOL setup_merge_file(struct filter_struct *ex,
dirbuf_len = y - dirbuf;
strlcpy(x, ex->pattern, MAXPATHLEN - (x - buf));
parse_filter_file(lp, buf, ex->match_flags, XFLG_ANCHORED2ABS);
- if (ex->match_flags & MATCHFLG_NO_INHERIT)
+ if (ex->match_flags & MATCHFLG_NO_INHERIT) {
+ /* Free the undesired rules to clean up any per-dir
+ * mergelists they defined. Otherwise pop_local_filters
+ * may crash trying to restore nonexistent state for
+ * those mergelists. */
+ free_filters(lp->head);
lp->head = NULL;
+ }
lp->tail = NULL;
strlcpy(y, save, MAXPATHLEN);
while ((*x++ = *y++) != '/') {}
}
+ /* Save current head for freeing when the mergelist becomes inactive. */
+ lp->parent_dirscan_head = lp->head;
parent_dirscan = False;
free(pat);
return 1;
diff --git a/rsync.h b/rsync.h
index 320d340..6083c81 100644
--- a/rsync.h
+++ b/rsync.h
@@ -813,6 +813,7 @@ struct filter_struct {
struct filter_list_struct {
struct filter_struct *head;
struct filter_struct *tail;
+ struct filter_struct *parent_dirscan_head;
char *debug_type;
};
--
1.6.0.rc3.13.gdfe0a
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 197 bytes
Desc: This is a digitally signed message part
URL: <http://mattmccutchen.net/mailman/archives/rsync-patches/attachments/20080817/6b5eaf35/attachment.pgp>
More information about the rsync-patches
mailing list