|
Packit |
1470ea |
|
|
Packit |
1470ea |
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" type="topic" id="memory-management" xml:lang="de">
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<info>
|
|
Packit |
1470ea |
<link type="guide" xref="index#general-guidelines"/>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<credit type="author copyright">
|
|
Packit |
1470ea |
<name>Philip Withnall</name>
|
|
Packit |
1470ea |
<email its:translate="no">philip.withnall@collabora.co.uk</email>
|
|
Packit |
1470ea |
<years>2015</years>
|
|
Packit |
1470ea |
</credit>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<include xmlns="http://www.w3.org/2001/XInclude" href="cc-by-sa-3-0.xml"/>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<desc>Managing memory allocation and deallocation in C</desc>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
|
|
Packit |
1470ea |
<mal:name>Mario Blättermann</mal:name>
|
|
Packit |
1470ea |
<mal:email>mario.blaettermann@gmail.com</mal:email>
|
|
Packit |
1470ea |
<mal:years>2016</mal:years>
|
|
Packit |
1470ea |
</mal:credit>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
|
|
Packit |
1470ea |
<mal:name>Christian Kirbach</mal:name>
|
|
Packit |
1470ea |
<mal:email>christian.kirbach@gmail.com</mal:email>
|
|
Packit |
1470ea |
<mal:years>2016</mal:years>
|
|
Packit |
1470ea |
</mal:credit>
|
|
Packit |
1470ea |
</info>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<title>Speicherverwaltung</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
The GNOME stack is predominantly written in C, so dynamically allocated
|
|
Packit |
1470ea |
memory has to be managed manually. Through use of GLib convenience APIs,
|
|
Packit |
1470ea |
memory management can be trivial, but programmers always need to keep memory
|
|
Packit |
1470ea |
in mind when writing code.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
It is assumed that the reader is familiar with the idea of heap allocation
|
|
Packit |
1470ea |
of memory using malloc() and free() , and knows of
|
|
Packit |
1470ea |
the paired GLib equivalents, g_malloc() and
|
|
Packit |
1470ea |
g_free() .
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<synopsis>
|
|
Packit |
1470ea |
<title>Zusammenfassung</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
There are three situations to avoid, in order of descending importance:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<list type="numbered">
|
|
Packit |
1470ea |
<item>Using memory after freeing it (use-after-free). </item>
|
|
Packit |
1470ea |
<item>Using memory before allocating it. </item>
|
|
Packit |
1470ea |
<item>Not freeing memory after allocating it (leaking). </item>
|
|
Packit |
1470ea |
</list>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Key principles, in no particular order:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<list>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Determine and document whether each variable is owned or unowned. They
|
|
Packit |
1470ea |
must never change from one to the other at runtime.
|
|
Packit |
1470ea |
(<link xref="#principles"/>)
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Determine and document the ownership transfers at function boundaries.
|
|
Packit |
1470ea |
(<link xref="#principles"/>)
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Ensure that each assignment, function call and function return respects
|
|
Packit |
1470ea |
the relevant ownership transfers. (<link xref="#assignments"/>,
|
|
Packit |
1470ea |
<link xref="#function-calls"/>, <link xref="#function-returns"/>)
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Use reference counting rather than explicit finalization where possible.
|
|
Packit |
1470ea |
(<link xref="#reference-counting"/>)
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Use GLib convenience functions like
|
|
Packit |
1470ea |
<link xref="#g-clear-object">g_clear_object() </link> where
|
|
Packit |
1470ea |
possible. (<link xref="#convenience-functions"/>)
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Do not split memory management across code paths.
|
|
Packit |
1470ea |
(<link xref="#principles"/>)
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Use the single-path cleanup pattern for large or complex functions.
|
|
Packit |
1470ea |
(<link xref="#single-path-cleanup"/>)
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Leaks should be checked for using Valgrind or the address sanitizer.
|
|
Packit |
1470ea |
(<link xref="#verification"/>)
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
</list>
|
|
Packit |
1470ea |
</synopsis>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="principles">
|
|
Packit |
1470ea |
<title>Prinzipien der Speicherverwaltung</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
The normal approach to memory management is for the programmer to keep
|
|
Packit |
1470ea |
track of which variables point to allocated memory, and to manually free
|
|
Packit |
1470ea |
them when they are no longer needed. This is correct, but can be clarified
|
|
Packit |
1470ea |
by introducing the concept of ownership, which is the piece of
|
|
Packit |
1470ea |
code (such as a function, struct or object) which is responsible for
|
|
Packit |
1470ea |
freeing a piece of allocated memory (an allocation). Each
|
|
Packit |
1470ea |
allocation has exactly one owner; this owner may change as the program
|
|
Packit |
1470ea |
runs, by transferring ownership to another piece of code. Each
|
|
Packit |
1470ea |
variable is owned or unowned, according to whether the
|
|
Packit |
1470ea |
scope containing it is always its owner. Each function parameter and
|
|
Packit |
1470ea |
return type either transfers ownership of the values passed to it, or it
|
|
Packit |
1470ea |
doesn’t. If code which owns some memory doesn’t deallocate that memory,
|
|
Packit |
1470ea |
that’s a memory leak. If code which doesn’t own some memory frees it,
|
|
Packit |
1470ea |
that’s a double-free. Both are bad.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
By statically calculating which variables are owned, memory
|
|
Packit |
1470ea |
management becomes a simple task of unconditionally freeing the owned
|
|
Packit |
1470ea |
variables before they leave their scope, and not freeing the
|
|
Packit |
1470ea |
unowned variables (see <link xref="#single-path-cleanup"/>). The key
|
|
Packit |
1470ea |
question to answer for all memory is: which code has ownership of this
|
|
Packit |
1470ea |
memory?
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
There is an important restriction here: variables must
|
|
Packit |
1470ea |
never change from owned to unowned (or vice-versa)
|
|
Packit |
1470ea |
at runtime. This restriction is key to simplifying memory management.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
For example, consider the functions:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
gchar *generate_string (const gchar *template);
|
|
Packit |
1470ea |
void print_string (const gchar *str);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
The following code has been annotated to note where the ownership
|
|
Packit |
1470ea |
transfers happen:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
gchar *my_str = NULL; /* owned */
|
|
Packit |
1470ea |
const gchar *template; /* unowned */
|
|
Packit |
1470ea |
GValue value = G_VALUE_INIT; /* owned */
|
|
Packit |
1470ea |
g_value_init (&value, G_TYPE_STRING);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/* Transfers ownership of a string from the function to the variable. */
|
|
Packit |
1470ea |
template = "XXXXXX";
|
|
Packit |
1470ea |
my_str = generate_string (template);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/* No ownership transfer. */
|
|
Packit |
1470ea |
print_string (my_str);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/* Transfer ownership. We no longer have to free @my_str. */
|
|
Packit |
1470ea |
g_value_take_string (&value, my_str);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/* We still have ownership of @value, so free it before it goes out of scope. */
|
|
Packit |
1470ea |
g_value_unset (&value);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
There are a few points here: Firstly, the ‘owned’ comments by the variable
|
|
Packit |
1470ea |
declarations denote that those variables are owned by the local scope, and
|
|
Packit |
1470ea |
hence need to be freed before they go out of scope. The alternative is
|
|
Packit |
1470ea |
‘unowned’, which means the local scope does not have ownership,
|
|
Packit |
1470ea |
and must not free the variables before going out of scope.
|
|
Packit |
1470ea |
Similarly, ownership must not be transferred to them on
|
|
Packit |
1470ea |
assignment.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Secondly, the variable type modifiers reflect whether they transfer
|
|
Packit |
1470ea |
ownership: because my_str is owned by the local scope, it has
|
|
Packit |
1470ea |
type gchar , whereas template is
|
|
Packit |
1470ea |
const to denote it is unowned. Similarly, the
|
|
Packit |
1470ea |
template parameter of generate_string() and the
|
|
Packit |
1470ea |
str parameter of print_string() are
|
|
Packit |
1470ea |
const because no ownership is transferred when those
|
|
Packit |
1470ea |
functions are called. As ownership is transferred for the string
|
|
Packit |
1470ea |
parameter of g_value_take_string() , we can expect its type to
|
|
Packit |
1470ea |
be gchar .
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
(Note that this is not the case for
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html">
|
|
Packit |
1470ea |
GObject </link>s and subclasses, which can never be
|
|
Packit |
1470ea |
const . It is only the case for strings and simple
|
|
Packit |
1470ea |
struct s.)
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Finally, a few libraries use a function naming convention to indicate
|
|
Packit |
1470ea |
ownership transfer, for example using ‘take’ in a function name to
|
|
Packit |
1470ea |
indicate full transfer of parameters, as with
|
|
Packit |
1470ea |
g_value_take_string() . Note that different libraries use
|
|
Packit |
1470ea |
different conventions, as shown below:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Funktionsname
|
|
Packit |
1470ea |
Convention 1 (standard)
|
|
Packit |
1470ea |
Convention 2 (alternate)
|
|
Packit |
1470ea |
Convention 3 (<cmd>gdbus-codegen</cmd>)
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
get
|
|
Packit |
1470ea |
No transfer
|
|
Packit |
1470ea |
Any transfer
|
|
Packit |
1470ea |
Full transfer
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
dup
|
|
Packit |
1470ea |
Full transfer
|
|
Packit |
1470ea |
Nicht verwendet
|
|
Packit |
1470ea |
Nicht verwendet
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
peek
|
|
Packit |
1470ea |
Nicht verwendet
|
|
Packit |
1470ea |
Nicht verwendet
|
|
Packit |
1470ea |
No transfer
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
gesetzt
|
|
Packit |
1470ea |
No transfer
|
|
Packit |
1470ea |
No transfer
|
|
Packit |
1470ea |
No transfer
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
take
|
|
Packit |
1470ea |
Full transfer
|
|
Packit |
1470ea |
Nicht verwendet
|
|
Packit |
1470ea |
Nicht verwendet
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
steal
|
|
Packit |
1470ea |
Full transfer
|
|
Packit |
1470ea |
Full transfer
|
|
Packit |
1470ea |
Full transfer
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Ideally, all functions have a (transfer)
|
|
Packit |
1470ea |
<link xref="introspection">introspection annotation</link> for all
|
|
Packit |
1470ea |
relevant parameters and the return value. Failing that, here is a set of
|
|
Packit |
1470ea |
guidelines to use to determine whether ownership of a return value is
|
|
Packit |
1470ea |
transferred:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<steps>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
If the type has an introspection (transfer) annotation,
|
|
Packit |
1470ea |
look at that.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Otherwise, if the type is const , there is no transfer.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Otherwise, if the function documentation explicitly specifies the return
|
|
Packit |
1470ea |
value must be freed, there is full or container transfer.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Otherwise, if the function is named ‘dup’, ‘take’ or ‘steal’, there is
|
|
Packit |
1470ea |
full or container transfer.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Otherwise, if the function is named ‘peek’, there is no transfer.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Otherwise, you need to look at the function’s code to determine whether
|
|
Packit |
1470ea |
it intends ownership to be transferred. Then file a bug against the
|
|
Packit |
1470ea |
documentation for that function, and ask for an introspection annotation
|
|
Packit |
1470ea |
to be added.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
</steps>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Given this ownership and transfer infrastructure, the correct approach to
|
|
Packit |
1470ea |
memory allocation can be mechanically determined for each situation. In
|
|
Packit |
1470ea |
each case, the copy() function must be appropriate to the
|
|
Packit |
1470ea |
data type, for example g_strdup() for strings, or
|
|
Packit |
1470ea |
g_object_ref() for GObjects.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
When thinking about ownership transfer,
|
|
Packit |
1470ea |
malloc() /free() and reference counting are
|
|
Packit |
1470ea |
equivalent: in the former case, a newly allocated piece of heap memory is
|
|
Packit |
1470ea |
transferred; in the latter, a newly incremented reference.
|
|
Packit |
1470ea |
See <link xref="#reference-counting"/>.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="assignments">
|
|
Packit |
1470ea |
<title>Zuweisungen</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Zuweisungen von/nach
|
|
Packit |
1470ea |
Owned destination
|
|
Packit |
1470ea |
Unowned destination
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Owned source
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Copy or move the source to the destination.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
owned_dest = copy (owned_src)
|
|
Packit |
1470ea |
owned_dest = owned_src; owned_src = NULL
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Pure assignment, assuming the unowned variable is not used after
|
|
Packit |
1470ea |
the owned one is freed.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
unowned_dest = owned_src
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Unowned source
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Copy the source to the destination.
|
|
Packit |
1470ea |
owned_dest = copy (unowned_src)
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Pure assignment.
|
|
Packit |
1470ea |
unowned_dest = unowned_src
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="function-calls">
|
|
Packit |
1470ea |
<title>Funktionsaufrufe</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Aufruf von/nach
|
|
Packit |
1470ea |
Transfer full parameter
|
|
Packit |
1470ea |
Transfer none parameter
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Owned source
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Copy or move the source for the parameter.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
function_call (copy (owned_src))
|
|
Packit |
1470ea |
function_call (owned_src); owned_src = NULL
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Pure parameter passing.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
function_call (owned_src)
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Unowned source
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Copy the source for the parameter.
|
|
Packit |
1470ea |
function_call (copy (unowned_src))
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Pure parameter passing.
|
|
Packit |
1470ea |
function_call (unowned_src)
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="function-returns">
|
|
Packit |
1470ea |
<title>Funktionsrückgaben</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Rückkehr von/nach
|
|
Packit |
1470ea |
Transfer full return
|
|
Packit |
1470ea |
Transfer none return
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Owned source
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Pure variable return.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
return owned_src
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Invalid. The source needs to be freed, so the return value would
|
|
Packit |
1470ea |
use freed memory — a use-after-free error.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Unowned source
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Copy the source for the return.
|
|
Packit |
1470ea |
return copy (unowned_src)
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Pure variable passing.
|
|
Packit |
1470ea |
return unowned_src
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="documentation">
|
|
Packit |
1470ea |
<title>Dokumentation</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Documenting the ownership transfer for each function parameter and return,
|
|
Packit |
1470ea |
and the ownership for each variable, is important. While they may be clear
|
|
Packit |
1470ea |
when writing the code, they are not clear a few months later; and may
|
|
Packit |
1470ea |
never be clear to users of an API. They should always be documented.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
The best way to document ownership transfer is to use the
|
|
Packit |
1470ea |
<link href="https://wiki.gnome.org/Projects/GObjectIntrospection/Annotations#Memory_and_lifecycle_management">
|
|
Packit |
1470ea |
(transfer) </link> annotation introduced by
|
|
Packit |
1470ea |
<link xref="introspection">gobject-introspection</link>. Include this in
|
|
Packit |
1470ea |
the API documentation comment for each function parameter and return type.
|
|
Packit |
1470ea |
If a function is not public API, write a documentation comment for it
|
|
Packit |
1470ea |
anyway and include the (transfer) annotations. By doing so,
|
|
Packit |
1470ea |
the introspection tools can also read the annotations and use them to
|
|
Packit |
1470ea |
correctly introspect the API.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Zum Beispiel:
|
|
Packit |
1470ea |
/**
|
|
Packit |
1470ea |
* g_value_take_string:
|
|
Packit |
1470ea |
* @value: (transfer none): an initialized #GValue
|
|
Packit |
1470ea |
* @str: (transfer full): string to set it to
|
|
Packit |
1470ea |
*
|
|
Packit |
1470ea |
* Function documentation goes here.
|
|
Packit |
1470ea |
*/
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/**
|
|
Packit |
1470ea |
* generate_string:
|
|
Packit |
1470ea |
* @template: (transfer none): a template to follow when generating the string
|
|
Packit |
1470ea |
*
|
|
Packit |
1470ea |
* Function documentation goes here.
|
|
Packit |
1470ea |
*
|
|
Packit |
1470ea |
* Returns: (transfer full): a newly generated string
|
|
Packit |
1470ea |
*/
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Ownership for variables can be documented using inline comments. These are
|
|
Packit |
1470ea |
non-standard, and not read by any tools, but can form a convention if used
|
|
Packit |
1470ea |
consistently.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
GObject *some_owned_object = NULL; /* owned */
|
|
Packit |
1470ea |
GObject *some_unowned_object; /* unowned */
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
The documentation for <link xref="#container-types"/> is similarly only a
|
|
Packit |
1470ea |
convention; it includes the type of the contained elements too:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
GPtrArray/*<owned gchar*>*/ *some_unowned_string_array; /* unowned */
|
|
Packit |
1470ea |
GPtrArray/*<owned gchar*>*/ *some_owned_string_array = NULL; /* owned */
|
|
Packit |
1470ea |
GPtrArray/*<unowned GObject*>*/ *some_owned_object_array = NULL; /* owned */
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Note also that owned variables should always be initialized so that
|
|
Packit |
1470ea |
freeing them is more convenient. See
|
|
Packit |
1470ea |
<link xref="#convenience-functions"/>.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Also note that some types, for example basic C types like strings, can
|
|
Packit |
1470ea |
have the const modifier added if they are unowned, to take
|
|
Packit |
1470ea |
advantage of compiler warnings resulting from assigning those variables to
|
|
Packit |
1470ea |
owned variables (which must not use the const
|
|
Packit |
1470ea |
modifier). If so, the /* unowned */ comment may be omitted.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="reference-counting">
|
|
Packit |
1470ea |
<title>Referenzenzählung</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
As well as conventional malloc() /free() -style
|
|
Packit |
1470ea |
types, GLib has various reference counted types —
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html">
|
|
Packit |
1470ea |
GObject </link> being a prime example.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
The concepts of ownership and transfer apply just as well to reference
|
|
Packit |
1470ea |
counted types as they do to allocated types. A scope owns a
|
|
Packit |
1470ea |
reference counted type if it holds a strong reference to the instance
|
|
Packit |
1470ea |
(for example by calling
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html#g-object-ref">
|
|
Packit |
1470ea |
g_object_ref() </link>). An instance can be ‘copied’ by
|
|
Packit |
1470ea |
calling g_object_ref() again. Ownership can be freed with
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html#g-object-unref">
|
|
Packit |
1470ea |
g_object_unref() </link> — even though this may not actually
|
|
Packit |
1470ea |
finalize the instance, it frees the current scope’s ownership of that
|
|
Packit |
1470ea |
instance.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
See <link xref="#g-clear-object"/> for a convenient way of handling
|
|
Packit |
1470ea |
GObject references.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
There are other reference counted types in GLib, such as
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/glib/stable/glib-Hash-Tables.html">
|
|
Packit |
1470ea |
GHashTable </link> (using
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/glib/stable/glib-Hash-Tables.html#g-hash-table-ref">
|
|
Packit |
1470ea |
g_hash_table_ref() </link> and
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/glib/stable/glib-Hash-Tables.html#g-hash-table-unref">
|
|
Packit |
1470ea |
g_hash_table_unref() </link>), or
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/glib/stable/glib-GVariant.html">
|
|
Packit |
1470ea |
GVariant </link>
|
|
Packit |
1470ea |
(<link href="https://developer.gnome.org/glib/stable/glib-GVariant.html#g-variant-ref">
|
|
Packit |
1470ea |
g_variant_ref() </link>,
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/glib/stable/glib-GVariant.html#g-variant-unref">
|
|
Packit |
1470ea |
g_variant_unref() </link>). Some types, like
|
|
Packit |
1470ea |
GHashTable , support both reference counting and explicit
|
|
Packit |
1470ea |
finalization. Reference counting should always be used in preference,
|
|
Packit |
1470ea |
because it allows instances to be easily shared between multiple scopes
|
|
Packit |
1470ea |
(each holding their own reference) without having to allocate multiple
|
|
Packit |
1470ea |
copies of the instance. This saves memory.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="floating-references">
|
|
Packit |
1470ea |
<title>Floating References</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Classes which are derived from
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html#GInitiallyUnowned">GInitiallyUnowned </link>,
|
|
Packit |
1470ea |
as opposed to
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html#GObject-struct">GObject </link>
|
|
Packit |
1470ea |
have an initial reference which is floating, meaning that no
|
|
Packit |
1470ea |
code owns the reference. As soon as
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html#g-object-ref-sink">g_object_ref_sink() </link>
|
|
Packit |
1470ea |
is called on the object, the floating reference is converted to a strong
|
|
Packit |
1470ea |
reference, and the calling code assumes ownership of the object.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Floating references are a convenience for use in C in APIs, such as
|
|
Packit |
1470ea |
GTK+, where large numbers of objects must be created and organized into
|
|
Packit |
1470ea |
a hierarchy. In these cases, calling g_object_unref() to
|
|
Packit |
1470ea |
drop all the strong references would result in a lot of code.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<example>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Floating references allow the following code to be simplified:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
GtkWidget *new_widget;
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
new_widget = gtk_some_widget_new ();
|
|
Packit |
1470ea |
gtk_container_add (some_container, new_widget);
|
|
Packit |
1470ea |
g_object_unref (new_widget);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Instead, the following code can be used, with the
|
|
Packit |
1470ea |
GtkContainer assuming ownership of the floating
|
|
Packit |
1470ea |
reference:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
gtk_container_add (some_container, gtk_some_widget_new ());
|
|
Packit |
1470ea |
</example>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Floating references are only used by a few APIs — in particular,
|
|
Packit |
1470ea |
GtkWidget and all its subclasses. You must learn which APIs
|
|
Packit |
1470ea |
support it, and which APIs consume floating references, and only use
|
|
Packit |
1470ea |
them together.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Note that g_object_ref_sink() is equivalent to
|
|
Packit |
1470ea |
g_object_ref() when called on a non-floating reference,
|
|
Packit |
1470ea |
making gtk_container_add() no different from any other
|
|
Packit |
1470ea |
function in such cases.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
See the <link href="https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html#floating-ref">GObject
|
|
Packit |
1470ea |
manual</link> for more information on floating references.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="convenience-functions">
|
|
Packit |
1470ea |
<title>Convenience Functions</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
GLib provides various convenience functions for memory management,
|
|
Packit |
1470ea |
especially for GObjects. Three will be covered here, but others exist —
|
|
Packit |
1470ea |
check the GLib API documentation for more. They typically follow similar
|
|
Packit |
1470ea |
naming schemas to these three (using ‘_full’ suffixes, or the verb ‘clear’
|
|
Packit |
1470ea |
in the function name).
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="g-clear-object">
|
|
Packit |
1470ea |
<title>g_clear_object() </title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html#g-clear-object">
|
|
Packit |
1470ea |
g_clear_object() </link> is a version of
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html#g-object-unref">
|
|
Packit |
1470ea |
g_object_unref() </link> which unrefs a GObject and then
|
|
Packit |
1470ea |
clears the pointer to it to NULL .
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
This makes it easier to implement code that guarantees a GObject pointer
|
|
Packit |
1470ea |
is always either NULL , or has ownership of a GObject (but
|
|
Packit |
1470ea |
which never points to a GObject it no longer owns).
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
By initialising all owned GObject pointers to NULL , freeing
|
|
Packit |
1470ea |
them at the end of the scope is as simple as calling
|
|
Packit |
1470ea |
g_clear_object() without any checks, as discussed in
|
|
Packit |
1470ea |
<link xref="#single-path-cleanup"/>:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
void
|
|
Packit |
1470ea |
my_function (void)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
GObject *some_object = NULL; /* owned */
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
if (rand ())
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
some_object = create_new_object ();
|
|
Packit |
1470ea |
/* do something with the object */
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
g_clear_object (&some_object);
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="g-list-free-full">
|
|
Packit |
1470ea |
<title>g_list_free_full() </title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/glib/stable/glib-Doubly-Linked-Lists.html#g-list-free-full">
|
|
Packit |
1470ea |
g_list_free_full() </link> frees all the elements in a
|
|
Packit |
1470ea |
linked list, and all their data. It is much more convenient
|
|
Packit |
1470ea |
than iterating through the list to free all the elements’ data, then
|
|
Packit |
1470ea |
calling <link href="https://developer.gnome.org/glib/stable/glib-Doubly-Linked-Lists.html#g-list-free">
|
|
Packit |
1470ea |
g_list_free() </link> to free the GList
|
|
Packit |
1470ea |
elements themselves.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="g-hash-table-new-full">
|
|
Packit |
1470ea |
<title>g_hash_table_new_full() </title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/glib/stable/glib-Hash-Tables.html#g-hash-table-new-full">
|
|
Packit |
1470ea |
g_hash_table_new_full() </link> is a newer version of
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/glib/stable/glib-Hash-Tables.html#g-hash-table-new">
|
|
Packit |
1470ea |
g_hash_table_new() </link> which allows setting functions to
|
|
Packit |
1470ea |
destroy each key and value in the hash table when they are removed.
|
|
Packit |
1470ea |
These functions are then automatically called for all keys and values
|
|
Packit |
1470ea |
when the hash table is destroyed, or when an entry is removed using
|
|
Packit |
1470ea |
g_hash_table_remove() .
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Essentially, it simplifies memory management of keys and values to the
|
|
Packit |
1470ea |
question of whether they are present in the hash table. See
|
|
Packit |
1470ea |
<link xref="#container-types"/> for a discussion on ownership of
|
|
Packit |
1470ea |
elements within container types.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
A similar function exists for GPtrArray :
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/glib/stable/glib-Pointer-Arrays.html#g-ptr-array-new-with-free-func">
|
|
Packit |
1470ea |
g_ptr_array_new_with_free_func() </link>.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="container-types">
|
|
Packit |
1470ea |
<title>Containertypen</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
When using container types, such as GPtrArray or
|
|
Packit |
1470ea |
GList , an additional level of ownership is introduced: as
|
|
Packit |
1470ea |
well as the ownership of the container instance, each element in the
|
|
Packit |
1470ea |
container is either owned or unowned too. By nesting containers, multiple
|
|
Packit |
1470ea |
levels of ownership must be tracked. Ownership of owned elements belongs
|
|
Packit |
1470ea |
to the container; ownership of the container belongs to the scope it’s in
|
|
Packit |
1470ea |
(which may be another container).
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
A key principle for simplifying this is to ensure that all elements in a
|
|
Packit |
1470ea |
container have the same ownership: they are either all owned, or all
|
|
Packit |
1470ea |
unowned. This happens automatically if the normal
|
|
Packit |
1470ea |
<link xref="#convenience-functions"/> are used for types like
|
|
Packit |
1470ea |
GPtrArray and GHashTable .
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
If elements in a container are owned, adding them to the
|
|
Packit |
1470ea |
container is essentially an ownership transfer. For example, for an array
|
|
Packit |
1470ea |
of strings, if the elements are owned, the definition of
|
|
Packit |
1470ea |
g_ptr_array_add() is effectively:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/**
|
|
Packit |
1470ea |
* g_ptr_array_add:
|
|
Packit |
1470ea |
* @array: a #GPtrArray
|
|
Packit |
1470ea |
* @str: (transfer full): string to add
|
|
Packit |
1470ea |
*/
|
|
Packit |
1470ea |
void
|
|
Packit |
1470ea |
g_ptr_array_add (GPtrArray *array,
|
|
Packit |
1470ea |
gchar *str);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
So, for example, constant (unowned) strings must be added to the array
|
|
Packit |
1470ea |
using g_ptr_array_add (array, g_strdup ("constant string")) .
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Whereas if the elements are unowned, the definition is effectively:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/**
|
|
Packit |
1470ea |
* g_ptr_array_add:
|
|
Packit |
1470ea |
* @array: a #GPtrArray
|
|
Packit |
1470ea |
* @str: (transfer none): string to add
|
|
Packit |
1470ea |
*/
|
|
Packit |
1470ea |
void
|
|
Packit |
1470ea |
g_ptr_array_add (GPtrArray *array,
|
|
Packit |
1470ea |
const gchar *str);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Here, constant strings can be added without copying them:
|
|
Packit |
1470ea |
g_ptr_array_add (array, "constant string") .
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
See <link xref="#documentation"/> for examples of comments to add to
|
|
Packit |
1470ea |
variable definitions to annotate them with the element type and ownership.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="single-path-cleanup">
|
|
Packit |
1470ea |
<title>Single-Path Cleanup</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
A useful design pattern for more complex functions is to have a single
|
|
Packit |
1470ea |
control path which cleans up (frees) allocations and returns to the
|
|
Packit |
1470ea |
caller. This vastly simplifies tracking of allocations, as it’s no longer
|
|
Packit |
1470ea |
necessary to mentally work out which allocations have been freed on each
|
|
Packit |
1470ea |
code path — all code paths end at the same point, so perform all the frees
|
|
Packit |
1470ea |
then. The benefits of this approach rapidly become greater for larger
|
|
Packit |
1470ea |
functions with more owned local variables; it may not make sense to apply
|
|
Packit |
1470ea |
the pattern to smaller functions.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
This approach has two requirements:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<list type="numbered">
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
The function returns from a single point, and uses goto to
|
|
Packit |
1470ea |
reach that point from other paths.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
All owned variables are set to NULL when initialized or
|
|
Packit |
1470ea |
when ownership is transferred away from them.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
</list>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
The example below is for a small function (for brevity), but should
|
|
Packit |
1470ea |
illustrate the principles for application of the pattern to larger
|
|
Packit |
1470ea |
functions:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<listing>
|
|
Packit |
1470ea |
<title>Single-Path Cleanup Example</title>
|
|
Packit |
1470ea |
<desc>
|
|
Packit |
1470ea |
Example of implementing single-path cleanup for a simple function
|
|
Packit |
1470ea |
</desc>
|
|
Packit |
1470ea |
GObject *
|
|
Packit |
1470ea |
some_function (GError **error)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
gchar *some_str = NULL; /* owned */
|
|
Packit |
1470ea |
GObject *temp_object = NULL; /* owned */
|
|
Packit |
1470ea |
const gchar *temp_str;
|
|
Packit |
1470ea |
GObject *my_object = NULL; /* owned */
|
|
Packit |
1470ea |
GError *child_error = NULL; /* owned */
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
temp_object = generate_object ();
|
|
Packit |
1470ea |
temp_str = "example string";
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
if (rand ())
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
some_str = g_strconcat (temp_str, temp_str, NULL);
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
else
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
some_operation_which_might_fail (&child_error);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
if (child_error != NULL)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
goto done;
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
my_object = generate_wrapped_object (temp_object);
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
done:
|
|
Packit |
1470ea |
/* Here, @some_str is either NULL or a string to be freed, so can be passed to
|
|
Packit |
1470ea |
* g_free() unconditionally.
|
|
Packit |
1470ea |
*
|
|
Packit |
1470ea |
* Similarly, @temp_object is either NULL or an object to be unreffed, so can
|
|
Packit |
1470ea |
* be passed to g_clear_object() unconditionally. */
|
|
Packit |
1470ea |
g_free (some_str);
|
|
Packit |
1470ea |
g_clear_object (&temp_object);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/* The pattern can also be used to ensure that the function always returns
|
|
Packit |
1470ea |
* either an error or a return value (but never both). */
|
|
Packit |
1470ea |
if (child_error != NULL)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
g_propagate_error (error, child_error);
|
|
Packit |
1470ea |
g_clear_object (&my_object);
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
return my_object;
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
</listing>
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="verification">
|
|
Packit |
1470ea |
<title>Überprüfung</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Memory leaks can be checked for in two ways: static analysis, and runtime
|
|
Packit |
1470ea |
leak checking.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Static analysis with tools like
|
|
Packit |
1470ea |
<link xref="tooling#coverity">Coverity</link>, the
|
|
Packit |
1470ea |
<link xref="tooling#clang-static-analyzer">Clang static analyzer</link> or
|
|
Packit |
1470ea |
<link xref="tooling#tartan">Tartan</link> can
|
|
Packit |
1470ea |
catch some leaks, but require knowledge of the ownership transfer of every
|
|
Packit |
1470ea |
function called in the code. Domain-specific static analyzers like Tartan
|
|
Packit |
1470ea |
(which knows about GLib memory allocation and transfer) can perform better
|
|
Packit |
1470ea |
here, but Tartan is quite a young project and still misses things (a low
|
|
Packit |
1470ea |
true positive rate). It is recommended that code be put through a static
|
|
Packit |
1470ea |
analyzer, but the primary tool for detecting leaks should be runtime leak
|
|
Packit |
1470ea |
checking.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Runtime leak checking is done using
|
|
Packit |
1470ea |
<link xref="tooling#valgrind">Valgrind</link>, using its
|
|
Packit |
1470ea |
<link xref="tooling#memcheck">memcheck</link> tool. Any leak it detects as
|
|
Packit |
1470ea |
‘definitely losing memory’ should be fixed. Many of the leaks which
|
|
Packit |
1470ea |
‘potentially’ lose memory are not real leaks, and should be added to the
|
|
Packit |
1470ea |
suppression file.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
If compiling with a recent version of Clang or GCC, the
|
|
Packit |
1470ea |
<link xref="tooling#address-sanitizer">address sanitizer</link> can be
|
|
Packit |
1470ea |
enabled instead, and it will detect memory leaks and overflow problems at
|
|
Packit |
1470ea |
runtime, but without the difficulty of running Valgrind in the right
|
|
Packit |
1470ea |
environment. Note, however, that it is still a young tool, so may fail in
|
|
Packit |
1470ea |
some cases.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
See <link xref="tooling#valgrind"/> for more information on using
|
|
Packit |
1470ea |
Valgrind.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
</page>
|