Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #399456 > unrolled thread
| Started by | fir <profesor.fir@gmail.com> |
|---|---|
| First post | 2026-05-27 19:53 +0200 |
| Last post | 2026-05-30 11:18 +0200 |
| Articles | 20 on this page of 368 — 21 participants |
Back to article view | Back to comp.lang.c
this girl calls c ugly fir <profesor.fir@gmail.com> - 2026-05-27 19:53 +0200
Re: this girl calls c ugly fir <profesor.fir@gmail.com> - 2026-05-27 20:15 +0200
Re: this girl calls c ugly BGB <cr88192@gmail.com> - 2026-05-27 18:49 -0500
Re: this girl calls c ugly Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-05-28 04:53 +0000
Re: this girl calls c ugly BGB <cr88192@gmail.com> - 2026-05-28 02:35 -0500
Re: this girl calls c ugly Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-05-28 23:32 +0000
Re: this girl calls c ugly BGB <cr88192@gmail.com> - 2026-05-28 20:07 -0500
Re: this girl calls c ugly Bonita Montero <Bonita.Montero@gmail.com> - 2026-05-28 11:48 +0200
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-28 09:18 +0200
Re: this girl calls c ugly BGB <cr88192@gmail.com> - 2026-05-28 04:57 -0500
Re: this girl calls c ugly Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-05-28 23:35 +0000
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 09:52 +0200
Re: this girl calls c ugly BGB <cr88192@gmail.com> - 2026-05-29 05:20 -0500
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-29 13:22 +0200
Re: this girl calls c ugly BGB <cr88192@gmail.com> - 2026-05-29 15:16 -0500
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-30 13:52 +0200
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-30 14:40 +0200
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-30 16:36 +0200
Re: this girl calls c ugly BGB <cr88192@gmail.com> - 2026-05-30 15:48 -0500
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-31 11:14 +0200
Re: this girl calls c ugly BGB <cr88192@gmail.com> - 2026-05-31 13:25 -0500
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-31 22:14 +0200
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 15:22 +0200
Re: this girl calls c ugly Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-05-30 03:49 +0000
Re: this girl calls c ugly "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2026-05-28 12:47 -0700
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 09:56 +0200
Re: this girl calls c ugly "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2026-05-29 11:00 -0700
Re: this girl calls c ugly fir <profesor.fir@gmail.com> - 2026-05-28 17:12 +0200
Re: this girl calls c ugly BGB <cr88192@gmail.com> - 2026-05-28 14:07 -0500
Re: this girl calls c ugly Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-05-28 23:54 +0000
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 10:02 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-29 12:19 +0100
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 14:46 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-29 14:22 +0100
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 17:15 +0200
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-05-29 15:59 +0000
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-29 17:12 +0100
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 18:48 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-29 19:09 +0100
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 22:00 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-29 22:14 +0100
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-29 12:09 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-29 17:05 +0100
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 18:34 +0200
Re: this girl calls c ugly tTh <tth@none.invalid> - 2026-05-29 19:29 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-29 18:53 +0100
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-29 12:28 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-29 20:49 +0100
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 22:03 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-29 13:56 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-29 22:54 +0100
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-29 15:52 -0700
Re: this girl calls c ugly James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-05-29 20:31 -0400
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-30 02:03 +0100
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-29 19:02 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-30 12:12 +0100
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-05-30 12:29 +0000
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-30 13:56 +0100
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-30 16:43 -0700
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-31 03:37 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-30 19:53 -0700
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-02 12:16 +0200
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-31 11:47 +0200
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-02 12:55 +0200
Re: this girl calls c ugly Richard Harnden <richard.nospam@gmail.invalid> - 2026-05-31 09:12 +0100
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-31 11:49 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-31 11:10 +0100
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-31 13:18 +0200
Re: this girl calls c ugly James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-05-31 10:24 -0400
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-31 17:35 +0200
Re: this girl calls c ugly James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-05-31 12:46 -0400
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-31 22:24 +0200
Re: this girl calls c ugly James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-05-31 18:26 -0400
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-01 08:28 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-31 15:54 -0700
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-01 08:39 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-01 02:33 -0700
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-02 11:48 +0200
Re: this girl calls c ugly James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-06-02 06:37 -0400
Constants and undefined behavior Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-02 05:06 -0700
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-02 16:28 +0000
Re: Constants and undefined behavior Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-04 03:37 -0700
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-04 16:31 +0000
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-04 13:36 -0700
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-04 23:49 +0000
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-04 18:04 -0700
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-06 03:10 +0000
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-05 23:50 -0700
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-08 02:20 +0000
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-08 12:39 -0700
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-08 23:15 +0000
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-08 18:51 -0700
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-09 09:46 +0000
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-09 15:07 -0700
Re: Constants and undefined behavior antispam@fricas.org (Waldek Hebisch) - 2026-06-09 01:25 +0000
Re: Constants and undefined behavior James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-06-09 18:29 -0400
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-09 16:01 -0700
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-10 12:36 +0000
Re: Constants and undefined behavior Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-11 16:49 +0200
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-11 15:20 +0000
Re: Constants and undefined behavior Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-11 18:08 +0200
Re: Constants and undefined behavior antispam@fricas.org (Waldek Hebisch) - 2026-06-11 16:30 +0000
Re: Constants and undefined behavior Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-11 20:52 +0200
Re: Constants and undefined behavior antispam@fricas.org (Waldek Hebisch) - 2026-06-12 02:20 +0000
Re: Constants and undefined behavior Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-13 14:57 +0200
Re: Constants and undefined behavior Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-06 15:47 -0700
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-06 16:36 -0700
Re: Constants and undefined behavior Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-06 16:43 -0700
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-06 17:41 -0700
Re: Constants and undefined behavior Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-05 10:41 +0200
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-05 10:49 -0700
Re: Constants and undefined behavior Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-06 16:15 -0700
Re: Constants and undefined behavior Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-06 18:06 -0700
Re: Constants and undefined behavior Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-07 22:34 -0700
Re: Constants and undefined behavior Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-08 23:05 -0700
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-09 10:19 +0000
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-09 15:12 -0700
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-10 14:37 +0000
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-10 18:30 +0000
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-10 14:55 -0700
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-10 23:32 +0000
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-10 14:47 -0700
Re: Constants and undefined behavior David Brown <david.brown@hesbynett.no> - 2026-06-11 08:56 +0200
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-11 11:38 +0000
Re: Constants and undefined behavior David Brown <david.brown@hesbynett.no> - 2026-06-11 14:05 +0200
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-11 15:38 -0700
Re: Constants and undefined behavior scott@slp53.sl.home (Scott Lurndal) - 2026-06-11 23:07 +0000
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-11 17:43 -0700
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-12 02:02 +0000
Re: Constants and undefined behavior Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-11 17:34 +0200
Re: Constants and undefined behavior David Brown <david.brown@hesbynett.no> - 2026-06-12 10:58 +0200
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-12 12:27 -0700
Re: Constants and undefined behavior David Brown <david.brown@hesbynett.no> - 2026-06-13 12:36 +0200
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-13 12:03 +0000
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-13 12:02 +0000
Re: Constants and undefined behavior ram@zedat.fu-berlin.de (Stefan Ram) - 2026-06-13 12:13 +0000
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-13 12:44 +0000
Re: Constants and undefined behavior David Brown <david.brown@hesbynett.no> - 2026-06-13 18:32 +0200
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-11 13:29 -0700
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-12 02:08 +0000
Re: Constants and undefined behavior David Brown <david.brown@hesbynett.no> - 2026-06-12 11:02 +0200
Re: Constants and undefined behavior Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-11 17:45 +0200
Re: Constants and undefined behavior Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-10 15:11 -0700
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-10 22:44 +0000
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-10 16:19 -0700
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-11 11:50 +0000
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-11 16:28 -0700
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-11 23:46 +0000
Re: Constants and undefined behavior Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-11 18:29 -0700
Re: Constants and undefined behavior cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-12 01:54 +0000
Re: Constants and undefined behavior David Brown <david.brown@hesbynett.no> - 2026-06-12 11:37 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-02 05:35 -0700
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-02 06:29 -0700
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-02 16:10 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-02 15:29 -0700
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-05 06:41 -0700
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-05 11:24 -0700
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-08 08:35 -0700
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-08 17:33 +0000
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-09 00:54 -0700
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-09 10:08 +0000
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-08 13:40 -0700
Meaning of "expression" Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-08 14:05 -0700
Expression statements (was Re: Meaning of "expression") Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-09 15:17 +0200
Re: Expression statements (was Re: Meaning of "expression") Bart <bc@freeuk.com> - 2026-06-09 14:53 +0100
Re: Expression statements (was Re: Meaning of "expression") Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-09 16:30 +0200
Re: Expression statements (was Re: Meaning of "expression") David Brown <david.brown@hesbynett.no> - 2026-06-09 17:13 +0200
Re: Expression statements (was Re: Meaning of "expression") Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-09 15:34 -0700
Re: Expression statements (was Re: Meaning of "expression") David Brown <david.brown@hesbynett.no> - 2026-06-10 09:04 +0200
Re: Expression statements (was Re: Meaning of "expression") Bart <bc@freeuk.com> - 2026-06-10 11:10 +0100
Re: Expression statements (was Re: Meaning of "expression") David Brown <david.brown@hesbynett.no> - 2026-06-10 13:29 +0200
Re: Expression statements (was Re: Meaning of "expression") Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-10 03:17 -0700
Re: Expression statements (was Re: Meaning of "expression") David Brown <david.brown@hesbynett.no> - 2026-06-10 13:43 +0200
Re: Expression statements (was Re: Meaning of "expression") Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-10 14:08 -0700
Re: Expression statements (was Re: Meaning of "expression") David Brown <david.brown@hesbynett.no> - 2026-06-11 09:10 +0200
Re: Expression statements (was Re: Meaning of "expression") Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-11 20:29 +0200
Re: Expression statements (was Re: Meaning of "expression") David Brown <david.brown@hesbynett.no> - 2026-06-12 12:55 +0200
Re: Expression statements (was Re: Meaning of "expression") Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-13 15:01 +0200
Re: Expression statements (was Re: Meaning of "expression") Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-11 20:12 +0200
Re: Expression statements (was Re: Meaning of "expression") James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-06-11 15:13 -0400
Re: Expression statements (was Re: Meaning of "expression") Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-12 00:37 +0200
Re: Expression statements (was Re: Meaning of "expression") scott@slp53.sl.home (Scott Lurndal) - 2026-06-11 23:05 +0000
Re: Expression statements (was Re: Meaning of "expression") Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-12 01:18 +0200
Re: Expression statements (was Re: Meaning of "expression") Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-11 17:41 -0700
Re: Expression statements (was Re: Meaning of "expression") James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-06-11 20:41 -0400
Re: Expression statements (was Re: Meaning of "expression") tTh <tth@none.invalid> - 2026-06-09 19:27 +0200
Re: Expression statements (was Re: Meaning of "expression") Bart <bc@freeuk.com> - 2026-06-09 19:19 +0100
Re: Expression statements (was Re: Meaning of "expression") Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-09 15:22 -0700
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-06 03:22 +0000
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-05 23:56 -0700
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-07 13:37 +0000
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-07 15:09 -0700
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-08 02:33 +0000
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-08 00:16 -0700
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-08 12:41 +0000
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-08 17:37 +0000
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-09 16:05 +0200
Re: this girl calls c ugly "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2026-06-02 13:59 -0700
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-02 13:05 +0000
Parentheses (was: this girl calls c ugly) Bart <bc@freeuk.com> - 2026-06-02 14:38 +0100
Re: Parentheses (was: this girl calls c ugly) cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-02 15:19 +0000
Re: Parentheses antispam@fricas.org (Waldek Hebisch) - 2026-06-03 22:30 +0000
Re: Parentheses Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-03 16:24 -0700
Re: Parentheses antispam@fricas.org (Waldek Hebisch) - 2026-06-04 02:03 +0000
Re: Parentheses Bart <bc@freeuk.com> - 2026-06-04 01:12 +0100
Re: Parentheses antispam@fricas.org (Waldek Hebisch) - 2026-06-04 01:58 +0000
Re: Parentheses Bart <bc@freeuk.com> - 2026-06-04 11:37 +0100
Re: Parentheses cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-04 10:51 +0000
Re: Parentheses Bart <bc@freeuk.com> - 2026-06-04 12:47 +0100
Re: Parentheses Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-04 14:57 +0200
Re: Parentheses cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-04 14:31 +0000
[OT] Fancy graphics (was Re: this girl calls c ugly) Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-02 15:54 +0200
Re: [OT] Fancy graphics (was Re: this girl calls c ugly) Bart <bc@freeuk.com> - 2026-06-02 15:19 +0100
Re: [OT] Fancy graphics (was Re: this girl calls c ugly) cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-02 15:19 +0000
Re: [OT] Fancy graphics (was Re: this girl calls c ugly) Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-02 17:39 +0200
Re: [OT] Fancy graphics (was Re: this girl calls c ugly) cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-02 16:36 +0000
Re: [OT] Fancy graphics (was Re: this girl calls c ugly) scott@slp53.sl.home (Scott Lurndal) - 2026-06-02 21:33 +0000
Re: [OT] Fancy graphics (was Re: this girl calls c ugly) "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2026-06-02 14:43 -0700
Re: [OT] Fancy graphics (was Re: this girl calls c ugly) ram@zedat.fu-berlin.de (Stefan Ram) - 2026-06-02 17:08 +0000
Re: [OT] Fancy graphics (was Re: this girl calls c ugly) cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-02 19:19 +0000
Re: [OT] Fancy graphics (was Re: this girl calls c ugly) Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-06-04 00:11 +0000
Re: [OT] Fancy graphics (was Re: this girl calls c ugly) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-02 15:39 -0700
Re: [OT] Fancy graphics (was Re: this girl calls c ugly) cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-03 13:14 +0000
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-06-02 15:10 +0000
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-02 15:31 +0000
Re: this girl calls c ugly James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-05-31 10:15 -0400
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-31 16:29 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-31 03:45 -0700
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-31 04:02 -0700
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-05-31 09:04 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-31 18:11 +0100
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-05-31 19:34 +0000
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-05-31 19:10 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-01 11:12 +0100
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-01 12:36 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-01 14:26 -0700
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-04 02:34 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-04 12:40 +0100
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-04 14:35 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-04 14:18 +0100
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-04 15:47 +0200
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-04 15:57 +0200
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-04 16:27 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-04 16:46 +0100
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-04 20:15 +0200
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-04 20:54 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-04 20:29 +0100
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-04 14:06 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-04 22:47 +0100
Famous (hopefully last) words [on this topic] Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-05 00:27 +0200
Re: Famous (hopefully last) words [on this topic] Bad Post <invalid@invalid.invalid> - 2026-06-05 01:20 +0100
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-04 16:09 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-05 00:44 +0100
Re: this girl calls c ugly "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2026-06-04 17:26 -0700
Re: this girl calls c ugly antispam@fricas.org (Waldek Hebisch) - 2026-06-05 12:58 +0000
Re: this girl calls c ugly "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2026-06-05 14:27 -0700
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-05 02:47 +0000
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-05 00:53 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-05 11:04 +0100
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-05 05:34 -0700
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-06 03:45 +0000
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-06 03:44 +0000
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-06 07:39 +0200
Re: this girl calls c ugly "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2026-06-04 15:25 -0700
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-05 09:29 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-05 12:39 +0100
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-05 15:42 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-05 16:50 +0100
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-05 11:09 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-05 20:29 +0100
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-06-04 16:18 +0000
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-04 17:23 +0100
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-06-04 16:47 +0000
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-04 19:57 +0100
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-06-04 20:34 +0000
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-04 22:28 +0100
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-06-04 21:58 +0000
Re: this girl calls c ugly Richard Harnden <richard.nospam@gmail.invalid> - 2026-06-04 23:25 +0100
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-05 02:49 +0000
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-04 19:47 +0200
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-04 21:04 +0200
Re: this girl calls c ugly Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2026-06-04 19:13 +0000
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-05 10:34 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-04 12:11 -0700
Re: this girl calls c ugly James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-06-04 16:33 -0400
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-04 14:16 -0700
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-05 00:02 +0000
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-04 18:36 -0700
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-05 02:54 +0000
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-05 05:49 -0700
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-05 11:01 -0700
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-05 11:53 -0700
Re: this girl calls c ugly Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2026-06-04 18:45 +0000
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-04 20:19 +0000
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-06-04 20:31 +0000
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-04 20:41 +0000
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-06-04 20:49 +0000
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-05 00:03 +0000
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-06-05 00:18 +0000
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-05 03:02 +0000
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-06-05 14:04 +0000
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-06 03:49 +0000
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-06-06 15:13 +0000
Re: this girl calls c ugly scott@slp53.sl.home (Scott Lurndal) - 2026-06-06 17:53 +0000
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-04 11:59 -0700
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-04 15:21 +0200
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-04 06:38 -0700
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-01 09:52 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-01 02:42 -0700
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-01 12:50 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-01 11:47 +0100
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-01 12:55 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-01 14:39 -0700
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-01 15:11 -0700
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-02 08:41 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-02 02:07 -0700
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-02 11:38 +0200
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-02 05:01 -0700
It is not futile to change the subject line (Was: this girl calls c ugly) gazelle@shell.xmission.com (Kenny McCormack) - 2026-06-02 12:39 +0000
Re: It is not futile to change the subject line (Was: this girl calls c ugly) gazelle@shell.xmission.com (Kenny McCormack) - 2026-06-02 12:42 +0000
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-02 11:46 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-02 11:09 +0100
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-02 05:25 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-02 14:20 +0100
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-02 15:12 -0700
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-02 04:16 -0700
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-01 15:23 -0700
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-01 16:06 -0700
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-01 23:24 +0100
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-06-02 11:35 +0200
Operator precedence in other (non-C, but "C-like") languages (Was: something about a girl) gazelle@shell.xmission.com (Kenny McCormack) - 2026-06-02 12:36 +0000
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-01 11:04 +0000
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-01 14:04 +0200
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-01 18:48 +0000
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-01 21:04 +0100
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-02 09:17 +0200
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-02 09:09 +0200
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-02 12:07 +0000
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-06-02 14:37 +0200
Microcontroller software stacks (was Re: this girl calls c ugly) scott@slp53.sl.home (Scott Lurndal) - 2026-06-02 15:06 +0000
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-04 03:58 -0700
Re: this girl calls c ugly dave_thompson_2@comcast.net - 2026-06-06 19:02 -0400
Re: this girl calls c ugly cross@spitfire.i.gajendra.net (Dan Cross) - 2026-05-31 19:11 +0000
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-05-31 16:08 -0700
Re: this girl calls c ugly Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-31 16:32 -0700
Re: this girl calls c ugly Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-05-31 17:12 -0700
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-30 14:07 +0200
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 18:10 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-29 19:18 +0100
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 22:17 +0200
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-29 21:47 +0100
Re: this girl calls c ugly James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-05-29 15:57 -0400
Re: this girl calls c ugly Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-05-29 22:34 +0200
Re: this girl calls c ugly Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-05-29 23:18 +0000
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-30 01:26 +0100
Re: this girl calls c ugly Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-05-30 04:25 +0000
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-30 12:01 +0100
Re: this girl calls c ugly Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-05-31 00:29 +0000
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-05-31 10:59 +0100
Re: this girl calls c ugly Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-06-01 00:33 +0000
Re: this girl calls c ugly Bart <bc@freeuk.com> - 2026-06-01 02:26 +0100
Re: this girl calls c ugly David Brown <david.brown@hesbynett.no> - 2026-05-31 13:24 +0200
Re: this girl calls c ugly Bonita Montero <Bonita.Montero@gmail.com> - 2026-05-29 08:09 +0200
Re: this girl calls c ugly BGB <cr88192@gmail.com> - 2026-05-29 04:15 -0500
Re: this girl calls c ugly Bonita Montero <Bonita.Montero@gmail.com> - 2026-05-29 14:58 +0200
Re: this girl calls c ugly BGB <cr88192@gmail.com> - 2026-05-30 01:04 -0500
Re: this girl calls c ugly Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-05-29 23:20 +0000
Re: this girl calls c ugly Bonita Montero <Bonita.Montero@gmail.com> - 2026-05-30 11:18 +0200
Page 5 of 19 — ← Prev page 1 … 3 4 [5] 6 7 … 19 Next page →
| From | cross@spitfire.i.gajendra.net (Dan Cross) |
|---|---|
| Date | 2026-06-02 16:28 +0000 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <10vn0bk$ghg$1@reader1.panix.com> |
| In reply to | #399615 |
In article <86ik81cfk5.fsf_-_@linuxsc.com>,
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
>
>> On 2026-06-01 00:54, Keith Thompson wrote:
>>
>>>> [...]
>>>
>>> Yes, a compiler can reduce (a + b) * 0 to just 0. But it's not
>>> required to do so, and (INT_MAX + 1) * 0 still has undefined
>>> behavior. Undefined behavior is determined by the rules of the
>>> abstract machine *without* any adjustments permitted by the as-if
>>> rule.
>>
>> This is something I really don't get in the actual C-logic...
>>
>> Using constants that can be determined at compile time is UB here,
>> despite the '* 0' mathematically indicating an IMO clear semantics,
>> but using variables is only UB possibly at runtime? [...]
>
>There's an important distinction to make here. Consider this
>program:
>
> #include <limits.h>
>
> int
> foo(){
> int zero = (INT_MAX+1)*0;
> return zero;
> }
>
> int
> main(){
> return 0;
> }
>
>This program does not transgress the bounds of undefined behavior.
Given that `foo` has external linkage, I find this hard to
believe, and `clang -fsanitize=undefined` agrees with me,
both emitting a diagnostic about the overflow and generating
code in `foo` to call into the sanitizer machinery.
Perhaps you mean that this is irrelevant because `foo` is not
invoked, but I see no reason why that need be the case in e.g.
a freestanding environment. In a hosted environment, I don't
think anything explicitly prevents `foo` from being called after
`main` returns (though I can't imagine that would happen in real
life; it would be weird if it did).
But I'm not sure what _you_ mean by "transgress the bounds of
undefined behavior" here.
>Even more than that, the program is strictly conforming, and must be
>accepted by a conforming implementation.
See above.
>Now let's change the program slightly:
>
> #include <limits.h>
>
> int
> foo(){
> static int zero = (INT_MAX+1)*0;
> return zero;
> }
>
> int
> main(){
> return 0;
> }
>
>This program does transgress the bounds of undefined behavior. The
>reason for the difference is that in the first program the semantics
>of foo() is to evaluate the expression to be stored in 'zero' only
>at runtime, whereas in the second program the semantics of foo() is
>to evaluate the expression to be stored in 'zero' before program
>startup (informally, "at compile time"). What matters is not
>whether the offending expression /might/ be evaluated "at compile
>time", but whether the offending expression /must/ be evaluated "at
>compile time". Only in the second case is undefined behavior
>inevitable (and thus it does not occur in the first program).
>
>Fine point: strictly speaking, I believe the C standard allows even
>the second program to complete translation phase 8 successfully, and
>for any offending behavior to occur only when we actually try to run
>the program. To say that another way, there is no requirement that
>possible nasal demons be made manifest at any point before an actual
>attempted execution. On the other hand, because that possibility is
>there lurking in the background, there is no requirement that the
>program be accepted, and could be rejected by a conforming compiler.
Indeed. Further, I believe that the same is true for the first
program, as well.
- Dan C.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2026-06-04 03:37 -0700 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <865x3yd21n.fsf@linuxsc.com> |
| In reply to | #399636 |
cross@spitfire.i.gajendra.net (Dan Cross) writes:
> In article <86ik81cfk5.fsf_-_@linuxsc.com>,
> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>
>> Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
>>
>>> On 2026-06-01 00:54, Keith Thompson wrote:
>>>
>>>>> [...]
>>>>
>>>> Yes, a compiler can reduce (a + b) * 0 to just 0. But it's not
>>>> required to do so, and (INT_MAX + 1) * 0 still has undefined
>>>> behavior. Undefined behavior is determined by the rules of the
>>>> abstract machine *without* any adjustments permitted by the as-if
>>>> rule.
>>>
>>> This is something I really don't get in the actual C-logic...
>>>
>>> Using constants that can be determined at compile time is UB here,
>>> despite the '* 0' mathematically indicating an IMO clear semantics,
>>> but using variables is only UB possibly at runtime? [...]
>>
>> There's an important distinction to make here. Consider this
>> program:
>>
>> #include <limits.h>
>>
>> int
>> foo(){
>> int zero = (INT_MAX+1)*0;
>> return zero;
>> }
>>
>> int
>> main(){
>> return 0;
>> }
>>
>> This program does not transgress the bounds of undefined behavior.
To clarify, the comments in my posting were meant to be read as
saying the given text is the entire program, and that it is strictly
conforming with respect to conforming hosted implementations.
(Incidentally, given the rules for freestanding implementations, I'm
not sure that it is even possible for any program to be strictly
conforming with respect to conforming freestanding implementations.
In any case my statements were meant only in the context of hosted
implementations.)
> Given that `foo` has external linkage, I find this hard to
> believe, and `clang -fsanitize=undefined` agrees with me,
> both emitting a diagnostic about the overflow and generating
> code in `foo` to call into the sanitizer machinery.
A conforming implementation is free to emit a diagnostic whenever it
chooses, for any reason at all, regardless of whether the program
source is legal C or not. (I feel obliged to point out that, if a
preprocessing #error directive is encountered, then there may be an
exception to that statement; however, there is no such #error in
the program shown above.)
> Perhaps you mean that this is irrelevant because `foo` is not
> invoked, but I see no reason why that need be the case in e.g.
> a freestanding environment.
I explained the context of my previous statements above. Sorry for
not saying that in the original message.
> In a hosted environment, I don't
> think anything explicitly prevents `foo` from being called after
> `main` returns (though I can't imagine that would happen in real
> life; it would be weird if it did).
The semantics described in the ISO C standard don't admit that
possibility. Whether foo() has external linkage or internal
linkage doesn't change that. Only those actions initiated by
statements in main() are ever elaborated.
> But I'm not sure what _you_ mean by "transgress the bounds of
> undefined behavior" here.
It's a grammatical fine point. I think for present purposes it's
okay to gloss over the distinction, and say this statement may be
read as saying "the program does not have undefined behavior".
>> Even more than that, the program is strictly conforming, and must be
>> accepted by a conforming implementation.
>
> See above.
>
>> Now let's change the program slightly:
>>
>> #include <limits.h>
>>
>> int
>> foo(){
>> static int zero = (INT_MAX+1)*0;
>> return zero;
>> }
>>
>> int
>> main(){
>> return 0;
>> }
>>
>> This program does transgress the bounds of undefined behavior. The
>> reason for the difference is that in the first program the semantics
>> of foo() is to evaluate the expression to be stored in 'zero' only
>> at runtime, whereas in the second program the semantics of foo() is
>> to evaluate the expression to be stored in 'zero' before program
>> startup (informally, "at compile time"). What matters is not
>> whether the offending expression /might/ be evaluated "at compile
>> time", but whether the offending expression /must/ be evaluated "at
>> compile time". Only in the second case is undefined behavior
>> inevitable (and thus it does not occur in the first program).
>>
>> Fine point: strictly speaking, I believe the C standard allows even
>> the second program to complete translation phase 8 successfully, and
>> for any offending behavior to occur only when we actually try to run
>> the program. To say that another way, there is no requirement that
>> possible nasal demons be made manifest at any point before an actual
>> attempted execution. On the other hand, because that possibility is
>> there lurking in the background, there is no requirement that the
>> program be accepted, and could be rejected by a conforming compiler.
>
> Indeed. Further, I believe that the same is true for the first
> program, as well.
It isn't. In the first program the offending expression is never
evaluated, because foo() is never called.
[toc] | [prev] | [next] | [standalone]
| From | cross@spitfire.i.gajendra.net (Dan Cross) |
|---|---|
| Date | 2026-06-04 16:31 +0000 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <10vs997$rp5$1@reader1.panix.com> |
| In reply to | #399674 |
In article <865x3yd21n.fsf@linuxsc.com>,
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>> In article <86ik81cfk5.fsf_-_@linuxsc.com>,
>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>>> Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
>>>> On 2026-06-01 00:54, Keith Thompson wrote:
>>>>>> [...]
>>>>>
>>>>> Yes, a compiler can reduce (a + b) * 0 to just 0. But it's not
>>>>> required to do so, and (INT_MAX + 1) * 0 still has undefined
>>>>> behavior. Undefined behavior is determined by the rules of the
>>>>> abstract machine *without* any adjustments permitted by the as-if
>>>>> rule.
>>>>
>>>> This is something I really don't get in the actual C-logic...
>>>>
>>>> Using constants that can be determined at compile time is UB here,
>>>> despite the '* 0' mathematically indicating an IMO clear semantics,
>>>> but using variables is only UB possibly at runtime? [...]
>>>
>>> There's an important distinction to make here. Consider this
>>> program:
>>>
>>> #include <limits.h>
>>>
>>> int
>>> foo(){
>>> int zero = (INT_MAX+1)*0;
>>> return zero;
>>> }
>>>
>>> int
>>> main(){
>>> return 0;
>>> }
>>>
>>> This program does not transgress the bounds of undefined behavior.
>
>To clarify, the comments in my posting were meant to be read as
>saying the given text is the entire program, and that it is strictly
>conforming with respect to conforming hosted implementations.
>(Incidentally, given the rules for freestanding implementations, I'm
>not sure that it is even possible for any program to be strictly
>conforming with respect to conforming freestanding implementations.
>In any case my statements were meant only in the context of hosted
>implementations.)
Ok.
>> [snip]
>> Perhaps you mean that this is irrelevant because `foo` is not
>> invoked, but I see no reason why that need be the case in e.g.
>> a freestanding environment.
>
>I explained the context of my previous statements above. Sorry for
>not saying that in the original message.
>
>> In a hosted environment, I don't
>> think anything explicitly prevents `foo` from being called after
>> `main` returns (though I can't imagine that would happen in real
>> life; it would be weird if it did).
>
>The semantics described in the ISO C standard don't admit that
>possibility.
Could you please point to where it says this, in the C standard?
I cannot find anything that says that arbitrary code cannot run
after `main()` returns, and I don't see how that could possibly
be true.
>Whether foo() has external linkage or internal
>linkage doesn't change that.
I disagree. There's no possible way for the implementation to
know whether a function with external linkage will be ultimately
invoked or not; consider a system that supports loadable shared
modules. Nothing prevents even this simple program from being
compiled as a shared module, dynamically loaded, the loading
program explicitly searching for and finding the symbol
corresponding to the `foo` function, and invoking it.
Hence, the compiler _must_ treat with UB as written, which is
why `ubsan` inserts trapping code in `foo`.
In your example, `foo` clearly exhibits UB; I think your
argument is whether that has a realized effect or not, since the
UB is not invoked. I'm saying that in general a compiler cannot
possibly know that when it compiles `foo`, and is free to assume
the worst.
>Only those actions initiated by
>statements in main() are ever elaborated.
This is not true: code can obviously run outside of the bounds
of `main`, for several reasons.
First, there is the issue of static initializers, which you had
mentioned earlier. Not at play here, but it does invalidate
your statement above, as these run "before" main is invoked.
Second, we know that code can run after because `atexit` can be
used to register handlers that will run after it terminates: as
section 5.1.2.3.4 of n3220 says, "a return from the initial call
to the main function is equivalent to calling the exit function
with the value returned by the main function as its argument",
which means that it will run `atexit` handlers. (But, as the
footnote warns, lifetimes of variables with automatic storage
duration have ended in this case in accordance with sec 6.2.4,
since `main` has terminated.)
Third, it is possible to invoke code that may conditionally be
executed, such as signal handlers, in response to external
events. Certainly, `signal(SIGINT, some_handler);` does not
immediately guarantee that `some_handler` is run, but it does
not prevent it from running, either.
Of course, for the second and third points, we must acknowledge
that one might quibble about what it means to say that a program
invokes "actions initiated by statements in main()".
Registering signal and exit handlers is (generally) going to be
something done in as the consequence of an "action initiated by
statements in main()". And subsequent invocation of (say)
`some_handler` in the example above in response to receipt of a
`SIGINT` signal is arguably a consequence of that.
>> But I'm not sure what _you_ mean by "transgress the bounds of
>> undefined behavior" here.
>
>It's a grammatical fine point. I think for present purposes it's
>okay to gloss over the distinction, and say this statement may be
>read as saying "the program does not have undefined behavior".
Except it does. `foo` is an example of what Regehr calls a
"Type 3" function in https://blog.regehr.org/archives/213.
Also you are discounting time-travel; code not not actually
invoke UB to suffer from it. The mere existence of it can be
enough.
https://devblogs.microsoft.com/oldnewthing/20140627-00/?p=633
Moreover, undefined behavior simply is; the definition from the
C standard does not say that time-traveling "post-modern"
compilers are free to assume and do anything if they observe UB
anywhere in a program.
Here, because `foo` has external linkage, the compiler cannot
know whether `foo` is invoked or not, and I see nothing
preventing it from assuming that the entire program is in error.
In particular, I don't think there is anything that prevents a
compiler from simply emitting `int main(void) { abort(); }`.
>>> Even more than that, the program is strictly conforming, and must be
>>> accepted by a conforming implementation.
>>
>> See above.
>>
>>> Now let's change the program slightly:
>>>
>>> #include <limits.h>
>>>
>>> int
>>> foo(){
>>> static int zero = (INT_MAX+1)*0;
>>> return zero;
>>> }
>>>
>>> int
>>> main(){
>>> return 0;
>>> }
>>>
>>> This program does transgress the bounds of undefined behavior. The
>>> reason for the difference is that in the first program the semantics
>>> of foo() is to evaluate the expression to be stored in 'zero' only
>>> at runtime, whereas in the second program the semantics of foo() is
>>> to evaluate the expression to be stored in 'zero' before program
>>> startup (informally, "at compile time"). What matters is not
>>> whether the offending expression /might/ be evaluated "at compile
>>> time", but whether the offending expression /must/ be evaluated "at
>>> compile time". Only in the second case is undefined behavior
>>> inevitable (and thus it does not occur in the first program).
>>>
>>> Fine point: strictly speaking, I believe the C standard allows even
>>> the second program to complete translation phase 8 successfully, and
>>> for any offending behavior to occur only when we actually try to run
>>> the program. To say that another way, there is no requirement that
>>> possible nasal demons be made manifest at any point before an actual
>>> attempted execution. On the other hand, because that possibility is
>>> there lurking in the background, there is no requirement that the
>>> program be accepted, and could be rejected by a conforming compiler.
>>
>> Indeed. Further, I believe that the same is true for the first
>> program, as well.
>
>It isn't. In the first program the offending expression is never
>evaluated, because foo() is never called.
See above.
Of course, I don't think any of this would _actually_ happen,
and if it did, one should take the compiler that does it and
toss it in the trash. But I don't think it's prohibited,
either; such is one of the consequences of an informal
specification like the C standard. Time-travel is especially
pernicious in post-modern compilers.
- Dan C.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2026-06-04 13:36 -0700 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <10vsnl7$lkmu$1@kst.eternal-september.org> |
| In reply to | #399693 |
cross@spitfire.i.gajendra.net (Dan Cross) writes:
> In article <865x3yd21n.fsf@linuxsc.com>,
> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>>> In article <86ik81cfk5.fsf_-_@linuxsc.com>,
>>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
[...]
>>>> There's an important distinction to make here. Consider this
>>>> program:
>>>>
>>>> #include <limits.h>
>>>>
>>>> int
>>>> foo(){
>>>> int zero = (INT_MAX+1)*0;
>>>> return zero;
>>>> }
>>>>
>>>> int
>>>> main(){
>>>> return 0;
>>>> }
>>>>
>>>> This program does not transgress the bounds of undefined behavior.
>>
>>To clarify, the comments in my posting were meant to be read as
>>saying the given text is the entire program, and that it is strictly
>>conforming with respect to conforming hosted implementations.
>>(Incidentally, given the rules for freestanding implementations, I'm
>>not sure that it is even possible for any program to be strictly
>>conforming with respect to conforming freestanding implementations.
>>In any case my statements were meant only in the context of hosted
>>implementations.)
>
> Ok.
>
>>> [snip]
>>> Perhaps you mean that this is irrelevant because `foo` is not
>>> invoked, but I see no reason why that need be the case in e.g.
>>> a freestanding environment.
>>
>>I explained the context of my previous statements above. Sorry for
>>not saying that in the original message.
>>
>>> In a hosted environment, I don't
>>> think anything explicitly prevents `foo` from being called after
>>> `main` returns (though I can't imagine that would happen in real
>>> life; it would be weird if it did).
>>
>>The semantics described in the ISO C standard don't admit that
>>possibility.
>
> Could you please point to where it says this, in the C standard?
>
> I cannot find anything that says that arbitrary code cannot run
> after `main()` returns, and I don't see how that could possibly
> be true.
N3220 5.1.2.4, Program semantics.
It defines the *observable behavior* of a program, which consists of
accesses to volatile objects, data written to files, and I/O dynamics of
interactive devices.
If the usual "Hello, world" program prints "Hello, world" followed
by "Goodbye", the implementation is non-conforming. If it formats
my hard drive after printing "Goodbye", it's non-conforming and
dangerous.
>>Whether foo() has external linkage or internal
>>linkage doesn't change that.
>
> I disagree. There's no possible way for the implementation to
> know whether a function with external linkage will be ultimately
> invoked or not; consider a system that supports loadable shared
> modules. Nothing prevents even this simple program from being
> compiled as a shared module, dynamically loaded, the loading
> program explicitly searching for and finding the symbol
> corresponding to the `foo` function, and invoking it.
Remember that linking is translation phase 8. The compiler is not
the entire implementation.
> Hence, the compiler _must_ treat with UB as written, which is
> why `ubsan` inserts trapping code in `foo`.
I don't know what "_must_ treat with UB" means.
foo() has undefined behavior if it's called, so replacing its
body with trapping code is valid. But (I'm reasonably sure that)
an implementation cannot reject a program just because it can't
prove that it has no undefined behavior during execution. It can
reject it if it can prove that it *always* has undefined behavior
during execution.
> In your example, `foo` clearly exhibits UB; I think your
> argument is whether that has a realized effect or not, since the
> UB is not invoked. I'm saying that in general a compiler cannot
> possibly know that when it compiles `foo`, and is free to assume
> the worst.
foo() exhibits UB if and only if it's called during execution.
Yes, a compiler can't know whether foo() will be called.
An implementation, particularly a linker, might know, but is not
required to. No, it is not free to assume the worst.
I certainly wouldn't want a compiler to reject `1/time(NULL)`
because it can't prove that time(NULL) won't be zero, or reject
`argc+1` because it can't prove that argc < INT_MAX. Code whose
behavior would be undefined if it were executed has no behavior
(and therefore no UB) if it's not executed.
[...]
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | cross@spitfire.i.gajendra.net (Dan Cross) |
|---|---|
| Date | 2026-06-04 23:49 +0000 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <10vt2un$fuu$1@reader1.panix.com> |
| In reply to | #399710 |
In article <10vsnl7$lkmu$1@kst.eternal-september.org>,
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>> In article <865x3yd21n.fsf@linuxsc.com>,
>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>>>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>>>> In article <86ik81cfk5.fsf_-_@linuxsc.com>,
>>>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>[...]
>>>>> There's an important distinction to make here. Consider this
>>>>> program:
>>>>>
>>>>> #include <limits.h>
>>>>>
>>>>> int
>>>>> foo(){
>>>>> int zero = (INT_MAX+1)*0;
>>>>> return zero;
>>>>> }
>>>>>
>>>>> int
>>>>> main(){
>>>>> return 0;
>>>>> }
>>>>>
>>>>> This program does not transgress the bounds of undefined behavior.
>>>
>>>To clarify, the comments in my posting were meant to be read as
>>>saying the given text is the entire program, and that it is strictly
>>>conforming with respect to conforming hosted implementations.
>>>(Incidentally, given the rules for freestanding implementations, I'm
>>>not sure that it is even possible for any program to be strictly
>>>conforming with respect to conforming freestanding implementations.
>>>In any case my statements were meant only in the context of hosted
>>>implementations.)
>>
>> Ok.
>>
>>>> [snip]
>>>> Perhaps you mean that this is irrelevant because `foo` is not
>>>> invoked, but I see no reason why that need be the case in e.g.
>>>> a freestanding environment.
>>>
>>>I explained the context of my previous statements above. Sorry for
>>>not saying that in the original message.
>>>
>>>> In a hosted environment, I don't
>>>> think anything explicitly prevents `foo` from being called after
>>>> `main` returns (though I can't imagine that would happen in real
>>>> life; it would be weird if it did).
>>>
>>>The semantics described in the ISO C standard don't admit that
>>>possibility.
>>
>> Could you please point to where it says this, in the C standard?
>>
>> I cannot find anything that says that arbitrary code cannot run
>> after `main()` returns, and I don't see how that could possibly
>> be true.
>
>N3220 5.1.2.4, Program semantics.
>
>It defines the *observable behavior* of a program, which consists of
>accesses to volatile objects, data written to files, and I/O dynamics of
>interactive devices.
Yes, but it does so for strictly-conforming programs with no UB.
To understand conformance, we have to jump over to section 4,
which explicitly says that, 'Undefined behavior is otherwise
indicated in this document by the words "undefined behavior" or
by the omission of any explicit definition of behavior.' As it
does not say that a program with an instance of undefined
behavior in an integer constant expression that is not executed
must otherwise behave in any given manner, what the program does
is undefined. A constaint violation mandates a diagnostic, but
beyond that, the standard is (AFAICT) silent.
Undefined Behavior, in turn, is not defined as specific only to
execution: the standard simply says that it is "behavior, upon
use of a *nonportable or erroneous program construct*..." for
which there are no requirements, and there are examples of
things that are explicitly UB at translation time, such as
improperly terminated lexemes and so forth.
Furthermore, the expression above is obviously an integer
constant expression as defined by sec 6.6 para 8. Section 6.6,
para 4, reads in part, "Each constant expression shall evaluate
to a constant that is in the range of representable values for
its type." The expression, `(INT_MAX+1)*0` violates this
constraint, and so therefore a diagnostic is mandated as per
sec 5.1.1.3 para 1. That it appears in code that is not
obviously called from `main` doesn't change that.
Morever, sec 6.6 para 17 says that, "the semantic rules for
evaluation of a constant expression are the same as for
nonconstant expressions." This brings us back to 5.1.2.4,
though I submit that para (4) is a stronger argument for what
you and Tim are saying, as it reads in part, "An actual
implementation is not required to evaluate part of an expression
if it can deduce that its value is not used and that no needed
side effects are produced (including any caused by calling a
function or through volatile access to an object)." I interpret
this to mean that, if the implementation can determine that
there is no way that `foo` can be called, it does not _have_ to
evaluate the above expression. However, it must satisfy the
range constraint from section 6.6, so it likely will, and in any
event, the standard does not say that it, "shall not" evaluate
it, or when.
Once the compiler does that, if it does, and observes UB, the
standard is silent on what requirements it imposes, which means
the behavior is undefined. I see no reason it couldn't arrange
to invoke `foo` at that point.
So no, I do not see how execution according to the rules of the
abstract machine is not guaranteed, here. I certainly see no
way in which this can be regarded as a strictly conforming
program.
>If the usual "Hello, world" program prints "Hello, world" followed
>by "Goodbye", the implementation is non-conforming. If it formats
>my hard drive after printing "Goodbye", it's non-conforming and
>dangerous.
Two separate things. My point earlier was that code can
obviously run after `main` terminates. Moreoever, I can't
imagine what would _prevent_ a runtime system that invokes
`main` from doing something like printing, "PROGRAM STOPPED"
after `main` returned. C imposes no requirements here.
Whether `foo` could be invoked after, I think, is undefined.
>>>Whether foo() has external linkage or internal
>>>linkage doesn't change that.
>>
>> I disagree. There's no possible way for the implementation to
>> know whether a function with external linkage will be ultimately
>> invoked or not; consider a system that supports loadable shared
>> modules. Nothing prevents even this simple program from being
>> compiled as a shared module, dynamically loaded, the loading
>> program explicitly searching for and finding the symbol
>> corresponding to the `foo` function, and invoking it.
>
>Remember that linking is translation phase 8. The compiler is not
>the entire implementation.
Exactly my point. The compiler cannot know how `foo` might be
used, or how the translated object might be exercised. There's
I don't see how it could possibly know that, given that `foo`
has external linkage.
>> Hence, the compiler _must_ treat with UB as written, which is
>> why `ubsan` inserts trapping code in `foo`.
>
>I don't know what "_must_ treat with UB" means.
>
>foo() has undefined behavior if it's called, so replacing its
>body with trapping code is valid. But (I'm reasonably sure that)
>an implementation cannot reject a program just because it can't
>prove that it has no undefined behavior during execution. It can
>reject it if it can prove that it *always* has undefined behavior
>during execution.
What I'm saying is that, `foo` has undefined behavior _period_.
That's manifest in an integer constant expression, whether it is
executed at runtime or not. I believe that the standard forces
the expression to be evaluated at translation time, via the
"shall" mandate when checking the constraint on the range in sec
6.6 para 4. Further, that evaluation must happen in accordance
with the rules of the abstract machine, as per 5.1.2.4 para 17.
The diagnostic is mandated, as is the translation-time
evaluation. The expression is itself manifestly exhibits UB,
and so therefore the result of the rest of the translation is
undefined.
I could be wrong; this is all excessively pedantic. And of
course, if an implementation does something silly and emits
garbage for Tim's program, then I argue it should be chucked
onto the dustbin of excessive fawning over the standard. But
I'm not convinced that the standard _prohibits_ such an extreme
interpretation.
>> In your example, `foo` clearly exhibits UB; I think your
>> argument is whether that has a realized effect or not, since the
>> UB is not invoked. I'm saying that in general a compiler cannot
>> possibly know that when it compiles `foo`, and is free to assume
>> the worst.
>
>foo() exhibits UB if and only if it's called during execution.
>
>Yes, a compiler can't know whether foo() will be called.
>An implementation, particularly a linker, might know, but is not
>required to. No, it is not free to assume the worst.
See above.
>I certainly wouldn't want a compiler to reject `1/time(NULL)`
>because it can't prove that time(NULL) won't be zero, or reject
>`argc+1` because it can't prove that argc < INT_MAX. Code whose
>behavior would be undefined if it were executed has no behavior
>(and therefore no UB) if it's not executed.
That's categorically different; what you are describing are what
Regehr calls, "Type-2" functions, and I agree with you for
those.
The program that Tim posted has a "Type-3" function, and
constraints dictate that the UB express must be evaluated at
translation time, and a diagnostic emitted. In the most
charitable interpretation, it cannot be considered a strictly
conforming program, even if the implementation is smart enough
to avoid evaluating the constant expression, as it is
unspecified whether it's evaluated or not, and strictly
conforming programs shall not rely on unspecified behavior.
- Dan C.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2026-06-04 18:04 -0700 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <10vt7b9$pi3s$1@kst.eternal-september.org> |
| In reply to | #399725 |
cross@spitfire.i.gajendra.net (Dan Cross) writes:
> In article <10vsnl7$lkmu$1@kst.eternal-september.org>,
> Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>>> In article <865x3yd21n.fsf@linuxsc.com>,
>>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>>>>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>>>>> In article <86ik81cfk5.fsf_-_@linuxsc.com>,
>>>>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>>[...]
>>>>>> There's an important distinction to make here. Consider this
>>>>>> program:
>>>>>>
>>>>>> #include <limits.h>
>>>>>>
>>>>>> int
>>>>>> foo(){
>>>>>> int zero = (INT_MAX+1)*0;
>>>>>> return zero;
>>>>>> }
>>>>>>
>>>>>> int
>>>>>> main(){
>>>>>> return 0;
>>>>>> }
>>>>>>
>>>>>> This program does not transgress the bounds of undefined behavior.
>>>>
>>>>To clarify, the comments in my posting were meant to be read as
>>>>saying the given text is the entire program, and that it is strictly
>>>>conforming with respect to conforming hosted implementations.
>>>>(Incidentally, given the rules for freestanding implementations, I'm
>>>>not sure that it is even possible for any program to be strictly
>>>>conforming with respect to conforming freestanding implementations.
>>>>In any case my statements were meant only in the context of hosted
>>>>implementations.)
>>>
>>> Ok.
>>>
>>>>> [snip]
>>>>> Perhaps you mean that this is irrelevant because `foo` is not
>>>>> invoked, but I see no reason why that need be the case in e.g.
>>>>> a freestanding environment.
>>>>
>>>>I explained the context of my previous statements above. Sorry for
>>>>not saying that in the original message.
>>>>
>>>>> In a hosted environment, I don't
>>>>> think anything explicitly prevents `foo` from being called after
>>>>> `main` returns (though I can't imagine that would happen in real
>>>>> life; it would be weird if it did).
>>>>
>>>>The semantics described in the ISO C standard don't admit that
>>>>possibility.
>>>
>>> Could you please point to where it says this, in the C standard?
>>>
>>> I cannot find anything that says that arbitrary code cannot run
>>> after `main()` returns, and I don't see how that could possibly
>>> be true.
>>
>>N3220 5.1.2.4, Program semantics.
>>
>>It defines the *observable behavior* of a program, which consists of
>>accesses to volatile objects, data written to files, and I/O dynamics of
>>interactive devices.
>
> Yes, but it does so for strictly-conforming programs with no UB.
It does so for programs in general, not just strictly conforming
ones. If a program has undefined behavior, all bets are off,
but for example a program that evaluates `printf("%d\n", INT_MAX)`
is not strictly conforming, but it's fully subject to 5.1.2.4.
> To understand conformance, we have to jump over to section 4,
> which explicitly says that, 'Undefined behavior is otherwise
> indicated in this document by the words "undefined behavior" or
> by the omission of any explicit definition of behavior.' As it
> does not say that a program with an instance of undefined
> behavior in an integer constant expression that is not executed
> must otherwise behave in any given manner, what the program does
> is undefined. A constaint violation mandates a diagnostic, but
> beyond that, the standard is (AFAICT) silent.
I don't think an integer constant expression can have undefined
behavior. INT_MAX+1 and 1/0 are not constant expressions, because
neither "evaluate(s) to a constant that is in the range of
representable values for its type".
I claim that an expression that looks like a constant expression
*isn't* a constant-expression if it doesn't appear in a context
that requires a constant-expression.
The program in question, quoted above, has:
int zero = (INT_MAX+1)*0;
`(INT_MAX+1)*0` is not a constant expression, not because of the
overflow, but because a constant expression is not required in
that context. "constant-expression" is defined by a production in
the grammar (it reduces to "conditional-expression"). Even in
int n = 42;
42 is not a a constant expression, because the grammar doesn't
call for a constant expression in that context -- even though it
looks like one. Similarly, in `a + b * c`, `a + b` looks like an
additive expression, but it isn't one. (Not a perfect analogy.)
> Undefined Behavior, in turn, is not defined as specific only to
> execution: the standard simply says that it is "behavior, upon
> use of a *nonportable or erroneous program construct*..." for
> which there are no requirements, and there are examples of
> things that are explicitly UB at translation time, such as
> improperly terminated lexemes and so forth.
Yes, there are constructs that are explicitly UB at translation time.
(I think that's unfortunate, and there are efforts to clear up some
such cases in C2y.)
Signed integer overflow is not one of those constructs.
Any undefined behavior from evaluating INT_MAX+1 happens during
execution (barring constraint violations).
> Furthermore, the expression above is obviously an integer
> constant expression as defined by sec 6.6 para 8. Section 6.6,
> para 4, reads in part, "Each constant expression shall evaluate
> to a constant that is in the range of representable values for
> its type." The expression, `(INT_MAX+1)*0` violates this
> constraint, and so therefore a diagnostic is mandated as per
> sec 5.1.1.3 para 1. That it appears in code that is not
> obviously called from `main` doesn't change that.
It satisfies the requirements for an integer constant expression in
6.6p8, but it violates the constraint in 6.6p4. (I presume that an
"integer constant expression" must be a "constant expression".)
But since "constant-expression" is a grammatical production,
it doesn't have to satisfy that constraint, and no diagnostic
is required. (A warning is certainly permitted.)
Similarly, this:
int n = INT_MAX + 1;
at block scope doesn't require a diagnostic, though of course it
has undefined behavior -- but at file scope, the initializer is a
constant expression, so that would be a constraint violation.
> Morever, sec 6.6 para 17 says that, "the semantic rules for
> evaluation of a constant expression are the same as for
> nonconstant expressions." This brings us back to 5.1.2.4,
> though I submit that para (4) is a stronger argument for what
> you and Tim are saying, as it reads in part, "An actual
> implementation is not required to evaluate part of an expression
> if it can deduce that its value is not used and that no needed
> side effects are produced (including any caused by calling a
> function or through volatile access to an object)." I interpret
> this to mean that, if the implementation can determine that
> there is no way that `foo` can be called, it does not _have_ to
> evaluate the above expression. However, it must satisfy the
> range constraint from section 6.6, so it likely will, and in any
> event, the standard does not say that it, "shall not" evaluate
> it, or when.
Overflow in a constant expression is not undefined behavior. It's a
constraint violation. But that doesn't apply here, because the
initializer is not a constant expression. (Sorry if I'm repeating
myself.)
> Once the compiler does that, if it does, and observes UB, the
> standard is silent on what requirements it imposes, which means
> the behavior is undefined. I see no reason it couldn't arrange
> to invoke `foo` at that point.
Any UB in the program would occur during execution, and in fact
it *won't* occur during execution because foo() isn't called.
A compiler can't generate code with arbitrary behavior just because
it can't prove that there will be no UB. If it could, every signed
or floating-point arithmetic operation with unknown operand values
would grant the same permission.
> So no, I do not see how execution according to the rules of the
> abstract machine is not guaranteed, here. I certainly see no
> way in which this can be regarded as a strictly conforming
> program.
foo()'s behavior would be undefined if it were called. It *isn't*
called, so there's no actual UB. The program does not violate any
of the other requirements for strict conformance.
>>If the usual "Hello, world" program prints "Hello, world" followed
>>by "Goodbye", the implementation is non-conforming. If it formats
>>my hard drive after printing "Goodbye", it's non-conforming and
>>dangerous.
>
> Two separate things. My point earlier was that code can
> obviously run after `main` terminates. Moreoever, I can't
> imagine what would _prevent_ a runtime system that invokes
> `main` from doing something like printing, "PROGRAM STOPPED"
> after `main` returned. C imposes no requirements here.
Yes, it does. An OS can print "PROGRAM STOPPED", but not as part
of the execution of the program. On my system, a shell prompt is
printed after a program terminates, but not by the program. If I
execute a "hello, world" program with its output redirected to a file
(on a system that supports that), the resulting file cannot contain
"PROGRAM STOPPED". The requirements in 5.1.2.4 specify both what
the execution of a program must do and what it must not do.
> Whether `foo` could be invoked after, I think, is undefined.
>
>>>>Whether foo() has external linkage or internal
>>>>linkage doesn't change that.
>>>
>>> I disagree. There's no possible way for the implementation to
>>> know whether a function with external linkage will be ultimately
>>> invoked or not; consider a system that supports loadable shared
>>> modules. Nothing prevents even this simple program from being
>>> compiled as a shared module, dynamically loaded, the loading
>>> program explicitly searching for and finding the symbol
>>> corresponding to the `foo` function, and invoking it.
>>
>>Remember that linking is translation phase 8. The compiler is not
>>the entire implementation.
>
> Exactly my point. The compiler cannot know how `foo` might be
> used, or how the translated object might be exercised. There's
> I don't see how it could possibly know that, given that `foo`
> has external linkage.
We were presented with a complete translation unit that included a
function definition for "main". It's a complete program. There's no
valid way for some other program to call foo. If OS provided such
a mechanism, it would be outside the scope of C.
>>> Hence, the compiler _must_ treat with UB as written, which is
>>> why `ubsan` inserts trapping code in `foo`.
>>
>>I don't know what "_must_ treat with UB" means.
>>
>>foo() has undefined behavior if it's called, so replacing its
>>body with trapping code is valid. But (I'm reasonably sure that)
>>an implementation cannot reject a program just because it can't
>>prove that it has no undefined behavior during execution. It can
>>reject it if it can prove that it *always* has undefined behavior
>>during execution.
>
> What I'm saying is that, `foo` has undefined behavior _period_.
> That's manifest in an integer constant expression, whether it is
> executed at runtime or not. I believe that the standard forces
> the expression to be evaluated at translation time, via the
> "shall" mandate when checking the constraint on the range in sec
> 6.6 para 4. Further, that evaluation must happen in accordance
> with the rules of the abstract machine, as per 5.1.2.4 para 17.
> The diagnostic is mandated, as is the translation-time
> evaluation. The expression is itself manifestly exhibits UB,
> and so therefore the result of the rest of the translation is
> undefined.
foo is a function. foo does not have undefined behavior; it has no
behavior at all. A *call* to foo during execution has undefined
behavior. (`foo;` is a statement-expression that does nothing;
it does not have undefined behavior.)
[SNIP]
I think the question of whether the initializer is a
constant-expression or not has caused some not entirely relevant
confusion.
Here's another example that avoids that issue.
#include <limits.h>
int foo(void) {
int zero;
zero = INT_MAX;
zero ++;
zero *= 0;
return zero;
}
int main(void) {
return 0;
}
Given my grammatical argument above, I would say that this program
has no constant expressions. Whether that argument is correct or
not, it certainly has no constant expressions that violate any
constraint or that have undefined behavior. Evaluating `zero ++`
(which doesn't even pretend to be a constant expression) would have
run-time undefined behavior -- *if* foo() were ever called.
And given this translation unit, I don't think there's any way to
construct a multi-TU program that calls foo, so a compiler *can*
determine that foo is never called (but there's no requirement to
do so, or to make any use of that information).
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | cross@spitfire.i.gajendra.net (Dan Cross) |
|---|---|
| Date | 2026-06-06 03:10 +0000 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <110032s$clq$1@reader1.panix.com> |
| In reply to | #399731 |
In article <10vt7b9$pi3s$1@kst.eternal-september.org>,
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>> In article <10vsnl7$lkmu$1@kst.eternal-september.org>,
>> Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>>>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>>>> In article <865x3yd21n.fsf@linuxsc.com>,
>>>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>>>>>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>>>>>> In article <86ik81cfk5.fsf_-_@linuxsc.com>,
>>>>>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>>>[...]
>>>>>>> There's an important distinction to make here. Consider this
>>>>>>> program:
>>>>>>>
>>>>>>> #include <limits.h>
>>>>>>>
>>>>>>> int
>>>>>>> foo(){
>>>>>>> int zero = (INT_MAX+1)*0;
>>>>>>> return zero;
>>>>>>> }
>>>>>>>
>>>>>>> int
>>>>>>> main(){
>>>>>>> return 0;
>>>>>>> }
>>>>>>>
>>>>>>> This program does not transgress the bounds of undefined behavior.
>>>>>
>>>>>To clarify, the comments in my posting were meant to be read as
>>>>>saying the given text is the entire program, and that it is strictly
>>>>>conforming with respect to conforming hosted implementations.
>>>>>(Incidentally, given the rules for freestanding implementations, I'm
>>>>>not sure that it is even possible for any program to be strictly
>>>>>conforming with respect to conforming freestanding implementations.
>>>>>In any case my statements were meant only in the context of hosted
>>>>>implementations.)
>>>>
>>>> Ok.
>>>>
>>>>>> [snip]
>>>>>> Perhaps you mean that this is irrelevant because `foo` is not
>>>>>> invoked, but I see no reason why that need be the case in e.g.
>>>>>> a freestanding environment.
>>>>>
>>>>>I explained the context of my previous statements above. Sorry for
>>>>>not saying that in the original message.
>>>>>
>>>>>> In a hosted environment, I don't
>>>>>> think anything explicitly prevents `foo` from being called after
>>>>>> `main` returns (though I can't imagine that would happen in real
>>>>>> life; it would be weird if it did).
>>>>>
>>>>>The semantics described in the ISO C standard don't admit that
>>>>>possibility.
>>>>
>>>> Could you please point to where it says this, in the C standard?
>>>>
>>>> I cannot find anything that says that arbitrary code cannot run
>>>> after `main()` returns, and I don't see how that could possibly
>>>> be true.
>>>
>>>N3220 5.1.2.4, Program semantics.
>>>
>>>It defines the *observable behavior* of a program, which consists of
>>>accesses to volatile objects, data written to files, and I/O dynamics of
>>>interactive devices.
>>
>> Yes, but it does so for strictly-conforming programs with no UB.
>
>It does so for programs in general, not just strictly conforming
>ones. If a program has undefined behavior, all bets are off,
>but for example a program that evaluates `printf("%d\n", INT_MAX)`
>is not strictly conforming, but it's fully subject to 5.1.2.4.
>
>> To understand conformance, we have to jump over to section 4,
>> which explicitly says that, 'Undefined behavior is otherwise
>> indicated in this document by the words "undefined behavior" or
>> by the omission of any explicit definition of behavior.' As it
>> does not say that a program with an instance of undefined
>> behavior in an integer constant expression that is not executed
>> must otherwise behave in any given manner, what the program does
>> is undefined. A constaint violation mandates a diagnostic, but
>> beyond that, the standard is (AFAICT) silent.
>
>I don't think an integer constant expression can have undefined
>behavior. INT_MAX+1 and 1/0 are not constant expressions, because
>neither "evaluate(s) to a constant that is in the range of
>representable values for its type".
>
>I claim that an expression that looks like a constant expression
>*isn't* a constant-expression if it doesn't appear in a context
>that requires a constant-expression.
That's a bold claim, but I think I see why you're saying that.
>The program in question, quoted above, has:
>
> int zero = (INT_MAX+1)*0;
>
>`(INT_MAX+1)*0` is not a constant expression, not because of the
>overflow, but because a constant expression is not required in
>that context. "constant-expression" is defined by a production in
>the grammar (it reduces to "conditional-expression"). Even in
>
> int n = 42;
>
>42 is not a a constant expression, because the grammar doesn't
>call for a constant expression in that context -- even though it
>looks like one. Similarly, in `a + b * c`, `a + b` looks like an
>additive expression, but it isn't one. (Not a perfect analogy.)
Right; I see what you mean. In this case, the
`assignment-expression` production applies, not
`constant-expression`.
>> Undefined Behavior, in turn, is not defined as specific only to
>> execution: the standard simply says that it is "behavior, upon
>> use of a *nonportable or erroneous program construct*..." for
>> which there are no requirements, and there are examples of
>> things that are explicitly UB at translation time, such as
>> improperly terminated lexemes and so forth.
>
>Yes, there are constructs that are explicitly UB at translation time.
>(I think that's unfortunate, and there are efforts to clear up some
>such cases in C2y.)
It's unclear to me how it could be any other way. If UB was
_only_ an issue at runtime, then how could a compiler take
advantage of it to perform optimizations during translation?
We know that compilers do this.
>Signed integer overflow is not one of those constructs.
This I'm not sure I agree with. It the compiler detects signed
integer overflow in (perhaps not relevant in _this_ example) an
integer constant expression, I still don't see anthing that
makes that anything other than UB. It's a constaint violation,
sure, but nothing says it is not also UB.
>Any undefined behavior from evaluating INT_MAX+1 happens during
>execution (barring constraint violations).
I'm not sure the standard says that. The standard says this
happens during _evaluation_, and that evaluation must be
performed in accordance with the rules of the abstract syntax
machine. But it doesn't precisely specify _when_ evaluation
takes place, and in particular, there are places in the standard
that explicitly mention evaluation during translation. I still
don't see anything that prohibits a compiler from evaluating
that expression at compile time (indeed, it clearly does, as it
generates a diagnostic about the overflow).
I suppose that changes the matter: does the language merely
leave that unspecified, in which case, this program is not
strictly conforming, or does it say that it _cannot_ make any
translation-time decisions about it? I cannot find a satisfying
argument for the latter.
>> Furthermore, the expression above is obviously an integer
>> constant expression as defined by sec 6.6 para 8. Section 6.6,
>> para 4, reads in part, "Each constant expression shall evaluate
>> to a constant that is in the range of representable values for
>> its type." The expression, `(INT_MAX+1)*0` violates this
>> constraint, and so therefore a diagnostic is mandated as per
>> sec 5.1.1.3 para 1. That it appears in code that is not
>> obviously called from `main` doesn't change that.
>
>It satisfies the requirements for an integer constant expression in
>6.6p8, but it violates the constraint in 6.6p4. (I presume that an
>"integer constant expression" must be a "constant expression".)
>But since "constant-expression" is a grammatical production,
>it doesn't have to satisfy that constraint, and no diagnostic
>is required. (A warning is certainly permitted.)
Fair point. It's grammatical position makes it an
assignment-expression. I clearly misinterpreted that before.
>Similarly, this:
> int n = INT_MAX + 1;
>at block scope doesn't require a diagnostic, though of course it
>has undefined behavior -- but at file scope, the initializer is a
>constant expression, so that would be a constraint violation.
Right. The semantics of this are defined in sec 6.7.11 para 5.
>> Morever, sec 6.6 para 17 says that, "the semantic rules for
>> evaluation of a constant expression are the same as for
>> nonconstant expressions." This brings us back to 5.1.2.4,
>> though I submit that para (4) is a stronger argument for what
>> you and Tim are saying, as it reads in part, "An actual
>> implementation is not required to evaluate part of an expression
>> if it can deduce that its value is not used and that no needed
>> side effects are produced (including any caused by calling a
>> function or through volatile access to an object)." I interpret
>> this to mean that, if the implementation can determine that
>> there is no way that `foo` can be called, it does not _have_ to
>> evaluate the above expression. However, it must satisfy the
>> range constraint from section 6.6, so it likely will, and in any
>> event, the standard does not say that it, "shall not" evaluate
>> it, or when.
>
>Overflow in a constant expression is not undefined behavior. It's a
>constraint violation. But that doesn't apply here, because the
>initializer is not a constant expression. (Sorry if I'm repeating
>myself.)
Where does it say that UB and constraint violations are mutually
exclusive? I don't see any such statement in the standard. Am
I missing it?
The standard says that if a constraint is violated, a diagnostic
must be emitted, regardless of whether or not the constraint
violation is the result of something that is UB not; that is, if
a constraint violation occurs due to something that is UB, the
implementation must still emit a diagnostic: UB is not an escape
hatch from that requirement.
It also says, 'If a "shall" or "shall not" requirement that
appears outside of a constraint or runtime-constraint is
violated, the behavior is undefined. Undefined behavior is
otherwise indicated in this document by the words "undefined
behavior" or by the omission of any explicit definition of
behavior.' However, that does not preclude such behavior being
undefined; it just means that the words "shall" and "shall not"
in a constraint violation do not a priori describe behavior vis
definition.
>> Once the compiler does that, if it does, and observes UB, the
>> standard is silent on what requirements it imposes, which means
>> the behavior is undefined. I see no reason it couldn't arrange
>> to invoke `foo` at that point.
>
>Any UB in the program would occur during execution,
I suppose; but it's not clear to me that UB is tied _only_ to
execution time.
The standard is explicit that there _are_ things that are
evaluated at translation time, like the initializer for an
object with storage class `constexpr`. It is not clear me that
a compiler is otherwise _prohibited_ from evaluating an
expression during translation; indeed, one could imagine it
doing so to perform constant folding, and I do not believe there
exists any normative text defining it as such.
I realize this is an extreme interpretation, and not one that is
not widely shared. Personally, I think it's rather silly.
However, I that is _a_ danger of the informality of the C
specification; it does not define the semantics of the abstract
machine in the formally precise way that, say, the SML spec
defines that language's semantics. Rather, it informally
specifies them in prose, and that prose is ambiguous.
Probably much good would be done if C's semantics _were_
rigorously defined, but they are not. Thus, they are open to
radical interpretation, and as extreme as those may be, I do not
see how the normative text of the standard explicitly
_prohibits_ them.
>and in fact
>it *won't* occur during execution because foo() isn't called.
>A compiler can't generate code with arbitrary behavior just because
>it can't prove that there will be no UB. If it could, every signed
>or floating-point arithmetic operation with unknown operand values
>would grant the same permission.
But that's not the situation here. The situation is that the
compiler can prove that something _is_ UB.
Regardless, I think you highlighted an actual problem with the
spec; I don't think that behavior is _explicitly_ prohibited,
therefore, it is likely undefined, but at a minimum unspecified,
whether it actually could happen. If the argument against that
is that this renders the language essentially unusuable, then
my response is, "yeah, well, welcome to programming in C in the
2020s." Most compilers would never be that extreme, but I see
no evidence that it would not be an invalid reading of the
literal text of the standard if they did.
>> So no, I do not see how execution according to the rules of the
>> abstract machine is not guaranteed, here. I certainly see no
>> way in which this can be regarded as a strictly conforming
>> program.
>
>foo()'s behavior would be undefined if it were called. It *isn't*
>called, so there's no actual UB. The program does not violate any
>of the other requirements for strict conformance.
I understand _what_ you're saying: despite the expression itself
manifesting undefined behavior, in this case it's not UB because
`foo` is never executed. What I'm saying is that I don't see
anything in the standard that restricts UB to _only_ executed
code. A reputable compiler obviously instruments `foo` with
code to trap into ubsan; if it's not UB, since it's not
executed, then why do so? Granted, that's not evidence of
anything other than the behavior of those compilers, but still.
It is clearly the _intent_ that this be a strictly conforming
program. The C standard, as an imprecise, informal document,
cannot guarantee it.
>>>If the usual "Hello, world" program prints "Hello, world" followed
>>>by "Goodbye", the implementation is non-conforming. If it formats
>>>my hard drive after printing "Goodbye", it's non-conforming and
>>>dangerous.
>>
>> Two separate things. My point earlier was that code can
>> obviously run after `main` terminates. Moreoever, I can't
>> imagine what would _prevent_ a runtime system that invokes
>> `main` from doing something like printing, "PROGRAM STOPPED"
>> after `main` returned. C imposes no requirements here.
>
>Yes, it does. An OS can print "PROGRAM STOPPED", but not as part
>of the execution of the program. On my system, a shell prompt is
>printed after a program terminates, but not by the program. If I
>execute a "hello, world" program with its output redirected to a file
>(on a system that supports that), the resulting file cannot contain
>"PROGRAM STOPPED". The requirements in 5.1.2.4 specify both what
>the execution of a program must do and what it must not do.
Files are a separate case. There's no guarantee that the
standard output refers to a file; it may well refer to an
"interactive device", the semantics of which are (necessarily)
unspecified.
Here's an example: consider an interactive user who uses a
screen reader device. Suppose that user makes use of an
implementation that includes runtime support for that device,
and that precedes invocation of `main` with a command sequence
causing the screen reader to (perhaps) change intonation; and
suceeds return from main by outputing another command sequence
that resets to the original state.
I do not see how C could prohibit that, assuming that the
implementation takes care to detect whether standard output
really refers to the screen reader, and does emit the control
sequences if output is redirected to a file. Another user who
runs that same program without a screen reader may see the
standard text printed on the screen, without the control
sequence sandwich.
I don't think a conforming implementation can prohibit that kind
of thing.
>>>>>Whether foo() has external linkage or internal
>>>>>linkage doesn't change that.
>>>>
>>>> I disagree. There's no possible way for the implementation to
>>>> know whether a function with external linkage will be ultimately
>>>> invoked or not; consider a system that supports loadable shared
>>>> modules. Nothing prevents even this simple program from being
>>>> compiled as a shared module, dynamically loaded, the loading
>>>> program explicitly searching for and finding the symbol
>>>> corresponding to the `foo` function, and invoking it.
>>>
>>>Remember that linking is translation phase 8. The compiler is not
>>>the entire implementation.
>>
>> Exactly my point. The compiler cannot know how `foo` might be
>> used, or how the translated object might be exercised. There's
>> I don't see how it could possibly know that, given that `foo`
>> has external linkage.
>
>We were presented with a complete translation unit that included a
>function definition for "main". It's a complete program. There's no
>valid way for some other program to call foo. If OS provided such
>a mechanism, it would be outside the scope of C.
Given an excessively pedantic and literal reading of the text of
the standard, I don't think an implementation is explicitly
prohibited from evaluating the initializer at translation time,
deducing that the behavior is undefined, and blaming it on the
program, at which point, all bets are off.
>>>> Hence, the compiler _must_ treat with UB as written, which is
>>>> why `ubsan` inserts trapping code in `foo`.
>>>
>>>I don't know what "_must_ treat with UB" means.
>>>
>>>foo() has undefined behavior if it's called, so replacing its
>>>body with trapping code is valid. But (I'm reasonably sure that)
>>>an implementation cannot reject a program just because it can't
>>>prove that it has no undefined behavior during execution. It can
>>>reject it if it can prove that it *always* has undefined behavior
>>>during execution.
>>
>> What I'm saying is that, `foo` has undefined behavior _period_.
>> That's manifest in an integer constant expression, whether it is
>> executed at runtime or not. I believe that the standard forces
>> the expression to be evaluated at translation time, via the
>> "shall" mandate when checking the constraint on the range in sec
>> 6.6 para 4. Further, that evaluation must happen in accordance
>> with the rules of the abstract machine, as per 5.1.2.4 para 17.
>> The diagnostic is mandated, as is the translation-time
>> evaluation. The expression is itself manifestly exhibits UB,
>> and so therefore the result of the rest of the translation is
>> undefined.
>
>foo is a function. foo does not have undefined behavior; it has no
>behavior at all. A *call* to foo during execution has undefined
>behavior. (`foo;` is a statement-expression that does nothing;
>it does not have undefined behavior.)
The _evaluation_ of that expression in `foo` has undefined
behavior. The standard does not say that it _cannot_ be
evaluated at translation time.
>[SNIP]
>
>I think the question of whether the initializer is a
>constant-expression or not has caused some not entirely relevant
>confusion.
>
>Here's another example that avoids that issue.
>
>#include <limits.h>
>
>int foo(void) {
> int zero;
> zero = INT_MAX;
> zero ++;
> zero *= 0;
> return zero;
>}
>
>int main(void) {
> return 0;
>}
>
>Given my grammatical argument above, I would say that this program
>has no constant expressions.
Agreed, if by "constant expressions" you mean those mandated to
use the `constant-expression` grammatical production.
>Whether that argument is correct or
>not, it certainly has no constant expressions that violate any
>constraint or that have undefined behavior. Evaluating `zero ++`
>(which doesn't even pretend to be a constant expression) would have
>run-time undefined behavior -- *if* foo() were ever called.
Let me turn this around in two ways: suppose that the
translation unit _only_ included `foo`. Could the compiler
deduce that the behavior of `foo`, if called, is undefined? If
not, why not?
Second, suppose that `foo` _were_ called, could the compiler
replace this with a program that was the equivalent of,
`int main(void) {printf("check your nose"); abort();}`? If so
why? If not, why not?
>And given this translation unit, I don't think there's any way to
>construct a multi-TU program that calls foo, so a compiler *can*
>determine that foo is never called (but there's no requirement to
>do so, or to make any use of that information).
This is the crux of my point, as well. There's not requirement
for the translator to _not_ evaluate the expression and become
privy to UB.
Would it be stupid if a compiler did that? Yes. Do existing
compilers do so? No, not that I'm aware of. Would some dweeb
nerd compiler douche who thinks this would make a compiler
benchmark some microfraction of a percent faster take advantage
of that? I absolutely think so, yes.
- Dan C.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2026-06-05 23:50 -0700 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <1100g0e$1lt8i$1@kst.eternal-september.org> |
| In reply to | #399760 |
cross@spitfire.i.gajendra.net (Dan Cross) writes:
> In article <10vt7b9$pi3s$1@kst.eternal-september.org>,
> Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>>> In article <10vsnl7$lkmu$1@kst.eternal-september.org>,
>>> Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>>>>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>>>>> In article <865x3yd21n.fsf@linuxsc.com>,
>>>>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>>>>>>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>>>>>>> In article <86ik81cfk5.fsf_-_@linuxsc.com>,
>>>>>>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>>>>[...]
>>>>>>>> There's an important distinction to make here. Consider this
>>>>>>>> program:
>>>>>>>>
>>>>>>>> #include <limits.h>
>>>>>>>>
>>>>>>>> int
>>>>>>>> foo(){
>>>>>>>> int zero = (INT_MAX+1)*0;
>>>>>>>> return zero;
>>>>>>>> }
>>>>>>>>
>>>>>>>> int
>>>>>>>> main(){
>>>>>>>> return 0;
>>>>>>>> }
>>>>>>>>
>>>>>>>> This program does not transgress the bounds of undefined behavior.
>>>>>>
>>>>>>To clarify, the comments in my posting were meant to be read as
>>>>>>saying the given text is the entire program, and that it is strictly
>>>>>>conforming with respect to conforming hosted implementations.
>>>>>>(Incidentally, given the rules for freestanding implementations, I'm
>>>>>>not sure that it is even possible for any program to be strictly
>>>>>>conforming with respect to conforming freestanding implementations.
>>>>>>In any case my statements were meant only in the context of hosted
>>>>>>implementations.)
>>>>>
>>>>> Ok.
>>>>>
>>>>>>> [snip]
>>>>>>> Perhaps you mean that this is irrelevant because `foo` is not
>>>>>>> invoked, but I see no reason why that need be the case in e.g.
>>>>>>> a freestanding environment.
>>>>>>
>>>>>>I explained the context of my previous statements above. Sorry for
>>>>>>not saying that in the original message.
>>>>>>
>>>>>>> In a hosted environment, I don't
>>>>>>> think anything explicitly prevents `foo` from being called after
>>>>>>> `main` returns (though I can't imagine that would happen in real
>>>>>>> life; it would be weird if it did).
>>>>>>
>>>>>>The semantics described in the ISO C standard don't admit that
>>>>>>possibility.
>>>>>
>>>>> Could you please point to where it says this, in the C standard?
>>>>>
>>>>> I cannot find anything that says that arbitrary code cannot run
>>>>> after `main()` returns, and I don't see how that could possibly
>>>>> be true.
>>>>
>>>>N3220 5.1.2.4, Program semantics.
>>>>
>>>>It defines the *observable behavior* of a program, which consists of
>>>>accesses to volatile objects, data written to files, and I/O dynamics of
>>>>interactive devices.
>>>
>>> Yes, but it does so for strictly-conforming programs with no UB.
>>
>>It does so for programs in general, not just strictly conforming
>>ones. If a program has undefined behavior, all bets are off,
>>but for example a program that evaluates `printf("%d\n", INT_MAX)`
>>is not strictly conforming, but it's fully subject to 5.1.2.4.
>>
>>> To understand conformance, we have to jump over to section 4,
>>> which explicitly says that, 'Undefined behavior is otherwise
>>> indicated in this document by the words "undefined behavior" or
>>> by the omission of any explicit definition of behavior.' As it
>>> does not say that a program with an instance of undefined
>>> behavior in an integer constant expression that is not executed
>>> must otherwise behave in any given manner, what the program does
>>> is undefined. A constaint violation mandates a diagnostic, but
>>> beyond that, the standard is (AFAICT) silent.
>>
>>I don't think an integer constant expression can have undefined
>>behavior. INT_MAX+1 and 1/0 are not constant expressions, because
>>neither "evaluate(s) to a constant that is in the range of
>>representable values for its type".
>>
>>I claim that an expression that looks like a constant expression
>>*isn't* a constant-expression if it doesn't appear in a context
>>that requires a constant-expression.
>
> That's a bold claim, but I think I see why you're saying that.
>
>>The program in question, quoted above, has:
>>
>> int zero = (INT_MAX+1)*0;
>>
>>`(INT_MAX+1)*0` is not a constant expression, not because of the
>>overflow, but because a constant expression is not required in
>>that context. "constant-expression" is defined by a production in
>>the grammar (it reduces to "conditional-expression"). Even in
>>
>> int n = 42;
>>
>>42 is not a a constant expression, because the grammar doesn't
>>call for a constant expression in that context -- even though it
>>looks like one. Similarly, in `a + b * c`, `a + b` looks like an
>>additive expression, but it isn't one. (Not a perfect analogy.)
>
> Right; I see what you mean. In this case, the
> `assignment-expression` production applies, not
> `constant-expression`.
>
>>> Undefined Behavior, in turn, is not defined as specific only to
>>> execution: the standard simply says that it is "behavior, upon
>>> use of a *nonportable or erroneous program construct*..." for
>>> which there are no requirements, and there are examples of
>>> things that are explicitly UB at translation time, such as
>>> improperly terminated lexemes and so forth.
>>
>>Yes, there are constructs that are explicitly UB at translation time.
>>(I think that's unfortunate, and there are efforts to clear up some
>>such cases in C2y.)
>
> It's unclear to me how it could be any other way. If UB was
> _only_ an issue at runtime, then how could a compiler take
> advantage of it to perform optimizations during translation?
> We know that compilers do this.
There are instances of undefined behavior that depend on specific
characteristics of a source file, not on run-time behavior.
The first example I found (N3220) is in the description of
translation phase 4, 5.1.1.2:
If a character sequence that matches the syntax of a universal
character name is produced by token concatenation (6.10.5.3), the
behavior is undefined.
That's something that can be detected during compilation. It would
be far better if it were either well defined or a syntax rule
violation. And in fact the latest C2y draft doesn't have that
wording. There's an ongoing effort to clean up this kind of thing.
That's not the kind of UB I'm talking about.
>>Signed integer overflow is not one of those constructs.
>
> This I'm not sure I agree with. It the compiler detects signed
> integer overflow in (perhaps not relevant in _this_ example) an
> integer constant expression, I still don't see anthing that
> makes that anything other than UB. It's a constaint violation,
> sure, but nothing says it is not also UB.
An implementation can choose to successfully translate a program that
violates a constraint. In my opinion, the resulting program has (or
should be considered to have) undefined behavior, but the standard
doesn't explicitly say so. My argument is based on the definition
of "constraint": "restriction, either syntactic or semantic,
by which the exposition of language elements is interpreted".
If a constraint is violated, I argue that there is no basis for
interpreting the exposition of language elements, and therefore no
definition of the behavior.
Other interpretations are possible.
So if an overflow in an ICE has undefined behavior, it's merely
an instance of this more general principle, which might even not
be valid.
An unambiguous case is:
case INT_MAX+1:
That's a constraint violation. The expression is required to be an
ICE, but it doesn't "evaluate to a constant that is in the range
of representable values for its type" (unless you want to argue
that it can evaluate to INT_MIN for a particular implementation,
but I really dislike the implications of that). If there's UB,
it's because of the constraint violation. (In fact I'd expect most
compilers to reject it, so there's no behavior at all.)
On the other hand, this:
int n = INT_MAX;
n++;
has undefined behavior and is not a constraint violation. A note on the
definition of "undefined behavior" says:
Possible undefined behavior ranges from ignoring the situation
completely with unpredictable results, to behaving during
translation or program execution in a documented manner
characteristic of the environment (with or without the issuance of a
diagnostic message), to terminating a translation or execution (with
the issuance of a diagnostic message).
So a compiler can reject it *if* it can prove that the undefined
behavior will always occur. The standard is not 100% clear about
whether it can be rejected if the code is never executed, or is
executed conditionally, but I think that's not permitted, or at least
it shouldn't be. Rejecting code because the compiler can't prove
the behavior is undefined has some very unpleasant implications.
>>Any undefined behavior from evaluating INT_MAX+1 happens during
>>execution (barring constraint violations).
>
> I'm not sure the standard says that. The standard says this
> happens during _evaluation_, and that evaluation must be
> performed in accordance with the rules of the abstract syntax
> machine. But it doesn't precisely specify _when_ evaluation
> takes place, and in particular, there are places in the standard
> that explicitly mention evaluation during translation. I still
> don't see anything that prohibits a compiler from evaluating
> that expression at compile time (indeed, it clearly does, as it
> generates a diagnostic about the overflow).
>
> I suppose that changes the matter: does the language merely
> leave that unspecified, in which case, this program is not
> strictly conforming, or does it say that it _cannot_ make any
> translation-time decisions about it? I cannot find a satisfying
> argument for the latter.
Ok, given:
case INT_MAX+1:
a compiler could issue the required diagnostic for the constraint
violation as a non-fatal warning, then generate code that executes
an ADD instruction with operands INT_MAX and 1. That would be
conforming but silly. The compiler has to determine that INT_MAX+1
overflows anyway so it can issue the diagnostic.
>>> Furthermore, the expression above is obviously an integer
>>> constant expression as defined by sec 6.6 para 8. Section 6.6,
>>> para 4, reads in part, "Each constant expression shall evaluate
>>> to a constant that is in the range of representable values for
>>> its type." The expression, `(INT_MAX+1)*0` violates this
>>> constraint, and so therefore a diagnostic is mandated as per
>>> sec 5.1.1.3 para 1. That it appears in code that is not
>>> obviously called from `main` doesn't change that.
>>
>>It satisfies the requirements for an integer constant expression in
>>6.6p8, but it violates the constraint in 6.6p4. (I presume that an
>>"integer constant expression" must be a "constant expression".)
>>But since "constant-expression" is a grammatical production,
>>it doesn't have to satisfy that constraint, and no diagnostic
>>is required. (A warning is certainly permitted.)
>
> Fair point. It's grammatical position makes it an
> assignment-expression. I clearly misinterpreted that before.
>
>>Similarly, this:
>> int n = INT_MAX + 1;
>>at block scope doesn't require a diagnostic, though of course it
>>has undefined behavior -- but at file scope, the initializer is a
>>constant expression, so that would be a constraint violation.
>
> Right. The semantics of this are defined in sec 6.7.11 para 5.
>
>>> Morever, sec 6.6 para 17 says that, "the semantic rules for
>>> evaluation of a constant expression are the same as for
>>> nonconstant expressions." This brings us back to 5.1.2.4,
>>> though I submit that para (4) is a stronger argument for what
>>> you and Tim are saying, as it reads in part, "An actual
>>> implementation is not required to evaluate part of an expression
>>> if it can deduce that its value is not used and that no needed
>>> side effects are produced (including any caused by calling a
>>> function or through volatile access to an object)." I interpret
>>> this to mean that, if the implementation can determine that
>>> there is no way that `foo` can be called, it does not _have_ to
>>> evaluate the above expression. However, it must satisfy the
>>> range constraint from section 6.6, so it likely will, and in any
>>> event, the standard does not say that it, "shall not" evaluate
>>> it, or when.
>>
>>Overflow in a constant expression is not undefined behavior. It's a
>>constraint violation. But that doesn't apply here, because the
>>initializer is not a constant expression. (Sorry if I'm repeating
>>myself.)
>
> Where does it say that UB and constraint violations are mutually
> exclusive? I don't see any such statement in the standard. Am
> I missing it?
It doesn't.
As a practical matter, when I look at C code, if it violates a
constraint, I typically don't care about its behavior. I want it
to be rejected at compile time (unless it's deliberately taking
advantage of a documented extension). I'll fix it rather than
worrying about its behavior.
(Unless the code has somehow gotten into production and it's my
job to analyze how it misbehaves.)
Yes, a program that violates a constraint can have run-time behavior if
the compiler chooses not to reject it, and that behavior may be
undefined.
> The standard says that if a constraint is violated, a diagnostic
> must be emitted, regardless of whether or not the constraint
> violation is the result of something that is UB not; that is, if
> a constraint violation occurs due to something that is UB, the
> implementation must still emit a diagnostic: UB is not an escape
> hatch from that requirement.
Right.
> It also says, 'If a "shall" or "shall not" requirement that
> appears outside of a constraint or runtime-constraint is
> violated, the behavior is undefined. Undefined behavior is
> otherwise indicated in this document by the words "undefined
> behavior" or by the omission of any explicit definition of
> behavior.' However, that does not preclude such behavior being
> undefined; it just means that the words "shall" and "shall not"
> in a constraint violation do not a priori describe behavior vis
> definition.
Right.
>>> Once the compiler does that, if it does, and observes UB, the
>>> standard is silent on what requirements it imposes, which means
>>> the behavior is undefined. I see no reason it couldn't arrange
>>> to invoke `foo` at that point.
>>
>>Any UB in the program would occur during execution,
>
> I suppose; but it's not clear to me that UB is tied _only_ to
> execution time.
>
> The standard is explicit that there _are_ things that are
> evaluated at translation time, like the initializer for an
> object with storage class `constexpr`. It is not clear me that
> a compiler is otherwise _prohibited_ from evaluating an
> expression during translation; indeed, one could imagine it
> doing so to perform constant folding, and I do not believe there
> exists any normative text defining it as such.
Certainly a compiler can, but need not, evaluate any expression at
compile time if it's able to:
int n;
n = 2 + 2;
I'd be surprised to see an ADD instruction in the generated code, but
a naive compiler could certainly generate one. For that matter, a
perverse compiler could generate code that adds 3 and 1 or divides 28
by 7. Anything that implements the required *observable behavior*
(5.1.2.4 Program semantics) is acceptable. Executing an ADD
instruction is not part of the observable behavior.
> I realize this is an extreme interpretation, and not one that is
> not widely shared. Personally, I think it's rather silly.
>
> However, I that is _a_ danger of the informality of the C
> specification; it does not define the semantics of the abstract
> machine in the formally precise way that, say, the SML spec
> defines that language's semantics. Rather, it informally
> specifies them in prose, and that prose is ambiguous.
There have been attempts to define C's semantics formally, but
those attempts are not part of the standard. Fully defining C's
semantics formally rather than in English would, I imagine it would
be a *lot* of work -- and fewer people would be able to understand
the specification or work on it.
> Probably much good would be done if C's semantics _were_
> rigorously defined, but they are not. Thus, they are open to
> radical interpretation, and as extreme as those may be, I do not
> see how the normative text of the standard explicitly
> _prohibits_ them.
>
>>and in fact
>>it *won't* occur during execution because foo() isn't called.
>>A compiler can't generate code with arbitrary behavior just because
>>it can't prove that there will be no UB. If it could, every signed
>>or floating-point arithmetic operation with unknown operand values
>>would grant the same permission.
>
> But that's not the situation here. The situation is that the
> compiler can prove that something _is_ UB.
In the program quoted at the top of this post, the UB occurs in
a function foo() that's never called. A compiler can replace the
body of foo() with a trap, and it can certainly warn about the UB,
but I don't believe it can reject the entire program. A clever
compiler could prove that the UB never occurs.
A naive compiler that performs no optimizations would generate
code for foo() that attempts to compute (INT_MAX+1)*0 step by
step, without recognizing the overflow, and that code would never
be executed.
> Regardless, I think you highlighted an actual problem with the
> spec; I don't think that behavior is _explicitly_ prohibited,
> therefore, it is likely undefined, but at a minimum unspecified,
> whether it actually could happen. If the argument against that
> is that this renders the language essentially unusuable, then
> my response is, "yeah, well, welcome to programming in C in the
> 2020s." Most compilers would never be that extreme, but I see
> no evidence that it would not be an invalid reading of the
> literal text of the standard if they did.
>
>>> So no, I do not see how execution according to the rules of the
>>> abstract machine is not guaranteed, here. I certainly see no
>>> way in which this can be regarded as a strictly conforming
>>> program.
>>
>>foo()'s behavior would be undefined if it were called. It *isn't*
>>called, so there's no actual UB. The program does not violate any
>>of the other requirements for strict conformance.
>
> I understand _what_ you're saying: despite the expression itself
> manifesting undefined behavior, in this case it's not UB because
> `foo` is never executed. What I'm saying is that I don't see
> anything in the standard that restricts UB to _only_ executed
> code. A reputable compiler obviously instruments `foo` with
> code to trap into ubsan; if it's not UB, since it's not
> executed, then why do so? Granted, that's not evidence of
> anything other than the behavior of those compilers, but still.
Probably the compiler generated the trap code because it didn't
(yet?) know whether foo is ever called. If it were clever enough
to prove that foo is never called, it could generate no code for
it at all.
The note on the definition of undefined behavior is a bit vague.
It permits terminating a translation in response to UB, but that
doesn't address exactly when it can do so. I believe it can do so
only when it can prove that the UB always occurs, but that's not
clearly stated.
However, the behavior of the program as a whole is clearly defined.
It returns a status of 0 from main and does nothing else.
A conforming implementation *must* generate code that implements
that behavior.
Another argument (subject to interpretation of wording): Undefined
behavior is "behavior, **upon use** of a nonportable or erroneous
program construct or of erroneous data, for which this document
imposes no requirements". The overflowing expression within foo()
is never *used*, so there is no undefined behavior.
To put it another way, undefined behavior is behavior. Something
that never occurs is not behavior.
> It is clearly the _intent_ that this be a strictly conforming
> program. The C standard, as an imprecise, informal document,
> cannot guarantee it.
>
>>>>If the usual "Hello, world" program prints "Hello, world" followed
>>>>by "Goodbye", the implementation is non-conforming. If it formats
>>>>my hard drive after printing "Goodbye", it's non-conforming and
>>>>dangerous.
>>>
>>> Two separate things. My point earlier was that code can
>>> obviously run after `main` terminates. Moreoever, I can't
>>> imagine what would _prevent_ a runtime system that invokes
>>> `main` from doing something like printing, "PROGRAM STOPPED"
>>> after `main` returned. C imposes no requirements here.
>>
>>Yes, it does. An OS can print "PROGRAM STOPPED", but not as part
>>of the execution of the program. On my system, a shell prompt is
>>printed after a program terminates, but not by the program. If I
>>execute a "hello, world" program with its output redirected to a file
>>(on a system that supports that), the resulting file cannot contain
>>"PROGRAM STOPPED". The requirements in 5.1.2.4 specify both what
>>the execution of a program must do and what it must not do.
>
> Files are a separate case. There's no guarantee that the
> standard output refers to a file; it may well refer to an
> "interactive device", the semantics of which are (necessarily)
> unspecified.
The requirements for "observable behavior" cover both files and
interactive devices.
> Here's an example: consider an interactive user who uses a
> screen reader device. Suppose that user makes use of an
> implementation that includes runtime support for that device,
> and that precedes invocation of `main` with a command sequence
> causing the screen reader to (perhaps) change intonation; and
> suceeds return from main by outputing another command sequence
> that resets to the original state.
>
> I do not see how C could prohibit that, assuming that the
> implementation takes care to detect whether standard output
> really refers to the screen reader, and does emit the control
> sequences if output is redirected to a file. Another user who
> runs that same program without a screen reader may see the
> standard text printed on the screen, without the control
> sequence sandwich.
>
> I don't think a conforming implementation can prohibit that kind
> of thing.
I agree. printf("hello, world\n") must write that string to standard
output, which may be a file or an interactive device. Just what
that means is unspecified or implementation-defined. It might be
printed in EBCDIC or incised into clay tablets. Closing stdout,
which occurs when main() terminates, might involve firing the tablet
or emitting control sequences for a screen reader.
>>>>>>Whether foo() has external linkage or internal
>>>>>>linkage doesn't change that.
>>>>>
>>>>> I disagree. There's no possible way for the implementation to
>>>>> know whether a function with external linkage will be ultimately
>>>>> invoked or not; consider a system that supports loadable shared
>>>>> modules. Nothing prevents even this simple program from being
>>>>> compiled as a shared module, dynamically loaded, the loading
>>>>> program explicitly searching for and finding the symbol
>>>>> corresponding to the `foo` function, and invoking it.
>>>>
>>>>Remember that linking is translation phase 8. The compiler is not
>>>>the entire implementation.
>>>
>>> Exactly my point. The compiler cannot know how `foo` might be
>>> used, or how the translated object might be exercised. There's
>>> I don't see how it could possibly know that, given that `foo`
>>> has external linkage.
>>
>>We were presented with a complete translation unit that included a
>>function definition for "main". It's a complete program. There's no
>>valid way for some other program to call foo. If OS provided such
>>a mechanism, it would be outside the scope of C.
>
> Given an excessively pedantic and literal reading of the text of
> the standard, I don't think an implementation is explicitly
> prohibited from evaluating the initializer at translation time,
> deducing that the behavior is undefined, and blaming it on the
> program, at which point, all bets are off.
An implementation can certainly evaluate the initializer at
translation time, deduce that the behavior would be undefined
*if the initializer were evaluated*, and blame it on the program.
That doesn't mean it can reject a strictly conforming program.
>>>>> Hence, the compiler _must_ treat with UB as written, which is
>>>>> why `ubsan` inserts trapping code in `foo`.
>>>>
>>>>I don't know what "_must_ treat with UB" means.
>>>>
>>>>foo() has undefined behavior if it's called, so replacing its
>>>>body with trapping code is valid. But (I'm reasonably sure that)
>>>>an implementation cannot reject a program just because it can't
>>>>prove that it has no undefined behavior during execution. It can
>>>>reject it if it can prove that it *always* has undefined behavior
>>>>during execution.
>>>
>>> What I'm saying is that, `foo` has undefined behavior _period_.
>>> That's manifest in an integer constant expression, whether it is
>>> executed at runtime or not. I believe that the standard forces
>>> the expression to be evaluated at translation time, via the
>>> "shall" mandate when checking the constraint on the range in sec
>>> 6.6 para 4. Further, that evaluation must happen in accordance
>>> with the rules of the abstract machine, as per 5.1.2.4 para 17.
>>> The diagnostic is mandated, as is the translation-time
>>> evaluation. The expression is itself manifestly exhibits UB,
>>> and so therefore the result of the rest of the translation is
>>> undefined.
>>
>>foo is a function. foo does not have undefined behavior; it has no
>>behavior at all. A *call* to foo during execution has undefined
>>behavior. (`foo;` is a statement-expression that does nothing;
>>it does not have undefined behavior.)
>
> The _evaluation_ of that expression in `foo` has undefined
> behavior. The standard does not say that it _cannot_ be
> evaluated at translation time.
If a compiler sees a subexpression INT_MAX+1 it can attempt to
evaluate it at compile time. But it can't just blindly add the
values if overflow would cause a fatal trap, crashing the compiler.
That would be a serious compiler bug. The behavior *of the compiler*
is not undefined.
>>[SNIP]
>>
>>I think the question of whether the initializer is a
>>constant-expression or not has caused some not entirely relevant
>>confusion.
>>
>>Here's another example that avoids that issue.
>>
>>#include <limits.h>
>>
>>int foo(void) {
>> int zero;
>> zero = INT_MAX;
>> zero ++;
>> zero *= 0;
>> return zero;
>>}
>>
>>int main(void) {
>> return 0;
>>}
>>
>>Given my grammatical argument above, I would say that this program
>>has no constant expressions.
>
> Agreed, if by "constant expressions" you mean those mandated to
> use the `constant-expression` grammatical production.
Yes, that's what I mean by it.
>>Whether that argument is correct or
>>not, it certainly has no constant expressions that violate any
>>constraint or that have undefined behavior. Evaluating `zero ++`
>>(which doesn't even pretend to be a constant expression) would have
>>run-time undefined behavior -- *if* foo() were ever called.
>
> Let me turn this around in two ways: suppose that the
> translation unit _only_ included `foo`. Could the compiler
> deduce that the behavior of `foo`, if called, is undefined? If
> not, why not?
Certainly.
> Second, suppose that `foo` _were_ called, could the compiler
> replace this with a program that was the equivalent of,
> `int main(void) {printf("check your nose"); abort();}`? If so
> why? If not, why not?
Yes, if foo were called in every possible execution of the program,
the program's behavior would be undefined. The compiler could also
reject it.
>>And given this translation unit, I don't think there's any way to
>>construct a multi-TU program that calls foo, so a compiler *can*
>>determine that foo is never called (but there's no requirement to
>>do so, or to make any use of that information).
>
> This is the crux of my point, as well. There's not requirement
> for the translator to _not_ evaluate the expression and become
> privy to UB.
I believe there is. The program is strictly conforming, which means,
among other things, that it does not produce output depending on any
undefined behavior. There is no undefined behavior because foo() is
never called.
A *strictly conforming program* shall use only those features of the
language and library specified in this document. It shall not
produce output dependent on any unspecified, undefined, or
implementation- defined behavior, and shall not exceed any minimum
implementation limit.
...
A *conforming hosted implementation* shall accept any strictly
conforming program.
An implementation that rejects the program quoted at the top of this
article is non-conforming.
> Would it be stupid if a compiler did that? Yes. Do existing
> compilers do so? No, not that I'm aware of. Would some dweeb
> nerd compiler douche who thinks this would make a compiler
> benchmark some microfraction of a percent faster take advantage
> of that? I absolutely think so, yes.
And I'd submit a bug report.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | cross@spitfire.i.gajendra.net (Dan Cross) |
|---|---|
| Date | 2026-06-08 02:20 +0000 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <11058u3$mv5$1@reader1.panix.com> |
| In reply to | #399766 |
In article <1100g0e$1lt8i$1@kst.eternal-september.org>,
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>>>and in fact
>>>it *won't* occur during execution because foo() isn't called.
>>>A compiler can't generate code with arbitrary behavior just because
>>>it can't prove that there will be no UB. If it could, every signed
>>>or floating-point arithmetic operation with unknown operand values
>>>would grant the same permission.
>>
>> But that's not the situation here. The situation is that the
>> compiler can prove that something _is_ UB.
>
>In the program quoted at the top of this post, the UB occurs in
>a function foo() that's never called. A compiler can replace the
>body of foo() with a trap, and it can certainly warn about the UB,
>but I don't believe it can reject the entire program. A clever
>compiler could prove that the UB never occurs.
So there are two things that are at play here.
First, this notion that UB is _only_ a runtime matter. The text
of the standard contradicting that aside, if a translator can
detect that the behavior of a construct is provably undefined if
executed, then it seems axiomatic that UB is clearly something
that plays a role at translation time, as well.
Indeed, I would go so far as to suggest that _most_ instances of
UB are detected and used (by the translator) during translation.
So to say that, "this program doesn't have UB because the
statement that contains UB is never executed" doesn't make a lot
of sense to me. It would be closer to being correct if one said
"this program is unaffected by UB since the expression that has
UB is never evaluated when the program executes": again, in this
case (as, I suspect, in most cases) the UB simply _is_: the
expression `INT_MAX + 1` does not become well-defined just
because it is never executed.
Second, there's this notion that the standard is just
underspecified with respect to these matters, specifically, it
does not _prohibit_ a translation from implementing an emulator
for the abstract machine that evaluates code at translation
time. Indeed, I suspect that _most_ compilers do something
largely analogous to that; that's how they detect UB so that
they can take advantage of it when optimizing. But if that's
the case, then nothing prohibits them from relieving themselves
of their obligation to follow the standard once they observe
that some bit of code has UB.
>A naive compiler that performs no optimizations would generate
>code for foo() that attempts to compute (INT_MAX+1)*0 step by
>step, without recognizing the overflow, and that code would never
>be executed.
Sure. But a far more sophisticated translator (and I would
argue a nefarious one) could emulate that code, decide it was
UB, and immediately fail translation with an error.
>>>foo()'s behavior would be undefined if it were called. It *isn't*
>>>called, so there's no actual UB. The program does not violate any
>>>of the other requirements for strict conformance.
>>
>> I understand _what_ you're saying: despite the expression itself
>> manifesting undefined behavior, in this case it's not UB because
>> `foo` is never executed. What I'm saying is that I don't see
>> anything in the standard that restricts UB to _only_ executed
>> code. A reputable compiler obviously instruments `foo` with
>> code to trap into ubsan; if it's not UB, since it's not
>> executed, then why do so? Granted, that's not evidence of
>> anything other than the behavior of those compilers, but still.
>
>Probably the compiler generated the trap code because it didn't
>(yet?) know whether foo is ever called. If it were clever enough
>to prove that foo is never called, it could generate no code for
>it at all.
>
>The note on the definition of undefined behavior is a bit vague.
>It permits terminating a translation in response to UB, but that
>doesn't address exactly when it can do so. I believe it can do so
>only when it can prove that the UB always occurs, but that's not
>clearly stated.
Exactly. That it's not clearly stated makes be believe that it
is open to interpretation.
>However, the behavior of the program as a whole is clearly defined.
Is it? I am unable to locate where the standard _actually says
that it is_. That is my whole point.
>It returns a status of 0 from main and does nothing else.
>A conforming implementation *must* generate code that implements
>that behavior.
I have yet to find or be shown a way in which the standard
actually guarantees that.
>Another argument (subject to interpretation of wording): Undefined
>behavior is "behavior, **upon use** of a nonportable or erroneous
>program construct or of erroneous data, for which this document
>imposes no requirements". The overflowing expression within foo()
>is never *used*, so there is no undefined behavior.
>
>To put it another way, undefined behavior is behavior. Something
>that never occurs is not behavior.
And yet the standard does not say that. That is an
interpretation; I assume it is universally shared, but if we
want to limit ourselves to what the standard _actually says_ it
is woefully underspecified in this regard.
There was, once, a view that was almost universally shared that
UB was meant for things that could not be precisely described
because hardware was too varied. We're well past that; now it's
a vehicle for compiler writers to make benchmarks faster, but is
(generally) hostile to programmers. A lot of hay is made about
it in this group, but at the core, it's just (ironically) not
well-defined.
>> It is clearly the _intent_ that this be a strictly conforming
>> program. The C standard, as an imprecise, informal document,
>> cannot guarantee it.
>>
>>>>>If the usual "Hello, world" program prints "Hello, world" followed
>>>>>by "Goodbye", the implementation is non-conforming. If it formats
>>>>>my hard drive after printing "Goodbye", it's non-conforming and
>>>>>dangerous.
>>>>
>>>> Two separate things. My point earlier was that code can
>>>> obviously run after `main` terminates. Moreoever, I can't
>>>> imagine what would _prevent_ a runtime system that invokes
>>>> `main` from doing something like printing, "PROGRAM STOPPED"
>>>> after `main` returned. C imposes no requirements here.
>>>
>>>Yes, it does. An OS can print "PROGRAM STOPPED", but not as part
>>>of the execution of the program. On my system, a shell prompt is
>>>printed after a program terminates, but not by the program. If I
>>>execute a "hello, world" program with its output redirected to a file
>>>(on a system that supports that), the resulting file cannot contain
>>>"PROGRAM STOPPED". The requirements in 5.1.2.4 specify both what
>>>the execution of a program must do and what it must not do.
>>
>> Files are a separate case. There's no guarantee that the
>> standard output refers to a file; it may well refer to an
>> "interactive device", the semantics of which are (necessarily)
>> unspecified.
>
>The requirements for "observable behavior" cover both files and
>interactive devices.
Ok, but irrelevant.
>> Here's an example: consider an interactive user who uses a
>> screen reader device. Suppose that user makes use of an
>> implementation that includes runtime support for that device,
>> and that precedes invocation of `main` with a command sequence
>> causing the screen reader to (perhaps) change intonation; and
>> suceeds return from main by outputing another command sequence
>> that resets to the original state.
>>
>> I do not see how C could prohibit that, assuming that the
>> implementation takes care to detect whether standard output
>> really refers to the screen reader, and does emit the control
>> sequences if output is redirected to a file. Another user who
>> runs that same program without a screen reader may see the
>> standard text printed on the screen, without the control
>> sequence sandwich.
>>
>> I don't think a conforming implementation can prohibit that kind
>> of thing.
>
>I agree. printf("hello, world\n") must write that string to standard
>output, which may be a file or an interactive device. Just what
>that means is unspecified or implementation-defined. It might be
>printed in EBCDIC or incised into clay tablets. Closing stdout,
>which occurs when main() terminates, might involve firing the tablet
>or emitting control sequences for a screen reader.
Exactly. It could also emit the string, "GOODBYE WORLD."
>> [snip for size]
>> Given an excessively pedantic and literal reading of the text of
>> the standard, I don't think an implementation is explicitly
>> prohibited from evaluating the initializer at translation time,
>> deducing that the behavior is undefined, and blaming it on the
>> program, at which point, all bets are off.
>
>An implementation can certainly evaluate the initializer at
>translation time, deduce that the behavior would be undefined
>*if the initializer were evaluated*, and blame it on the program.
>That doesn't mean it can reject a strictly conforming program.
This is circular reasoning. You're saying that something that
is provably UB in this program cannot prevent that program from
being strictly confirming because the program is strictly
confirming.
This presupposes that the program is strictly conforming, but
in the limit, the standard can be interpreted in such a way that
if any statement in the program is proveably UB (as this one is)
then the program cannot said to be strictly conforming.
Does any compiler actually do this? No, probably not. Does the
standard explicitly prevent it? I haven't seen an argument for
that does not rely on either history or a subjective
interpretation.
>>>foo is a function. foo does not have undefined behavior; it has no
>>>behavior at all. A *call* to foo during execution has undefined
>>>behavior. (`foo;` is a statement-expression that does nothing;
>>>it does not have undefined behavior.)
>>
>> The _evaluation_ of that expression in `foo` has undefined
>> behavior. The standard does not say that it _cannot_ be
>> evaluated at translation time.
>
>If a compiler sees a subexpression INT_MAX+1 it can attempt to
>evaluate it at compile time. But it can't just blindly add the
>values if overflow would cause a fatal trap, crashing the compiler.
>That would be a serious compiler bug. The behavior *of the compiler*
>is not undefined.
I did not say that the behavior of the _compiler_ is undefined.
I said that a translator is not prohibited from evaluating the
expression at translation time, observing that the behavior is
undefined, and erroring out. There is no reason a translator
cannot include a simple emulator for the abstract machine as
specified in the standard for that purpose; it's behavior would
not be undefined, but it could detect undefined behavior.
>>>[SNIP]
>>>I think the question of whether the initializer is a
>>>constant-expression or not has caused some not entirely relevant
>>>confusion.
>>>
>>>Here's another example that avoids that issue.
>>>
>>>#include <limits.h>
>>>
>>>int foo(void) {
>>> int zero;
>>> zero = INT_MAX;
>>> zero ++;
>>> zero *= 0;
>>> return zero;
>>>}
>>>
>>>int main(void) {
>>> return 0;
>>>}
>>>
>>>Given my grammatical argument above, I would say that this program
>>>has no constant expressions.
>>
>> Agreed, if by "constant expressions" you mean those mandated to
>> use the `constant-expression` grammatical production.
>
>Yes, that's what I mean by it.
>
>>>Whether that argument is correct or
>>>not, it certainly has no constant expressions that violate any
>>>constraint or that have undefined behavior. Evaluating `zero ++`
>>>(which doesn't even pretend to be a constant expression) would have
>>>run-time undefined behavior -- *if* foo() were ever called.
>>
>> Let me turn this around in two ways: suppose that the
>> translation unit _only_ included `foo`. Could the compiler
>> deduce that the behavior of `foo`, if called, is undefined? If
>> not, why not?
>
>Certainly.
Ok, so in that case, would we say that "`foo` has undefined
behavior?" The qualification, "...if called" seems superfluous,
and I don't see anything in the standard that explicitly
disagrees.
>> Second, suppose that `foo` _were_ called, could the compiler
>> replace this with a program that was the equivalent of,
>> `int main(void) {printf("check your nose"); abort();}`? If so
>> why? If not, why not?
>
>Yes, if foo were called in every possible execution of the program,
>the program's behavior would be undefined. The compiler could also
>reject it.
UB can time-travel, however. Because it's undefined, the
compiler is free to assume that it never executes, or that it
always executes.
>>>And given this translation unit, I don't think there's any way to
>>>construct a multi-TU program that calls foo, so a compiler *can*
>>>determine that foo is never called (but there's no requirement to
>>>do so, or to make any use of that information).
>>
>> This is the crux of my point, as well. There's not requirement
>> for the translator to _not_ evaluate the expression and become
>> privy to UB.
>
>I believe there is. The program is strictly conforming, which means,
>among other things, that it does not produce output depending on any
>undefined behavior. There is no undefined behavior because foo() is
>never called.
You _say_ the program is stictly conforming. The brunt of what
I am saying is that I do not believe that the text of the
standard actually guarantees that. It is an assumption. Not an
unreasonable one, mind, but it's not guaranteed.
> A *strictly conforming program* shall use only those features of the
> language and library specified in this document. It shall not
> produce output dependent on any unspecified, undefined, or
> implementation- defined behavior, and shall not exceed any minimum
> implementation limit.
>
> ...
>
> A *conforming hosted implementation* shall accept any strictly
> conforming program.
>
>An implementation that rejects the program quoted at the top of this
>article is non-conforming.
So any program that produces no output at all is strictly
conforming? Then what about this?
#include <limits.h>
int
zero(void)
{
return (INT_MAX + 1) * 0;
}
int
main(void)
{
(void)zero();
return 0;
}
This program produces no output, yet clearly executes a function
that contains an expression that induces undefined behavior when
evaluated. I suppose an argument could be made that it _might_
generate output due to UB, as UB imposes no requirements Not to
do so, so perhaps the _absence_ of output depends on UB.
>> Would it be stupid if a compiler did that? Yes. Do existing
>> compilers do so? No, not that I'm aware of. Would some dweeb
>> nerd compiler douche who thinks this would make a compiler
>> benchmark some microfraction of a percent faster take advantage
>> of that? I absolutely think so, yes.
>
>And I'd submit a bug report.
I would go further and chuck that compiler in the trashcan.
However, I can find no normative textin the standard preventing
it.
In my ideal world, C would be rigorously defined with a precise
operational semantics. That would be accompanied by an
explanatory document that presented those semantics in lay
terms in prose, similar to the standard now, for those who did
not want to drive Coq or something similar. But at least we'd
have something definitive to define the language, so that when
there was apparent ambiguity, we had some objective metric by
which to judge. The C standard, as written, is nowhere close as
precise as it should be.
I do not think that this will ever happen: not only would it be
very difficult to produce (as you noted elsethread), I think the
compiler writers would rebel if they felt that their UB hands
were tied by a formal specification.
- Dan C.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2026-06-08 12:39 -0700 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <11075os$3fm4u$1@kst.eternal-september.org> |
| In reply to | #399786 |
cross@spitfire.i.gajendra.net (Dan Cross) writes:
> In article <1100g0e$1lt8i$1@kst.eternal-september.org>,
> Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
[...]
>>A naive compiler that performs no optimizations would generate
>>code for foo() that attempts to compute (INT_MAX+1)*0 step by
>>step, without recognizing the overflow, and that code would never
>>be executed.
>
> Sure. But a far more sophisticated translator (and I would
> argue a nefarious one) could emulate that code, decide it was
> UB, and immediately fail translation with an error.
I disagree. That's not a sensible interpretation of what the
standard says.
A call to a foo() would have undefined behavior if it occurred. There
is no call to foo().
Similarly:
int a = ..., b = ...;
int c;
if (b != 0) {
c = a / b;
}
else {
c = 0;
}
A division by zero would have undefined behavior if it occurred,
but it never occurs. A compiler cannot reject the above code
because of UB that never happens.
[...]
>> It returns a status of 0 from main and does nothing else.
>> A conforming implementation *must* generate code that implements
>> that behavior.
>
> I have yet to find or be shown a way in which the standard
> actually guarantees that.
How does the standard guarantee *anything*?
This strictly conforming program:
int main(void) { return 0; }
when executed returns a status of 0 from main and does nothing else.
Adding an uncalled function to the same source file doesn't change
that.
[...]
> There was, once, a view that was almost universally shared that
> UB was meant for things that could not be precisely described
> because hardware was too varied. We're well past that; now it's
> a vehicle for compiler writers to make benchmarks faster, but is
> (generally) hostile to programmers. A lot of hay is made about
> it in this group, but at the core, it's just (ironically) not
> well-defined.
The standard does say what UB is meant for. It says what UB
*is*, and what constructs lead to it (by omission in some cases).
Any optimization tricks played by compiler implementers must be
based on that specification.
[...]
>> I agree. printf("hello, world\n") must write that string to standard
>> output, which may be a file or an interactive device. Just what
>> that means is unspecified or implementation-defined. It might be
>> printed in EBCDIC or incised into clay tablets. Closing stdout,
>> which occurs when main() terminates, might involve firing the tablet
>> or emitting control sequences for a screen reader.
>
> Exactly. It could also emit the string, "GOODBYE WORLD."
No, it couldn't. It must emit "hello, world\n" in some form.
It must emit the character 'h' as represented in the execution
character set, followed by 'e', and so on.
[...]
> This presupposes that the program is strictly conforming, but
> in the limit, the standard can be interpreted in such a way that
> if any statement in the program is proveably UB (as this one is)
> then the program cannot said to be strictly conforming.
It's not UB if it's never called. Behavior that doesn't happen is
not behavior.
I did not presuppose that the program is strictly conforming.
I read the source code and determined that it meets the standard's
definition of a strictly conforming program.
[...]
> Ok, so in that case, would we say that "`foo` has undefined
> behavior?" The qualification, "...if called" seems superfluous,
> and I don't see anything in the standard that explicitly
> disagrees.
The qualification "if called" is the whole point.
[...]
> UB can time-travel, however. Because it's undefined, the
> compiler is free to assume that it never executes, or that it
> always executes.
"UB can time-travel" is perhaps an oversimplification. An example is
a bug that occurred in the Linux kernel, something like:
void func(int *ptr) {
do_something_with(*ptr);
if (ptr != NULL) {
blah();
}
}
The compiler, on seeing the expression `*ptr`, assumed that `ptr` is
not null, and elided the test on the following line.
But even assuming that's valid, a compiler absolutely cannot assume that
an instance UB always executes when, according to the semantics of the
program, it provably never executes.
[...]
> So any program that produces no output at all is strictly
> conforming? Then what about this?
>
> #include <limits.h>
>
> int
> zero(void)
> {
> return (INT_MAX + 1) * 0;
> }
>
> int
> main(void)
> {
> (void)zero();
> return 0;
> }
That's an interesting point. A more terse example:
#include <limits.h>
int main(void) {
int unused = INT_MAX + 1;
}
> This program produces no output, yet clearly executes a function
> that contains an expression that induces undefined behavior when
> evaluated. I suppose an argument could be made that it _might_
> generate output due to UB, as UB imposes no requirements Not to
> do so, so perhaps the _absence_ of output depends on UB.
The program clearly has undefined behavior when executed, but no
output depends on that undefined behavior. In my humble opinion,
this demonstrates a flaw in the standard's definition of "strictly
conforming program". (As a programmer: Don't do that.)
[...]
> In my ideal world, C would be rigorously defined with a precise
> operational semantics. That would be accompanied by an
> explanatory document that presented those semantics in lay
> terms in prose, similar to the standard now, for those who did
> not want to drive Coq or something similar. But at least we'd
> have something definitive to define the language, so that when
> there was apparent ambiguity, we had some objective metric by
> which to judge. The C standard, as written, is nowhere close as
> precise as it should be.
>
> I do not think that this will ever happen: not only would it be
> very difficult to produce (as you noted elsethread), I think the
> compiler writers would rebel if they felt that their UB hands
> were tied by a formal specification.
"There are only two kinds of languages: the ones people complain
about and the ones nobody uses."
-- Bjarne Stroustrup
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | cross@spitfire.i.gajendra.net (Dan Cross) |
|---|---|
| Date | 2026-06-08 23:15 +0000 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <1107if4$6sk$1@reader1.panix.com> |
| In reply to | #399797 |
In article <11075os$3fm4u$1@kst.eternal-september.org>,
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>> In article <1100g0e$1lt8i$1@kst.eternal-september.org>,
>> Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>[...]
>>>A naive compiler that performs no optimizations would generate
>>>code for foo() that attempts to compute (INT_MAX+1)*0 step by
>>>step, without recognizing the overflow, and that code would never
>>>be executed.
>>
>> Sure. But a far more sophisticated translator (and I would
>> argue a nefarious one) could emulate that code, decide it was
>> UB, and immediately fail translation with an error.
>
>I disagree. That's not a sensible interpretation of what the
>standard says.
I agree it's not sensible. But sadly, the standard does not
seem to explicitly prohibit it, either. This is the point: we
necessarily rely on a "reasonable interpretation" of the
standard to be able to usefully write C code. An adversarial
interpretation is not sensible, but it appears that such is
possible given the standard as written. This is a danger with a
language that is not formally specified.
>A call to a foo() would have undefined behavior if it occurred.
What I'm really trying to get at is that the behavior of
`int zero = (INT_MAX + 1)*0;` is undefined in all cases. There
is no input for which it is valid at all. It is qualitatively
different than other examples where UB cannot be detected
_except_ at runtime.
In particular, it does not become defined just because it's in a
function that is not called; the behavior is UB on its face. It
is utterly meaningless as far as C is concerned; it is what
Regehr calls a "Type 3" function in his taxonomy at
https://blog.regehr.org/archives/213: it literally has no
definition.
>There
>is no call to foo().
What I am further saying is that I do not see where the C
standard puts additional constraints on an implementation so
that it _must_ accept a program with such a construct in it, as
sensible as that may otherwise be (I actually don't think that
is very sensible, but that's my opinion). The specific wording
of the standard appears to allow a compiler to halt translation
if it observes that expression, whether it's in a function that
is called or not.
I readily concede that I may be wrong. But the arguments I have
heard opposing this interpration are not well-supported by the
text. I would be happy if someone could provide such an
argument that did not ultimately rely on either intuition or
assumptions about reasonable behavior, but so far, none have
been proferred.
>Similarly:
>
> int a = ..., b = ...;
> int c;
> if (b != 0) {
> c = a / b;
> }
> else {
> c = 0;
> }
>
>A division by zero would have undefined behavior if it occurred,
>but it never occurs. A compiler cannot reject the above code
>because of UB that never happens.
This I also agree with. But assuming this is in some function
that is otherwise well-defined, this is what Regehr calls a
"Type-1" function: there is no input for which it is undefined.
In this regard, it is qualitatively different than the `foo`
example that is the subject of this thread. I suggest that that
qualitative difference actually matters.
>[...]
>
>>> It returns a status of 0 from main and does nothing else.
>>> A conforming implementation *must* generate code that implements
>>> that behavior.
>>
>> I have yet to find or be shown a way in which the standard
>> actually guarantees that.
>
>How does the standard guarantee *anything*?
The thrust of what I have been driving at is that the standard
actually guarantees a lot less than people take for granted.
>This strictly conforming program:
>
> int main(void) { return 0; }
>
>when executed returns a status of 0 from main and does nothing else.
Actually, does it? It also implicitly closes the standard
input, output, and error streams. That could have side effects.
>Adding an uncalled function to the same source file doesn't change
>that.
But it's not _just_ an uncalled function. It's an uncalled
function that is manifestly gibberish because there is no input
for which that expression is well-defined.
I have not found evidence that the standard explicitly prohibits
a pathological compiler from doing something unexpected in that
case. An adversarial read of the standard could allow a
compiler to treat this in a manner similar to a syntax error.
>[...]
>
>> There was, once, a view that was almost universally shared that
>> UB was meant for things that could not be precisely described
>> because hardware was too varied. We're well past that; now it's
>> a vehicle for compiler writers to make benchmarks faster, but is
>> (generally) hostile to programmers. A lot of hay is made about
>> it in this group, but at the core, it's just (ironically) not
>> well-defined.
>
>The standard does say what UB is meant for. It says what UB
>*is*, and what constructs lead to it (by omission in some cases).
>Any optimization tricks played by compiler implementers must be
>based on that specification.
Yes. Just so. And it also says that anything not explicitly
stated in the standard is UB.
As we all know, the definition of UB in the standard is,
"behavior, upon use of a nonportable or erroneous program
construct or of erroneous data, for which this document imposes
no requirements."
Behavior is defined as, "external appearance or action". Note
that this does not explicitly state that "behavior" is only
applicable during execution, and we know that the standard, as
written today, says that some behaviors are "undefined" _at
translation time_. I cannot find something forbidding an
implementation from interpreting "external appearance or action"
to refer to the success or failure of translation and production
of an associated artifact. Translation phase 7 then says that
the after all of the preprocessing and so forth, "the resulting
tokens are syntactically and semantically analyzed and
translated as a translation unit." As written, a compiler could
certainly detect that that expression, whether executed or not,
is UB.
Indeed, sec 3.5.3 para 2, "Note 1 to entry", explicitly mentions
terminating translation as one of a few sample "undefined
behaviors". It doesn't say that the compiler _has_ to do that,
but does not say that it _must not_, either.
Sec 3.5.3 para 4 ("Note 3 to entry") is the closest I see to
mandating the interpretation you and Rentsch have taken, but
that is specific to _execution time_, not _translation time_,
and the latter is not outright banned from responding to UB: the
text of the standard imposes no requirements in this context.
Dare I say that the translation-time behavior is undefined?
>[...]
>
>>> I agree. printf("hello, world\n") must write that string to standard
>>> output, which may be a file or an interactive device. Just what
>>> that means is unspecified or implementation-defined. It might be
>>> printed in EBCDIC or incised into clay tablets. Closing stdout,
>>> which occurs when main() terminates, might involve firing the tablet
>>> or emitting control sequences for a screen reader.
>>
>> Exactly. It could also emit the string, "GOODBYE WORLD."
>
>No, it couldn't. It must emit "hello, world\n" in some form.
>It must emit the character 'h' as represented in the execution
>character set, followed by 'e', and so on.
I didn't say that it wouldn't; I was referring specifically to
the behavior on closing stdout. You are right, it must emit
something corresponding to, "hello, world\n"; but what it does
after that is up to the implementation. We agree that it could
emit a terminal reset sequence; there is no reason that sequence
couldn't be, "GOODBYE WORLD." It'd be a weird one, but it's not
impossible.
>[...]
>
>> This presupposes that the program is strictly conforming, but
>> in the limit, the standard can be interpreted in such a way that
>> if any statement in the program is proveably UB (as this one is)
>> then the program cannot said to be strictly conforming.
>
>It's not UB if it's never called. Behavior that doesn't happen is
>not behavior.
See above. The standard simply does not say that. The standard
merely says that behavior is something that manifests as
"external appearance or action." Translation is certainly an
action with an "external appearance" and nothing says that
behavior _during translation_ is any less "behavior" than
behavior during execution. In fact, the standard explicitly
mentions undefined behavior and translation.
>I did not presuppose that the program is strictly conforming.
Well, you kinda did: you said that the program is strictly
conforming, and then said that it must be accepted because it is
strictly conforming. That acceptance is predicated on it being
strictly conforming.
>I read the source code and determined that it meets the standard's
>definition of a strictly conforming program.
I have presented what I think is an equally valid, alternative
reading of the text of the standard where that does not hold.
That reading is, admittedly, adversarial. That does not mean it
is wrong. I am saying that this is a weakness of the standard,
not a good interpretation.
40 years ago people thought the idea of that a post-modern
compiler time-travelling in the pursuit of optimization when UB
is detected during translation was an adversarial read of the
standard. And yet, here we are.
>[...]
>
>> Ok, so in that case, would we say that "`foo` has undefined
>> behavior?" The qualification, "...if called" seems superfluous,
>> and I don't see anything in the standard that explicitly
>> disagrees.
>
>The qualification "if called" is the whole point.
Except it's not. The behavior of that expression is simply
undefined; whether executed or not, there's no way it _could_ be
defined.
>[...]
>
>> UB can time-travel, however. Because it's undefined, the
>> compiler is free to assume that it never executes, or that it
>> always executes.
>
>"UB can time-travel" is perhaps an oversimplification.
>
>An example is
>a bug that occurred in the Linux kernel, something like:
>
> void func(int *ptr) {
> do_something_with(*ptr);
> if (ptr != NULL) {
> blah();
> }
> }
>
>The compiler, on seeing the expression `*ptr`, assumed that `ptr` is
>not null, and elided the test on the following line.
>
>But even assuming that's valid, a compiler absolutely cannot assume that
>an instance UB always executes when, according to the semantics of the
>program, it provably never executes.
Time travel is a term of art, here. I posted this elsewhere in
the thread, and I think he does a much better job explaining it
than I can:
https://devblogs.microsoft.com/oldnewthing/20140627-00/?p=633
Reading a bit more, I think that C23 sec 3.5.3 para 4 appears
to be trying to reign that in. Hope springs eternal.
>[...]
>
>> So any program that produces no output at all is strictly
>> conforming? Then what about this?
>>
>> #include <limits.h>
>>
>> int
>> zero(void)
>> {
>> return (INT_MAX + 1) * 0;
>> }
>>
>> int
>> main(void)
>> {
>> (void)zero();
>> return 0;
>> }
>
>That's an interesting point. A more terse example:
>
>#include <limits.h>
>int main(void) {
> int unused = INT_MAX + 1;
>}
Sure. Or consider this program:
```
#include <limits.h>
int
foo(int a)
{
extern int int_max;
int_max = INT_MAX + 1;
return int_max;
}
int
main(void)
{
return 0;
}
```
Suppose that no definition for `int_max` is provided; is this a
strictly conforming program? Consider section 6.9.1, which
describes external definitions. The relevant paragraph is 5,
which reads in part, "If an identifier declared with external
linkage is used in an expression somewhere in the entire program
there shall be exactly one external definition for the
identifier; otherwise, there shall be no more than one."
But as has been argued, `int_max` is not actually _used_, since
`foo` is never called. If that holds, then this ought to be
accepted by a conforming implementation. Yet, this fails to
build with both gcc and clang, clearly both consider `int_max`
to be "used". Ok, so what about this?
#include <limits.h>
int
foo(int a)
{
extern int int_max;
if ((INT_MAX + 1)*0) {
int_max = INT_MAX + 1;
}
return 0;
}
int
main(void)
{
return 0;
}
This _does_ build.
So it appears that, at least for `gcc` and `clang`, merely not
calling `foo` is insufficient.
>> This program produces no output, yet clearly executes a function
>> that contains an expression that induces undefined behavior when
>> evaluated. I suppose an argument could be made that it _might_
>> generate output due to UB, as UB imposes no requirements Not to
>> do so, so perhaps the _absence_ of output depends on UB.
>
>The program clearly has undefined behavior when executed, but no
>output depends on that undefined behavior. In my humble opinion,
>this demonstrates a flaw in the standard's definition of "strictly
>conforming program". (As a programmer: Don't do that.)
That's kind of what I'm saying. Though this interpretation
hinges on whether the absence of output can be defined as output
in some sense; in this case, the compiler could emit code that
says, "this program has UB", and I think that would be fine with
respect to the standard.
But the standard says that an implementation can stop
translating a program if it detects UB, and nothing appears to
limit that to functions that have been called from `main`.
>[...]
>
>> In my ideal world, C would be rigorously defined with a precise
>> operational semantics. That would be accompanied by an
>> explanatory document that presented those semantics in lay
>> terms in prose, similar to the standard now, for those who did
>> not want to drive Coq or something similar. But at least we'd
>> have something definitive to define the language, so that when
>> there was apparent ambiguity, we had some objective metric by
>> which to judge. The C standard, as written, is nowhere close as
>> precise as it should be.
>>
>> I do not think that this will ever happen: not only would it be
>> very difficult to produce (as you noted elsethread), I think the
>> compiler writers would rebel if they felt that their UB hands
>> were tied by a formal specification.
>
>"There are only two kinds of languages: the ones people complain
>about and the ones nobody uses."
Yup.
- Dan C.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2026-06-08 18:51 -0700 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <1107rk3$3ldg4$1@kst.eternal-september.org> |
| In reply to | #399800 |
cross@spitfire.i.gajendra.net (Dan Cross) writes:
> In article <11075os$3fm4u$1@kst.eternal-september.org>,
> Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>>> In article <1100g0e$1lt8i$1@kst.eternal-september.org>,
>>> Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>>[...]
>>>>A naive compiler that performs no optimizations would generate
>>>>code for foo() that attempts to compute (INT_MAX+1)*0 step by
>>>>step, without recognizing the overflow, and that code would never
>>>>be executed.
>>>
>>> Sure. But a far more sophisticated translator (and I would
>>> argue a nefarious one) could emulate that code, decide it was
>>> UB, and immediately fail translation with an error.
>>
>>I disagree. That's not a sensible interpretation of what the
>>standard says.
>
> I agree it's not sensible. But sadly, the standard does not
> seem to explicitly prohibit it, either. This is the point: we
> necessarily rely on a "reasonable interpretation" of the
> standard to be able to usefully write C code. An adversarial
> interpretation is not sensible, but it appears that such is
> possible given the standard as written. This is a danger with a
> language that is not formally specified.
I started to compose a followup, but I found that I was mostly
repeating things I've already written.
I see no semantic difference between code in a function that's never
called and code that simply isn't in the program. Neither allows
an implementation to reject a strictly conforming program -- and
yes, the program we've been discussing is as strictly conforming as
`int main(void){}`.
There's nothing special about functions as units of a program
subject to undefined behavior. These two programs are semantically
equivalent:
void foo(void) { do_something(); }
int main(void) { foo(); }
and
int main(void) { do_something(); }
A simpler demonstration program might be:
#include <limits.h>
int main(void) {
return 0;
INT_MAX+1;
}
I assert that it is strictly conforming.
The permission for UB to result in terminating a translation
isn't even in normative text. It's in a non-normative note,
which in principle means that it should be derivable from the
normative text of the standard. (I'm not entirely sure it can be.)
It certainly doesn't override the requirement that a conforming
hosted implementation shall accept any strictly conforming program.
[...]
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | cross@spitfire.i.gajendra.net (Dan Cross) |
|---|---|
| Date | 2026-06-09 09:46 +0000 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <1108ncp$sl5$1@reader1.panix.com> |
| In reply to | #399804 |
In article <1107rk3$3ldg4$1@kst.eternal-september.org>,
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>> In article <11075os$3fm4u$1@kst.eternal-september.org>,
>> Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>>>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>>>> In article <1100g0e$1lt8i$1@kst.eternal-september.org>,
>>>> Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>>>[...]
>>>>>A naive compiler that performs no optimizations would generate
>>>>>code for foo() that attempts to compute (INT_MAX+1)*0 step by
>>>>>step, without recognizing the overflow, and that code would never
>>>>>be executed.
>>>>
>>>> Sure. But a far more sophisticated translator (and I would
>>>> argue a nefarious one) could emulate that code, decide it was
>>>> UB, and immediately fail translation with an error.
>>>
>>>I disagree. That's not a sensible interpretation of what the
>>>standard says.
>>
>> I agree it's not sensible. But sadly, the standard does not
>> seem to explicitly prohibit it, either. This is the point: we
>> necessarily rely on a "reasonable interpretation" of the
>> standard to be able to usefully write C code. An adversarial
>> interpretation is not sensible, but it appears that such is
>> possible given the standard as written. This is a danger with a
>> language that is not formally specified.
>
>I started to compose a followup, but I found that I was mostly
>repeating things I've already written.
Yeah, I feel we're going around in circles, here.
>I see no semantic difference between code in a function that's never
>called and code that simply isn't in the program. Neither allows
>an implementation to reject a strictly conforming program -- and
>yes, the program we've been discussing is as strictly conforming as
>`int main(void){}`.
That's the crux of the issue. I'm not convinced that it is. I
can see an argument for it (and it's a pretty strong one) but I
can see an argument against, and the standard as written is
underspecified in my opinion. Really, that's it.
>There's nothing special about functions as units of a program
>subject to undefined behavior. These two programs are semantically
>equivalent:
> void foo(void) { do_something(); }
> int main(void) { foo(); }
>and
> int main(void) { do_something(); }
>
>A simpler demonstration program might be:
>
> #include <limits.h>
> int main(void) {
> return 0;
> INT_MAX+1;
> }
>
>I assert that it is strictly conforming.
>
>The permission for UB to result in terminating a translation
>isn't even in normative text. It's in a non-normative note,
>which in principle means that it should be derivable from the
>normative text of the standard. (I'm not entirely sure it can be.)
That specific instance is not, no; that's in a note as you point
out. I believe deriving it from the normative text is based on
UB imposing no requirement at all on the implementation.
>It certainly doesn't override the requirement that a conforming
>hosted implementation shall accept any strictly conforming program.
...assuming the program is strictly conforming.
I have arrived at the same place you are with your "42 is not an
expression" example. The wording of the standard could be
improved to avoid things like this.
- Dan C.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2026-06-09 15:07 -0700 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <110a2rq$b2kq$1@kst.eternal-september.org> |
| In reply to | #399811 |
cross@spitfire.i.gajendra.net (Dan Cross) writes:
> In article <1107rk3$3ldg4$1@kst.eternal-september.org>,
> Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
[...]
>> The permission for UB to result in terminating a translation
>> isn't even in normative text. It's in a non-normative note,
>> which in principle means that it should be derivable from the
>> normative text of the standard. (I'm not entirely sure it can be.)
>
> That specific instance is not, no; that's in a note as you point
> out. I believe deriving it from the normative text is based on
> UB imposing no requirement at all on the implementation.
No, the standard imposes no requirements on the *behavior*.
It still imposes requirements on the implementation.
The requirements imposed on an implementation are of a different
kind than the requirements imposed on a running program.
(An implementation might not even be writtin in C.)
For example, if a program dies with a segfault, it's likely due to
the program having undefined behavior. If a compiler dies with a
segfault, it's always a bug in the compiler (though the standard
doesn't say this).
If, as I suggest, the word "behavior" ("external appearance or
action") refers only to the behavior of a running program, then I
don't see how the non-normative permission to terminate a translation
follows from any normative text.
One possible argument is the statement in Section 4 that "A
*conforming hosted implementation* shall accept any strictly
conforming program", which *might* imply that a conforming hosted
implementation is permitted to reject (not accept) any program that
is not strictly conforming. I'm not comfortable with that argument.
>>It certainly doesn't override the requirement that a conforming
>>hosted implementation shall accept any strictly conforming program.
>
> ...assuming the program is strictly conforming.
Or deriving the fact that a program is strictly conforming by reading
the program and the definition of "strictly conforming program".
> I have arrived at the same place you are with your "42 is not an
> expression" example. The wording of the standard could be
> improved to avoid things like this.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | antispam@fricas.org (Waldek Hebisch) |
|---|---|
| Date | 2026-06-09 01:25 +0000 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <1107q1e$ccfa$1@paganini.bofh.team> |
| In reply to | #399786 |
Dan Cross <cross@spitfire.i.gajendra.net> wrote:
> In article <1100g0e$1lt8i$1@kst.eternal-september.org>,
> Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>
>>>>and in fact
>>>>it *won't* occur during execution because foo() isn't called.
>>>>A compiler can't generate code with arbitrary behavior just because
>>>>it can't prove that there will be no UB. If it could, every signed
>>>>or floating-point arithmetic operation with unknown operand values
>>>>would grant the same permission.
>>>
>>> But that's not the situation here. The situation is that the
>>> compiler can prove that something _is_ UB.
>>
>>In the program quoted at the top of this post, the UB occurs in
>>a function foo() that's never called. A compiler can replace the
>>body of foo() with a trap, and it can certainly warn about the UB,
>>but I don't believe it can reject the entire program. A clever
>>compiler could prove that the UB never occurs.
>
> So there are two things that are at play here.
>
> First, this notion that UB is _only_ a runtime matter. The text
> of the standard contradicting that aside, if a translator can
> detect that the behavior of a construct is provably undefined if
> executed, then it seems axiomatic that UB is clearly something
> that plays a role at translation time, as well.
I think that this paragraph (and several other it this post and
other posts) represent fundamental misanderstanding. This may
be due to the way C standard is written. AFAIK Extended Pascal
standard (once you translate terminalogy) states the same things as
C about UB, but in clearer way. Some relevant parts below:
: 3.1 Dynamic-violation
: A violation by a program of the requirements of this International
: Standard that a processor is permitted to leave undetected up to,
: but not beyond, execution of the declaration, definition, or
: statement that exhibits (see clause 6) the dynamic-violation.
: 3.2 Error
: A violation by a program of the requirements of this International
: Standard that a processor is permitted to leave undetected.
...
: 5.1 Processors
...
: e) be able to determine whether or not the program violates any
: requirements of this International Standard, where such a violation is
: not designated an error or dynamic-violation,
...
: 5.2 Programs
...
: b) if it conforms at level 1, use only those features of the language
: specified in clause 6;
UB in C standard corresponds with 'error' in Pascal standard. And
(by clause above) program is allowed only to use defined features,
trying to use something that has no definition (undefined by
ommision of definition) is automatically an error.
Overflow in arithmetic in Pascal is an error, as is accessing
wrong variant of variant record. Due to this accessing variable
using wring type is an error in Pascal.
Since valid programs shall contain no errors (as defined above)
Pascal compiler my optimize assuming that user program contains
no errors. This is the same as C compiler optimizing on assumption
that there is no udefined behaviour in the program.
Of course, C is different language than Pascal and in particular
C contains more "dangerous" constructs that may lead to
undefined behaviour.
However, the fundamental thing remain: detecting undefined behaviour
("errors") at compile time in general is hard, and compilers are
not obliged to do so. But they may optimize trusting that program
contains no undefined behaviour ("no error").
> Indeed, I would go so far as to suggest that _most_ instances of
> UB are detected and used (by the translator) during translation.
I think it is different: compiler _assumes_ no undefined behaviour
and optimizes accoringly. But when there is undefined behaviour,
then program behaves in unexpected way at runtime. Also, when
you assume a false thing, then you can logically derive anything
from it, so there is no limit to possible damage.
> So to say that, "this program doesn't have UB because the
> statement that contains UB is never executed" doesn't make a lot
> of sense to me. It would be closer to being correct if one said
> "this program is unaffected by UB since the expression that has
> UB is never evaluated when the program executes": again, in this
> case (as, I suspect, in most cases) the UB simply _is_: the
> expression `INT_MAX + 1` does not become well-defined just
> because it is never executed.
Well, what is interesting to users is runtime behaviour of programs
and undefined behaviour usually is runtime thing (as troubles that
can be easily detected at compile time are usually constraint
violations which should be detected at compile time). Fact that
some undefined behaviour can be detected at compile time does
not change this. And AFAICS there was very deliberate decision to
allow programs which contains code that would be undefined behaviour
if executed, but are considerd OK if such code is not executed.
BTW: Pascal wording is different but Pascal standard contains
identical provision and Pascal validation suite contains explicit
tests of this sort.
> Second, there's this notion that the standard is just
> underspecified with respect to these matters, specifically, it
> does not _prohibit_ a translation from implementing an emulator
> for the abstract machine that evaluates code at translation
> time. Indeed, I suspect that _most_ compilers do something
> largely analogous to that; that's how they detect UB so that
> they can take advantage of it when optimizing. But if that's
> the case, then nothing prohibits them from relieving themselves
> of their obligation to follow the standard once they observe
> that some bit of code has UB.
As I wrote, this is different. Compilers routinely compute some
constant expressions at compile time. Constant here meaning that
expression does not depend on runtime values. Compilers track
ranges of variables. But this is done using assumption that
there are no undefined behaviour. For example in loop:
for(int i = 1; i > 0; i++) {
...
}
absent assigments to i in loop body compiler may infer that 'i > 0'
and skip the test. If however there is undefined behaviour, then
compiler may infer any nonsense. This may look like compiler
detected undefined behaviour, but compiler typically do not check
consistency of inferences. In fact, intermediate things and
useless facts are quickly discarded, so detecting undefined
behaviour via inconsistency of inferred facts would significantly
increase memory use and probably also compile time.
>>A naive compiler that performs no optimizations would generate
>>code for foo() that attempts to compute (INT_MAX+1)*0 step by
>>step, without recognizing the overflow, and that code would never
>>be executed.
>
> Sure. But a far more sophisticated translator (and I would
> argue a nefarious one) could emulate that code, decide it was
> UB, and immediately fail translation with an error.
As already noted C standard explictely forbids such behaviour.
BTW: There were past discussions of the same and other people
quited relevant passage which is quite explicit. I am not
going to search for it, but it is in the standard.
> Is it? I am unable to locate where the standard _actually says
> that it is_. That is my whole point.
Sorry, I looked in place given by other people, but I do not
remember exact location. I would say that once you find right
place and read it carefuly it is pretty clear.
> And yet the standard does not say that. That is an
> interpretation; I assume it is universally shared, but if we
> want to limit ourselves to what the standard _actually says_ it
> is woefully underspecified in this regard.
>
> There was, once, a view that was almost universally shared that
> UB was meant for things that could not be precisely described
> because hardware was too varied.
Originally C was defined by single implementation which was not
doing much optimisation. But clearly starting from the first
C standard undefined behaviour had the same meaning as Pascal
error: permission for compilers to optimize on assumption that
is does not happen. The issue was well understood in seventies.
Already in late sixties Fortran compilers could do interesting
optimizations, not expected by naive users. In seventies
majority (or at least most influential) view was that it is
programmer resonsibility to obey language rules and that
compiler should optimize on assumption that rules are obeyed.
C reflect this point of view.
One can discuss if such point of view is valid now, but C
is a product of such thinking.
> This is circular reasoning. You're saying that something that
> is provably UB in this program cannot prevent that program from
> being strictly confirming because the program is strictly
> confirming.
What you wrote above is similar to standard wording, except that
standard formilates it much better, closer to "code that would
cause undefined behaviour if executed does not prevent otherwise
strictly confirming program from being strictly confirming".
In the past there were disscusion when an implementation can reject
a program. I do not remember what was the conclusion in the case
when implementation can prove that program must cause undefined
behaviour, but otherwise program violates no constraints. Probably
it can reject it, but I am not sure. But if there were any possiblity
that program may execute without undefined behaviour (including
containg code that would cause undefined behaviour if executed),
then implementation should accept such program.
> This presupposes that the program is strictly conforming, but
> in the limit, the standard can be interpreted in such a way that
> if any statement in the program is proveably UB (as this one is)
> then the program cannot said to be strictly conforming.
As I wrote, there is quite explicit statement in the standard
which says opposite of what you wrote above: mere presence of
code that would cause undefined behaviour if executed does not
make program non conforming.
> In my ideal world, C would be rigorously defined with a precise
> operational semantics. That would be accompanied by an
> explanatory document that presented those semantics in lay
> terms in prose, similar to the standard now, for those who did
> not want to drive Coq or something similar. But at least we'd
> have something definitive to define the language, so that when
> there was apparent ambiguity, we had some objective metric by
> which to judge. The C standard, as written, is nowhere close as
> precise as it should be.
>
> I do not think that this will ever happen: not only would it be
> very difficult to produce (as you noted elsethread), I think the
> compiler writers would rebel if they felt that their UB hands
> were tied by a formal specification.
I do not thing operational semantics is best way to define C.
Naive operational semantics would define too much things, so
one would need serious work to define what should be defined
and leave undefined what should be undefined.
My personal favorite is axiomatic semantics. IMO it is quite well
adapted to defining programming languages. Substantial part of
Pascal was given axiomatic semantics in Alagic and Arbib book.
Pascal standard do not explitely use axiomatic semantics, but
my impression was that with managable effort it coulde be rewritten
using axiomatic semantics. Modern C standard is bigger, partly due
to library case, partly because C have much more operators. But
problem seem to be mostly quantity of needed text.
I think that compiler writers would welcome axiomatic semantics,
it would make their work simpler. More preciely, now compiler
writers must temselves translate standad text into formulation
similar to axiomatic semantics. Having official semantics
would make their work simpler. It would prevent implementing
some optimizations based on misunderstanding of the standard,
but if such optimizations were deemed worthty they could
implement then as a nonstandard thing (like -fast-math now)
and lobby for change in the standard.
I think biggest trouble is normal programmers. They already
struggle with current standard text. More formal presentation
could alienate even folks who now are able to explain standard
rules to other programmers.
--
Waldek Hebisch
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@alumni.caltech.edu> |
|---|---|
| Date | 2026-06-09 18:29 -0400 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <110a44i$aedl$1@dont-email.me> |
| In reply to | #399803 |
On 2026-06-08 21:25, Waldek Hebisch wrote: > Dan Cross <cross@spitfire.i.gajendra.net> wrote: >> In article <1100g0e$1lt8i$1@kst.eternal-september.org>, >> Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote: ... >>> In the program quoted at the top of this post, the UB occurs in >>> a function foo() that's never called. A compiler can replace the >>> body of foo() with a trap, and it can certainly warn about the UB, >>> but I don't believe it can reject the entire program. A clever >>> compiler could prove that the UB never occurs. >> >> So there are two things that are at play here. >> >> First, this notion that UB is _only_ a runtime matter. The text >> of the standard contradicting that aside, if a translator can >> detect that the behavior of a construct is provably undefined if >> executed, then it seems axiomatic that UB is clearly something >> that plays a role at translation time, as well. The committee has decided otherwise. The committee's resolution to DR 109 said: "A conforming implementation must not fail to translate a strictly conforming program simply because some possible execution of that program would result in undefined behavior. Because foo might never be called, the example given must be successfully translated by a conforming implementation." The module in question defined a function with a line that contained the expression-statement 1/0; and that statement was absolutely guaranteed to be executed if the function was called. However, since the module did not contain any calls to that function, the committee ruled that an implementation was not allowed to refuse to translate it. If linked to another module that contained a call to that function, whether or not the implementation could refuse translation depends upon what could be said about the call: 1. If the call to that function was guaranteed to be executed upon starting the program, the implementation may refuse translation. 2. If the call to that function was guaranteed to never be executed, the undefined behavior associated with 1/0 has no effect. 3. If the call to that function might or might not be executed, the undefined behavior associated with 1/0 cannot have effect until execution of that call becomes inevitable.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2026-06-09 16:01 -0700 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <110a5vr$b2kq$5@kst.eternal-september.org> |
| In reply to | #399833 |
James Kuyper <jameskuyper@alumni.caltech.edu> writes:
[...]
> The committee has decided otherwise. The committee's resolution to DR
> 109 said:
>
> "A conforming implementation must not fail to translate a strictly
> conforming program simply because some possible execution of that
> program would result in undefined behavior. Because foo might never be
> called, the example given must be successfully translated by a
> conforming implementation."
https://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_109.html
[...]
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | cross@spitfire.i.gajendra.net (Dan Cross) |
|---|---|
| Date | 2026-06-10 12:36 +0000 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <110bloc$cak$1@reader1.panix.com> |
| In reply to | #399835 |
In article <110a5vr$b2kq$5@kst.eternal-september.org>, Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote: >James Kuyper <jameskuyper@alumni.caltech.edu> writes: >[...] >> The committee has decided otherwise. The committee's resolution to DR >> 109 said: >> >> "A conforming implementation must not fail to translate a strictly >> conforming program simply because some possible execution of that >> program would result in undefined behavior. Because foo might never be >> called, the example given must be successfully translated by a >> conforming implementation." > >https://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_109.html > >[...] That does appear to settle the matter definitively, thanks. Ok, I was wrong and I concede that the program we've been discussing is strictly conforming, regardless of however antagnostic a reader of the standard may be. - Dan C.
[toc] | [prev] | [next] | [standalone]
| From | Janis Papanagnou <janis_papanagnou+ng@hotmail.com> |
|---|---|
| Date | 2026-06-11 16:49 +0200 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <110eht5$1naub$5@dont-email.me> |
| In reply to | #399803 |
On 2026-06-09 03:25, Waldek Hebisch wrote: > [...] Interesting views. - Thanks. > > I think biggest trouble is normal programmers. They already > struggle with current standard text. More formal presentation > could alienate even folks who now are able to explain standard > rules to other programmers. I'm not sure what "normal programmers" are. From own experience I can just say that there's a difference between what's "formal" in a "lawyer's speeches and texts" sense and what's formal in a mathematical sense. - The C-Standard as had been quoted here is more of a lawyer's text, with its inherent property of not being formally (in a mathematical sense) accurate (despite their tries; in both areas, law and programming language, respectively). It's thus not necessarily a problem if we'd have a more [mathematical] formal standard. - Programmers, as I see it, need definite texts. And rejection of the "lawyer's" sort of texts is not surprising. That not necessarily affects their acceptance will of more formal specifications. Janis
[toc] | [prev] | [next] | [standalone]
| From | cross@spitfire.i.gajendra.net (Dan Cross) |
|---|---|
| Date | 2026-06-11 15:20 +0000 |
| Subject | Re: Constants and undefined behavior |
| Message-ID | <110ejn1$96r$1@reader1.panix.com> |
| In reply to | #399900 |
In article <110eht5$1naub$5@dont-email.me>, Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote: >On 2026-06-09 03:25, Waldek Hebisch wrote: >> [...] > >Interesting views. - Thanks. > >> >> I think biggest trouble is normal programmers. They already >> struggle with current standard text. More formal presentation >> could alienate even folks who now are able to explain standard >> rules to other programmers. > >I'm not sure what "normal programmers" are. From own experience >I can just say that there's a difference between what's "formal" >in a "lawyer's speeches and texts" sense and what's formal in a >mathematical sense. - The C-Standard as had been quoted here is >more of a lawyer's text, with its inherent property of not being >formally (in a mathematical sense) accurate (despite their tries; >in both areas, law and programming language, respectively). It's >thus not necessarily a problem if we'd have a more [mathematical] >formal standard. - Programmers, as I see it, need definite texts. >And rejection of the "lawyer's" sort of texts is not surprising. >That not necessarily affects their acceptance will of more formal >specifications. One hopes that a formal specification (that's a term of art, and implies something that's mathematically precise) would be accompanied by a commentary for more casual reading. However, the truly precise, formal specification would be considered definitive. I think the odds of this ever happening for C are slim to none, but it would be useful. - Dan C.
[toc] | [prev] | [next] | [standalone]
Page 5 of 19 — ← Prev page 1 … 3 4 [5] 6 7 … 19 Next page →
Back to top | Article view | comp.lang.c
csiph-web