commit 6bde3d47c036300cc2896b8dec3877fc60fd3687 Author: Timo Sirainen AuthorDate: Tue Feb 22 17:44:02 2022 +0100 Commit: Jacob Welsh CommitDate: Sat Oct 29 03:13:01 2022 +0000 Type: fix for existing bug lib-imap: imap_bodystructure_parse*() - Reset parts.data on failure Having the data filled only to some message_parts can confuse the callers, thinking that all the parts were successfully filled. Fixes: Panic: file message-part-data.c: line 579 (message_part_is_attachment): assertion failed: (data != NULL) Ported from release-2.3 branch, which diverged from release-2.3.19, by jfw. diff --git a/src/lib-imap/imap-bodystructure.c b/src/lib-imap/imap-bodystructure.c index 522c250067..d4f42209f5 100644 --- a/src/lib-imap/imap-bodystructure.c +++ b/src/lib-imap/imap-bodystructure.c @@ -680,6 +680,15 @@ imap_bodystructure_parse_args(const struct imap_arg *args, pool_t pool, (part, pool, args, error_r); } + +static void imap_bodystructure_reset_data(struct message_part *parts) +{ + for (; parts != NULL; parts = parts->next) { + parts->data = NULL; + imap_bodystructure_reset_data(parts->children); + } +} + int imap_bodystructure_parse_full(const char *bodystructure, pool_t pool, struct message_part **parts, const char **error_r) @@ -710,6 +719,13 @@ int imap_bodystructure_parse_full(const char *bodystructure, } T_END_PASS_STR_IF(ret < 0, error_r); } + if (ret < 0) { + /* Don't leave partially filled data to message_parts. Some of + the code expects that if the first message_part->data is + filled, they all are. */ + imap_bodystructure_reset_data(*parts); + } + imap_parser_unref(&parser); i_stream_destroy(&input); return ret; diff --git a/src/lib-imap/test-imap-bodystructure.c b/src/lib-imap/test-imap-bodystructure.c index 6035118abd..736eb99f0e 100644 --- a/src/lib-imap/test-imap-bodystructure.c +++ b/src/lib-imap/test-imap-bodystructure.c @@ -554,6 +554,7 @@ static void test_imap_bodystructure_parse_invalid(void) parts = msg_parse(pool, test->message, 0, 0, FALSE); test_assert_idx(imap_bodystructure_parse(test->bodystructure, pool, parts, &error) == -1, i); + test_assert(parts->data == NULL); test_assert_strcmp_idx(error, test->error, i); pool_unref(&pool); } T_END;