On 04/08/2020 21.23, Kees Cook wrote: > On Tue, Aug 04, 2020 at 08:11:45AM +0200, Rasmus Villemoes wrote: >> What we might do, to deal with the "caller fails to check the result", >> is to add a >> >> static inline bool __must_check must_check_overflow(bool b) { return >> unlikely(b); } >> >> and wrap all the final "did it overflow" results in that one - perhaps >> also for the __builtin_* cases, I don't know if those are automatically >> equipped with that attribute. [I also don't know if gcc propagates >> likely/unlikely out to the caller, but it shouldn't hurt to have it >> there and might improve code gen if it does.] > > (What is the formal name for the ({ ...; return_value; }) C construct?) https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html > Will that work as a macro return value? If so, that's extremely useful. Yes and no. Just wrapping the last expression in the statement expression with my must_check_overflow(), as in @@ -67,17 +72,18 @@ typeof(d) __d = (d); \ (void) (&__a == &__b); \ (void) (&__a == __d); \ - __builtin_sub_overflow(__a, __b, __d); \ + must_check_overflow(__builtin_sub_overflow(__a, __b, __d)); \ }) does not appear to work. For some reason, this can't be (ab)used to overrule the __must_check this simply: - kstrtoint(a, b, c); + ({ kstrtoint(a, b, c); }); still gives a warning for kstrtoint(). But failing to use the result of check_sub_overflow() as patched above does not give a warning. I'm guessing gcc has some internal very early simplification that replaces single-expression statement-exprs with just that expression, and the warn-unused-result triggers later. But as soon as the statement-expr becomes a little non-trivial (e.g. above), my guess is that the whole thing gets assigned to some internal "variable" representing the result, and that assignment then counts as a use of the return value from must_check_overflow() - cc'ing Segher, as he usually knows these details. Anyway, we don't need to apply it to the last expression inside ({}), we can just pass the whole ({}) to must_check_overflow() as in -#define check_sub_overflow(a, b, d) ({ \ +#define check_sub_overflow(a, b, d) must_check_overflow(({ \ typeof(a) __a = (a); \ typeof(b) __b = (b); \ typeof(d) __d = (d); \ (void) (&__a == &__b); \ (void) (&__a == __d); \ __builtin_sub_overflow(__a, __b, __d); \ -}) +})) and that's even more natural for the fallback cases which would be #define check_sub_overflow(a, b, d) \ + must_check_overflow( \ __builtin_choose_expr(is_signed_type(typeof(a)), \ __signed_sub_overflow(a, b, d), \ - __unsigned_sub_overflow(a, b, d)) + __unsigned_sub_overflow(a, b, d))) (in all cases with some whitespace reflowing). Rasmus