On Mon, May 13, 2024 at 02:46:32PM -0600, Jeff Law wrote:
>
>
> On 5/13/24 1:48 PM, Qing Zhao wrote:
> > -Warray-bounds is an important option to enable linux kernal to keep
> > the array out-of-bound errors out of the source tree.
> >
> > However, due to the false positive warnings reported in PR109071
> > (-Warray-bounds false positive warnings due to code duplication from
> > jump threading), -Warray-bounds=1 cannot be added on by default.
> >
> > Although it's impossible to elinimate all the false positive warnings
> > from -Warray-bounds=1 (See PR104355 Misleading -Warray-bounds
> > documentation says "always out of bounds"), we should minimize the
> > false positive warnings in -Warray-bounds=1.
> >
> > The root reason for the false positive warnings reported in PR109071 is:
> >
> > When the thread jump optimization tries to reduce the # of branches
> > inside the routine, sometimes it needs to duplicate the code and
> > split into two conditional pathes. for example:
> >
> > The original code:
> >
> > void sparx5_set (int * ptr, struct nums * sg, int index)
> > {
> > if (index >= 4)
> > warn ();
> > *ptr = 0;
> > *val = sg->vals[index];
> > if (index >= 4)
> > warn ();
> > *ptr = *val;
> >
> > return;
> > }
> >
> > With the thread jump, the above becomes:
> >
> > void sparx5_set (int * ptr, struct nums * sg, int index)
> > {
> > if (index >= 4)
> > {
> > warn ();
> > *ptr = 0; // Code duplications since "warn" does return;
> > *val = sg->vals[index]; // same this line.
> > // In this path, since it's under the condition
> > // "index >= 4", the compiler knows the value
> > // of "index" is larger then 4, therefore the
> > // out-of-bound warning.
> > warn ();
> > }
> > else
> > {
> > *ptr = 0;
> > *val = sg->vals[index];
> > }
> > *ptr = *val;
> > return;
> > }
> >
> > We can see, after the thread jump optimization, the # of branches inside
> > the routine "sparx5_set" is reduced from 2 to 1, however, due to the
> > code duplication (which is needed for the correctness of the code), we
> > got a false positive out-of-bound warning.
> >
> > In order to eliminate such false positive out-of-bound warning,
> >
> > A. Add one more flag for GIMPLE: is_splitted.
> > B. During the thread jump optimization, when the basic blocks are
> > duplicated, mark all the STMTs inside the original and duplicated
> > basic blocks as "is_splitted";
> > C. Inside the array bound checker, add the following new heuristic:
> >
> > If
> > 1. the stmt is duplicated and splitted into two conditional paths;
> > + 2. the warning level < 2;
> > + 3. the current block is not dominating the exit block
> > Then not report the warning.
> >
> > The false positive warnings are moved from -Warray-bounds=1 to
> > -Warray-bounds=2 now.
> >
> > Bootstrapped and regression tested on both x86 and aarch64. adjusted
> > -Warray-bounds-61.c due to the false positive warnings.
> >
> > Let me know if you have any comments and suggestions.
> This sounds horribly wrong. In the code above, the warning is correct.
It's not sensible from a user's perspective.
If this doesn't warn:
void sparx5_set (int * ptr, struct nums * sg, int index)
{
*ptr = 0;
*val = sg->vals[index];
*ptr = *val;
}
... because the value range tracking of "index" spans [INT_MIN,INT_MAX],
and warnings based on the value range are silenced if they haven't been
clamped at all. (Otherwise warnings would be produced everywhere: only
when a limited set of values is known is it useful to produce a warning.)
But it makes no sense to warn about:
void sparx5_set (int * ptr, struct nums * sg, int index)
{
if (index >= 4)
warn ();
*ptr = 0;
*val = sg->vals[index];
if (index >= 4)
warn ();
*ptr = *val;
}
Because at "*val = sg->vals[index];" the actual value range tracking for
index is _still_ [INT_MIN,INT_MAX]. (Only within the "then" side of the
"if" statements is the range tracking [4,INT_MAX].)
However, in the case where jump threading has split the execution flow
and produced a copy of "*val = sg->vals[index];" where the value range
tracking for "index" is now [4,INT_MAX], is the warning valid. But it
is only for that instance. Reporting it for effectively both (there is
only 1 source line for the array indexing) is misleading because there
is nothing the user can do about it -- the compiler created the copy and
then noticed it had a range it could apply to that array index.
This situation makes -Warray-bounds unusable for the Linux kernel (we
cannot have false positives says BDFL), but we'd *really* like to have
it enabled since it usually finds real bugs. But these false positives
can't be fixed on our end. :( So, moving them to -Warray-bounds=2 makes
sense as that's the level documented to have potential false positives.
-Kees
--
Kees Cook