[PATCH] newlib: Fix memory leak regarding gdtoa-based _ldtoa_r().

Takashi Yano <[email protected]>
Newsgroups gmane.comp.lib.newlib
Message-ID <[email protected]>
After the commit a4705d387f78, printf() for floating-point values
causes a memory leak. The legacy _ldtoa_r() assumed the char pointer
returned will be free'ed by Bfree(). However, gdtoa-based _ldtoa_r()
returns the pointer returned by gdtoa() which should be free'ed by
freedtoa(). Due to this issue, the caller of _ldtoa_r() fails to free
the allocated char buffer. This is the cause of the said memory leak.
https://cygwin.com/pipermail/cygwin/2023-July/254054.html

With this patch, a new buffer is allocated using Balloc() and the
buffer returned by gdtoa() is copied into it. Then, free the original
buffer using freedtoa().

Fixes: a4705d387f78 ("ldtoa: Import gdtoa from OpenBSD.")
Reported-by: natan_b <[email protected]>
Signed-off-by: Takashi Yano <[email protected]>
---
 newlib/libc/stdlib/gdtoa-ldtoa.c | 21 +++++++++++++++++++--
 winsup/cygwin/release/3.4.8      |  3 +++
 2 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/newlib/libc/stdlib/gdtoa-ldtoa.c b/newlib/libc/stdlib/gdtoa-ldtoa.c
index 14b99042c..7a484613f 100644
--- a/newlib/libc/stdlib/gdtoa-ldtoa.c
+++ b/newlib/libc/stdlib/gdtoa-ldtoa.c
@@ -63,7 +63,8 @@ _ldtoa_r(struct _reent *ptr,
 #endif
 	};
 	int be, kind;
-	char *ret;
+	int i, j;
+	char *ret, *outbuf;
 	struct ieee_ext *p = (struct ieee_ext *)&ld;
 	uint32_t bits[(LDBL_MANT_DIG + 31) / 32];
 	void *vbits = bits;
@@ -113,7 +114,23 @@ _ldtoa_r(struct _reent *ptr,
 		abort();
 	}
 
-	ret = gdtoa(ptr, &fpi, be, vbits, &kind, mode, ndigits, decpt, rve);
+	outbuf = gdtoa(ptr, &fpi, be, vbits, &kind, mode, ndigits, decpt, rve);
+
+	i = strlen (outbuf);
+	j = sizeof (__ULong);
+	for (_REENT_MP_RESULT_K (ptr) = 0;
+	     sizeof (_Bigint) - sizeof (__ULong) + j <= i; j <<= 1)
+		_REENT_MP_RESULT_K (ptr)++;
+	_REENT_MP_RESULT (ptr) = eBalloc (ptr, _REENT_MP_RESULT_K (ptr));
+
+	/* Copy from gdtoa-type buffer (which is allocated by rv_alloc())
+	   to the buffer used by ldtoa (which is allocated by Balloc()). */
+	ret = (char *) _REENT_MP_RESULT (ptr);
+	strcpy (ret, outbuf);
+	if (rve)
+		*rve = ret + (*rve - outbuf);
+	freedtoa (ptr, outbuf);
+
 	if (*decpt == -32768)
 		*decpt = INT_MAX;
 	return ret;
diff --git a/winsup/cygwin/release/3.4.8 b/winsup/cygwin/release/3.4.8
index d37272eef..448831c65 100644
--- a/winsup/cygwin/release/3.4.8
+++ b/winsup/cygwin/release/3.4.8
@@ -14,3 +14,6 @@ Bug Fixes
 - Rename internal macros _NL_CTYPE_OUTDIGITSx_MB/WC to GLibc compatible
   _NL_CTYPE_OUTDIGITx_MB/WC.
   Addresses: https://cygwin.com/pipermail/cygwin-developers/2023-July/012637.html
+
+- Fix memory leak in printf() regarding gdtoa-based _ldtoa_r().
+  Addresses: https://cygwin.com/pipermail/cygwin/2023-July/254054.html
-- 
2.39.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.