aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@redhat.com>2025-08-23 01:02:10 +0100
committerMaciej W. Rozycki <macro@redhat.com>2025-08-23 01:02:46 +0100
commitaa4dbb2eebf7b047689f5fbad7fe58ae5434a72c (patch)
tree154fef3601aaab1a2786860a8c569759ea29db28
parenta1e5ee13ab9b786f291c8f55f93db11be1ae286c (diff)
downloadglibc-aa4dbb2eebf7b047689f5fbad7fe58ae5434a72c.zip
glibc-aa4dbb2eebf7b047689f5fbad7fe58ae5434a72c.tar.gz
glibc-aa4dbb2eebf7b047689f5fbad7fe58ae5434a72c.tar.bz2
stdio-common: Convert macros across scanf input specifier tests
Convert 'compare_real', 'read_real', and 'verify_input' macros to functions so as to improve readability and avoid pitfalls. Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
-rw-r--r--stdio-common/tst-scanf-format-character.h133
-rw-r--r--stdio-common/tst-scanf-format-integer.h55
-rw-r--r--stdio-common/tst-scanf-format-real.h601
-rw-r--r--stdio-common/tst-scanf-format-skeleton.c5
-rw-r--r--sysdeps/ieee754/ldbl-96/tst-scanf-format-skeleton-ldouble.c18
5 files changed, 412 insertions, 400 deletions
diff --git a/stdio-common/tst-scanf-format-character.h b/stdio-common/tst-scanf-format-character.h
index b68a5e1..170218f 100644
--- a/stdio-common/tst-scanf-format-character.h
+++ b/stdio-common/tst-scanf-format-character.h
@@ -16,6 +16,7 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
+#include <stdbool.h>
#include <string.h>
#include <support/next_to_fault.h>
@@ -62,69 +63,69 @@ do \
} \
while (0)
-#define verify_input(f, val, count, errp) \
-({ \
- __label__ out, skip; \
- bool match = true; \
- int err = 0; \
- size_t i; \
- int ch; \
- \
- for (i = 0; i < count; i++) \
- { \
- ch = read_input (); \
- if (ch < 0) \
- { \
- err = ch; \
- goto out; \
- } \
- if (ch == ':' && val[i] == '\0' && f == 's') \
- goto skip; \
- if (ch != val[i]) \
- { \
- match = false; \
- goto out; \
- } \
- } \
- ch = read_input (); \
- if (ch < 0) \
- { \
- err = ch; \
- goto out; \
- } \
- \
-skip: \
- if (f != 'c' && val[i++] != '\0') \
- { \
- err = OUTPUT_TERM; \
- goto out; \
- } \
- if (val[i] != '\xa5') \
- { \
- err = OUTPUT_OVERRUN; \
- goto out; \
- } \
- \
- while (ch != ':') \
- { \
- ch = read_input (); \
- if (ch < 0) \
- { \
- err = ch; \
- goto out; \
- } \
- match = false; \
- } \
- \
-out: \
- if (err || !match) \
- { \
- printf ("error: %s:%d: input buffer: `", __FILE__, __LINE__); \
- for (size_t j = 0; j <= i; j++) \
- printf ("%c", val[j]); \
- printf ("'\n"); \
- } \
- \
- *errp = err; \
- match; \
-})
+static bool
+verify_input (char f, type_t val, long long count, int *errp)
+{
+ bool match = true;
+ int err = 0;
+ size_t i;
+ int ch;
+
+ for (i = 0; i < count; i++)
+ {
+ ch = read_input ();
+ if (ch < 0)
+ {
+ err = ch;
+ goto out;
+ }
+ if (ch == ':' && val[i] == '\0' && f == 's')
+ goto skip;
+ if (ch != val[i])
+ {
+ match = false;
+ goto out;
+ }
+ }
+ ch = read_input ();
+ if (ch < 0)
+ {
+ err = ch;
+ goto out;
+ }
+
+skip:
+ if (f != 'c' && val[i++] != '\0')
+ {
+ err = OUTPUT_TERM;
+ goto out;
+ }
+ if (val[i] != '\xa5')
+ {
+ err = OUTPUT_OVERRUN;
+ goto out;
+ }
+
+ while (ch != ':')
+ {
+ ch = read_input ();
+ if (ch < 0)
+ {
+ err = ch;
+ goto out;
+ }
+ match = false;
+ }
+
+out:
+ if (err || !match)
+ {
+ printf ("error: %s:%d: input buffer: `", __FILE__, __LINE__);
+ for (size_t j = 0; j <= i; j++)
+ printf ("%c", val[j]);
+ printf ("'\n");
+ }
+
+ *errp = err;
+ return match;
+}
diff --git a/stdio-common/tst-scanf-format-integer.h b/stdio-common/tst-scanf-format-integer.h
index 28f91a4..3d5a12a 100644
--- a/stdio-common/tst-scanf-format-integer.h
+++ b/stdio-common/tst-scanf-format-integer.h
@@ -16,36 +16,45 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
+#include <stdbool.h>
#include <string.h>
/* Reference data is a signed decimal integer constant to compare against
arithmetically. */
+/* Tweak our environment according to any TYPE_T_UNSIGNED_P setting
+ supplied by the individual test case. */
+#ifdef TYPE_T_UNSIGNED_P
+# define UNSIGNED unsigned
+#else
+# define UNSIGNED
+#endif
+
#define pointer_to_value(val) (&(val))
#define initialize_value(val) \
memset (&val, 0xa5, sizeof (val))
-#define verify_input(f, val, count, errp) \
-({ \
- __label__ out; \
- bool match = true; \
- int err; \
- \
- UNSIGNED long long v = read_integer (&err); \
- if (err < 0) \
- goto out; \
- match = val == v; \
- \
-out: \
- if (err || !match) \
- { \
- printf ("error: %s:%d: input: %016llx\n", \
- __FILE__, __LINE__, (long long) val); \
- printf ("error: %s:%d: value: %016llx\n", \
- __FILE__, __LINE__, v); \
- } \
- \
- *errp = err; \
- match; \
-})
+static bool
+verify_input (char f, type_t val, long long count, int *errp)
+{
+ bool match = true;
+ int err;
+
+ UNSIGNED long long v = read_integer (&err);
+ if (err < 0)
+ goto out;
+ match = val == v;
+
+out:
+ if (err || !match)
+ {
+ printf ("error: %s:%d: input: %016llx\n",
+ __FILE__, __LINE__, (long long) val);
+ printf ("error: %s:%d: value: %016llx\n",
+ __FILE__, __LINE__, v);
+ }
+
+ *errp = err;
+ return match;
+}
diff --git a/stdio-common/tst-scanf-format-real.h b/stdio-common/tst-scanf-format-real.h
index 93de3ca..a4e5109 100644
--- a/stdio-common/tst-scanf-format-real.h
+++ b/stdio-common/tst-scanf-format-real.h
@@ -66,301 +66,306 @@
#define initialize_value(val) \
memset (&val, 0xa5, sizeof (val))
-#define compare_real(x, y) \
- (memcmp (&(x), &(y), sizeof (y)) == 0)
-
-#define verify_input(f, val, count, errp) \
-({ \
- __label__ out; \
- bool match = true; \
- int errx = 0; \
- type_t v; \
- \
- initialize_value (v); \
- /* Make sure it's been committed. */ \
- __asm__ ("" : : : "memory"); \
- \
- v = read_real (&errx); \
- if (errx < 0) \
- goto out; \
- \
- match = compare_real (val, v); \
- if (!match) \
- { \
- union \
- { \
- type_t v; \
- unsigned char x[sizeof (type_t)]; \
- } \
- uv = { .v = v }, ui = { .v = val }; \
- \
- printf ("error: %s:%d: input buffer: `", __FILE__, __LINE__); \
- for (size_t j = 0; j < sizeof (ui.x); j++) \
- printf ("%02hhx", ui.x[j]); \
- printf ("'\n"); \
- printf ("error: %s:%d: value buffer: `", __FILE__, __LINE__); \
- for (size_t j = 0; j < sizeof (uv.x); j++) \
- printf ("%02hhx", uv.x[j]); \
- printf ("'\n"); \
- } \
- \
-out: \
- *errp = errx; \
- match; \
-})
-
-#define read_real(errp) \
-({ \
- __label__ out; \
- bool m = false; \
- int err = 0; \
- type_t v; \
- int ch; \
- \
- ch = read_input (); \
- if (ch == '-' || ch == '+') \
- { \
- m = ch == '-'; \
- ch = read_input (); \
- } \
- \
- switch (ch) \
- { \
- case '0': \
- break; \
- case 'I': \
- case 'i': \
- { \
- static const char unf[] = { 'N', 'F' }; \
- static const char lnf[] = { 'n', 'f' }; \
- size_t i; \
- \
- for (i = 0; i < sizeof (unf); i++) \
- { \
- ch = read_input (); \
- if (ch != unf[i] && ch != lnf[i]) \
- { \
- err = ch < 0 ? ch : INPUT_FORMAT; \
- v = NAN; \
- goto out; \
- } \
- } \
- \
- ch = read_input (); \
- if (ch == ':') \
- { \
- v = m ? -INFINITY : +INFINITY; \
- goto out; \
- } \
- \
- static const char uinity[] = { 'I', 'N', 'I', 'T', 'Y' }; \
- static const char linity[] = { 'i', 'n', 'i', 't', 'y' }; \
- \
- for (i = 0; i < sizeof (uinity); i++) \
- { \
- if (ch != uinity[i] && ch != linity[i]) \
- { \
- err = ch < 0 ? ch : INPUT_FORMAT; \
- v = NAN; \
- goto out; \
- } \
- ch = read_input (); \
- } \
- if (ch == ':') \
- { \
- v = m ? -INFINITY : +INFINITY; \
- goto out; \
- } \
- } \
- err = ch < 0 ? ch : INPUT_FORMAT; \
- v = NAN; \
- goto out; \
- \
- case 'N': \
- case 'n': \
- { \
- static const char uan[] = { 'A', 'N' }; \
- static const char lan[] = { 'a', 'n' }; \
- size_t i; \
- \
- for (i = 0; i < sizeof (uan); i++) \
- { \
- ch = read_input (); \
- if (ch != uan[i] && ch != lan[i]) \
- { \
- err = ch < 0 ? ch : INPUT_FORMAT; \
- v = NAN; \
- goto out; \
- } \
- } \
- \
- ch = read_input (); \
- if (ch == ':') \
- { \
- v = m ? -nan (v, ".") : nan (v, "."); \
- goto out; \
- } \
- \
- if (ch == '(') \
- { \
- size_t seq_size = 0; \
- char *seq = NULL; \
- i = 0; \
- while (1) \
- { \
- if (i == seq_size) \
- { \
- seq_size += SIZE_CHUNK; \
- seq = xrealloc (seq, seq_size); \
- } \
- ch = read_input (); \
- if (ch == ')') \
- break; \
- if (ch != '_' && !isdigit (ch) \
- && !(ch >= 'A' && ch <= 'Z') \
- && !(ch >= 'a' && ch <= 'z')) \
- { \
- free (seq); \
- err = ch < 0 ? ch : INPUT_FORMAT; \
- v = NAN; \
- goto out; \
- } \
- seq[i++] = ch; \
- } \
- seq[i] = '\0'; \
- \
- ch = read_input (); \
- if (ch == ':') \
- { \
- v = m ? -nan (v, seq) : nan (v, seq); \
- free (seq); \
- goto out; \
- } \
- free (seq); \
- } \
- } \
- err = ch < 0 ? ch : INPUT_FORMAT; \
- v = NAN; \
- goto out; \
- \
- default: \
- err = ch < 0 ? ch : INPUT_FORMAT; \
- v = NAN; \
- goto out; \
- } \
- \
- ch = read_input (); \
- if (ch != 'X' && ch != 'x') \
- { \
- err = ch < 0 ? ch : INPUT_FORMAT; \
- v = NAN; \
- goto out; \
- } \
- \
- type_t f = m ? -1.0 : 1.0; \
- v = m ? -0.0 : 0.0; \
- int i = 0; \
- do \
- { \
- int d = 0; \
- \
- ch = read_input (); \
- \
- if (i == 1) \
- switch (ch) \
- { \
- case '.': \
- i++; \
- continue; \
- \
- case ':': \
- case 'P': \
- case 'p': \
- break; \
- \
- default: \
- err = ch < 0 ? ch : INPUT_FORMAT; \
- v = NAN; \
- goto out; \
- } \
- \
- switch (ch) \
- { \
- case '0': \
- case '1': \
- case '2': \
- case '3': \
- case '4': \
- case '5': \
- case '6': \
- case '7': \
- case '8': \
- case '9': \
- d = ch - '0'; \
- break; \
- \
- case 'A': \
- case 'B': \
- case 'C': \
- case 'D': \
- case 'E': \
- case 'F': \
- d = ch - 'A' + 10; \
- break; \
- \
- case 'a': \
- case 'b': \
- case 'c': \
- case 'd': \
- case 'e': \
- case 'f': \
- d = ch - 'a' + 10; \
- break; \
- \
- case ':': \
- case 'P': \
- case 'p': \
- if (i == 0) \
- { \
- err = INPUT_FORMAT; \
- v = NAN; \
- goto out; \
- } \
- break; \
- \
- default: \
- err = ch < 0 ? ch : INPUT_FORMAT; \
- v = NAN; \
- goto out; \
- } \
- \
- v += f * d; \
- f /= 16.0l; \
- i++; \
- } \
- while (ch != ':' && ch != 'P' && ch != 'p'); \
- \
- long long exp = 0; \
- if (ch == 'P' || ch == 'p') \
- { \
- exp = read_integer (&err); \
- if (err) \
- { \
- v = NAN; \
- goto out; \
- } \
- } \
- \
- errno = 0; \
- v = ldexp (v, exp); \
- if ((v == HUGE_VALL || v == -HUGE_VALL) && errno != 0) \
- { \
- err = INPUT_OVERFLOW; \
- v = NAN; \
- goto out; \
- } \
- \
-out: \
- *errp = err; \
- v; \
-})
+#ifndef compare_real
+static bool
+compare_real (type_t x, type_t y)
+{
+ return memcmp (&x, &y, sizeof (y)) == 0;
+}
+#endif
+
+static type_t
+read_real (int *errp)
+{
+ bool m = false;
+ int err = 0;
+ type_t v;
+ int ch;
+
+ ch = read_input ();
+ if (ch == '-' || ch == '+')
+ {
+ m = ch == '-';
+ ch = read_input ();
+ }
+
+ switch (ch)
+ {
+ case '0':
+ break;
+ case 'I':
+ case 'i':
+ {
+ static const char unf[] = { 'N', 'F' };
+ static const char lnf[] = { 'n', 'f' };
+ size_t i;
+
+ for (i = 0; i < sizeof (unf); i++)
+ {
+ ch = read_input ();
+ if (ch != unf[i] && ch != lnf[i])
+ {
+ err = ch < 0 ? ch : INPUT_FORMAT;
+ v = NAN;
+ goto out;
+ }
+ }
+
+ ch = read_input ();
+ if (ch == ':')
+ {
+ v = m ? -INFINITY : +INFINITY;
+ goto out;
+ }
+
+ static const char uinity[] = { 'I', 'N', 'I', 'T', 'Y' };
+ static const char linity[] = { 'i', 'n', 'i', 't', 'y' };
+
+ for (i = 0; i < sizeof (uinity); i++)
+ {
+ if (ch != uinity[i] && ch != linity[i])
+ {
+ err = ch < 0 ? ch : INPUT_FORMAT;
+ v = NAN;
+ goto out;
+ }
+ ch = read_input ();
+ }
+ if (ch == ':')
+ {
+ v = m ? -INFINITY : +INFINITY;
+ goto out;
+ }
+ }
+ err = ch < 0 ? ch : INPUT_FORMAT;
+ v = NAN;
+ goto out;
+
+ case 'N':
+ case 'n':
+ {
+ static const char uan[] = { 'A', 'N' };
+ static const char lan[] = { 'a', 'n' };
+ size_t i;
+
+ for (i = 0; i < sizeof (uan); i++)
+ {
+ ch = read_input ();
+ if (ch != uan[i] && ch != lan[i])
+ {
+ err = ch < 0 ? ch : INPUT_FORMAT;
+ v = NAN;
+ goto out;
+ }
+ }
+
+ ch = read_input ();
+ if (ch == ':')
+ {
+ v = m ? -nan (v, ".") : nan (v, ".");
+ goto out;
+ }
+
+ if (ch == '(')
+ {
+ size_t seq_size = 0;
+ char *seq = NULL;
+ i = 0;
+ while (1)
+ {
+ if (i == seq_size)
+ {
+ seq_size += SIZE_CHUNK;
+ seq = xrealloc (seq, seq_size);
+ }
+ ch = read_input ();
+ if (ch == ')')
+ break;
+ if (ch != '_' && !isdigit (ch)
+ && !(ch >= 'A' && ch <= 'Z')
+ && !(ch >= 'a' && ch <= 'z'))
+ {
+ free (seq);
+ err = ch < 0 ? ch : INPUT_FORMAT;
+ v = NAN;
+ goto out;
+ }
+ seq[i++] = ch;
+ }
+ seq[i] = '\0';
+
+ ch = read_input ();
+ if (ch == ':')
+ {
+ v = m ? -nan (v, seq) : nan (v, seq);
+ free (seq);
+ goto out;
+ }
+ free (seq);
+ }
+ }
+ err = ch < 0 ? ch : INPUT_FORMAT;
+ v = NAN;
+ goto out;
+
+ default:
+ err = ch < 0 ? ch : INPUT_FORMAT;
+ v = NAN;
+ goto out;
+ }
+
+ ch = read_input ();
+ if (ch != 'X' && ch != 'x')
+ {
+ err = ch < 0 ? ch : INPUT_FORMAT;
+ v = NAN;
+ goto out;
+ }
+
+ type_t f = m ? -1.0 : 1.0;
+ v = m ? -0.0 : 0.0;
+ int i = 0;
+ do
+ {
+ int d = 0;
+
+ ch = read_input ();
+
+ if (i == 1)
+ switch (ch)
+ {
+ case '.':
+ i++;
+ continue;
+
+ case ':':
+ case 'P':
+ case 'p':
+ break;
+
+ default:
+ err = ch < 0 ? ch : INPUT_FORMAT;
+ v = NAN;
+ goto out;
+ }
+
+ switch (ch)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ d = ch - '0';
+ break;
+
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ d = ch - 'A' + 10;
+ break;
+
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ d = ch - 'a' + 10;
+ break;
+
+ case ':':
+ case 'P':
+ case 'p':
+ if (i == 0)
+ {
+ err = INPUT_FORMAT;
+ v = NAN;
+ goto out;
+ }
+ break;
+
+ default:
+ err = ch < 0 ? ch : INPUT_FORMAT;
+ v = NAN;
+ goto out;
+ }
+
+ v += f * d;
+ f /= 16.0l;
+ i++;
+ }
+ while (ch != ':' && ch != 'P' && ch != 'p');
+
+ long long exp = 0;
+ if (ch == 'P' || ch == 'p')
+ {
+ exp = read_integer (&err);
+ if (err)
+ {
+ v = NAN;
+ goto out;
+ }
+ }
+
+ errno = 0;
+ v = ldexp (v, exp);
+ if ((v == HUGE_VALL || v == -HUGE_VALL) && errno != 0)
+ {
+ err = INPUT_OVERFLOW;
+ v = NAN;
+ goto out;
+ }
+
+out:
+ *errp = err;
+ return v;
+}
+
+static bool
+verify_input (char f, type_t val, long long count, int *errp)
+{
+ bool match = true;
+ int err = 0;
+ type_t v;
+
+ initialize_value (v);
+ /* Make sure it's been committed. */
+ __asm__ ("" : : : "memory");
+
+ v = read_real (&err);
+ if (err < 0)
+ goto out;
+
+ match = compare_real (val, v);
+ if (!match)
+ {
+ union
+ {
+ type_t v;
+ unsigned char x[sizeof (type_t)];
+ }
+ uv = { .v = v }, ui = { .v = val };
+
+ printf ("error: %s:%d: input buffer: `", __FILE__, __LINE__);
+ for (size_t j = 0; j < sizeof (ui.x); j++)
+ printf ("%02hhx", ui.x[j]);
+ printf ("'\n");
+ printf ("error: %s:%d: value buffer: `", __FILE__, __LINE__);
+ for (size_t j = 0; j < sizeof (uv.x); j++)
+ printf ("%02hhx", uv.x[j]);
+ printf ("'\n");
+ }
+
+out:
+ *errp = err;
+ return match;
+}
diff --git a/stdio-common/tst-scanf-format-skeleton.c b/stdio-common/tst-scanf-format-skeleton.c
index bf1129b..450e340 100644
--- a/stdio-common/tst-scanf-format-skeleton.c
+++ b/stdio-common/tst-scanf-format-skeleton.c
@@ -60,11 +60,6 @@
#ifndef TYPE_T_UNSIGNED_P
# define TYPE_T_UNSIGNED_P 0
#endif
-#if TYPE_T_UNSIGNED_P
-# define UNSIGNED unsigned
-#else
-# define UNSIGNED
-#endif
/* Read and return a single character from standard input, returning
end-of-file or error status indication where applicable. */
diff --git a/sysdeps/ieee754/ldbl-96/tst-scanf-format-skeleton-ldouble.c b/sysdeps/ieee754/ldbl-96/tst-scanf-format-skeleton-ldouble.c
index 79903cc..a2f598e 100644
--- a/sysdeps/ieee754/ldbl-96/tst-scanf-format-skeleton-ldouble.c
+++ b/sysdeps/ieee754/ldbl-96/tst-scanf-format-skeleton-ldouble.c
@@ -17,19 +17,21 @@
<https://www.gnu.org/licenses/>. */
#include <math_ldbl.h>
+#include <stdbool.h>
#include <stdint.h>
#include <string.h>
typedef long double type_t;
-#include "tst-scanf-format-real.h"
+static bool
+compare_real (type_t x, type_t y)
+{
+ ieee_long_double_shape_type ux = { .value = x }, uy = { .value = y };
-#undef compare_real
-#define compare_real(x, y) \
-({ \
- ieee_long_double_shape_type ux = { .value = x }, uy = { .value = y }; \
- (ux.parts.lsw == uy.parts.lsw && ux.parts.msw == uy.parts.msw \
- && ux.parts.sign_exponent == uy.parts.sign_exponent); \
-})
+ return (ux.parts.lsw == uy.parts.lsw && ux.parts.msw == uy.parts.msw
+ && ux.parts.sign_exponent == uy.parts.sign_exponent);
+}
+#define compare_real compare_real
+#include "tst-scanf-format-real.h"
#include "tst-scanf-format-skeleton.c"