Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F164378946
D58058.id182522.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
D58058.id182522.diff
View Options
diff --git a/lib/libc/gen/uexterr_format.c b/lib/libc/gen/uexterr_format.c
--- a/lib/libc/gen/uexterr_format.c
+++ b/lib/libc/gen/uexterr_format.c
@@ -61,6 +61,170 @@
}
}
+static void
+uexterr_format_msg(const struct uexterror *ue, char *buf, size_t bufsz)
+{
+ char fmt[32]; /* XXX: how big? */
+ const char *msg = ue->msg;
+ int nextarg = 1, psz;
+ size_t cindex, mindex;
+
+#define PCHAR(c) if (bufsz > 1) { *buf++ = c; bufsz--; } /* reserve last byte */
+#define PFMT(f, a) ({ \
+ psz = snprintf(buf, bufsz, f, a); \
+ if (psz > bufsz) \
+ return; /* Out of space */ \
+ buf += psz; \
+ bufsz -= psz; \
+ })
+#define ARG(_n) ({ \
+ int n = (_n); \
+ n == 1 ? ue->p1 : (n == 2 ? ue->p2 : (uint64_t)-1); \
+ })
+
+ while (*msg != '\0') {
+ if (*msg != '%') {
+ PCHAR(*msg++);
+ continue;
+ }
+
+ msg++;
+ /*
+ * Find the conversion, reject unsound or nonsensical
+ * ones, and then call snprintf to format the result
+ * using the correct argument type cast (potentially
+ * determined by the length modifier).
+ */
+ /* Conversion list ordred by printf(3). */
+ cindex = strcspn(msg, "bBdiouxXDOUeEfFgGaACcSspnm%");
+
+ /* Format too large, just complain */
+ if (cindex >= sizeof(fmt)) {
+ PFMT("%s", "<format-too-large>");
+ goto format_handled;
+ }
+
+ /*
+ * Note: msg points to one past the initial '%' and
+ * cindex is an index to the conversion in msg.
+ */
+ memcpy(fmt, msg - 1, cindex + 2);
+ fmt[cindex + 2] = '\0';
+
+ switch (msg[cindex]) {
+ case 'b':
+ case 'B':
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ /*
+ * Treat longs as 64-bit in 32-bit ABIs because
+ * that's what the kernel will do (unless we're
+ * in some 32-bit only code).
+ *
+ * This isn't quite right for signed values
+ * from 32-bit kernels unless the programmer
+ * took care to sign extend them, but 32-bit
+ * kernels aren't long for the world...
+ */
+
+ /* Find the first length modifier */
+ mindex = strcspn(fmt, "hjltwz");
+
+ switch (fmt[mindex]) {
+ case '\0': /* No length modifier */
+ case 'h': /* h or hh modifier */
+ PFMT(fmt, (unsigned)ARG(nextarg));
+ break;
+
+ case 'l':
+#ifdef __ILP32__
+ if (fmt[mindex + 1] != 'l')
+ fmt[mindex] = 'j';
+#endif
+ PFMT(fmt, (uintmax_t)ARG(nextarg));
+ break;;
+
+ case 't':
+ case 'z':
+#ifdef __ILP32__
+ fmt[mindex] = 'j';
+ /* FALLTHROUGH */
+#endif
+ case 'j':
+ PFMT(fmt, (uintmax_t)ARG(nextarg));
+ break;;
+
+ case 'w':
+ if (fmt[mindex + 1] == 'f')
+ mindex++;
+ if (fmt[mindex + 1] == '6' && fmt[mindex + 2] == '4')
+ PFMT(fmt, (uint64_t)ARG(nextarg));
+ else
+ PFMT(fmt, (unsigned)ARG(nextarg));
+ break;
+ }
+ break;
+
+ case 'C':
+ case 'c':
+ PFMT(fmt, (unsigned)ARG(nextarg));
+ break;
+
+ case 'p':
+ PFMT(fmt, (void *)ARG(nextarg));
+ break;
+
+ case '%':
+ PCHAR('%');
+ break;
+
+ /*
+ * %n is a write-what-where gadget
+ */
+ case 'n':
+ PFMT("<illegal-format>:%s", fmt);
+ break;
+
+ /*
+ * Things we don't support
+ */
+ /* Incomplete expression */
+ case '\0':
+ /* Obsolete formats */
+ case 'D':
+ case 'O':
+ case 'U':
+ /* Floating point */
+ case 'f':
+ case 'F':
+ case 'g':
+ case 'G':
+ case 'a':
+ case 'A':
+ /* String */
+ case 'S':
+ case 's':
+ /* errno */
+ case 'm':
+ /* strcspn list out of sync with this switch. */
+ default:
+ PFMT("<unsupported-format>:%s", fmt);
+ break;
+ }
+format_handled:
+ nextarg++;
+ msg += cindex + 1;
+ }
+ *buf = '\0';
+#undef PCHAR
+#undef PFMT
+#undef ARG
+}
+
int
__uexterr_format(const struct uexterror *ue, char *buf, size_t bufsz)
{
@@ -76,8 +240,7 @@
has_msg = ue->msg[0] != '\0';
if (has_msg) {
- snprintf(buf, bufsz, ue->msg, (uintmax_t)ue->p1,
- (uintmax_t)ue->p2);
+ uexterr_format_msg(ue, buf, bufsz);
} else {
strlcpy(buf, "", bufsz);
}
diff --git a/share/man/man9/exterror.9 b/share/man/man9/exterror.9
--- a/share/man/man9/exterror.9
+++ b/share/man/man9/exterror.9
@@ -6,7 +6,7 @@
.\" Konstantin Belousov <kib@FreeBSD.org> under sponsorship
.\" from the FreeBSD Foundation.
.\"
-.Dd July 21, 2026
+.Dd July 22, 2026
.Dt EXTERROR 9
.Os
.Sh NAME
@@ -94,12 +94,15 @@
specifiers to insert the optional argument values in the
user output, which is done in userspace.
.Pp
-The format specifier must be for an integer type, and include the
-.Dq j
-format modifier to accept only the types
-.Vt intmax_t
-or
-.Vt uintmax_t .
+The format specifier must be for an character, integer, or pointer type.
+Note that userspace printing assumes all
+.Dt long Ns -derived
+types such as
+.Dt size_t
+are 64-bit and prints them accordingly.
+Signed integer types should thus be cast to
+.Dt int64_t
+or similar to insure proper sign extension.
.El
.Pp
The strings passed as the second argument are only retained
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Aug 1, 7:48 AM (13 h, 13 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35816826
Default Alt Text
D58058.id182522.diff (4 KB)
Attached To
Mode
D58058: exterr: relax format restrictions
Attached
Detach File
Event Timeline
Log In to Comment