Bug 83172

Summary: -Wstack-size= doesn't detect the correct stack size with VLA or alloca
Product: gcc Reporter: Hao Hou <hao.hou>
Component: middle-endAssignee: Not yet assigned to anyone <unassigned>
Status: NEW ---    
Severity: normal CC: ebotcazou, egallager, muecker
Priority: P3 Keywords: diagnostic
Version: 7.1.0   
Target Milestone: ---   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2017-11-27 00:00:00
Attachments: The preprocessed source code repoduce the bug

Description Hao Hou 2017-11-26 23:40:58 UTC
Created attachment 42723 [details]
The preprocessed source code repoduce the bug

The -Wstack-usage= doesn't deduce the correct stack size and reports an unbounded stack size in the following case:
1. The function uses a variable length array
2. The function uses alloca

Even with alloca(constant) or __builtin_unreachable hints the VLA size, compiler still mark the max stack size unbounded. 

Another related option -Wvla-larger-than= does inferred the maximum VLA size from the __builtin_unreachable hints. 

The expected behavior should be -Wstack-usage= also follows the hint, at least, for the alloca(constant) case, it should realize the stack size could not be unbounded.

GCC Version:
Using built-in specs.
COLLECT_GCC=gcc-7
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 7.1.0-10ubuntu1~16.04.york0' --with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 7.1.0 (Ubuntu 7.1.0-10ubuntu1~16.04.york0) 

And the preprocessed file that repo this bug is attached. 

The command used to repo the bug and it's output:

$ gcc-7 -save-temps -Wvla-larger-than=128 -Wstack-usage=102400 -O3 -c t.c 
t.c: In function ‘stack_usage_only’:
t.c:21:5: warning: stack usage might be unbounded [-Wstack-usage=]
 int stack_usage_only(unsigned x)
     ^~~~~~~~~~~~~~~~
t.c: In function ‘alloca_fails_even_with_const’:
t.c:30:5: warning: stack usage might be unbounded [-Wstack-usage=]
 int alloca_fails_even_with_const()
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~


Expected:
Compiles without any warning.
Comment 1 Eric Botcazou 2017-11-27 17:24:36 UTC
What happens for -Wvla-larger-than= if you use -O0 or -O1 instead of -O3?
Comment 2 Hao Hou 2017-11-27 17:42:47 UTC
(In reply to Eric Botcazou from comment #1)
> What happens for -Wvla-larger-than= if you use -O0 or -O1 instead of -O3?

The same result:

$ gcc-7 -Wvla-larger-than=128 -Wstack-usage=102400 -O0 -c t.c 
t.c: In function ‘stack_usage_only’:
t.c:23:5: warning: stack usage might be unbounded [-Wstack-usage=]
 int stack_usage_only(unsigned x)
     ^~~~~~~~~~~~~~~~
t.c: In function ‘alloca_fails_even_with_const’:
t.c:32:5: warning: stack usage might be unbounded [-Wstack-usage=]
 int alloca_fails_even_with_const()
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~

-O1 results the same.
Comment 3 Eric Botcazou 2017-11-27 20:06:13 UTC
> The same result:
> 
> $ gcc-7 -Wvla-larger-than=128 -Wstack-usage=102400 -O0 -c t.c 
> t.c: In function ‘stack_usage_only’:
> t.c:23:5: warning: stack usage might be unbounded [-Wstack-usage=]
>  int stack_usage_only(unsigned x)
>      ^~~~~~~~~~~~~~~~
> t.c: In function ‘alloca_fails_even_with_const’:
> t.c:32:5: warning: stack usage might be unbounded [-Wstack-usage=]
>  int alloca_fails_even_with_const()
>      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 
> -O1 results the same.

Try -Wvla-larger-than=100 though.

In any case, note that for:

int vla_size_only(unsigned x)
{
 if(x > 128) __builtin_unreachable();
 char buf[x];
 do_something(buf);
 return 0;
}

the warning is expected since the code may allocate more than 128 bytes.

-Wstack-usage is designed to be *conservatively* correct and to yield the same result at all optimization levels, i.e. it will never say that the stack usage is bounded if there is a path where it may not be.  So it's very different from 
-Wvla-larger-than or -Walloca-larger-than which say nothing at -O0 or -O1 and are not conservatively correct.
Comment 4 Hao Hou 2017-11-27 20:55:48 UTC
(In reply to Eric Botcazou from comment #3)
> > The same result:
> > 
> > $ gcc-7 -Wvla-larger-than=128 -Wstack-usage=102400 -O0 -c t.c 
> > t.c: In function ‘stack_usage_only’:
> > t.c:23:5: warning: stack usage might be unbounded [-Wstack-usage=]
> >  int stack_usage_only(unsigned x)
> >      ^~~~~~~~~~~~~~~~
> > t.c: In function ‘alloca_fails_even_with_const’:
> > t.c:32:5: warning: stack usage might be unbounded [-Wstack-usage=]
> >  int alloca_fails_even_with_const()
> >      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > 
> > -O1 results the same.
> 
> Try -Wvla-larger-than=100 though.
> 
> In any case, note that for:
> 
> int vla_size_only(unsigned x)
> {
>  if(x > 128) __builtin_unreachable();
>  char buf[x];
>  do_something(buf);
>  return 0;
> }
> 
> the warning is expected since the code may allocate more than 128 bytes.
> 
> -Wstack-usage is designed to be *conservatively* correct and to yield the
> same result at all optimization levels, i.e. it will never say that the
> stack usage is bounded if there is a path where it may not be.  So it's very
> different from 
> -Wvla-larger-than or -Walloca-larger-than which say nothing at -O0 or -O1
> and are not conservatively correct.

Thanks Eric, that's a good point. I understand that eventhough the behavior of the code when x > 128 is undefined, but it's up to the compiler if take this case into consideration. 

I tried to modify the code a little bit: 

int stack_usage_only(unsigned x)
{
	if(x <= 128)
	{
		if(x > 128) __builtin_unreachable();
		char buf[x];
		do_something(buf);
	}
	return 0;
}


The warning is stil there. I totally understand that the compiler infers the size conservatively. But this case makes -Wstack-size= somehow equivalent to -Wvla.

My idea on this warning is that it actually make much more sense when the VLA or alloca has been used in the code, since it preventing VLA or alloca allocating unbounded size of memory. That is why I was expecting it actually infers the range of the x, thus it's an useful indicator of using VLA correctly.
Comment 5 Martin Uecker 2023-06-25 11:27:09 UTC
I agree. It would nice to have a solution here, as it would make using VLAs safer. And the alternatives to VLAs people tend to use because they are scared are usually worse in terms of readability, performance, and bounds checking.