Constants that are to be used in bitwise operations should be unsigned,
or a user could easily trigger Undefined Behavior.
Also, the types where these constants are to be assigned are unsigned,
so this makes it more consistent.
alx@debian:/usr/include$ grepc -tt termios asm-generic/
asm-generic/termbits.h:struct termios {
tcflag_t c_iflag; /* input mode flags */
tcflag_t c_oflag; /* output mode flags */
tcflag_t c_cflag; /* control mode flags */
tcflag_t c_lflag; /* local mode flags */
cc_t c_line; /* line discipline */
cc_t c_cc[NCCS]; /* control characters */
};
alx@debian:/usr/include$ grepc -tt tcflag_t asm-generic/
asm-generic/termbits.h:typedef unsigned int tcflag_t;
alx@debian:/usr/include$ grepc -tt cc_t asm-generic/
asm-generic/termbits-common.h:typedef unsigned char cc_t;
alx@debian:/usr/include$ grepc -tt speed_t asm-generic/
asm-generic/termbits-common.h:typedef unsigned int speed_t;
Link: <https://lore.kernel.org/linux-api/2024061222-scuttle-expanse-6438@gregkh/T/>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Palmer Dabbelt <redacted>
Cc: <redacted>
Cc: <redacted>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
Hi Greg,
On Wed, Jun 12, 2024 at 02:22:37PM GMT, Greg KH wrote:
Have a proposed patch that you feel would resolve this?
thanks,
greg k-h
Here it is. :)
For reviewing it, I suggest using '--word-diff-regex=.'.
I compiled the kernel, and it seems ok; didn't test more than that.
Have a lovely day!
Alex
Range-diff:
-: ------------ > 1: 588eb01ac153 uapi/asm/termbits: Use the U integer suffix for bit fields
arch/alpha/include/uapi/asm/termbits.h | 154 +++++++++---------
arch/mips/include/uapi/asm/termbits.h | 154 +++++++++---------
arch/parisc/include/uapi/asm/termbits.h | 152 +++++++++---------
arch/powerpc/include/uapi/asm/termbits.h | 156 +++++++++---------
arch/sparc/include/uapi/asm/termbits.h | 192 +++++++++++------------
include/uapi/asm-generic/termbits.h | 152 +++++++++---------
6 files changed, 480 insertions(+), 480 deletions(-)
Hi Greg,
On Wed, Jun 12, 2024 at 03:35:20PM GMT, Greg KH wrote:
On Wed, Jun 12, 2024 at 03:16:58PM +0200, Alejandro Colomar wrote:
quoted
Constants that are to be used in bitwise operations should be unsigned,
or a user could easily trigger Undefined Behavior.
Wait, do we really have such broken compilers out there?
I meant this as a generic statement that signed integers on bitwise ops
are bad, not as a specific statement that these values would trigger UB.
I expect that these specific values and the operations done on them
probably don't trigger UB, since the shifts are done by a controlled
amount, and there are justa few operations done on them.
For example, a left shift where a set bit overflows the type (e.g.,
1<<32), causes UB.
The reason why it's better to avoid this at all even if we know these
values work fine, is that programs using <asm/termbits.h> would need to
disable those compiler warnings, which could silence warnings on other
code which might be broken.
TL;DR: The kernel isn't broken, but improving this would allow users to
enable stricter warnings, which is a good thing.
With this change, can the glibc versions then be dropped to just rely on
these instead?
On Wed, Jun 12, 2024 at 04:00:18PM +0200, Alejandro Colomar wrote:
Hi Greg,
On Wed, Jun 12, 2024 at 03:35:20PM GMT, Greg KH wrote:
quoted
On Wed, Jun 12, 2024 at 03:16:58PM +0200, Alejandro Colomar wrote:
quoted
Constants that are to be used in bitwise operations should be unsigned,
or a user could easily trigger Undefined Behavior.
Wait, do we really have such broken compilers out there?
I meant this as a generic statement that signed integers on bitwise ops
are bad, not as a specific statement that these values would trigger UB.
I expect that these specific values and the operations done on them
probably don't trigger UB, since the shifts are done by a controlled
amount, and there are justa few operations done on them.
These, for the most part, are NOT used as shifts.
For example, a left shift where a set bit overflows the type (e.g.,
1<<32), causes UB.
Sure, but that's not in play here.
The reason why it's better to avoid this at all even if we know these
values work fine, is that programs using <asm/termbits.h> would need to
disable those compiler warnings, which could silence warnings on other
code which might be broken.
But again, you aren't using these as bit shifts, they are bit masks, or
values, only.
TL;DR: The kernel isn't broken, but improving this would allow users to
enable stricter warnings, which is a good thing.
From: Paul Eggert <hidden> Date: 2024-06-12 14:55:16
On 2024-06-12 05:16, Alejandro Colomar wrote:
tcgets.c:53:24:
error: implicit conversion changes signedness: 'int' to 'tcflag_t' (aka
'unsigned int') [clang-diagnostic-sign-conversion,-warnings-as-errors]
This is a bug in Clang not glibc, and if you're worried about it I
suggest sending a bug report to the Clang folks about the false positive.
Even GCC's -Wsign-conversion, which is at least smart enough to not warn
about benign conversions like that, is too often so chatty that it's
best avoided.
A lot of this stuff is pedanticism that dates back to the bad old days
when the C standard allowed ones' complement and signed magnitude
representations of signed integers. Although it can be amusing to worry
about that possibility (I know I've done it) it's never been a practical
worry, and even the motivation of pedanticism is going away now that C23
requires two's complement.
Hi Greg,
On Wed, Jun 12, 2024 at 04:21:25PM GMT, Greg KH wrote:
On Wed, Jun 12, 2024 at 04:00:18PM +0200, Alejandro Colomar wrote:
quoted
I expect that these specific values and the operations done on them
probably don't trigger UB, since the shifts are done by a controlled
amount, and there are justa few operations done on them.
These, for the most part, are NOT used as shifts.
Quoting the EXAMPLES section in the manual page:
tio.c_cflag &= ~(CBAUD << IBSHIFT);
(And yeah, that shift is presumably controlled, so that it doesn't
overflow, which is why I mean these are presumably just fine.)
quoted
TL;DR: The kernel isn't broken, but improving this would allow users to
enable stricter warnings, which is a good thing.
Enable it where?
I meant in user space programs that use termbits stuff. (That this may
also allow the kernel to eventually have stricter warnings, I don't
know. It might help. But mostly meant it for user space.)
So, if I have a user-space program (or more likely a library) which
wraps these ioctls, I'd prefer to be able to enable the warnings I
reported, to preclude any mistakes in my code. That would need the
constants to be unsigned, to avoid false negatives.
Cheers,
Alex
--
<https://www.alejandro-colomar.es/>
Hi Paul,
On Wed, Jun 12, 2024 at 07:55:14AM GMT, Paul Eggert wrote:
On 2024-06-12 05:16, Alejandro Colomar wrote:
quoted
tcgets.c:53:24:
error: implicit conversion changes signedness: 'int' to 'tcflag_t' (aka
'unsigned int') [clang-diagnostic-sign-conversion,-warnings-as-errors]
This is a bug in Clang not glibc, and if you're worried about it I suggest
sending a bug report to the Clang folks about the false positive.
Even GCC's -Wsign-conversion, which is at least smart enough to not warn
about benign conversions like that, is too often so chatty that it's best
avoided.
A lot of this stuff is pedanticism that dates back to the bad old days when
the C standard allowed ones' complement and signed magnitude representations
of signed integers. Although it can be amusing to worry about that
possibility (I know I've done it) it's never been a practical worry, and
even the motivation of pedanticism is going away now that C23 requires two's
complement.
I know; I think I have -Weverything enabled in that run, which is known
for its pedanticity. I usually disable it when it triggers a warning,
since they are usually nonsense. But in this case, adding U is a net
improvement, without downsides (or I can't see them).
So, while the kernel and glibc are just fine with this implicit
conversion, they would be equally fine and even better without the
conversion. Not a bug, but rather a slight improvement.
Have a lovely day!
Alex
--
<https://www.alejandro-colomar.es/>
On Wed, Jun 12, 2024 at 12:29 PM Alejandro Colomar [off-list ref] wrote:
Hi Paul,
On Wed, Jun 12, 2024 at 07:55:14AM GMT, Paul Eggert wrote:
quoted
On 2024-06-12 05:16, Alejandro Colomar wrote:
quoted
tcgets.c:53:24:
error: implicit conversion changes signedness: 'int' to 'tcflag_t' (aka
'unsigned int') [clang-diagnostic-sign-conversion,-warnings-as-errors]
This is a bug in Clang not glibc, and if you're worried about it I suggest
sending a bug report to the Clang folks about the false positive.
Even GCC's -Wsign-conversion, which is at least smart enough to not warn
about benign conversions like that, is too often so chatty that it's best
avoided.
A lot of this stuff is pedanticism that dates back to the bad old days when
the C standard allowed ones' complement and signed magnitude representations
of signed integers. Although it can be amusing to worry about that
possibility (I know I've done it) it's never been a practical worry, and
even the motivation of pedanticism is going away now that C23 requires two's
complement.
I know; I think I have -Weverything enabled in that run, which is known
for its pedanticity. I usually disable it when it triggers a warning,
since they are usually nonsense. But in this case, adding U is a net
improvement, without downsides (or I can't see them).
well, any change like this is a potential source incompatibility ... i
hacked these changes into AOSP, and it did break one bit of existing
code that was already working around the sign differences --- this
warning was enabled but the code had a cast to make the _other_ side
of the comparison signed (rather than make this side of the comparison
unsigned).
Android's libc [bionic] uses the uapi headers directly, so we would be
affected, but to be clear --- i'm fine with this if the consensus is
to go this way.
(but, yeah, i'm with the "how about we fix the language and compiler
rather than all the extant code?" sentiment from Paul Eggert.)
So, while the kernel and glibc are just fine with this implicit
conversion, they would be equally fine and even better without the
conversion. Not a bug, but rather a slight improvement.
Have a lovely day!
Alex
--
<https://www.alejandro-colomar.es/>
From: Paul Eggert <hidden> Date: 2024-06-12 18:27:10
On 2024-06-12 09:28, Alejandro Colomar wrote:
adding U is a net
improvement, without downsides (or I can't see them)
Adding U can change the generated code and thus cause behavior change in
programs (admittedly not well-written ones). It could also create new
false positives in well-written programs.
If adding U fixed real bugs then of course we should do it. Here, though....
Hi Elliott, Paul,
On Wed, Jun 12, 2024 at 01:47:03PM GMT, enh wrote:
well, any change like this is a potential source incompatibility ... i
hacked these changes into AOSP, and it did break one bit of existing
code that was already working around the sign differences --- this
warning was enabled but the code had a cast to make the _other_ side
of the comparison signed (rather than make this side of the comparison
unsigned).
Android's libc [bionic] uses the uapi headers directly, so we would be
affected, but to be clear --- i'm fine with this if the consensus is
to go this way.
Hmmm; I see. I guess for this already-existent case we can just live
with it. Then I'll just ask to consider using unsigned constants for
new stuff that is a bit pattern and not just a number.
Let's drop the patch.
Have a lovely day!
Alex
(but, yeah, i'm with the "how about we fix the language and compiler
rather than all the extant code?" sentiment from Paul Eggert.)
On Wed, Jun 12, 2024 at 01:47:03PM GMT, enh wrote:
hacked these changes into AOSP, and it did break one bit of existing
code that was already working around the sign differences --- this
warning was enabled but the code had a cast to make the _other_ side
of the comparison signed (rather than make this side of the comparison
unsigned).
BTW, that seems to be a bogus way to workaround this; the cast should
have been on the other side. I'd say whoever maintains that code should
probably fix that to use unsigned types. These constants are meant to
be 'tcflag_t', so a cast should be to that type, or the type of the
other side of the comparison, but casting to 'int' just for silencing a
waring seems nuts.
This makes me wonder if breaking _those_ users could be a good thing...
--
<https://www.alejandro-colomar.es/>
On Wed, Jun 12, 2024 at 3:01 PM Alejandro Colomar [off-list ref] wrote:
On Wed, Jun 12, 2024 at 01:47:03PM GMT, enh wrote:
quoted
hacked these changes into AOSP, and it did break one bit of existing
code that was already working around the sign differences --- this
warning was enabled but the code had a cast to make the _other_ side
of the comparison signed (rather than make this side of the comparison
unsigned).
BTW, that seems to be a bogus way to workaround this; the cast should
have been on the other side. I'd say whoever maintains that code should
probably fix that to use unsigned types.
indeed. i've already sent out such a change :-)
These constants are meant to
be 'tcflag_t', so a cast should be to that type, or the type of the
other side of the comparison, but casting to 'int' just for silencing a
waring seems nuts.
i suspect the reasoning was one of readability --- keeping the [short]
constants legible at the cost of making the expression slightly
longer.
This makes me wonder if breaking _those_ users could be a good thing...
like Paul Eggert said somewhere else today --- only if we're finding
real bugs. and so far we're not.
it's like the warn_unused_result argument. a purist would argue that
every function should have that annotation, because you should always
check for errors, and if you're not already doing so, your code is
already broken. whereas a pragmatist would argue that most people are
just going to add the "shut up, compiler" cast (or disable the warning
entirely) if their already-working code suddenly starts spamming
warnings next time they build it.
while my bar for that might not be as high as my bar for ABI breakage,
my source compatibility bar is still pretty high. it would be almost
unethical of me to make app developers do random busywork. i have to
be pretty confident (as with, say, "you just passed an fd > 1024 to an
fd_set function/macro and thus corrupted memory") that their code is
_definitely_ wrong. (and even there, that's going to have to be a
runtime check!)
Hi Elliott,
On Wed, Jun 12, 2024 at 05:54:43PM GMT, enh wrote:
quoted
BTW, that seems to be a bogus way to workaround this; the cast should
have been on the other side. I'd say whoever maintains that code should
probably fix that to use unsigned types.
indeed. i've already sent out such a change :-)
quoted
These constants are meant to
be 'tcflag_t', so a cast should be to that type, or the type of the
other side of the comparison, but casting to 'int' just for silencing a
waring seems nuts.
i suspect the reasoning was one of readability --- keeping the [short]
constants legible at the cost of making the expression slightly
longer.
quoted
This makes me wonder if breaking _those_ users could be a good thing...
like Paul Eggert said somewhere else today --- only if we're finding
real bugs. and so far we're not.
it's like the warn_unused_result argument. a purist would argue that
every function should have that annotation, because you should always
check for errors, and if you're not already doing so, your code is
already broken. whereas a pragmatist would argue that most people are
just going to add the "shut up, compiler" cast (or disable the warning
entirely) if their already-working code suddenly starts spamming
warnings next time they build it.
while my bar for that might not be as high as my bar for ABI breakage,
my source compatibility bar is still pretty high. it would be almost
unethical of me to make app developers do random busywork. i have to
be pretty confident (as with, say, "you just passed an fd > 1024 to an
fd_set function/macro and thus corrupted memory") that their code is
_definitely_ wrong. (and even there, that's going to have to be a
runtime check!)
Yeah, I can agree with that. I'm that kind of pedantic purist for my
own code, and it's painful that historic accidents like this one don't
allow me to be so in my own code. But I agree that fixing the entire
world when their code is braindamaged but works is asking too much.
I'll just disable that pedantic warning when I use termbits. :)
Btw, thanks for fixing that brain-damaged cast. ;-)
Have a lovely night!
Alex
--
<https://www.alejandro-colomar.es/>
On Wed, Jun 12, 2024, at 10:55 AM, Paul Eggert wrote:
A lot of this stuff is pedanticism that dates back to the bad old days
when the C standard allowed ones' complement and signed magnitude
representations of signed integers. Although it can be amusing to
worry about that possibility (I know I've done it) it's never been a
practical worry, and even the motivation of pedanticism is going away
now that C23 requires two's complement.
Unless C23 eliminated *all* the cases where an operation on unsigned
integers is well-defined but the same operation on signed integers is
undefined, and last I checked it had not, there is still a need for
caution around conversions that change signedness.
zw
From: Paul Eggert <hidden> Date: 2024-06-13 21:12:27
On 6/13/24 05:32, Zack Weinberg wrote:
there is still a need for
caution around conversions that change signedness.
Yes, just as there is need for caution around any use of unsigned types.
Unfortunately in my experience Clang's (and even GCC's) warnings about
signedness conversion are more likely to cause harm than good, with this
thread being an example of the harm.
Part of the issue here is that GCC and Clang often do a better job of
warning when constants are signed, not unsigned. For example, suppose a
program mistakenly packages termios flags along with three other bits
into an 'unsigned long', with code like this:
unsigned long
tagged_pendin (unsigned tag)
{
return (PENDIN << 3) | tag;
}
Since PENDIN is 0x20000000 Clang and GCC by default warn about the
mistake, as the signed integer overflow has undefined behavior. But if
PENDIN were changed to 0x20000000U the behavior would be well-defined,
there would be no warning even with -Wall -Wextra -Wsign-conversion, and
the code would silently behave as if PENDIN were zero, which is not
intended.
This is another reason why appending "U" to PENDIN's value would have
drawbacks as well as advantages.
On Thu, Jun 13, 2024 at 02:12:20PM GMT, Paul Eggert wrote:
Part of the issue here is that GCC and Clang often do a better job of
warning when constants are signed, not unsigned. For example, suppose a
program mistakenly packages termios flags along with three other bits into
an 'unsigned long', with code like this:
unsigned long
tagged_pendin (unsigned tag)
{
return (PENDIN << 3) | tag;
}
Since PENDIN is 0x20000000 Clang and GCC by default warn about the mistake,
as the signed integer overflow has undefined behavior. But if PENDIN were
changed to 0x20000000U the behavior would be well-defined, there would be no
warning even with -Wall -Wextra -Wsign-conversion, and the code would
silently behave as if PENDIN were zero, which is not intended.
This is another reason why appending "U" to PENDIN's value would have
drawbacks as well as advantages.
Hmmmm, very interesting point! I'll have that in mind when doing
bitwise stuff with constants.
--
<https://www.alejandro-colomar.es/>