The leak was triggered in mutt_make_message_attach() with
$mime_forward set and $allow_8bit unset, on an attachment with 8-bit
characters. However, it probably occurred in other situations too.
mutt_make_message_attach() indirectly chains down to
mutt_message_to_7bit(), which calls the originator of the leak:
_parse_messageRFC822(). That function overwrites parent->hdr with a
newly allocated header.
At first I tried to "fix" the problem in that function, but it turns
out to be difficult to do given the wide variety of callers and
state of the data structures. Some callers pass a header with
content set, and other times it's not set.
After further research I discovered other callers of the
mutt_parse_(part/multipart/messageRFC822) set of functions take care
to save a top level header and restore it. (Which also made solving
the leak inside _parse_messageRFC822() difficult.)
After more research I decided the right place to fix was
mutt_message_to_7bit(): the caller of mutt_parse_messageRFC822() in
this case.
Since this is a generic function used in different circumstances, I
made no assumptions about whether a->hdr exists. If so, I save and
restore it.
The original function frees the a->hdr->content (or a->parts), so I
kept the same logic.
---
sendlib.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/sendlib.c b/sendlib.c
index dbd3eabe..db73eaf1 100644
--- a/sendlib.c
+++ b/sendlib.c
@@ -1108,6 +1108,7 @@ void mutt_message_to_7bit(BODY *a, FILE *fp)
FILE *fpin = NULL;
FILE *fpout = NULL;
struct stat sb;
+ HEADER *saved_hdr = NULL;
if (!a->filename && fp)
fpin = fp;
@@ -1138,6 +1139,10 @@ void mutt_message_to_7bit(BODY *a, FILE *fp)
}
fseeko(fpin, a->offset, SEEK_SET);
+ /* Note: mutt_parse_messageRFC822() overwrites a->hdr, so it needs to
+ * saved and restored below.
+ */
+ saved_hdr = a->hdr;
a->parts = mutt_parse_messageRFC822(fpin, a);
transform_to_7bit(a->parts, fpin);
@@ -1167,8 +1172,14 @@ void mutt_message_to_7bit(BODY *a, FILE *fp)
goto cleanup;
}
a->length = sb.st_size;
- mutt_free_body(&a->parts);
- a->hdr->content = NULL;
+
+ if (saved_hdr)
+ {
+ mutt_free_header(&a->hdr);
+ a->hdr = saved_hdr;
+ }
+ mutt_free_body(&a->hdr->content);
+ a->parts = NULL;
cleanup:
if (fpin && fpin != fp)
--
2.55.0