summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4>2018-07-30 13:34:14 +0000
committervlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4>2018-07-30 13:34:14 +0000
commit461b550532a825c64e1eb4a9854f616f117512c3 (patch)
tree5e4524b4a2bde8b7ddbba52573b104b816bcf375
parent12fbad8c30256b0b7a9681f0e7a63cf0ca690d1f (diff)
downloadmpfr-461b550532a825c64e1eb4a9854f616f117512c3.tar.gz
[src/vasprintf.c] Bug fix: in case of some errors (via "goto error;"),
va_end wasn't called, yielding undefined behavior. (reverse-merged r12965; merged changesets r12955,12957 from the trunk) git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/branches/4.0@12966 280ebfd0-de03-0410-8827-d642c229c3f4
-rw-r--r--src/vasprintf.c73
1 files changed, 41 insertions, 32 deletions
diff --git a/src/vasprintf.c b/src/vasprintf.c
index 19d9998bc..99c8780b7 100644
--- a/src/vasprintf.c
+++ b/src/vasprintf.c
@@ -33,11 +33,22 @@ http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
So, for the time being, we return a negative value and set the erange
flag, and set errno to EOVERFLOW in POSIX system. */
-/* Note: Due to limitations from the C standard and GMP, if
- size_t < unsigned int (which is allowed by the C standard but unlikely
- to occur on any platform), the behavior is undefined for output that
- would reach SIZE_MAX = (size_t) -1 (if the result cannot be delivered,
- there should be an assertion failure, but this could not be tested). */
+/* Notes about limitations on some platforms:
+
+ Due to limitations from the C standard and GMP, if size_t < unsigned int
+ (which is allowed by the C standard but unlikely to occur on any
+ platform), the behavior is undefined for output that would reach
+ SIZE_MAX = (size_t) -1 (if the result cannot be delivered, there should
+ be an assertion failure, but this could not be tested).
+
+ The stdarg(3) Linux man page says:
+ On some systems, va_end contains a closing '}' matching a '{' in
+ va_start, so that both macros must occur in the same function,
+ and in a way that allows this.
+ However, the only requirement from ISO C is that both macros must be
+ invoked in the same function (MPFR uses va_copy instead of va_start,
+ but the requirement is the same). Here, MPFR just follows ISO C.
+*/
#ifdef HAVE_CONFIG_H
# include "config.h"
@@ -2273,44 +2284,42 @@ mpfr_vasnprintf_aux (char **ptr, char *Buf, size_t size, const char *fmt,
va_end (ap2);
- if (buf.len > INT_MAX) /* overflow */
- buf.len = -1;
+ if (buf.len == -1 || buf.len > INT_MAX) /* overflow */
+ goto overflow;
- if (buf.len != -1)
- {
- nbchar = buf.len;
- MPFR_ASSERTD (nbchar >= 0);
+ nbchar = buf.len;
+ MPFR_ASSERTD (nbchar >= 0);
- if (ptr != NULL) /* implement mpfr_vasprintf */
+ if (ptr != NULL) /* implement mpfr_vasprintf */
+ {
+ MPFR_ASSERTD (nbchar == strlen (buf.start));
+ *ptr = (char *) mpfr_reallocate_func (buf.start, buf.size, nbchar + 1);
+ }
+ else if (size != 0) /* implement mpfr_vsnprintf */
+ {
+ if (nbchar < size)
{
- MPFR_ASSERTD (nbchar == strlen (buf.start));
- *ptr = (char *)
- mpfr_reallocate_func (buf.start, buf.size, nbchar + 1);
+ strncpy (Buf, buf.start, nbchar);
+ Buf[nbchar] = '\0';
}
- else if (size > 0) /* implement mpfr_vsnprintf */
+ else
{
- if (nbchar < size)
- {
- strncpy (Buf, buf.start, nbchar);
- Buf[nbchar] = '\0';
- }
- else
- {
- strncpy (Buf, buf.start, size - 1);
- Buf[size-1] = '\0';
- }
- mpfr_free_func (buf.start, buf.size);
+ strncpy (Buf, buf.start, size - 1);
+ Buf[size-1] = '\0';
}
-
- MPFR_SAVE_EXPO_FREE (expo);
- return nbchar; /* return the number of characters that would have
- been written had 'size' been sufficiently large,
- not counting the terminating null character */
+ mpfr_free_func (buf.start, buf.size);
}
+ MPFR_SAVE_EXPO_FREE (expo);
+ return nbchar; /* return the number of characters that would have
+ been written had 'size' been sufficiently large,
+ not counting the terminating null character */
+
error:
+ va_end (ap2);
if (buf.len == -1) /* overflow */
{
+ overflow:
MPFR_LOG_MSG (("Overflow\n", 0));
MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, MPFR_FLAGS_ERANGE);
#ifdef EOVERFLOW