On 6/29/21 6:27 AM, David Brown wrote:
On 28/06/2021 21:06, Martin Sebor via Gcc wrote:
I wrote an article for the Red Hat Developer blog about how
to annotate code to get the most out of GCC's access checking
warnings like -Warray-bounds, -Wformat-overflow, and
-Wstringop-overflow. The article published last week:
https://developers.redhat.com/articles/2021/06/25/use-source-level-annotations-help-gcc-detect-buffer-overflows
Thanks for that write-up - and of course thank you to whoever
implemented these attributes!
The caveat that the access attributes are lost when a function is
inlined is an important one. As a user who appreciates all the checks I
can get, it is disappointing - but I assume there are good reasons for
that limitation. I can merely hope that will change in future gcc versions.
There's nothing the attribute could obviously attach to after a call
has been inlined. An extreme example is a function whose argument
isn't used:
__attribute__ ((access (write_only, 1, 2))) void
f (char *p, int n) { }
(The function might have a body in the original source that could
be eliminated from the IL based on the values of other arguments.)
Calls to it that are not inlined will be checked but those that are
won't be. This could be improved by doing the checking also before
inlining but at a cost of some false positives for code that's later
determined to be unreachable. I don't have a sense of how bad it
might be so it's something to try. This class of false positives
could also be dealt with by queuing up the warnings (e.g., by
emitting them into the IL via __builtin_warning) and issuing them
only if they survive dead code elimination. This is something I'd
like to try to tackle for GCC 12.
I believe it would make sense to add this information to the gcc manual
page for common function attributes. There are quite a number of
attributes that are useful for static checking, such as
"warn_unused_result" and "nonnull". Are these also dropped if the
function is inlined?
I agree the documentation could stand to be made clearer on this
point. In general, I think it would be helpful to give users
more guidance about what to expect from attributes as well as
warnings: which ones are purely lexical and which ones flow-
sensitive and so inherently susceptible to false positives and
negatives, and to what extent.
Whether an attribute has an effect depends on the compilation stage
where it's handled. warn_unused_result is handled very early (well
before inlining) so it always has the expected effect. Attribute
nonnull is handled both early (to catch the simple cases) and also
later, after inlining, to benefit from some flow analysis, so its
effect is lost if the function it attaches to is inlined. Attribute
access is handled very late and so it suffers from this problem
even more.
The new attribute malloc (to associate allocators with deallocators)
is also handled very late but it deals with the same problem by
disabling inlining. This was done to avoid false positives, not
to prevent false negatives, but it works for both. Disabling
inlining is obviously suboptimal and wouldn't be appropriate for
simple accessor functions but for memory allocation it seems like
an acceptable tradeoff.
The inlining problem is not unique to attributes that affect
warnings. It impacts all function (and function type) attributes,
including those that affect optimization. Those that specifically
change optimization options disable inlining to avoid meaningless
mismatches between options controlling the codegen of the caller
and those intended to control the codegen for the callee.
Martin