| <!-- ##### SECTION Title ##### --> |
| Error Reporting |
| |
| <!-- ##### SECTION Short_Description ##### --> |
| a system for reporting errors. |
| |
| <!-- ##### SECTION Long_Description ##### --> |
| |
| <para> |
| GLib provides a standard method of reporting errors from a called function to |
| the calling code. (This is the same problem solved by exceptions in other |
| languages.) It's important to understand that this method is both a |
| <emphasis>data type</emphasis> (the #GError object) and a <emphasis>set of |
| rules.</emphasis> If you use #GError incorrectly, then your code will not |
| properly interoperate with other code that uses #GError, and users of your API |
| will probably get confused. |
| </para> |
| |
| <para> |
| First and foremost: <emphasis>#GError should only be used to report |
| recoverable runtime errors, never to report programming errors.</emphasis> If |
| the programmer has screwed up, then you should use g_warning(), |
| g_return_if_fail(), g_assert(), g_error(), or some similar facility. |
| (Incidentally, remember that the g_error() function should |
| <emphasis>only</emphasis> be used for programming errors, it should not be used |
| to print any error reportable via #GError.) |
| </para> |
| |
| <para> |
| Examples of recoverable runtime errors are "file not found" or "failed to parse |
| input." Examples of programming errors are "NULL passed to strcmp()" or |
| "attempted to free the same pointer twice." These two kinds of errors are |
| fundamentally different: runtime errors should be handled or reported to the |
| user, programming errors should be eliminated by fixing the bug in the program. |
| This is why most functions in GLib and GTK+ do not use the #GError facility. |
| </para> |
| |
| <para> |
| Functions that can fail take a return location for a #GError as their last argument. |
| For example: |
| <informalexample><programlisting> |
| gboolean g_file_get_contents (const gchar *filename, |
| gchar **contents, |
| gsize *length, |
| GError **error); |
| </programlisting></informalexample> |
| If you pass a non-%NULL value for the <literal>error</literal> argument, it should |
| point to a location where an error can be placed. For example: |
| <informalexample><programlisting> |
| gchar *contents; |
| GError *err = NULL; |
| g_file_get_contents ("foo.txt", &contents, NULL, &err); |
| g_assert ((contents == NULL && err != NULL) || (contents != NULL && err == NULL)); |
| if (err != NULL) |
| { |
| /* Report error to user, and free error */ |
| g_assert (contents == NULL); |
| fprintf (stderr, "Unable to read file: %s\n", err->message); |
| g_error_free (err); |
| } |
| else |
| { |
| /* Use file contents */ |
| g_assert (contents != NULL); |
| } |
| </programlisting></informalexample> |
| Note that <literal>err != NULL</literal> in this example is a |
| <emphasis>reliable</emphasis> indicator of whether |
| g_file_get_contents() failed. Additionally, g_file_get_contents() returns |
| a boolean which indicates whether it was successful. |
| </para> |
| |
| <para> |
| Because g_file_get_contents() returns %FALSE on failure, if you are only |
| interested in whether it failed and don't need to display an error message, you |
| can pass %NULL for the <literal>error</literal> argument: |
| <informalexample><programlisting> |
| if (g_file_get_contents ("foo.txt", &contents, NULL, NULL)) /* ignore errors */ |
| /* no error occurred */ ; |
| else |
| /* error */ ; |
| </programlisting></informalexample> |
| </para> |
| |
| <para> |
| The #GError object contains three fields: <literal>domain</literal> indicates |
| the module the error-reporting function is located in, <literal>code</literal> |
| indicates the specific error that occurred, and <literal>message</literal> is a |
| user-readable error message with as many details as possible. Several functions |
| are provided to deal with an error received from a called function: |
| g_error_matches() returns %TRUE if the error matches a given domain and code, |
| g_propagate_error() copies an error into an error location (so the calling |
| function will receive it), and g_clear_error() clears an error location by |
| freeing the error and resetting the location to %NULL. To display an error to the |
| user, simply display <literal>error->message</literal>, perhaps along with |
| additional context known only to the calling function (the file being opened, or |
| whatever -- though in the g_file_get_contents() case, |
| <literal>error->message</literal> already contains a filename). |
| </para> |
| |
| <para> |
| When implementing a function that can report errors, the basic tool is |
| g_set_error(). Typically, if a fatal error occurs you want to g_set_error(), |
| then return immediately. g_set_error() does nothing if the error location passed |
| to it is %NULL. Here's an example: |
| <informalexample><programlisting> |
| gint |
| foo_open_file (GError **error) |
| { |
| gint fd; |
| |
| fd = open ("file.txt", O_RDONLY); |
| |
| if (fd < 0) |
| { |
| g_set_error (error, |
| FOO_ERROR, /* error domain */ |
| FOO_ERROR_BLAH, /* error code */ |
| "Failed to open file: %s", /* error message format string */ |
| g_strerror (errno)); |
| return -1; |
| } |
| else |
| return fd; |
| } |
| </programlisting></informalexample> |
| </para> |
| |
| <para> |
| Things are somewhat more complicated if you yourself call another function that |
| can report a #GError. If the sub-function indicates fatal errors in some way |
| other than reporting a #GError, such as by returning %TRUE on success, you can |
| simply do the following: |
| <informalexample><programlisting> |
| gboolean |
| my_function_that_can_fail (GError **err) |
| { |
| g_return_val_if_fail (err == NULL || *err == NULL, FALSE); |
| |
| if (!sub_function_that_can_fail (err)) |
| { |
| /* assert that error was set by the sub-function */ |
| g_assert (err == NULL || *err != NULL); |
| return FALSE; |
| } |
| |
| /* otherwise continue, no error occurred */ |
| g_assert (err == NULL || *err == NULL); |
| } |
| </programlisting></informalexample> |
| </para> |
| |
| <para> |
| If the sub-function does not indicate errors other than by reporting a #GError, |
| you need to create a temporary #GError since the passed-in one may be %NULL. |
| g_propagate_error() is intended for use in this case. |
| <informalexample><programlisting> |
| gboolean |
| my_function_that_can_fail (GError **err) |
| { |
| GError *tmp_error; |
| |
| g_return_val_if_fail (err == NULL || *err == NULL, FALSE); |
| |
| tmp_error = NULL; |
| sub_function_that_can_fail (&tmp_error); |
| |
| if (tmp_error != NULL) |
| { |
| /* store tmp_error in err, if err != NULL, |
| * otherwise call g_error_free(<!-- -->) on tmp_error |
| */ |
| g_propagate_error (err, tmp_error); |
| return FALSE; |
| } |
| |
| /* otherwise continue, no error occurred */ |
| } |
| </programlisting></informalexample> |
| </para> |
| |
| <para> |
| Error pileups are always a bug. For example, this code is incorrect: |
| <informalexample><programlisting> |
| gboolean |
| my_function_that_can_fail (GError **err) |
| { |
| GError *tmp_error; |
| |
| g_return_val_if_fail (err == NULL || *err == NULL, FALSE); |
| |
| tmp_error = NULL; |
| sub_function_that_can_fail (&tmp_error); |
| other_function_that_can_fail (&tmp_error); |
| |
| if (tmp_error != NULL) |
| { |
| g_propagate_error (err, tmp_error); |
| return FALSE; |
| } |
| } |
| </programlisting></informalexample> |
| <literal>tmp_error</literal> should be checked immediately after |
| <function>sub_function_that_can_fail()</function>, and either cleared or propagated upward. The rule |
| is: <emphasis>after each error, you must either handle the error, or return it to the |
| calling function</emphasis>. Note that passing %NULL for the error location is the |
| equivalent of handling an error by always doing nothing about it. So the |
| following code is fine, assuming errors in <function>sub_function_that_can_fail()</function> are not |
| fatal to <function>my_function_that_can_fail()</function>: |
| <informalexample><programlisting> |
| gboolean |
| my_function_that_can_fail (GError **err) |
| { |
| GError *tmp_error; |
| |
| g_return_val_if_fail (err == NULL || *err == NULL, FALSE); |
| |
| sub_function_that_can_fail (NULL); /* ignore errors */ |
| |
| tmp_error = NULL; |
| other_function_that_can_fail (&tmp_error); |
| |
| if (tmp_error != NULL) |
| { |
| g_propagate_error (err, tmp_error); |
| return FALSE; |
| } |
| } |
| </programlisting></informalexample> |
| </para> |
| |
| <para> |
| Note that passing %NULL for the error location <emphasis>ignores</emphasis> |
| errors; it's equivalent to <literal>try { sub_function_that_can_fail (); } catch |
| (...) {}</literal> in C++. It does <emphasis>not</emphasis> mean to leave errors |
| unhandled; it means to handle them by doing nothing. |
| </para> |
| |
| <para> |
| Error domains and codes are conventionally named as follows: |
| <itemizedlist> |
| <listitem> |
| <para> |
| The error domain is called |
| <literal><NAMESPACE>_<MODULE>_ERROR</literal>, for example |
| %G_EXEC_ERROR or %G_THREAD_ERROR. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| The error codes are in an enumeration called |
| <literal><Namespace>_<Module>_Error</literal>; for example, |
| #GThreadError or #GSpawnError. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Members of the error code enumeration are called <literal><NAMESPACE>_<MODULE>_ERROR_<CODE></literal>, for example %G_SPAWN_ERROR_FORK or %G_THREAD_ERROR_AGAIN. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| If there's a "generic" or "unknown" error code for unrecoverable errors it |
| doesn't make sense to distinguish with specific codes, it should be called |
| <literal><NAMESPACE>_<MODULE>_ERROR_FAILED</literal>, for |
| example %G_SPAWN_ERROR_FAILED or %G_THREAD_ERROR_FAILED. |
| </para> |
| </listitem> |
| </itemizedlist> |
| </para> |
| |
| <para> |
| Summary of rules for use of #GError: |
| <itemizedlist> |
| <listitem> |
| <para> |
| Do not report programming errors via #GError. |
| </para> |
| </listitem> |
| |
| <listitem> |
| <para> |
| The last argument of a function that returns an error should be a |
| location where a #GError can be placed (i.e. "#GError** error"). If |
| #GError is used with varargs, the #GError** should be the last |
| argument before the "...". |
| </para> |
| </listitem> |
| |
| <listitem> |
| <para> |
| The caller may pass %NULL for the #GError** if they are not interested |
| in details of the exact error that occurred. |
| </para> |
| </listitem> |
| |
| <listitem> |
| <para> |
| If %NULL is passed for the #GError** argument, then errors should |
| not be returned to the caller, but your function should still |
| abort and return if an error occurs. That is, control flow should |
| not be affected by whether the caller wants to get a #GError. |
| </para> |
| </listitem> |
| |
| <listitem> |
| <para> |
| If a #GError is reported, then your function by definition |
| <emphasis>had a fatal failure and did not complete whatever it was supposed |
| to do</emphasis>. If the failure was not fatal, then you handled it |
| and you should not report it. If it was fatal, then you must report it |
| and discontinue whatever you were doing immediately. |
| </para> |
| </listitem> |
| |
| <listitem> |
| <para> |
| A #GError* must be initialized to %NULL before passing its address to |
| a function that can report errors. |
| </para> |
| </listitem> |
| |
| <listitem> |
| <para> |
| "Piling up" errors is always a bug. That is, if you assign a new |
| #GError to a #GError* that is non-%NULL, thus overwriting the previous |
| error, it indicates that you should have aborted the operation instead |
| of continuing. If you were able to continue, you should have cleared |
| the previous error with g_clear_error(). g_set_error() will complain |
| if you pile up errors. |
| </para> |
| </listitem> |
| |
| |
| <listitem> |
| <para> |
| By convention, if you return a boolean value indicating success |
| then %TRUE means success and %FALSE means failure. If %FALSE is returned, |
| the error <emphasis>must</emphasis> be set to a non-%NULL value. |
| </para> |
| </listitem> |
| |
| |
| <listitem> |
| <para> |
| A %NULL return value is also frequently used to mean that an error |
| occurred. You should make clear in your documentation whether %NULL is |
| a valid return value in non-error cases; if %NULL is a valid value, |
| then users must check whether an error was returned to see if the |
| function succeeded. |
| </para> |
| </listitem> |
| |
| <listitem> |
| <para> |
| When implementing a function that can report errors, you may want to |
| add a check at the top of your function that the error return location |
| is either %NULL or contains a %NULL error |
| (e.g. <literal>g_return_if_fail (error == NULL || *error == |
| NULL);</literal>). |
| </para> |
| </listitem> |
| |
| |
| </itemizedlist> |
| </para> |
| |
| <!-- ##### SECTION See_Also ##### --> |
| <para> |
| |
| </para> |
| |
| <!-- ##### SECTION Stability_Level ##### --> |
| |
| |
| <!-- ##### STRUCT GError ##### --> |
| <para> |
| The <structname>GError</structname> structure contains |
| information about an error that has occurred. |
| </para> |
| |
| @domain: error domain, e.g. #G_FILE_ERROR. |
| @code: error code, e.g. %G_FILE_ERROR_NOENT. |
| @message: human-readable informative error message. |
| |
| <!-- ##### FUNCTION g_error_new ##### --> |
| <para> |
| |
| </para> |
| |
| @domain: |
| @code: |
| @format: |
| @Varargs: |
| @Returns: |
| |
| |
| <!-- ##### FUNCTION g_error_new_literal ##### --> |
| <para> |
| |
| </para> |
| |
| @domain: |
| @code: |
| @message: |
| @Returns: |
| |
| |
| <!-- ##### FUNCTION g_error_free ##### --> |
| <para> |
| |
| </para> |
| |
| @error: |
| |
| |
| <!-- ##### FUNCTION g_error_copy ##### --> |
| <para> |
| |
| </para> |
| |
| @error: |
| @Returns: |
| |
| |
| <!-- ##### FUNCTION g_error_matches ##### --> |
| <para> |
| |
| </para> |
| |
| @error: |
| @domain: |
| @code: |
| @Returns: |
| |
| |
| <!-- ##### FUNCTION g_set_error ##### --> |
| <para> |
| |
| </para> |
| |
| @err: |
| @domain: |
| @code: |
| @format: |
| @Varargs: |
| |
| |
| <!-- ##### FUNCTION g_propagate_error ##### --> |
| <para> |
| |
| </para> |
| |
| @dest: |
| @src: |
| |
| |
| <!-- ##### FUNCTION g_clear_error ##### --> |
| <para> |
| |
| </para> |
| |
| @err: <!-- |
| Local variables: |
| mode: sgml |
| sgml-parent-document: ("../glib-docs.sgml" "book" "refsect2" "") |
| End: |
| --> |
| |
| |