Add OPENSSL_asprintf and friends for asprintf(3) functionality.
This includes an internal version which allows a flag to specify
the use of system malloc, or OPENSSL_malloc - this in turn allows
us to use this function in the ERR family of functions and allow
for ERR to not call OPENSSL_malloc with a circular dependency.
Bug: 564
Change-Id: Ifd02d062fda9695cddbb0dbef2e1c1db0802a486
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/57005
Auto-Submit: Bob Beck <bbe@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: Bob Beck <bbe@google.com>
diff --git a/crypto/internal.h b/crypto/internal.h
index 576ad85..f12871f 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -1299,6 +1299,13 @@
extern uint8_t BORINGSSL_function_hit[7];
#endif // BORINGSSL_DISPATCH_TEST
+// OPENSSL_vasprintf_internal is just like |vasprintf(3)|. if |system_malloc| is
+// 0, memory will be allocated with |OPENSSL_malloc| and must be freed with
+// |OPENSSL_free|. Otherwise the system |malloc| function is used and the memory
+// must be freed with the system |free| function.
+OPENSSL_EXPORT int OPENSSL_vasprintf_internal(char **str, const char *format,
+ va_list args, int system_malloc)
+ OPENSSL_PRINTF_FORMAT_FUNC(2, 0);
#if defined(__cplusplus)
} // extern C
diff --git a/crypto/mem.c b/crypto/mem.c
index 97a85e9..f75e89e 100644
--- a/crypto/mem.c
+++ b/crypto/mem.c
@@ -57,9 +57,11 @@
#include <openssl/mem.h>
#include <assert.h>
+#include <errno.h>
+#include <limits.h>
#include <stdarg.h>
-#include <stdlib.h>
#include <stdio.h>
+#include <stdlib.h>
#include <openssl/err.h>
@@ -127,7 +129,7 @@
// primitives used must tolerate every other synchronization primitive linked
// into the process, including pthreads locks. Failing to meet these constraints
// may result in deadlocks, crashes, or memory corruption.
-WEAK_SYMBOL_FUNC(void*, OPENSSL_memory_alloc, (size_t size));
+WEAK_SYMBOL_FUNC(void *, OPENSSL_memory_alloc, (size_t size));
WEAK_SYMBOL_FUNC(void, OPENSSL_memory_free, (void *ptr));
WEAK_SYMBOL_FUNC(size_t, OPENSSL_memory_get_size, (void *ptr));
@@ -135,10 +137,25 @@
// are linking in BoringSSL and, roughly, what version they are using.
static const uint8_t kBoringSSLBinaryTag[18] = {
// 16 bytes of magic tag.
- 0x8c, 0x62, 0x20, 0x0b, 0xd2, 0xa0, 0x72, 0x58,
- 0x44, 0xa8, 0x96, 0x69, 0xad, 0x55, 0x7e, 0xec,
+ 0x8c,
+ 0x62,
+ 0x20,
+ 0x0b,
+ 0xd2,
+ 0xa0,
+ 0x72,
+ 0x58,
+ 0x44,
+ 0xa8,
+ 0x96,
+ 0x69,
+ 0xad,
+ 0x55,
+ 0x7e,
+ 0xec,
// Current source iteration. Incremented ~monthly.
- 3, 0,
+ 3,
+ 0,
};
#if defined(BORINGSSL_MALLOC_FAILURE_TESTING)
@@ -321,9 +338,7 @@
#endif // !OPENSSL_NO_ASM
}
-void OPENSSL_clear_free(void *ptr, size_t unused) {
- OPENSSL_free(ptr);
-}
+void OPENSSL_clear_free(void *ptr, size_t unused) { OPENSSL_free(ptr); }
int CRYPTO_secure_malloc_init(size_t size, size_t min_size) { return 0; }
@@ -394,9 +409,7 @@
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
-int OPENSSL_isdigit(int c) {
- return c >= '0' && c <= '9';
-}
+int OPENSSL_isdigit(int c) { return c >= '0' && c <= '9'; }
int OPENSSL_isxdigit(int c) {
return OPENSSL_isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
@@ -418,9 +431,7 @@
return 0;
}
-int OPENSSL_isalnum(int c) {
- return OPENSSL_isalpha(c) || OPENSSL_isdigit(c);
-}
+int OPENSSL_isalnum(int c) { return OPENSSL_isalpha(c) || OPENSSL_isdigit(c); }
int OPENSSL_tolower(int c) {
if (c >= 'A' && c <= 'Z') {
@@ -478,6 +489,65 @@
return vsnprintf(buf, n, format, args);
}
+int OPENSSL_vasprintf_internal(char **str, const char *format, va_list args,
+ int system_malloc) {
+ void *(*allocate)(size_t) = system_malloc ? malloc : OPENSSL_malloc;
+ void (*deallocate)(void *) = system_malloc ? free : OPENSSL_free;
+ void *(*reallocate)(void *, size_t) =
+ system_malloc ? realloc : OPENSSL_realloc;
+ char *candidate = NULL;
+ size_t candidate_len = 64; // TODO(bbe) what's the best initial size?
+
+ if ((candidate = allocate(candidate_len)) == NULL) {
+ goto err;
+ }
+ va_list args_copy;
+ va_copy(args_copy, args);
+ int ret = vsnprintf(candidate, candidate_len, format, args_copy);
+ va_end(args_copy);
+ if (ret == INT_MAX || ret < 0) {
+ // Failed, or size not int representable.
+ goto err;
+ }
+ if ((size_t)ret >= candidate_len) {
+ // Too big to fit in allocation.
+ char *tmp;
+
+ candidate_len = ret + 1;
+ if ((tmp = reallocate(candidate, candidate_len)) == NULL) {
+ goto err;
+ }
+ candidate = tmp;
+ va_copy(args_copy, args);
+ ret = vsnprintf(candidate, candidate_len, format, args_copy);
+ va_end(args_copy);
+ }
+ // At this point this can't happen unless vsnprintf is insane.
+ if (ret < 0 || (size_t)ret >= candidate_len) {
+ goto err;
+ }
+ *str = candidate;
+ return ret;
+
+ err:
+ deallocate(candidate);
+ *str = NULL;
+ errno = ENOMEM;
+ return -1;
+}
+
+int OPENSSL_vasprintf(char **str, const char *format, va_list args) {
+ return OPENSSL_vasprintf_internal(str, format, args, /*system_malloc=*/0);
+}
+
+int OPENSSL_asprintf(char **str, const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ int ret = OPENSSL_vasprintf(str, format, args);
+ va_end(args);
+ return ret;
+}
+
char *OPENSSL_strndup(const char *str, size_t size) {
size = OPENSSL_strnlen(str, size);
diff --git a/include/openssl/mem.h b/include/openssl/mem.h
index 374e188..0cce93d 100644
--- a/include/openssl/mem.h
+++ b/include/openssl/mem.h
@@ -84,7 +84,8 @@
// OPENSSL_realloc returns a pointer to a buffer of |new_size| bytes that
// contains the contents of |ptr|. Unlike |realloc|, a new buffer is always
-// allocated and the data at |ptr| is always wiped and freed.
+// allocated and the data at |ptr| is always wiped and freed. Memory is
+// allocated with |OPENSSL_malloc| and must be freed with |OPENSSL_free|.
OPENSSL_EXPORT void *OPENSSL_realloc(void *ptr, size_t new_size);
// OPENSSL_cleanse zeros out |len| bytes of memory at |ptr|. This is similar to
@@ -160,12 +161,25 @@
OPENSSL_EXPORT int BIO_vsnprintf(char *buf, size_t n, const char *format,
va_list args) OPENSSL_PRINTF_FORMAT_FUNC(3, 0);
+// OPENSSL_vasprintf has the same behavior as vasprintf(3), except that
+// memory allocated in a returned string must be freed with |OPENSSL_free|.
+OPENSSL_EXPORT int OPENSSL_vasprintf(char **str, const char *format,
+ va_list args)
+ OPENSSL_PRINTF_FORMAT_FUNC(2, 0);
+
+// OPENSSL_asprintf has the same behavior as asprintf(3), except that
+// memory allocated in a returned string must be freed with |OPENSSL_free|.
+OPENSSL_EXPORT int OPENSSL_asprintf(char **str, const char *format, ...)
+ OPENSSL_PRINTF_FORMAT_FUNC(2, 3);
+
// OPENSSL_strndup returns an allocated, duplicate of |str|, which is, at most,
-// |size| bytes. The result is always NUL terminated.
+// |size| bytes. The result is always NUL terminated. The memory allocated
+// must be freed with |OPENSSL_free|.
OPENSSL_EXPORT char *OPENSSL_strndup(const char *str, size_t size);
// OPENSSL_memdup returns an allocated, duplicate of |size| bytes from |data| or
-// NULL on allocation failure.
+// NULL on allocation failure. The memory allocated must be freed with
+// |OPENSSL_free|.
OPENSSL_EXPORT void *OPENSSL_memdup(const void *data, size_t size);
// OPENSSL_strlcpy acts like strlcpy(3).