Clean up process of calling g_debug_init()

Make sure that it calls absolutely nothing that may ever recurse back
into GLib again:

  - g_ascii_strcasecmp() is unsafe because it has g_return_if_fail() at
    the top.  As far as I know, the only ASCII character letter that
    would get special treatment here is "i" and that appears in neither
    "help" nor "all".

  - g_getenv() is very complicated on Windows, so use a simple version
    that is sufficient for our purposes.

Now that it's completely safe, we can just call it from g_logv() in the
usual way without all of the hacks.

https://bugzilla.gnome.org/show_bug.cgi?id=660744
This commit is contained in:
Ryan Lortie 2011-09-21 21:20:07 -04:00
parent 1481b7bca3
commit 310c3ed4cc
2 changed files with 46 additions and 59 deletions

View File

@ -186,46 +186,44 @@ g_messages_prefixed_init (void)
}
}
static guint
g_parse_debug_envvar (const gchar *envvar,
const GDebugKey *keys,
gint n_keys)
{
const gchar *value;
#ifdef OS_WIN32
/* "fatal-warnings,fatal-criticals,all,help" is pretty short */
gchar buffer[80];
if (GetEnvironmentVariable (envvar, buffer, 100) < 100)
value = buffer;
else
return 0;
#else
value = getenv (envvar);
#endif
return g_parse_debug_string (value, keys, n_keys);
}
static void
g_debug_init (void)
{
typedef enum {
G_DEBUG_FATAL_WARNINGS = 1 << 0,
G_DEBUG_FATAL_CRITICALS = 1 << 1
} GDebugFlag;
const gchar *val;
guint flags = 0;
const GDebugKey keys[] = {
{"fatal-warnings", G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL },
{"fatal-criticals", G_LOG_LEVEL_CRITICAL }
};
GLogLevelFlags flags;
flags = g_parse_debug_envvar ("G_DEBUG", keys, G_N_ELEMENTS (keys));
g_mutex_lock (&g_messages_lock);
g_log_always_fatal |= flags;
g_mutex_unlock (&g_messages_lock);
g_debug_initialized = TRUE;
val = g_getenv ("G_DEBUG");
if (val != NULL)
{
const GDebugKey keys[] = {
{"fatal_warnings", G_DEBUG_FATAL_WARNINGS},
{"fatal_criticals", G_DEBUG_FATAL_CRITICALS}
};
flags = g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
}
if (flags & G_DEBUG_FATAL_WARNINGS)
{
GLogLevelFlags fatal_mask;
fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
g_log_set_always_fatal (fatal_mask);
}
if (flags & G_DEBUG_FATAL_CRITICALS)
{
GLogLevelFlags fatal_mask;
fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
fatal_mask |= G_LOG_LEVEL_CRITICAL;
g_log_set_always_fatal (fatal_mask);
}
}
static GLogDomain*
@ -500,6 +498,9 @@ g_logv (const gchar *log_domain,
gboolean was_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0;
gint i;
if (!g_debug_initialized)
g_debug_init ();
log_level &= G_LOG_LEVEL_MASK;
if (!log_level)
return;
@ -542,24 +543,6 @@ g_logv (const gchar *log_domain,
g_private_set (&g_log_depth, GUINT_TO_POINTER (depth));
/* had to defer debug initialization until we can keep track of recursion */
if (!(test_level & G_LOG_FLAG_RECURSION) && !g_debug_initialized)
{
GLogLevelFlags orig_test_level = test_level;
g_debug_init ();
if ((domain_fatal_mask | g_log_always_fatal) & test_level)
test_level |= G_LOG_FLAG_FATAL;
if (test_level != orig_test_level)
{
/* need a relookup, not nice, but not too bad either */
g_mutex_lock (&g_messages_lock);
domain = g_log_find_domain_L (log_domain ? log_domain : "");
log_func = g_log_domain_get_handler_L (domain, test_level, &data);
domain = NULL;
g_mutex_unlock (&g_messages_lock);
}
}
if (test_level & G_LOG_FLAG_RECURSION)
{

View File

@ -666,6 +666,7 @@ debug_key_matches (const gchar *key,
const gchar *token,
guint length)
{
/* may not call GLib functions: see note in g_parse_debug_string() */
for (; length; length--, key++, token++)
{
char k = (*key == '_') ? '-' : tolower (*key );
@ -708,17 +709,20 @@ g_parse_debug_string (const gchar *string,
if (string == NULL)
return 0;
/* this function is used by gmem.c/gslice.c initialization code,
* so introducing malloc dependencies here would require adaptions
* of those code portions.
/* this function is used during the initialisation of gmessages, gmem
* and gslice, so it may not do anything that causes memory to be
* allocated or risks messages being emitted.
*
* this means, more or less, that this code may not call anything
* inside GLib.
*/
if (!g_ascii_strcasecmp (string, "all"))
if (!strcasecmp (string, "all"))
{
for (i=0; i<nkeys; i++)
result |= keys[i].value;
}
else if (!g_ascii_strcasecmp (string, "help"))
else if (!strcasecmp (string, "help"))
{
/* using stdio directly for the reason stated above */
fprintf (stderr, "Supported debug values: ");