Dmitri A. Sergatskov wrote:
> octave:1> s = char([72 101 108 108 111 44 32 228 189 160 229 165 189]);
> octave:2> save -mat test.mat s
> ../../libgnu/unistr/u8-to-u16.c:80:34: runtime error: applying zero offset
> to null pointer
> SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior
> ../../libgnu/unistr/u8-to-u16.c:80:34
You can temporarily apply a workaround like the attached patch,
through the gnulib-tool --local-dir option. [1]
Bruno
[1] https://www.gnu.org/software/gnulib/manual/html_node/Extending-Gnulib.html
diff --git a/lib/unistr/u16-to-u8.c b/lib/unistr/u16-to-u8.c
index d9f092c48c..fe8b7228a1 100644
--- a/lib/unistr/u16-to-u8.c
+++ b/lib/unistr/u16-to-u8.c
@@ -36,10 +36,23 @@
#include <stdlib.h>
#include <string.h>
+/* END_OF_ARRAY(array,n) returns a pointer past the last element of the array
+ ARRAY that has N elements.
+ For clang, it uses a conditional expression that avoids adding 0 to a null
+ pointer, which is undefined according to ISO C 23 ?? 6.5.6.(9) and which
+ triggers an error in clang's undefined-behaviour sanitizer. When no
+ sanitizer is in effect, clang optimizes this conditional expression to
+ exactly the same code. */
+#if defined __clang__
+# define END_OF_ARRAY(array,n) ((n) ? (array) + (n) : (array))
+#else
+# define END_OF_ARRAY(array,n) ((array) + (n))
+#endif
+
DST_UNIT *
FUNC (const SRC_UNIT *s, size_t n, DST_UNIT *resultbuf, size_t *lengthp)
{
- const SRC_UNIT *s_end = s + n;
+ const SRC_UNIT *s_end = END_OF_ARRAY (s, n);
/* Output string accumulator. */
DST_UNIT *result;
size_t allocated;
@@ -77,7 +90,7 @@ FUNC (const SRC_UNIT *s, size_t n, DST_UNIT *resultbuf, size_t *lengthp)
s += count;
/* Store it in the output string. */
- count = u8_uctomb (result + length, uc, allocated - length);
+ count = u8_uctomb (END_OF_ARRAY (result, length), uc, allocated - length);
if (count == -1)
{
if (!(result == resultbuf || result == NULL))
@@ -109,7 +122,7 @@ FUNC (const SRC_UNIT *s, size_t n, DST_UNIT *resultbuf, size_t *lengthp)
memcpy ((char *) memory, (char *) result,
length * sizeof (DST_UNIT));
result = memory;
- count = u8_uctomb (result + length, uc, allocated - length);
+ count = u8_uctomb (END_OF_ARRAY (result, length), uc, allocated - length);
if (count < 0)
abort ();
}
diff --git a/lib/unistr/u32-to-u8.c b/lib/unistr/u32-to-u8.c
index 0c4f0bc3cc..9741058440 100644
--- a/lib/unistr/u32-to-u8.c
+++ b/lib/unistr/u32-to-u8.c
@@ -28,10 +28,23 @@
#include <stdlib.h>
#include <string.h>
+/* END_OF_ARRAY(array,n) returns a pointer past the last element of the array
+ ARRAY that has N elements.
+ For clang, it uses a conditional expression that avoids adding 0 to a null
+ pointer, which is undefined according to ISO C 23 ?? 6.5.6.(9) and which
+ triggers an error in clang's undefined-behaviour sanitizer. When no
+ sanitizer is in effect, clang optimizes this conditional expression to
+ exactly the same code. */
+#if defined __clang__
+# define END_OF_ARRAY(array,n) ((n) ? (array) + (n) : (array))
+#else
+# define END_OF_ARRAY(array,n) ((array) + (n))
+#endif
+
DST_UNIT *
FUNC (const SRC_UNIT *s, size_t n, DST_UNIT *resultbuf, size_t *lengthp)
{
- const SRC_UNIT *s_end = s + n;
+ const SRC_UNIT *s_end = END_OF_ARRAY (s, n);
/* Output string accumulator. */
DST_UNIT *result;
size_t allocated;
@@ -63,7 +76,7 @@ FUNC (const SRC_UNIT *s, size_t n, DST_UNIT *resultbuf, size_t *lengthp)
u8_uctomb will verify uc anyway. */
/* Store it in the output string. */
- count = u8_uctomb (result + length, uc, allocated - length);
+ count = u8_uctomb (END_OF_ARRAY (result, length), uc, allocated - length);
if (count == -1)
{
if (!(result == resultbuf || result == NULL))
@@ -95,7 +108,7 @@ FUNC (const SRC_UNIT *s, size_t n, DST_UNIT *resultbuf, size_t *lengthp)
memcpy ((char *) memory, (char *) result,
length * sizeof (DST_UNIT));
result = memory;
- count = u8_uctomb (result + length, uc, allocated - length);
+ count = u8_uctomb (END_OF_ARRAY (result, length), uc, allocated - length);
if (count < 0)
abort ();
}