From 6fa8dacb97587707156507aa35141e414fc284bb Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 25 Feb 2010 15:58:55 -0500 Subject: Add a tor_asprintf() function, and use it in a couple of places. asprintf() is a GNU extension that some BSDs have picked up: it does a printf into a newly allocated chunk of RAM. Our tor_asprintf() differs from standard asprintf() in that: - Like our other malloc functions, it asserts on OOM. - It works on windows. - It always sets its return-field. --- src/common/compat.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/common/compat.h | 4 +++ 2 files changed, 90 insertions(+) (limited to 'src/common') diff --git a/src/common/compat.c b/src/common/compat.c index 406d74eb25..49e66c6a69 100644 --- a/src/common/compat.c +++ b/src/common/compat.c @@ -307,6 +307,92 @@ tor_vsnprintf(char *str, size_t size, const char *format, va_list args) return r; } +/** + * Portable asprintf implementation. Does a printf() into a newly malloc'd + * string. Sets *strp to this string, and returns its length (not + * including the terminating NUL character). + * + * You can treat this function as if its implementation were something like +
+     char buf[_INFINITY_];
+     tor_snprintf(buf, sizeof(buf), fmt, args);
+     *strp = tor_strdup(buf);
+     return strlen(*strp):
+   
+ * Where _INFINITY_ is an imaginary constant so big that any string can fit + * into it. + */ +int +tor_asprintf(char **strp, const char *fmt, ...) +{ + int r; + va_list args; + va_start(args, fmt); + r = tor_vasprintf(strp, fmt, args); + va_end(args); + if (!*strp || r < 0) { + log_err(LD_BUG, "Internal error in asprintf"); + tor_assert(0); + } + return r; +} + +/** + * Portable vasprintf implementation. Does a printf() into a newly malloc'd + * string. Differs from regular vasprintf in the same ways that + * tor_asprintf() differs from regular asprintf. + */ +int +tor_vasprintf(char **strp, const char *fmt, va_list args) +{ +#ifdef HAVE_VASPRINTF + /* If the platform gives us one, use it. */ + int r = vasprintf(strp, fmt, args); + if (r < 0) + *strp = NULL; + return r; +#elif defined(MS_WINDOWS) + /* On Windows, _vsnprintf won't tell us the length of the string if it + * overflows, so we need to use _vcsprintf to tell how much to allocate */ + int len, r; + char *res; + len = _vcsprintf(fmt, args); + if (len < 0) { + strp = NULL; + return -1; + } + *strp = tor_malloc(len + 1); + r = _vsnprintf(*strp, len+1, fmt, args); + if (r != len) { + tor_free(*strp); + return -1; + } + return len; +#else + /* Everywhere else, we have a decent vsnprintf that tells us how many + * characters we need. We give it a try on a short buffer first, since + * it might be nice to avoid the second vsnprintf call. + */ + char buf[128]; + int len, r; + va_list tmp_args; + va_copy(tmp_args, args); + len = vsnprintf(buf, sizeof(buf), fmt, tmp_args); + va_end(tmp_args); + if (len < (int)sizeof(buf)) { + *strp = tor_strdup(buf); + return len; + } + *strp = tor_malloc(len+1); + r = vsnprintf(*strp, len+1, fmt, args); + if (r != len) { + tor_free(*strp); + return -1; + } + return len; +#endif +} + /** Given hlen bytes at haystack and nlen bytes at * needle, return a pointer to the first occurrence of the needle * within the haystack, or NULL if there is no such occurrence. diff --git a/src/common/compat.h b/src/common/compat.h index 554ae8919f..f3e30452bd 100644 --- a/src/common/compat.h +++ b/src/common/compat.h @@ -235,6 +235,10 @@ int tor_snprintf(char *str, size_t size, const char *format, ...) int tor_vsnprintf(char *str, size_t size, const char *format, va_list args) ATTR_NONNULL((1,3)); +int tor_asprintf(char **strp, const char *fmt, ...) + CHECK_PRINTF(2,3); +int tor_vasprintf(char **strp, const char *fmt, va_list args); + const void *tor_memmem(const void *haystack, size_t hlen, const void *needle, size_t nlen) ATTR_PURE ATTR_NONNULL((1,3)); static const void *tor_memstr(const void *haystack, size_t hlen, -- cgit v1.2.3-54-g00ecf From 897b0ebbace3a14cc02e8a281a87e7db156fbd53 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Sun, 28 Feb 2010 21:46:46 -0500 Subject: better handle the case where *strp is in asprintf args --- src/common/compat.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'src/common') diff --git a/src/common/compat.c b/src/common/compat.c index 49e66c6a69..e256f45a26 100644 --- a/src/common/compat.c +++ b/src/common/compat.c @@ -345,11 +345,15 @@ tor_asprintf(char **strp, const char *fmt, ...) int tor_vasprintf(char **strp, const char *fmt, va_list args) { + /* use a temporary variable in case *strp is in args. */ + char *strp_tmp=NULL; #ifdef HAVE_VASPRINTF /* If the platform gives us one, use it. */ - int r = vasprintf(strp, fmt, args); + int r = vasprintf(&strp_tmp, fmt, args); if (r < 0) *strp = NULL; + else + *strp = strp_tmp; return r; #elif defined(MS_WINDOWS) /* On Windows, _vsnprintf won't tell us the length of the string if it @@ -358,15 +362,17 @@ tor_vasprintf(char **strp, const char *fmt, va_list args) char *res; len = _vcsprintf(fmt, args); if (len < 0) { - strp = NULL; + *strp = NULL; return -1; } - *strp = tor_malloc(len + 1); - r = _vsnprintf(*strp, len+1, fmt, args); + strp_tmp = tor_malloc(len + 1); + r = _vsnprintf(strp_tmp, len+1, fmt, args); if (r != len) { - tor_free(*strp); + tor_free(strp_tmp); + *strp = NULL; return -1; } + *strp = strp_tmp; return len; #else /* Everywhere else, we have a decent vsnprintf that tells us how many @@ -383,12 +389,14 @@ tor_vasprintf(char **strp, const char *fmt, va_list args) *strp = tor_strdup(buf); return len; } - *strp = tor_malloc(len+1); - r = vsnprintf(*strp, len+1, fmt, args); + strp_tmp = tor_malloc(len+1); + r = vsnprintf(strp_tmp, len+1, fmt, args); if (r != len) { - tor_free(*strp); + tor_free(strp_tmp); + *strp = NULL; return -1; } + *strp = strp_tmp; return len; #endif } -- cgit v1.2.3-54-g00ecf