Fix undefined behaviour caused by shifting (unsigned char) << 24.
Reported by Tim Sweet <tsweet64@protonmail.com>
at <https://savannah.gnu.org/bugs/?66289>.
* lib/ucs4.h (ucs4_mbtowc): Cast 'unsigned char' values to ucs4_t before
shifting them to the left.
* lib/ucs4be.h (ucs4be_mbtowc): Likewise.
* lib/ucs4le.h (ucs4le_mbtowc): Likewise.
* lib/utf32.h (utf32_mbtowc): Likewise.
* lib/utf32be.h (utf32be_mbtowc): Likewise.
* lib/utf32le.h (utf32le_mbtowc): Likewise.
diff --git a/ChangeLog b/ChangeLog
index 467d642..b57b3f0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2024-10-04 Bruno Haible <bruno@clisp.org>
+
+ Fix undefined behaviour caused by shifting (unsigned char) << 24.
+ Reported by Tim Sweet <tsweet64@protonmail.com>
+ at <https://savannah.gnu.org/bugs/?66289>.
+ * lib/ucs4.h (ucs4_mbtowc): Cast 'unsigned char' values to ucs4_t before
+ shifting them to the left.
+ * lib/ucs4be.h (ucs4be_mbtowc): Likewise.
+ * lib/ucs4le.h (ucs4le_mbtowc): Likewise.
+ * lib/utf32.h (utf32_mbtowc): Likewise.
+ * lib/utf32be.h (utf32be_mbtowc): Likewise.
+ * lib/utf32le.h (utf32le_mbtowc): Likewise.
+
2024-09-26 Bruno Haible <bruno@clisp.org>
Switch to libtool 2.5.3.
diff --git a/lib/ucs4.h b/lib/ucs4.h
index e7a0c37..4ec051f 100644
--- a/lib/ucs4.h
+++ b/lib/ucs4.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1999-2001, 2008, 2011, 2016 Free Software Foundation, Inc.
+ * Copyright (C) 1999-2001, 2008, 2011, 2016, 2024 Free Software Foundation, Inc.
* This file is part of the GNU LIBICONV Library.
*
* The GNU LIBICONV Library is free software; you can redistribute it
@@ -31,8 +31,14 @@
int count = 0;
for (; n >= 4 && count <= RET_COUNT_MAX && count <= INT_MAX-4;) {
ucs4_t wc = (state
- ? s[0] + (s[1] << 8) + (s[2] << 16) + (s[3] << 24)
- : (s[0] << 24) + (s[1] << 16) + (s[2] << 8) + s[3]);
+ ? (ucs4_t) s[0]
+ + ((ucs4_t) s[1] << 8)
+ + ((ucs4_t) s[2] << 16)
+ + ((ucs4_t) s[3] << 24)
+ : ((ucs4_t) s[0] << 24)
+ + ((ucs4_t) s[1] << 16)
+ + ((ucs4_t) s[2] << 8)
+ + (ucs4_t) s[3]);
if (wc == 0x0000feff) {
} else if (wc == 0xfffe0000u) {
state ^= 1;
diff --git a/lib/ucs4be.h b/lib/ucs4be.h
index 2bbd8cf..942878d 100644
--- a/lib/ucs4be.h
+++ b/lib/ucs4be.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1999-2000, 2016 Free Software Foundation, Inc.
+ * Copyright (C) 1999-2000, 2016, 2024 Free Software Foundation, Inc.
* This file is part of the GNU LIBICONV Library.
*
* The GNU LIBICONV Library is free software; you can redistribute it
@@ -25,7 +25,10 @@
ucs4be_mbtowc (conv_t conv, ucs4_t *pwc, const unsigned char *s, size_t n)
{
if (n >= 4) {
- *pwc = (s[0] << 24) + (s[1] << 16) + (s[2] << 8) + s[3];
+ *pwc = ((ucs4_t) s[0] << 24)
+ + ((ucs4_t) s[1] << 16)
+ + ((ucs4_t) s[2] << 8)
+ + (ucs4_t) s[3];
return 4;
}
return RET_TOOFEW(0);
diff --git a/lib/ucs4le.h b/lib/ucs4le.h
index e1627c9..bd431c2 100644
--- a/lib/ucs4le.h
+++ b/lib/ucs4le.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1999-2000, 2016 Free Software Foundation, Inc.
+ * Copyright (C) 1999-2000, 2016, 2024 Free Software Foundation, Inc.
* This file is part of the GNU LIBICONV Library.
*
* The GNU LIBICONV Library is free software; you can redistribute it
@@ -25,7 +25,10 @@
ucs4le_mbtowc (conv_t conv, ucs4_t *pwc, const unsigned char *s, size_t n)
{
if (n >= 4) {
- *pwc = s[0] + (s[1] << 8) + (s[2] << 16) + (s[3] << 24);
+ *pwc = (ucs4_t) s[0]
+ + ((ucs4_t) s[1] << 8)
+ + ((ucs4_t) s[2] << 16)
+ + ((ucs4_t) s[3] << 24);
return 4;
}
return RET_TOOFEW(0);
diff --git a/lib/utf32.h b/lib/utf32.h
index 9ed5454..4c11a89 100644
--- a/lib/utf32.h
+++ b/lib/utf32.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1999-2001, 2008, 2011, 2016 Free Software Foundation, Inc.
+ * Copyright (C) 1999-2001, 2008, 2011, 2016, 2024 Free Software Foundation, Inc.
* This file is part of the GNU LIBICONV Library.
*
* The GNU LIBICONV Library is free software; you can redistribute it
@@ -37,8 +37,14 @@
int count = 0;
for (; n >= 4 && count <= RET_COUNT_MAX && count <= INT_MAX-4;) {
ucs4_t wc = (state
- ? s[0] + (s[1] << 8) + (s[2] << 16) + (s[3] << 24)
- : (s[0] << 24) + (s[1] << 16) + (s[2] << 8) + s[3]);
+ ? (ucs4_t) s[0]
+ + ((ucs4_t) s[1] << 8)
+ + ((ucs4_t) s[2] << 16)
+ + ((ucs4_t) s[3] << 24)
+ : ((ucs4_t) s[0] << 24)
+ + ((ucs4_t) s[1] << 16)
+ + ((ucs4_t) s[2] << 8)
+ + (ucs4_t) s[3]);
if (wc == 0x0000feff) {
} else if (wc == 0xfffe0000u) {
state ^= 1;
diff --git a/lib/utf32be.h b/lib/utf32be.h
index 1d33772..217706e 100644
--- a/lib/utf32be.h
+++ b/lib/utf32be.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1999-2001, 2016 Free Software Foundation, Inc.
+ * Copyright (C) 1999-2001, 2016, 2024 Free Software Foundation, Inc.
* This file is part of the GNU LIBICONV Library.
*
* The GNU LIBICONV Library is free software; you can redistribute it
@@ -27,7 +27,10 @@
utf32be_mbtowc (conv_t conv, ucs4_t *pwc, const unsigned char *s, size_t n)
{
if (n >= 4) {
- ucs4_t wc = (s[0] << 24) + (s[1] << 16) + (s[2] << 8) + s[3];
+ ucs4_t wc = ((ucs4_t) s[0] << 24)
+ + ((ucs4_t) s[1] << 16)
+ + ((ucs4_t) s[2] << 8)
+ + (ucs4_t) s[3];
if (wc < 0x110000 && !(wc >= 0xd800 && wc < 0xe000)) {
*pwc = wc;
return 4;
diff --git a/lib/utf32le.h b/lib/utf32le.h
index 41cf550..2d44526 100644
--- a/lib/utf32le.h
+++ b/lib/utf32le.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1999-2001, 2016 Free Software Foundation, Inc.
+ * Copyright (C) 1999-2001, 2016, 2024 Free Software Foundation, Inc.
* This file is part of the GNU LIBICONV Library.
*
* The GNU LIBICONV Library is free software; you can redistribute it
@@ -27,7 +27,10 @@
utf32le_mbtowc (conv_t conv, ucs4_t *pwc, const unsigned char *s, size_t n)
{
if (n >= 4) {
- ucs4_t wc = s[0] + (s[1] << 8) + (s[2] << 16) + (s[3] << 24);
+ ucs4_t wc = (ucs4_t) s[0]
+ + ((ucs4_t) s[1] << 8)
+ + ((ucs4_t) s[2] << 16)
+ + ((ucs4_t) s[3] << 24);
if (wc < 0x110000 && !(wc >= 0xd800 && wc < 0xe000)) {
*pwc = wc;
return 4;