[PATCH 15/40] Windows: A work-around for a misbehaved vsnprintf.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Windows, vsnprintf deviates in two regards from the "usual" behavior
that its callers in GIT expect:

- It returns -1 if the buffer is too small instead of the number of
  characters that the operation produces.

- The size parameter is the number of characters to write, which does not
  include the trailing NUL byte, instead of the available space.

This wrapper computes the needed buffer size by trying various sizes with
exponential growth. A large growth factor is used so as only few trials are
required if a really large result needs to be stored.

Signed-off-by: Johannes Sixt <johannes.sixt@xxxxxxxxxx>
---
 compat/mingw.c    |   34 ++++++++++++++++++++++++++++++++++
 git-compat-util.h |    3 +++
 2 files changed, 37 insertions(+), 0 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 4888a03..77e4b83 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -115,6 +115,40 @@ int mingw_rename(const char *pold, const char *pnew)
 	return -1;
 }
 
+#undef vsnprintf
+/* Note that the size parameter specifies the available space, i.e.
+ * includes the trailing NUL byte; but Windows's vsnprintf expects the
+ * number of characters to write without the trailing NUL.
+ */
+
+/* This is out of line because it uses alloca() behind the scenes,
+ * which must not be called in a loop (alloca() reclaims the allocations
+ * only at function exit).
+ */
+static int try_vsnprintf(size_t size, const char *fmt, va_list args)
+{
+	char buf[size];	/* gcc-ism */
+	return vsnprintf(buf, size-1, fmt, args);
+}
+
+int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+	int len;
+	if (size > 0) {
+		len = vsnprintf(buf, size-1, fmt, args);
+		if (len >= 0)
+			return len;
+	}
+	/* ouch, buffer too small; need to compute the size */
+	if (size < 250)
+		size = 250;
+	do {
+		size *= 4;
+		len = try_vsnprintf(size, fmt, args);
+	} while (len < 0);
+	return len;
+}
+
 struct passwd *getpwuid(int uid)
 {
 	static char user_name[100];
diff --git a/git-compat-util.h b/git-compat-util.h
index 483ace2..6fa93b6 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -602,6 +602,9 @@ char *mingw_getcwd(char *pointer, int len);
 int mingw_rename(const char*, const char*);
 #define rename mingw_rename
 
+int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
+#define vsnprintf mingw_vsnprintf
+
 sig_handler_t mingw_signal(int sig, sig_handler_t handler);
 #define signal mingw_signal
 
-- 
1.5.4.1.126.ge5a7d

-
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux