IFNDR on UB? [was: Straw poll on shifts with out of range operands]
Martin Uecker
muecker@gwdg.de
Sun Jun 30 06:56:41 GMT 2024
Actually, it is very much aligned with what I want in C.
In general I want to have pragma-based compilation modes
for memory safety:
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3211.pdf
(Bjarne Stroustrup has a proposal for profiles in C++ which
goes in similar direction I think)
>From an implementation point of view, if we annotated all
operations with UB in the front ends with a new
__builtin_undefined()
that - depending on configuration and/or mode - does:
0) nothing
1) expands to __builtin_unreachable()
2) expands to __builtin_trap()
3) expands to a __builtin_warning (as suggested before
by Martin Sebor) that causes the backend to emit an error
in a very late pass when the __builtin_warning has not
been removed during optimization.
Then this would solve all my problems related to UB.
Martin
Am Sonntag, dem 30.06.2024 um 08:33 +0200 schrieb Martin Uecker via Gcc:
> Am Sonntag, dem 30.06.2024 um 05:03 +0200 schrieb Matthias Kretz:
> > On Saturday, 29 June 2024 16:20:55 GMT+2 Martin Uecker wrote:
> > > Am Samstag, dem 29.06.2024 um 08:50 -0500 schrieb Matthias Kretz via Gcc:
> > > > I.e. once UB becomes IFNDR, the dreaded time-travel optimizations can't
> > > > happen anymore. Instead precondition checks bubble up because otherwise
> > > > the program is ill-formed.
> > >
> > > It is not clear to mean what you mean by this?
> >
> > It would help if you could point out what is unclear to you. I assume you know
> > IFNDR? And I gave an example for the "bubbling up" of precondition checks
> > directly above your quoted paragraph.
>
> I think I understood it now: You want to make UB be IFNDR so
> that the compiler is allowed to diagnose it at translation
> time in certain cases (although this would not generally be
> required for IFNDR).
>
> >
> > > Note that in C time-travel optimizations are already not allowed.
> >
> > Then, calling __builtin_unreachable is non-conforming for C? ... at least in
> > the English sense of "this code is impossible to reach", which implies that
> > the condition leading up to it must be 'false', allowing time-travel
> > optimization. Or how would C define 'unreachable'?
>
> __builtin_uneachable is an extension, it can do whatever it wants.
>
> But note that compilers do not seem to eliminate the control flow path
> leading to it:
>
>
> https://godbolt.org/z/coq9Yra1j
>
> So even if it is defined in terms of C's UB, these implementations
> would still be conforming to C.
>
> >
> > > But I am not sure how this is relevant here as this affects only
> > > observable behavior and the only case where GCC does not seem to
> > > already conform to this is volatile.
> >
> > Now you lost me.
>
> Consider the following example:
>
> int f(int x)
> {
> int r = 0;
> if (x < 10)
> r = 1;
> if (x < 10)
> __builtin_unreachable();
> return r;
> }
>
> But removing the store to 'r' here as GCC does:
>
> https://godbolt.org/z/h7qqrGsbz
>
> can simply be justified by the "as if" principle as
> any other optimization, it does not need to rely on a weird
> intepretation that the UB from __builin_unreachable() travels
> back in time.
>
> >
> > > Of course, C++ may be different but I suspect that some of the
> > > discussion is confusing compiler bugs with time-travel:
> >
> > "some of the discussion" is referring to what?
>
> To discussions inside WG21 that seems to believe that it
> is important that compilers can do time-travel optimizations,
> when this is actually not the case.
>
> >
> > > > Again, I don't believe this would be conforming to the C++ standard. But I
> > > > believe it's a very interesting mode to add as a compiler flag.
> > > >
> > > > -fharden=0 (default)
> > > > -fharden=1 (make UB ill-formed or unreachable)
> > > > -fharden=2 (make UB ill-formed or trap)
> > > >
> > > > If there's interest I'd be willing to look into a patch to libstdc++,
> > > > building upon the above sketch as a starting point. Ultimately, if this
> > > > becomes a viable build mode, I'd like to have a replacement for the
> > > > [[gnu::error("")]] hack with a dedicated builtin.
> > >
> > > -fharden should never turn this into unreachable.
> >
> > Well, if the default is 'unreachable' and the next step is 'ill-formed or
> > unreachable' it's a step up. But I'm all for a better name.
>
> I think it is a good idea. The compiler can optionally treat UB as
> a translation time error. We discussed similar ideas in the past
> in WG14. But this will only work for very specific instances of UB
> under certain conditions.
>
> >
> > > IMHO the FEs should insert the conditional traps when requested to
> > > and the middle end could then treat it as UB and more freely
> > > decide what to do.
> >
> > Right I was thinking of turning my library-solution hack into a builtin (if it
> > shows potential). The behavior of which then depends on a compiler flag. Then
> > both library and language UB could invoke that builtin. E.g. 'operator+(int,
> > int)' would add '__check_precondition(not __builtin_add_overflow_p(a, b, a));'
> > With my proposed '-fharden=1 -O2' you'd then get a compilation error on
> > '0x7fff'ffff + 1', but no code size increase for all other additions. With
> > '-fharden=2 -O2' the 'lea' would turn into an actual 'add' instruction with
> > subsequent 'jo' to 'ud2' (on x86).
>
> Yes, I fully agree with this.
> >
> > > Also IMHO this should be split up from
> > > UBsan which has specific semantics and upstream dependencies
> > > which are are not always ideal. (But UBSan could share the
> > > same infrastructure)
> >
> > I'm not sure what you're thinking of here. UBsan detects UB at runtime whereas
> > my '-fharden=1' proposal is about flagging UB as ill-formed on compile-time.
> > So UBsan is a more verbose '-fharden=2' then?
>
> Yes, I was talking about the -fharden=2 case. In principle UBSan
> with traps instead of diagnostics would do this. In practice,
> I think we need something which is not tied to UBSan.
>
> Martin
>
>
> >
> > - Matthias
> >
>
More information about the Libstdc++
mailing list