diff options
author | Eric Wong <e@80x24.org> | 2019-11-09 07:55:45 -0500 |
---|---|---|
committer | Jeffrey Stedfast <jestedfa@microsoft.com> | 2019-11-09 07:55:45 -0500 |
commit | 6d7c904e52bdfd723db990a326527fd65e45320a (patch) | |
tree | 8fda85639cc73213d1a40a1de9756123897e318e | |
parent | b8485678be773dab281c27933a510a59b2a81aba (diff) | |
download | gmime-6d7c904e52bdfd723db990a326527fd65e45320a.tar.gz |
gmime_multipart_foreach: avoid stack overflow from recursion
We can use a GQueue to emulate the behavior of an stack on the
heap. This allows us to parse deeply nested MIME parts since
RLIMIT_STACK is typically only a few megabytes while typical
GNU/Linux systems can use all available virtual memory for the
heap.
-rw-r--r-- | gmime/gmime-multipart.c | 52 |
1 files changed, 36 insertions, 16 deletions
diff --git a/gmime/gmime-multipart.c b/gmime/gmime-multipart.c index ade11d5b..f27dbb51 100644 --- a/gmime/gmime-multipart.c +++ b/gmime/gmime-multipart.c @@ -775,22 +775,10 @@ g_mime_multipart_get_boundary (GMimeMultipart *multipart) return GMIME_MULTIPART_GET_CLASS (multipart)->get_boundary (multipart); } - -static void -multipart_foreach (GMimeMultipart *multipart, GMimeObjectForeachFunc callback, gpointer user_data) -{ +typedef struct _GMimeForeachData { + GMimeObject *parent; GMimeObject *part; - guint i; - - for (i = 0; i < multipart->children->len; i++) { - part = (GMimeObject *) multipart->children->pdata[i]; - callback ((GMimeObject *) multipart, part, user_data); - - if (GMIME_IS_MULTIPART (part)) - multipart_foreach ((GMimeMultipart *) part, callback, user_data); - } -} - +} GMimeForeachData; /** * g_mime_multipart_foreach: @@ -804,10 +792,42 @@ multipart_foreach (GMimeMultipart *multipart, GMimeObjectForeachFunc callback, g void g_mime_multipart_foreach (GMimeMultipart *multipart, GMimeObjectForeachFunc callback, gpointer user_data) { + GMimeForeachData *tmp; + GQueue *queue; + guint i; g_return_if_fail (GMIME_IS_MULTIPART (multipart)); g_return_if_fail (callback != NULL); - multipart_foreach (multipart, callback, user_data); + tmp = g_malloc (sizeof (GMimeForeachData)); + queue = g_queue_new (); + + tmp->parent = (GMimeObject *) multipart; + tmp->part = (GMimeObject *) multipart; + + g_queue_push_tail (queue, tmp); + + while ((tmp = (GMimeForeachData *) g_queue_pop_head (queue))) { + GMimeObject *parent = tmp->parent; + GMimeObject *part = tmp->part; + + g_free (tmp); + if (part != parent) + callback (parent, part, user_data); + + if (GMIME_IS_MULTIPART (part)) { + multipart = (GMimeMultipart *) part; + i = multipart->children->len; + while (i > 0) { + tmp = g_malloc (sizeof (GMimeForeachData)); + tmp->parent = part; + tmp->part = (GMimeObject *) multipart->children->pdata[--i]; + + g_queue_push_head (queue, tmp); + } + } + } + + g_queue_free (queue); } |