Thread: VLA and pointers-to-VLA checking - ISOC90 / ISOC11

  1. #1
    Registered User
    Join Date
    Jul 2018
    Posts
    5

    Question VLA and pointers-to-VLA checking - ISOC90 / ISOC11

    Hi, I'am using only pointers-to-VLA in my code but if VLAs are not supported, syntax for this type of pointers is not supported too.
    So I have to check it using the preprocessor.

    I've tried:
    Code:
    #ifdef __STDC_NO_VLA__
    #error Your compiler does not support VLAs! Please use a supported compiler.
    #endif
    But if I use "-Werror=vla" flag I get errors deriving from the ISOC90 standard. Maybe #ifdef __STDC_NO_VLA__ is a check valid only for C11 compilers? What should I use?
    Thanks!
    Last edited by jfet97; 07-07-2018 at 01:56 PM.

  2. #2
    Registered User john.c's Avatar
    Join Date
    Dec 2017
    Posts
    356
    Maybe something like this:
    Code:
    #if __STDC_VERSION__ >= 201100L
    #  ifndef _STDC_NO_VLA_
    #    define HAS_VLA
    #  endif
    #elif __STDC_VERSION__ >= 199900L
    #  define HAS_VLA
    #endif
    Simplicity is the ultimate sophistication.

  3. #3
    Registered User
    Join Date
    Jul 2018
    Posts
    5
    Quote Originally Posted by john.c View Post
    Maybe something like this:
    Code:
    #if __STDC_VERSION__ >= 201100L
    #  ifndef _STDC_NO_VLA_
    #    define HAS_VLA
    #  endif
    #elif __STDC_VERSION__ >= 199900L
    #  define HAS_VLA
    #endif
    Checking the C version is a good idea but it isn't the complete solution. Because I can write code using C11 without defining _STDC_NO_VLA_ but using -Werror=vla flag.
    Maybe I have to check *argv[] using the preprocessor, but I don't know if it is possible. Maybe there is an easier way.

  4. #4
    Registered User
    Join Date
    May 2010
    Posts
    4,238
    Hi, I'am using only pointers-to-VLA in my code but if VLAs are not supported, syntax for this type of pointers is not supported too.
    Hopefully you are compiling with a standard C11 compatible compiler, any previous version doesn't have the "_STDC_NO_VLA_" macro.

    Also the "_STDC_NO_VLA_" macro by it's self doesn't control the use of VLA, it only tells you if VLA is a supported feature.

    The -Wvla flag should issue diagnostics if you attempt to use this "feature" regardless of the setting of the _STDC_NO_VLA_ macro. By the way this diagnostic can be either a warning or an error, depending on what other flags you use to compile you code.

    Is there a reason you're trying to support this "feature"? Since VLA are not supported by all compilers , remember VLA support is optional, you would probably be better off sticking with the tried and true dynamic memory allocation instead.

  5. #5
    Registered User
    Join Date
    Jul 2018
    Posts
    5

    Post

    Quote Originally Posted by jimblumberg View Post
    Hopefully you are compiling with a standard C11 compatible compiler, any previous version doesn't have the "_STDC_NO_VLA_" macro.

    Also the "_STDC_NO_VLA_" macro by it's self doesn't control the use of VLA, it only tells you if VLA is a supported feature.

    The -Wvla flag should issue diagnostics if you attempt to use this "feature" regardless of the setting of the _STDC_NO_VLA_ macro. By the way this diagnostic can be either a warning or an error, depending on what other flags you use to compile you code.

    Is there a reason you're trying to support this "feature"? Since VLA are not supported by all compilers , remember VLA support is optional, you would probably be better off sticking with the tried and true dynamic memory allocation instead.
    Thanks for your explanation. There isn't a particular reason, it is nothing more than a syntatic sugar, but I want to make it working.
    I would like to be able to write code suitable for any version of the C standard (from C90 to C11): using the preprocessor i would check VLA support, so that the code using pointers-to-VLA would be compiled only if the compiler is able to support them. But I have to take care to any flag that prevents me from using them.
    How can I achieve all these goals?

    I'm going to post my code right now so you can see what I'm doing. It's hard to find code like this, but it is simple enough.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    #ifdef __STDC_NO_VLA__
    #error Your compiler does not support VLAs! Please use a supported compiler.
    #endif
    
    void getDimensions(unsigned *, unsigned *);
    unsigned (*allocate(unsigned, unsigned))[];
    void doSomething(unsigned, unsigned, unsigned(*)[*]);
    
    
    int main()
    {
       unsigned r, c;
       
       getDimensions(&r, &c);
    
        
        unsigned(*matrix)[c] = (unsigned(*)[c]) allocate(r, c);
    
        
       if(matrix)
          doSomething(r, c, matrix);
       
       free(matrix);
       
        return 0;
    }
    
    
    
    void getDimensions(unsigned *r, unsigned *c) {
       do {
        scanf("%u", r);
        scanf("%u", c);
       } while(*r == 0 || *c == 0); // unsigned -> negative values in input will be considered positive
       return;
    }
    
    
    unsigned (*allocate(unsigned r, unsigned c))[]
    {
        return (unsigned(*)[]) malloc(r * c * sizeof(unsigned));
    }
    
    
    void doSomething(unsigned r, unsigned c, unsigned(*matrix)[c]) {
       
       unsigned i = 0;
       unsigned j;
       
       for(; i < r; i++)
          for(j = 0; j < c; j++)
             matrix[i][j] = j * i;
    
       for(i = 0; i < r; printf("%c", '\n'), i++)
          for(j = 0; j < c; j++)
             printf("%u ", matrix[i][j]);
       
       return;
    }

  6. #6
    Registered User
    Join Date
    May 2010
    Posts
    4,238
    I would like to be able to write code suitable for any version of the C standard (from C90 to C11)
    Then stop trying to use VLA and use good old fashioned malloc/free. VLA are only truly supported when using a C99 compatible compiler compiling in C99 mode. VLA are not supported in C90 and C11 this "feature" is optional.

    using the preprocessor i would check VLA support, so that the code using pointers-to-VLA would be compiled only if the compiler is able to support them
    Okay, then you need to actually do some checking where you're trying to use VLA and avoid that code.

    How can I achieve all these goals?
    IMO, it's best not to try. In the code you supplied you would be much better off using malloc/free on all of that array instead.

    By the way IMO, trying to malloc a VLA is asking for even more trouble. Do you realize that your malloc is trying to allocate memory for a single dimensional array?

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    36,631
    Another reason for not using VLA's in your code.

    The size depends on user input. A VLA dependent on user input is vulnerable to malicious users. Unlike malloc which returns NULL if the allocation doesn't succeed, a failure to allocate a VLA will at best just terminate your program with zero warning and no opportunity to cleanup. At worst, you could be looking at unknown stack manipulation hackery.

    Oh, and there is no need to cast the return result of malloc in C.
    The "void * to T*" implicit casting is guaranteed by the standards.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    Registered User
    Join Date
    Jul 2018
    Posts
    5
    Sorry jimblumberg, it's not my intention to offend you but I will be frank. What you are saying means that you have not fully understood my code.

    Quote Originally Posted by jimblumberg View Post
    Then stop trying to use VLA and use good old fashioned malloc/free.
    I am using malloc, not VLA. Using pointers-to-VLA does not mean using VLA.

    Quote Originally Posted by jimblumberg View Post
    Okay, then you need to actually do some checking where you're trying to use VLA and avoid that code.
    This is my question, I am not here to discuss about VLA. If you know a good solution for my problem your help is really appreciated.

    Quote Originally Posted by jimblumberg View Post
    In the code you supplied you would be much better off using malloc/free on all of that array instead.
    I am not using VLA. I am using malloc and free on all of that matrix.

    Quote Originally Posted by jimblumberg View Post
    By the way IMO, trying to malloc a VLA is asking for even more trouble. Do you realize that your malloc is trying to allocate memory for a single dimensional array?
    I am not "mallocing" a VLA. What you see is only a different way to interpret the address returned by malloc.

    Thanks again for your reply!

  9. #9
    Registered User
    Join Date
    Jul 2018
    Posts
    5
    Sorry Salem, it's not my intention to offend you but I will be frank to you too. What you are saying means that you have not fully understood my code.

    Quote Originally Posted by Salem View Post
    Another reason for not using VLA's in your code.
    I am not using VLA.

    Quote Originally Posted by Salem View Post
    The size depends on user input. A VLA dependent on user input is vulnerable to malicious users. Unlike malloc which returns NULL if the allocation doesn't succeed, a failure to allocate a VLA will at best just terminate your program with zero warning and no opportunity to cleanup. At worst, you could be looking at unknown stack manipulation hackery.
    I know. I am using malloc as you can see. Using pointers-to-VLA does not mean using VLAs.

    Quote Originally Posted by Salem View Post
    Oh, and there is no need to cast the return result of malloc in C.
    The "void * to T*" implicit casting is guaranteed by the standards.
    I know but I prefer to do it explicitly.

    So, thanks for your reply but I am not here to discuss about VLA. If you know a good solution for my problem your help will be really appreciated.

  10. #10
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    36,631
    > unsigned(*matrix)[c]
    Yes, you ARE using VLA's.

    You might only be using a VLA for type information, and not VLA allocations, but you can't cherry-pick one without getting the other.

    In a standard compiler, your choice for a 2D array (as a single monolithic block) is limited to
    Question 6.19

    > I know but I prefer to do it explicitly.
    Then your code is vulnerable to programmer induced errors.

    If you fail to include stdlib.h, then you hide the warning that tells you that you failed to prototype malloc properly.
    What you get is an implied declaration of malloc which returns an int (yes, really!), and all sorts of grief if pointers and ints are different sizes.

    Code:
    #include <stdio.h>
    
    // Add -D option to include the correct file
    #ifdef ADD_INCLUDE
    #include <stdlib.h>
    #endif
    
    // Add -D option to sweep the problem under the carpet
    #ifdef ADD_CAST
    #define CAST (char*)
    #else
    #define CAST
    #endif
    
    int main ( ) {
        char *p = CAST malloc(10);
        return 0;
    }
    
    gcc bar.c
    bar.c: In function ‘main’:
    bar.c:16:20: warning: implicit declaration of function ‘malloc’ [-Wimplicit-function-declaration]
         char *p = CAST malloc(10);
                        ^
    bar.c:16:20: warning: incompatible implicit declaration of built-in function ‘malloc’
    bar.c:16:20: note: include ‘<stdlib.h>’ or provide a declaration of ‘malloc’
    gcc -DADD_CAST bar.c
    bar.c: In function ‘main’:
    bar.c:16:20: warning: implicit declaration of function ‘malloc’ [-Wimplicit-function-declaration]
         char *p = CAST malloc(10);
                        ^
    bar.c:16:20: warning: incompatible implicit declaration of built-in function ‘malloc’
    bar.c:16:20: note: include ‘<stdlib.h>’ or provide a declaration of ‘malloc’
    gcc -DADD_INCLUDE bar.c
    gcc -DADD_INCLUDE -DADD_CAST bar.c
    
    
    gcc -fno-builtin bar.c
    bar.c: In function ‘main’:
    bar.c:16:20: warning: implicit declaration of function ‘malloc’ [-Wimplicit-function-declaration]
         char *p = CAST malloc(10);
                        ^
    bar.c:16:20: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
    gcc -fno-builtin -DADD_CAST bar.c
    bar.c: In function ‘main’:
    bar.c:16:20: warning: implicit declaration of function ‘malloc’ [-Wimplicit-function-declaration]
         char *p = CAST malloc(10);
                        ^
    bar.c:10:14: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
     #define CAST (char*)
                  ^
    bar.c:16:15: note: in expansion of macro ‘CAST’
         char *p = CAST malloc(10);
                   ^
    gcc -fno-builtin -DADD_INCLUDE bar.c
    gcc -fno-builtin -DADD_INCLUDE -DADD_CAST bar.c
    
    
    gcc -Wno-implicit-function-declaration -fno-builtin bar.c
    bar.c: In function ‘main’:
    bar.c:16:20: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
         char *p = CAST malloc(10);
                        ^
    gcc -Wno-implicit-function-declaration -fno-builtin -DADD_CAST bar.c
    bar.c: In function ‘main’:
    bar.c:10:14: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
     #define CAST (char*)
                  ^
    bar.c:16:15: note: in expansion of macro ‘CAST’
         char *p = CAST malloc(10);
                   ^
    gcc -Wno-implicit-function-declaration -fno-builtin -DADD_INCLUDE bar.c
    gcc -Wno-implicit-function-declaration -fno-builtin -DADD_INCLUDE -DADD_CAST bar.c
    
    
    gcc -Wno-implicit-function-declaration -Wno-int-to-pointer-cast -fno-builtin bar.c
    bar.c: In function ‘main’:
    bar.c:16:20: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
         char *p = CAST malloc(10);
                        ^
    gcc -Wno-implicit-function-declaration -Wno-int-to-pointer-cast -fno-builtin -DADD_CAST bar.c
    gcc -Wno-implicit-function-declaration -Wno-int-to-pointer-cast -fno-builtin -DADD_INCLUDE bar.c
    gcc -Wno-implicit-function-declaration -Wno-int-to-pointer-cast -fno-builtin -DADD_INCLUDE -DADD_CAST bar.c
    Nothing good comes from the cast by itself, and having the cast in the presence of a correct prototype adds nothing.

    It just introduces points of failure.
    Some of which happen silently, and you only figure out whilst staring at the debugger and wondering why half the bits in your pointers all happen to be zero.

    Do you habitually cast all sorts of other expressions just for "preference"?
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Bug Checking
    By xniinja in forum C Programming
    Replies: 4
    Last Post: 09-01-2010, 08:12 PM
  2. Checking for ' in an if
    By swanley007 in forum C++ Programming
    Replies: 3
    Last Post: 06-30-2006, 07:36 AM
  3. checking for any key
    By Cprogrammer in forum C Programming
    Replies: 2
    Last Post: 10-13-2003, 10:38 AM
  4. just checking again...
    By matheo917 in forum C++ Programming
    Replies: 0
    Last Post: 01-22-2002, 08:00 PM
  5. just checking....
    By matheo917 in forum C++ Programming
    Replies: 0
    Last Post: 01-22-2002, 07:43 PM

Tags for this Thread