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 675446 - gfile: Plug memory leak in g_file_make_directory_with_parents()
gfile: Plug memory leak in g_file_make_directory_with_parents()
Status: RESOLVED FIXED
Product: glib
Classification: Platform
Component: general
unspecified
Other All
: Normal normal
: ---
Assigned To: gtkdev
gtkdev
Depends on:
Blocks:
 
 
Reported: 2012-05-04 14:07 UTC by Colin Walters
Modified: 2012-05-15 15:16 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
gfile: Plug memory leak in g_file_make_directory_with_parents() (2.13 KB, patch)
2012-05-04 14:07 UTC, Colin Walters
committed Details | Review
patch (1.64 KB, patch)
2012-05-10 17:51 UTC, Paolo Borelli
needs-work Details | Review

Description Colin Walters 2012-05-04 14:07:40 UTC
The logic here is pretty twisted, but basically we were leaking a ref
for each non-existent parent.  The clearest way to fix this was to
move to more explicit refcounting logic; when a variable is pointing
to an object, it holds a ref.
Comment 1 Colin Walters 2012-05-04 14:07:42 UTC
Created attachment 213442 [details] [review]
gfile: Plug memory leak in g_file_make_directory_with_parents()
Comment 2 Paolo Borelli 2012-05-07 09:02:02 UTC
Review of attachment 213442 [details] [review]:

Patch looks good to me, just some nitpicks below

::: gio/gfile.c
@@ +3401,3 @@
 {
   gboolean result;
+  GFile *work_file = NULL;

this initialization is not really needed

@@ +3404,3 @@
   GList *list = NULL, *l;
   GError *my_error = NULL;
 

Not strictly related to the patch, but while at it we should probablly add

  g_return_val_if_fail (G_IS_FILE (file), FALSE);

@@ -3424,1 +3426,1 @@
       parent_file = g_file_get_parent (work_file);

I propose to move "unref(work_file); work_file = NULL" here right after its last use and then assign work_file to parent only in the "if"
Comment 3 Colin Walters 2012-05-07 20:50:03 UTC
(In reply to comment #2)
> Review of attachment 213442 [details] [review]:
> 
> Patch looks good to me, just some nitpicks below
> 
> ::: gio/gfile.c
> @@ +3401,3 @@
>  {
>    gboolean result;
> +  GFile *work_file = NULL;
> 
> this initialization is not really needed

I prefer to initialize all variables, because at some gcc optimization levels (namely -O0), you don't get warnings about used-but-not-initialized, and it's just safer.

> Not strictly related to the patch, but while at it we should probablly add
> 
>   g_return_val_if_fail (G_IS_FILE (file), FALSE);

Done.
 
> @@ -3424,1 +3426,1 @@
>        parent_file = g_file_get_parent (work_file);
> 
> I propose to move "unref(work_file); work_file = NULL" here right after its
> last use and then assign work_file to parent only in the "if"

Hmm... the logic here makes my head hurt...Why do you want to do this?  Can you provide a patch on top of mine so I can look at what you're suggesting concretely?
Comment 4 Paolo Borelli 2012-05-10 17:17:07 UTC
(In reply to comment #3)
> (In reply to comment #2)
> > Review of attachment 213442 [details] [review] [details]:
> > 
> > Patch looks good to me, just some nitpicks below
> > 
> > ::: gio/gfile.c
> > @@ +3401,3 @@
> >  {
> >    gboolean result;
> > +  GFile *work_file = NULL;
> > 
> > this initialization is not really needed
> 
> I prefer to initialize all variables, because at some gcc optimization levels
> (namely -O0), you don't get warnings about used-but-not-initialized, and it's
> just safer.
> 

Dunno, it is not consistent with the glib/gtk practice and usually I prefer to see the warning than to have to debug an unexpected NULL value. Anyway, just phylosophy, do not consider this blocking by any means

> > Not strictly related to the patch, but while at it we should probablly add
> > 
> >   g_return_val_if_fail (G_IS_FILE (file), FALSE);
> 
> Done.
> 
> > @@ -3424,1 +3426,1 @@
> >        parent_file = g_file_get_parent (work_file);
> > 
> > I propose to move "unref(work_file); work_file = NULL" here right after its
> > last use and then assign work_file to parent only in the "if"
> 
> Hmm... the logic here makes my head hurt...Why do you want to do this?  Can you
> provide a patch on top of mine so I can look at what you're suggesting
> concretely?

The logic here is indeed a bit twisted and when reviewing the patch I tried to think how to make the code shorter and slightly simpler, so I think we agree on the goal :)

I guess I'll give it a try and see if it works, but once again do not consider this blocking by any means and go ahead and commit as far as I am concerned
Comment 5 Paolo Borelli 2012-05-10 17:48:26 UTC
This is the way I was proposing to do it (I can provide it as a patch, but I think showing the full code makes it more clear)

..
  work_file = g_object_ref (file);

  while (work_file) 
    {
      GFile *parent_file;

      g_clear_error (&my_error);

      parent_file = g_file_get_parent (work_file);
      g_object_unref (work_file);
      work_file = NULL;

      if (parent_file == NULL)
        break;

      result = g_file_make_directory (parent_file, cancellable, &my_error);

      if (!result && my_error->code == G_IO_ERROR_NOT_FOUND)
        {
          list = g_list_prepend (list, parent_file);  /* Transfer ownership of ref */
          work_file = g_object_ref (parent_file);
        }
      else
        g_object_unref (parent_file);
    }

...
Comment 6 Paolo Borelli 2012-05-10 17:51:26 UTC
Created attachment 213823 [details] [review]
patch

here is the patch on top of yours in case you prefer it.

Note: not tested.


Speaking of which, this function could use an unit test in tests/live-g-file.c
Comment 7 Colin Walters 2012-05-15 14:59:08 UTC
Review of attachment 213823 [details] [review]:

::: gio/gfile.c
@@ +3418,3 @@
   work_file = g_object_ref (file);
+
+  while (work_file)

This change completely breaks the logic.  Note for example, "work_file" isn't changed in the non-error case.

Since I've tested my original patch in a few conditions, let's go with it.  I've fixed the trailing whitespace.
Comment 8 Colin Walters 2012-05-15 15:12:00 UTC
Attachment 213442 [details] pushed as 5a57144 - gfile: Plug memory leak in g_file_make_directory_with_parents()
Comment 9 Paolo Borelli 2012-05-15 15:16:57 UTC
(In reply to comment #7)
> Review of attachment 213823 [details] [review]:
> 
> ::: gio/gfile.c
> @@ +3418,3 @@
>    work_file = g_object_ref (file);
> +
> +  while (work_file)
> 
> This change completely breaks the logic.  Note for example, "work_file" isn't
> changed in the non-error case.
> 

I do not see what you mean: it is set to NULL and you exit the loop and since the if condition is the same as the loop condition it does not change things...

> Since I've tested my original patch in a few conditions, let's go with it. 
> I've fixed the trailing whitespace.

Anyway sure, no need to further fiddle with the function