mailing list of musl libc
 help / color / mirror / code / Atom feed
From: Jens Gustedt <Jens.Gustedt@inria.fr>
To: musl@lists.openwall.com
Subject: [musl] [C23 new stdlib 3/3] C23: implement the new strfrom[dfl] functions
Date: Wed, 31 May 2023 12:05:17 +0200	[thread overview]
Message-ID: <f68175347554b6db5f38c4de78c5682e01ab3159.1685527375.git.Jens.Gustedt@inria.fr> (raw)
In-Reply-To: <cover.1685527375.git.Jens.Gustedt@inria.fr>

These names had been reserved in C17, so it is not necessary to hide
these function in conditionals.

With the exception of strfroml, the implementation is direct because
format strings can be forwarded to snprintf (there is no length
modifier for float or double). For strfroml the format has to be
assembled from the received format to interlace "L".

Because compilers will probably not check their formats for these new
functions for some generations, in general this would be passing an
unsanitized dynamic format string into snprintf. So we do a relatively
simple check before hand, in particular to inhibit appearance of other
"%" specifiers in the string that could be used for attacks.
---
 include/stdlib.h      |  4 ++++
 src/stdlib/strfromd.c | 44 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+)
 create mode 100644 src/stdlib/strfromd.c

diff --git a/include/stdlib.h b/include/stdlib.h
index 10bdf7f8..72522cd6 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -29,6 +29,10 @@ float strtof (const char *__restrict, char **__restrict);
 double strtod (const char *__restrict, char **__restrict);
 long double strtold (const char *__restrict, char **__restrict);
 
+int strfromd(char *restrict, size_t, const char *restrict, double);
+int strfromf(char *restrict, size_t, const char *restrict, float);
+int strfroml(char *restrict, size_t, const char *restrict, long double);
+
 long strtol (const char *__restrict, char **__restrict, int);
 unsigned long strtoul (const char *__restrict, char **__restrict, int);
 long long strtoll (const char *__restrict, char **__restrict, int);
diff --git a/src/stdlib/strfromd.c b/src/stdlib/strfromd.c
new file mode 100644
index 00000000..f5b92956
--- /dev/null
+++ b/src/stdlib/strfromd.c
@@ -0,0 +1,44 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+
+static size_t sanitize(const char*format) {
+	size_t slen = format ? strlen(format) : 0;
+	if (format[0] != '%'
+		|| (slen > 2 && format[1] != '.')
+		|| strchr(&format[1], '%')
+		|| (strspn(&format[slen-1], "aAeEfFgG") != 1)) return 0;
+	else return slen;
+}
+
+int strfromd(char *restrict s, size_t n, const char *restrict format, double fp) {
+	return sanitize(format) ? snprintf(s, n, format, fp) : -1;
+}
+
+int strfromf(char *restrict s, size_t n, const char *restrict format, float fp) {
+	return sanitize(format) ? snprintf(s, n, format, fp) : -1;
+}
+
+int strfroml(char *restrict s, size_t n, const char *restrict format, long double fp) {
+	enum { max_len = 1+sizeof "%.18446744073709551615Lg", };
+	char ff[max_len];
+	size_t slen = sanitize(format);
+	if (!slen) return -1;
+	if (slen < max_len-2) {
+		memcpy(ff, format, slen-1);
+		ff[slen-1] = 'L';
+		ff[slen] = format[slen-1];
+		ff[slen+1] = 0;
+	} else {
+		// If the precision is unreasonably long, fallback to
+		// strtoull to parse it, and squeeze it into a
+		// reasonable length, if possible.
+		int eback = errno;
+		unsigned long long prec = strtoull(format+2, NULL, 10);
+		if (prec == ULLONG_MAX) errno = eback;
+		snprintf(ff, max_len, "%%.%lldL%c", prec, format[slen-1]);
+	}
+	return snprintf(s, n, ff, fp);
+}
-- 
2.34.1


      parent reply	other threads:[~2023-05-31 10:06 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-31 10:05 [musl] [C23 new stdlib 0/3] Jens Gustedt
2023-05-31 10:05 ` [musl] [C23 new stdlib 1/3] C23: add the new interfaces free_sized and free_aligned_sized for stdlib.h Jens Gustedt
2023-05-31 10:05 ` [musl] [C23 new stdlib 2/3] C23: add the memalignment function Jens Gustedt
2023-05-31 10:05 ` Jens Gustedt [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=f68175347554b6db5f38c4de78c5682e01ab3159.1685527375.git.Jens.Gustedt@inria.fr \
    --to=jens.gustedt@inria.fr \
    --cc=musl@lists.openwall.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).