Re: [gmime-devel] GObject unref hell



On 11/6/2013 4:21 AM, Mario Theodoridis wrote:
Hello,

i'm currently in the process of using GMime for a mail process application. First of all i'd like to thank Jeffrey and potential other contributors to GMime for writing this wonderful library, as MIME parsing and generating is everything but fun.

I find myself with a problem that i can't seem to wrap my head around.
The following code snippet deterministically works in some instances, but not in others.

#define rfunref(obj) if (obj) { if G_IS_OBJECT(obj) { \
    g_debug("[%s:%d] unref "#obj, __FILE__, __LINE__); \
    g_object_unref(obj); obj = NULL; \
    g_debug("[%s:%d] unrefed "#obj, __FILE__, __LINE__); }}

  GMimeDataWrapper *content = NULL;
  GMimeStream *mem = NULL;
  GMimePart *part = NULL;
  GMimeMultipart *multipart = NULL;
  char *fileName = NULL;
  char *type = NULL, *subtype = NULL, *param = NULL, *value = NULL;

  do{
    /* other stuff here */

    /* set type, subtype, filename, etc. */
    /* find type */
    getType(msg, res, resLen, &type, &subtype, &param, &value);
    part = g_mime_part_new_with_type(type, subtype);
    g_mime_part_set_filename(part, fileName);
    g_mime_object_set_content_type_parameter((GMimeObject*)part,
                                              param, value);
    if (g_ascii_strcasecmp(type, "text") == 0) {
        g_mime_part_set_content_encoding(
                part, GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE);
    } else {
        g_mime_part_set_content_encoding (
                part, GMIME_CONTENT_ENCODING_BASE64);
    }
    g_mime_part_set_content_object (part, content);
    rfunref (content);

    g_mime_multipart_add (multipart, (GMimeObject *) part);

where does multipart get set?

rfunref (part);
  } while(attachments);

  g_mime_message_set_mime_part (message, (GMimeObject*) multipart);
  headerList = g_mime_object_get_header_list((GMimeObject*)multipart);
  rfunref (multipart);
[snip]

The unref macro is a mere act of desperation.

I have 2 general questions here.
1. What is going on here. No code was skipped between unref part and multipart.

Hard to say without knowing where multipart is getting set.


2. Is there a way to safely unref a GObject, i.e. unref it if it needs to be? This is mainly because it is not always clear to me when and when not due to issues like the current.

No, but as a general set of rules:

1. if you create a new object and set it as a child on another object, you need to unref it 2. when you get an object from another object, you don't - think if it as returning a const pointer.

example of rule #1:

child = g_mime_child_new ();
g_mime_parent_add_child (parent, child);
g_object_unref (child);

The reason you unref here is because the parent adds a ref to the child when you add it.

Essentially you own a ref to child, and, once you've added the child to the parent, the parent *also* owns a ref to the child. Thus there are 2 references to it, but if you are done with the child, you need to unref it (or you leak a reference to it).

example of rule #2:

child = g_mime_parent_get_child (parent);
// no need to unref child because the parent does not ref the child when it returns it

// to extend this example further...
g_mime_parent_add_child (parent2, child);
// still don't unref the child because you never ref'd it

In this example, when you get the child from the parent, only the parent owns a reference to the child. When you add it to parent2, parent2 adds another reference, which means that now both parent objects own a ref to the child, but since you still don't own a reference to the child, you don't unref it.


Hope that helps,

Jeff


Attachment: smime.p7s
Description: S/MIME Cryptographic Signature



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]