Browse files

make error()'s constant return value more visible

When git is compiled with "gcc -Wuninitialized -O3", some
inlined calls provide an additional opportunity for the
compiler to do static analysis on variable initialization.
For example, with two functions like this:

  int get_foo(int *foo)
	if (something_that_might_fail() < 0)
		return error("unable to get foo");
	*foo = 0;
	return 0;

  void some_fun(void)
	  int foo;
	  if (get_foo(&foo) < 0)
		  return -1;
	  printf("foo is %d\n", foo);

If get_foo() is not inlined, then when compiling some_fun,
gcc sees only that a pointer to the local variable is
passed, and must assume that it is an out parameter that
is initialized after get_foo returns.

However, when get_foo() is inlined, the compiler may look at
all of the code together and see that some code paths in
get_foo() do not initialize the variable. As a result, it
prints a warning. But what the compiler can't see is that
error() always returns -1, and therefore we know that either
we return early from some_fun, or foo ends up initialized,
and the code is safe.  The warning is a false positive.

If we can make the compiler aware that error() will always
return -1, it can do a better job of analysis. The simplest
method would be to inline the error() function. However,
this doesn't work, because gcc will not inline a variadc
function. We can work around this by defining a macro. This
relies on two gcc extensions:

  1. Variadic macros (these are present in C99, but we do
     not rely on that).

  2. Gcc treats the "##" paste operator specially between a
     comma and __VA_ARGS__, which lets our variadic macro
     work even if no format parameters are passed to

Since we are using these extra features, we hide the macro
behind an #ifdef. This is OK, though, because our goal was
just to help gcc.

Signed-off-by: Jeff King <>
Signed-off-by: Junio C Hamano <>
  • Loading branch information...
1 parent bfae342 commit e208f9cc7574f5980faba498d0aa30b4defeb34f @peff peff committed with gitster Dec 15, 2012
Showing with 12 additions and 0 deletions.
  1. +11 −0 git-compat-util.h
  2. +1 −0 usage.c
@@ -288,6 +288,17 @@ extern NORETURN void die_errno(const char *err, ...) __attribute__((format (prin
extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
+ * Let callers be aware of the constant return value; this can help
+ * gcc with -Wuninitialized analysis. We have to restrict this trick to
+ * gcc, though, because of the variadic macro and the magic ## comma pasting
+ * behavior. But since we're only trying to help gcc, anyway, it's OK; other
+ * compilers will fall back to using the function as usual.
+ */
+#ifdef __GNUC__
+#define error(fmt, ...) (error((fmt), ##__VA_ARGS__), -1)
extern void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params));
extern void set_error_routine(void (*routine)(const char *err, va_list params));
@@ -130,6 +130,7 @@ void NORETURN die_errno(const char *fmt, ...)
+#undef error
int error(const char *err, ...)
va_list params;

0 comments on commit e208f9c

Please sign in to comment.