Search code examples
cgccg++gcc-warningstb-image

GCC produces errors on valid stb_image.h


Following shows two errors generated by GCC:

 In file included from /home/omar/Desktop/Lovelace/src/main.cpp:22:
         /home/omar/Desktop/Lovelace/include/stb/stb_image.h: In function ‘void* stbi__load_gif_main(stbi__context*, int**, int*, int*,
 int*, int*, int)’:
         /home/omar/Desktop/Lovelace/include/stb/stb_image.h:6778:11: **error: variable ‘out_size’ set but not used** [-Werror=unused-but-set-variable]
          6778 |       int out_size = 0;
               |           ^~~~~~~~
         /home/omar/Desktop/Lovelace/include/stb/stb_image.h:6779:11: **error: variable ‘delays_size’ set but not used** [-Werror=unused-but-set-variable]
          6779 |       int delays_size = 0;
               |           ^~~~~~~~~~~
         cc1plus: all warnings being treated as errors
         make[2]: *** [CMakeFiles/lovelace.dir/build.make:102: CMakeFiles/lovelace.dir/src/main.cpp.o] Error 1
         make[1]: *** [CMakeFiles/Makefile2:76: CMakeFiles/lovelace.dir/all] Error 2
         make: *** [Makefile:84: all] Error 2

Yet there doesn't seem to be any problem as the variables are indeed used:

  int out_size = 0;
  int delays_size = 0;
  memset(&g, 0, sizeof(g));
  if (delays) {
     *delays = 0;
  }

  do {
     u = stbi__gif_load_next(s, &g, comp, req_comp, two_back);
     if (u == (stbi_uc *) s) u = 0;  // end of animated gif marker

     if (u) {
        *x = g.w;
        *y = g.h;
        ++layers;
        stride = g.w * g.h * 4;

        if (out) {
           void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride );
           if (NULL == tmp) {
              STBI_FREE(g.out);
              STBI_FREE(g.history);
              STBI_FREE(g.background);
              return stbi__errpuc("outofmem", "Out of memory");
           }
           else {
               out = (stbi_uc*) tmp;
               out_size = layers * stride;
           }

           if (delays) {
              *delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers );
              delays_size = layers * sizeof(int);
           }
        } else {
           out = (stbi_uc*)stbi__malloc( layers * stride );
           out_size = layers * stride;
           if (delays) {
              *delays = (int*) stbi__malloc( layers * sizeof(int) );
              delays_size = layers * sizeof(int);
           }
        }      int out_size = 0;

Is this a compiler bug?

Edit: Version of GCC is 9.3.0

OS: Linux Mint latest


Solution

  • The code initialises and modifies out_sizeand delay_size but does not use them (they are only ever written, and never read). The one place it appears to be used is the STBI_REALLOC_SIZED() calls, but STBI_REALLOC_SIZED is a macro defined thus:

    #define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz)
    

    so oldsz is unused.

    Compiling without -Wunused-variable (or one of the -W options that imply this) and -Werror is an unsatisfactory solution as it will suppress warnings in your own code that you might want. Had this been normal library code rather the static functions in a header (a nasty thing in itself), then you could compile the third-party code with different options that your own code. The simplest solution is to modify the stb_image.h file such that it has:

    int out_size = 0; out_size = out_size ;
    int delays_size = 0; delays_size = delays_size ;
    

    or

    int out_size = 0; (void)out_size ;
    int delays_size = 0; (void)delays_size ;
    

    It turns out the header already has a macro for that:

    int out_size = 0; STBI_NOTUSED(out_size) ;
    int delays_size = 0; STBI_NOTUSED(delays_size) ;
    

    That will "use" the variables in a manner that has no real effect and can be optimised out (though clearly that is not a concern if you choose to use this hideous abuse of a header file). The dummy use suppresses the warning.

    Ordinarily you might not want to change a header to a third-party library, but in this case the header is the library so there is no risk of inconsistency if say it weer a header for an shared object library. The change is visible to all code that uses it. The only issue is that you might have to re-implement the fix if you adopt an updated version. One solution to that is to submit a change request to the author, so the problem goes away for everyone.