summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2019-11-09 07:55:45 -0500
committerJeffrey Stedfast <jestedfa@microsoft.com>2019-11-09 07:55:45 -0500
commit6d7c904e52bdfd723db990a326527fd65e45320a (patch)
tree8fda85639cc73213d1a40a1de9756123897e318e
parentb8485678be773dab281c27933a510a59b2a81aba (diff)
downloadgmime-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.c52
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);
}