c99 goto past initialization

后端 未结 7 1968
被撕碎了的回忆
被撕碎了的回忆 2020-11-30 07:34

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

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

    char         


        
相关标签:
7条回答
  • 2020-11-30 08:04

    A jump like that is indeed allowed by the standard, so this is not a bug in GCC. The standard lists this situation as a suggested warning in Annex I.

    The only restriction imposed on jumps in C99 with regard to scope is that it is illegal to jump into scope of a variable of variably modified type, like a VLA

    int main() {
      int n = 5;
      goto label; // <- ERROR: illegal jump
      int a[n];
    label:;
    }
    

    In other words, it is not correct to say that "a jump is just a jump in C". Jumps are somewhat restricted when it comes to entering variable scope, albeit not as strictly as in C++. The situation you describe is not one of the restricted ones.

    0 讨论(0)
  • 2020-11-30 08:05

    This is not a bug in gcc. A jump is just a jump in C. There is no special logic applied. The issue is that you are not initializing your pointers to NULL first. If you were to do that then you free call would be free(NULL) which would not crash. Start the function with char *p1 = NULL, *p2 = NULL; and all will be well.

    0 讨论(0)
  • 2020-11-30 08:10

    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;
    }
    
    0 讨论(0)
  • 2020-11-30 08:14

    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.

    0 讨论(0)
  • 2020-11-30 08:18

    Using gotos is not a smart idea, and you've just found one reason why. You should call an error handling function for each individual error.

    0 讨论(0)
  • 2020-11-30 08:21

    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

    0 讨论(0)
提交回复
热议问题