Alex Rivera | Logout

c99 goto past initialization

Asked 2010-05-12T18:27:42.560
25

While debugging a crash, I came across this issue in some code:

int func()
{
    char *p1 = malloc(...);
    if (p1 == NULL)
        goto err_exit;

    char *p2 = malloc(...);
    if (p2 == NULL)
        goto err_exit;

    ...

err_exit:
    free(p2);
    free(p1);

    return -1;
}

The problem occurs when the first malloc fails. Because we jump across the initialization of p2, it contains random data and the call to free(p2) can crash.

I would expect/hope that this would be treated the same way as in C++ where the compiler does not allow a goto to jump across an initialization.

My question: is jumping across an initialization allowed by the standard or is this a bug in gcc's implementation of c99?

Edit
Report

3 Answers

18

You can ask gcc to warn you when you jump over a variable definition by using -Wjump-misses-init and then you can use -Werror (or, more precisely, -Werror=jump-misses-init) to force the users to deal with it. This warning is included in -Wc++-compat so the gcc developers are aware that the code behaves differently in C versus C++.

You could also change the code slightly:

int func()
{
    char *p1 = malloc(...);
    if (p1 == NULL)
        goto err_exit_1;

    char *p2 = malloc(...);
    if (p2 == NULL)
        goto err_exit_2;

    ...

err_exit_2:
    free(p2);
err_exit_1:
    free(p1);

    return -1;
}

... and just keep pairing labels with initialized variables. You'll have the same problem with calling many other functions with unitialized variables, free just happens to be a more obvious one.

answered 2010-05-12T18:35:07.873
7

Hmm, it's not because the new standard allows for variable declarations anywhere that it's always a good idea to use it. In your case I would do like we did it in classic C.

int func()
{
char *p1 = NULL;    /* So we have a defined value */
char *p2 = NULL;

  p1 = malloc(...);
  if(!p1)
    goto err_exit;

  p2 = malloc(...);
  if(!p2)
    goto err_exit;

  ...

  err_exit:
    free(p2);
    free(p1);

  return -1;
}
answered 2010-05-13T15:46:07.967
2

if i compile this code with -O2 flag

gcc -Wall -std=c99 -O2 jump.c

i've got warning:

jump.c: In function ‘func’:
jump.c:10: warning: ‘p2’ may be used uninitialised in this function

and no warning without optimization

answered 2010-05-12T19:16:02.053

Your Answer