microsoft/checkedc-clang

Inconsistent warning when using pointer to incomplete structure type

john-h-kastner opened this issue · 2 comments

In this example, a warning is emitted on the first function call, but not on the second. This is odd for a couple of reasons. First, the bounds it can't prove are trivially correct, and will be checked correctly in other situations (without incomplete types). Second, the function call with bound count(1) seems more problematic than the first, since it depends on knowing the size of an incomplete type.

#pragma CHECKED_SCOPE on
struct vsf_sysutil_statbuf;
void vsf_sysutil_free0(_Array_ptr<struct vsf_sysutil_statbuf> : count(0));
void vsf_sysutil_free1(_Array_ptr<struct vsf_sysutil_statbuf> : count(1));
void test(void) {
  _Ptr<struct vsf_sysutil_statbuf> p_statbuf = 0;
  vsf_sysutil_free0(p_statbuf);
  vsf_sysutil_free1(p_statbuf);
}
struct.c:7:21: warning: cannot prove argument meets declared bounds for 1st parameter [-Wcheck-bounds-decls-checked-scope]
  vsf_sysutil_free0(p_statbuf);
                    ^~~~~~~~~
struct.c:7:21: note: (expanded) expected argument bounds are 'bounds((_Array_ptr<struct vsf_sysutil_statbuf>)p_statbuf, (_Array_ptr<struct vsf_sysutil_statbuf>)p_statbuf + 0)'
struct.c:7:21: note: (expanded) inferred bounds are 'bounds((_Array_ptr<struct vsf_sysutil_statbuf>)p_statbuf, (_Array_ptr<struct vsf_sysutil_statbuf>)p_statbuf + 1)'
  vsf_sysutil_free0(p_statbuf);
                    ^~~~~~~~~
1 warning generated.

Hi @john-h-kastner, this is currently a limitation in the compiler's ability to reason about bounds expressions. We plan to address this in the near term.

For the call to vsf_sysutil_free0, the expected argument bounds are bounds((_Array_ptr<struct vsf_sysutil_statbuf>)p_statbuf, (_Array_ptr<struct vsf_sysutil_statbuf>)p_statbuf + 0), while the inferred argument bounds are bounds((_Array_ptr<struct vsf_sysutil_statbuf>)p_statbuf, (_Array_ptr<struct vsf_sysutil_statbuf>)p_statbuf + 1). Since these bounds expressions are not identical, the compiler attempts to create a range (base expression, lower offset, and upper offset) for each bounds expression. In order to do this, the compiler needs to know the size of the referent type struct vsf_sysutil_statbuf for the type _Array_ptr<struct vsf_sysutil_statbuf>. Since struct vsf_sysutil_statbuf is an incomplete type, the compiler cannot create ranges for these bounds expressions, and currently defaults to emitting a warning.

For the call to vsf_sysutil_free1, the expected argument bounds are bounds((_Array_ptr<struct vsf_sysutil_statbuf>)p_statbuf, (_Array_ptr<struct vsf_sysutil_statbuf>)p_statbuf + 1) and the inferred argument bounds are bounds((_Array_ptr<struct vsf_sysutil_statbuf>)p_statbuf, (_Array_ptr<struct vsf_sysutil_statbuf>)p_statbuf + 1). Since these bounds expressions are identical, the compiler is able to prove that the argument satisfies the expected bounds. The compiler does not attempt to create ranges for either of these bounds expressions, so it doesn't need to know the size of the referent type struct vsf_sysutil_statbuf.

This was addressed by #1117.