Fix BIO_printf crash on Mac.
A single va_list may not be used twice. Nothing calls BIO_vprintf and it just (v)snprintfs into a buffer anyway, so remove it. If it's actually needed, we can fiddle with va_copy and the lack of it in C89 later, but anything that actually cares can just assemble the output externally. Add a test in bio_test.c. BUG=399546 Change-Id: Ia40a68b31cb5984d817e9c55351f49d9d6c964c1 Reviewed-on: https://boringssl-review.googlesource.com/1391 Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
parent
a59fbb0edd
commit
aa4efe7669
@ -17,6 +17,7 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
#include <string.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
@ -93,6 +94,56 @@ static int test_socket_connect() {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int test_printf() {
|
||||||
|
/* Test a short output, a very long one, and various sizes around
|
||||||
|
* 256 (the size of the buffer) to ensure edge cases are correct. */
|
||||||
|
static const size_t kLengths[] = { 5, 250, 251, 252, 253, 254, 1023 };
|
||||||
|
BIO *bio;
|
||||||
|
char string[1024];
|
||||||
|
int ret;
|
||||||
|
const uint8_t *contents;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
bio = BIO_new(BIO_s_mem());
|
||||||
|
if (!bio) {
|
||||||
|
fprintf(stderr, "BIO_new failed\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < sizeof(kLengths) / sizeof(kLengths[0]); i++) {
|
||||||
|
if (kLengths[i] >= sizeof(string)) {
|
||||||
|
fprintf(stderr, "Bad test string length\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memset(string, 'a', sizeof(string));
|
||||||
|
string[kLengths[i]] = '\0';
|
||||||
|
|
||||||
|
ret = BIO_printf(bio, "test %s", string);
|
||||||
|
if (ret != 5 + kLengths[i]) {
|
||||||
|
fprintf(stderr, "BIO_printf failed\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!BIO_mem_contents(bio, &contents, &len)) {
|
||||||
|
fprintf(stderr, "BIO_mem_contents failed\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (len != 5 + kLengths[i] ||
|
||||||
|
strncmp((const char *)contents, "test ", 5) != 0 ||
|
||||||
|
strncmp((const char *)contents + 5, string, kLengths[i]) != 0) {
|
||||||
|
fprintf(stderr, "Contents did not match: %.*s\n", (int)len, contents);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!BIO_reset(bio)) {
|
||||||
|
fprintf(stderr, "BIO_reset failed\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BIO_free(bio);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
ERR_load_crypto_strings();
|
ERR_load_crypto_strings();
|
||||||
|
|
||||||
@ -100,6 +151,10 @@ int main() {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!test_printf()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
printf("PASS\n");
|
printf("PASS\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -66,38 +66,30 @@
|
|||||||
|
|
||||||
#include <openssl/mem.h>
|
#include <openssl/mem.h>
|
||||||
|
|
||||||
|
|
||||||
int BIO_printf(BIO *bio, const char *format, ...) {
|
int BIO_printf(BIO *bio, const char *format, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
int ret;
|
|
||||||
|
|
||||||
va_start(args, format);
|
|
||||||
|
|
||||||
ret = BIO_vprintf(bio, format, args);
|
|
||||||
|
|
||||||
va_end(args);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int BIO_vprintf(BIO *bio, const char *format, va_list args) {
|
|
||||||
char buf[256], *out, out_malloced = 0;
|
char buf[256], *out, out_malloced = 0;
|
||||||
int out_len, ret;
|
int out_len, ret;
|
||||||
|
|
||||||
/* Note: this is assuming that va_list is ok to copy as POD. If the system
|
va_start(args, format);
|
||||||
* defines it with a pointer to mutable state then passing it twice to
|
|
||||||
* vsnprintf will not work. */
|
|
||||||
out_len = vsnprintf(buf, sizeof(buf), format, args);
|
out_len = vsnprintf(buf, sizeof(buf), format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
if (out_len >= sizeof(buf)) {
|
if (out_len >= sizeof(buf)) {
|
||||||
const int requested_len = out_len;
|
const int requested_len = out_len;
|
||||||
/* The output was truncated. */
|
/* The output was truncated. Note that vsnprintf's return value
|
||||||
out = OPENSSL_malloc(requested_len);
|
* does not include a trailing NUL, but the buffer must be sized
|
||||||
|
* for it. */
|
||||||
|
out = OPENSSL_malloc(requested_len + 1);
|
||||||
out_malloced = 1;
|
out_malloced = 1;
|
||||||
if (out == NULL) {
|
if (out == NULL) {
|
||||||
/* Unclear what can be done in this situation. OpenSSL has historically
|
/* Unclear what can be done in this situation. OpenSSL has historically
|
||||||
* crashed and that seems better than producing the wrong output. */
|
* crashed and that seems better than producing the wrong output. */
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
out_len = vsnprintf(out, requested_len, format, args);
|
va_start(args, format);
|
||||||
|
out_len = vsnprintf(out, requested_len + 1, format, args);
|
||||||
|
va_end(args);
|
||||||
assert(out_len == requested_len);
|
assert(out_len == requested_len);
|
||||||
} else {
|
} else {
|
||||||
out = buf;
|
out = buf;
|
||||||
|
@ -305,9 +305,6 @@ OPENSSL_EXPORT void BIO_copy_next_retry(BIO *bio);
|
|||||||
#endif
|
#endif
|
||||||
OPENSSL_EXPORT int BIO_printf(BIO *bio, const char *format, ...)
|
OPENSSL_EXPORT int BIO_printf(BIO *bio, const char *format, ...)
|
||||||
__bio_h__attr__((__format__(__printf__, 2, 3)));
|
__bio_h__attr__((__format__(__printf__, 2, 3)));
|
||||||
|
|
||||||
OPENSSL_EXPORT int BIO_vprintf(BIO *bio, const char *format, va_list args)
|
|
||||||
__bio_h__attr__((__format__(__printf__, 2, 0)));
|
|
||||||
#undef __bio_h__attr__
|
#undef __bio_h__attr__
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user