After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 350907 - fd leak in camel-filter-search.c?
fd leak in camel-filter-search.c?
Status: RESOLVED FIXED
Product: evolution-data-server
Classification: Platform
Component: Mailer
1.6.x (obsolete)
Other Linux
: Normal major
: ---
Assigned To: evolution-mail-maintainers
Evolution QA team
Depends on:
Blocks:
 
 
Reported: 2006-08-11 15:03 UTC by Matt Davey
Modified: 2006-11-16 17:52 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Fixes fd leaks pointed out by Matt (2.62 KB, patch)
2006-08-28 13:28 UTC, Veerapuram Varadhan
none Details | Review
Fix for first-set-of-leaks (2.22 KB, patch)
2006-08-29 20:07 UTC, Veerapuram Varadhan
none Details | Review

Description Matt Davey 2006-08-11 15:03:18 UTC
I've got a file descriptor leak.

I'm running Evolution, and one of my incoming filters pipes the incoming message to a shell command.  I find that this reliably leaks two FIFO fds, resulting in the need to restart evolution every few days when I exceed 1024 open files.

I think I've tracked down the leak to camel-filter-search.c:run_command, which was recently refactored to use g_spawn_async_with_pipes().

I'm running fc5 with evolution-data-server-1.6.2-1.fc5.2
Comment 1 Veerapuram Varadhan 2006-08-28 13:27:03 UTC
(In reply to comment #0)
> I've got a file descriptor leak.
> 
> I'm running Evolution, and one of my incoming filters pipes the incoming
> message to a shell command.  I find that this reliably leaks two FIFO fds,
> resulting in the need to restart evolution every few days when I exceed 1024
> open files.
> 
> I think I've tracked down the leak to camel-filter-search.c:run_command, which
> was recently refactored to use g_spawn_async_with_pipes().
> 
> I'm running fc5 with evolution-data-server-1.6.2-1.fc5.2
> 

Thanks for reporting the bug and tracking down the cause. :-)  Will be attaching a fix shortly.
Comment 2 Veerapuram Varadhan 2006-08-28 13:28:23 UTC
Created attachment 71770 [details] [review]
Fixes fd leaks pointed out by Matt
Comment 3 Matt Davey 2006-08-28 13:53:40 UTC
Great.  I'll test this patch.

When I'd been digging around trying to fix this bug, I had thought that the combination:
        camel_stream_flush (stream);
        camel_object_unref (stream);
should arrange for the stream to close its file descriptors, via the
finalize method.  Isn't this the case?  Is something else not working?
Comment 4 Ray Strode [halfline] 2006-08-28 15:36:33 UTC
*** Bug 348888 has been marked as a duplicate of this bug. ***
Comment 5 Veerapuram Varadhan 2006-08-28 17:47:06 UTC
(In reply to comment #3)
> Great.  I'll test this patch.
> 
> When I'd been digging around trying to fix this bug, I had thought that the
> combination:
>         camel_stream_flush (stream);
>         camel_object_unref (stream);
> should arrange for the stream to close its file descriptors, via the
> finalize method.  Isn't this the case?  Is something else not working?
> 
Technically, Yes, this should close its file descriptors via the finalize method. Can you run valgrind with --trace-fds=yes and attach the log?

Also, if somebody has 2.4.x, try reproducing this bug, pls. 
Comment 6 Jeffrey Stedfast 2006-08-28 17:58:42 UTC
perhaps the stream is being leaked? (e.g. the unref doesn't finalise the stream object because someone else holds a ref still)
Comment 7 Veerapuram Varadhan 2006-08-28 18:41:44 UTC
I am marking the patch as obsolete, as technically, camel_object_unref of a stream calls its finalize and thus associated fds gets closed.
Comment 8 Matt Davey 2006-08-29 10:11:29 UTC
I tested the patch, and I found that evolution soon took 100% CPU, so I reverted to the previous version.

I've just run the unpatched version under valgrind.
It didn't appear to leak fds when running with memcheck, so I turned off
memcheck (--tool=none) and got several instances of the following:

==10665== Open file descriptor 64:
==10665==    at 0x51528D2: pipe (in /lib/libc-2.4.so)
==10665==    by 0x502AA84: g_child_watch_source_new (gmain.c:3620)
==10665==    by 0x42129E5: ??? (camel-filter-search.c:595)
==10665==    by 0x43DC130: e_sexp_term_eval (e-sexp.c:710)
==10665==    by 0x43DC3D7: ??? (e-sexp.c:440)
==10665==    by 0x43DC178: e_sexp_term_eval (e-sexp.c:700)
==10665==    by 0x421384C: ??? (camel-filter-search.c:327)
==10665==    by 0x43DC178: e_sexp_term_eval (e-sexp.c:700)
==10665==    by 0x43DCEC6: ??? (e-sexp.c:255)
==10665==    by 0x43DC178: e_sexp_term_eval (e-sexp.c:700)
==10665==    by 0x43DC1FF: e_sexp_eval (e-sexp.c:1304)
==10665==    by 0x4212671: camel_filter_search_match (camel-filter-search.c:705)

Hope this helps.


Comment 9 Veerapuram Varadhan 2006-08-29 20:07:11 UTC
Created attachment 71859 [details] [review]
Fix for first-set-of-leaks

Fixes first set of leaks.  g_main_loop_new () ref's the context parameter and thus, context was never getting freed - memory leak + fd leak.
Comment 10 Veerapuram Varadhan 2006-08-30 09:37:19 UTC
It seems the other leak is in glib.  Look at the following code snippet...

static void
g_child_watch_source_init_multi_threaded (void)
{
  GError *error = NULL;
  struct sigaction action;

  g_assert (g_thread_supported());

  if (pipe (child_watch_wake_up_pipe) < 0)
    g_error ("Cannot create wake up pipe: %s\n", g_strerror (errno));
  fcntl (child_watch_wake_up_pipe[1], F_SETFL, O_NONBLOCK | fcntl (child_watch_wake_up_pipe[1], F_GETFL));

....
....
....
}

The above code gets called for every g_child_watch_source_new ().  The pipe *child_watch_wake_up_pipe* is a static array that holds the fds-of-pipe and never gets closed.  (or atleast, I haven't seen it getting closed in glib/gmain.c).
Comment 11 Matthew Barnes 2006-08-30 12:21:44 UTC
But your snippet leaves out the line

  child_watch_init_state = CHILD_WATCH_INITIALIZED_THREADED;

and that *should* prevent the function from getting called a second time from g_child_watch_source_init(), as shown below:

static void
g_child_watch_source_init (void)
{
  if (g_thread_supported())
    {
      if (child_watch_init_state == CHILD_WATCH_UNINITIALIZED)
        g_child_watch_source_init_multi_threaded ();
      else if (child_watch_init_state == CHILD_WATCH_INITIALIZED_SINGLE)
        g_child_watch_source_init_promote_single_to_threaded ();
    }
  else
    {
      if (child_watch_init_state == CHILD_WATCH_UNINITIALIZED)
        g_child_watch_source_init_single ();
    }
}

So this part of GLib should only be leaking two file descriptors at most.  It wouldn't hurt to have another assertion or two in the logic though, if only for readability's sake:

static void
g_child_watch_source_init_multi_threaded (void)
{
  ...
  g_assert (g_thread_supported());
  g_assert (child_watch_init_state != CHILD_WATCH_INITIALIZED_THREADED);
  ...
}

Have you actually *seen* g_child_watch_source_init_multi_threaded() getting called multiple times, and if so what is the value of "child_watch_init_state" upon entry each time?
Comment 12 Matt Davey 2006-08-30 14:04:03 UTC
Thanks Veerapuram,

It looks as though your second patch has completely fixed my issue.

Matt
Comment 13 Veerapuram Varadhan 2006-08-30 15:23:02 UTC
(In reply to comment #11)
> But your snippet leaves out the line
> 
>   child_watch_init_state = CHILD_WATCH_INITIALIZED_THREADED;
> 
Thanks for pointing out. :)

[snip...]
> So this part of GLib should only be leaking two file descriptors at most.  
Yes, two file descriptors are leaked for every application.
Comment 14 Veerapuram Varadhan 2006-11-16 17:52:24 UTC
Closing the bug as Resolved fixed as per comment#12.  Rest of the leak is in glib.