1.1 --- a/src/share/vm/utilities/ostream.cpp Wed Aug 01 04:19:22 2018 -0400 1.2 +++ b/src/share/vm/utilities/ostream.cpp Thu Aug 02 03:54:51 2018 -0700 1.3 @@ -1,5 +1,5 @@ 1.4 /* 1.5 - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. 1.6 + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. 1.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.8 * 1.9 * This code is free software; you can redistribute it and/or modify it 1.10 @@ -27,6 +27,7 @@ 1.11 #include "gc_implementation/shared/gcId.hpp" 1.12 #include "oops/oop.inline.hpp" 1.13 #include "runtime/arguments.hpp" 1.14 +#include "runtime/os.hpp" 1.15 #include "utilities/defaultStream.hpp" 1.16 #include "utilities/ostream.hpp" 1.17 #include "utilities/top.hpp" 1.18 @@ -89,6 +90,8 @@ 1.19 const char* format, va_list ap, 1.20 bool add_cr, 1.21 size_t& result_len) { 1.22 + assert(buflen >= 2, "buffer too small"); 1.23 + 1.24 const char* result; 1.25 if (add_cr) buflen--; 1.26 if (!strchr(format, '%')) { 1.27 @@ -101,18 +104,20 @@ 1.28 result = va_arg(ap, const char*); 1.29 result_len = strlen(result); 1.30 if (add_cr && result_len >= buflen) result_len = buflen-1; // truncate 1.31 - } else if (vsnprintf(buffer, buflen, format, ap) >= 0) { 1.32 + } else { 1.33 + int written = os::vsnprintf(buffer, buflen, format, ap); 1.34 + assert(written >= 0, "vsnprintf encoding error"); 1.35 result = buffer; 1.36 - result_len = strlen(result); 1.37 - } else { 1.38 - DEBUG_ONLY(warning("increase O_BUFLEN in ostream.hpp -- output truncated");) 1.39 - result = buffer; 1.40 - result_len = buflen - 1; 1.41 - buffer[result_len] = 0; 1.42 + if ((size_t)written < buflen) { 1.43 + result_len = written; 1.44 + } else { 1.45 + DEBUG_ONLY(warning("increase O_BUFLEN in ostream.hpp -- output truncated");) 1.46 + result_len = buflen - 1; 1.47 + } 1.48 } 1.49 if (add_cr) { 1.50 if (result != buffer) { 1.51 - strncpy(buffer, result, buflen); 1.52 + memcpy(buffer, result, result_len); 1.53 result = buffer; 1.54 } 1.55 buffer[result_len++] = '\n'; 1.56 @@ -578,6 +583,117 @@ 1.57 assert(o_result == NULL, err_msg("Too long file name after pid expansion should return NULL, but got '%s'", o_result)); 1.58 } 1.59 } 1.60 + 1.61 +////////////////////////////////////////////////////////////////////////////// 1.62 +// Test os::vsnprintf and friends. 1.63 + 1.64 +void check_snprintf_result(int expected, size_t limit, int actual, bool expect_count) { 1.65 + if (expect_count || ((size_t)expected < limit)) { 1.66 + assert(expected == actual, "snprintf result not expected value"); 1.67 + } else { 1.68 + // Make this check more permissive for jdk8u, don't assert that actual == 0. 1.69 + // e.g. jio_vsnprintf_wrapper and jio_snprintf return -1 when expected >= limit 1.70 + if (expected >= (int) limit) { 1.71 + assert(actual == -1, "snprintf result should be -1 for expected >= limit"); 1.72 + } else { 1.73 + assert(actual > 0, "snprintf result should be >0 for expected < limit"); 1.74 + } 1.75 + } 1.76 +} 1.77 + 1.78 +// PrintFn is expected to be int (*)(char*, size_t, const char*, ...). 1.79 +// But jio_snprintf is a C-linkage function with that signature, which 1.80 +// has a different type on some platforms (like Solaris). 1.81 +template<typename PrintFn> 1.82 +void test_snprintf(PrintFn pf, bool expect_count) { 1.83 + const char expected[] = "abcdefghijklmnopqrstuvwxyz"; 1.84 + const int expected_len = sizeof(expected) - 1; 1.85 + const size_t padding_size = 10; 1.86 + char buffer[2 * (sizeof(expected) + padding_size)]; 1.87 + char check_buffer[sizeof(buffer)]; 1.88 + const char check_char = '1'; // Something not in expected. 1.89 + memset(check_buffer, check_char, sizeof(check_buffer)); 1.90 + const size_t sizes_to_test[] = { 1.91 + sizeof(buffer) - padding_size, // Fits, with plenty of space to spare. 1.92 + sizeof(buffer)/2, // Fits, with space to spare. 1.93 + sizeof(buffer)/4, // Doesn't fit. 1.94 + sizeof(expected) + padding_size + 1, // Fits, with a little room to spare 1.95 + sizeof(expected) + padding_size, // Fits exactly. 1.96 + sizeof(expected) + padding_size - 1, // Doesn't quite fit. 1.97 + 2, // One char + terminating NUL. 1.98 + 1, // Only space for terminating NUL. 1.99 + 0 }; // No space at all. 1.100 + for (unsigned i = 0; i < ARRAY_SIZE(sizes_to_test); ++i) { 1.101 + memset(buffer, check_char, sizeof(buffer)); // To catch stray writes. 1.102 + size_t test_size = sizes_to_test[i]; 1.103 + ResourceMark rm; 1.104 + stringStream s; 1.105 + s.print("test_size: " SIZE_FORMAT, test_size); 1.106 + size_t prefix_size = padding_size; 1.107 + guarantee(test_size <= (sizeof(buffer) - prefix_size), "invariant"); 1.108 + size_t write_size = MIN2(sizeof(expected), test_size); 1.109 + size_t suffix_size = sizeof(buffer) - prefix_size - write_size; 1.110 + char* write_start = buffer + prefix_size; 1.111 + char* write_end = write_start + write_size; 1.112 + 1.113 + int result = pf(write_start, test_size, "%s", expected); 1.114 + 1.115 + check_snprintf_result(expected_len, test_size, result, expect_count); 1.116 + 1.117 + // Verify expected output. 1.118 + if (test_size > 0) { 1.119 + assert(0 == strncmp(write_start, expected, write_size - 1), "strncmp failure"); 1.120 + // Verify terminating NUL of output. 1.121 + assert('\0' == write_start[write_size - 1], "null terminator failure"); 1.122 + } else { 1.123 + guarantee(test_size == 0, "invariant"); 1.124 + guarantee(write_size == 0, "invariant"); 1.125 + guarantee(prefix_size + suffix_size == sizeof(buffer), "invariant"); 1.126 + guarantee(write_start == write_end, "invariant"); 1.127 + } 1.128 + 1.129 + // Verify no scribbling on prefix or suffix. 1.130 + assert(0 == strncmp(buffer, check_buffer, prefix_size), "prefix scribble"); 1.131 + assert(0 == strncmp(write_end, check_buffer, suffix_size), "suffix scribble"); 1.132 + } 1.133 + 1.134 + // Special case of 0-length buffer with empty (except for terminator) output. 1.135 + check_snprintf_result(0, 0, pf(NULL, 0, "%s", ""), expect_count); 1.136 + check_snprintf_result(0, 0, pf(NULL, 0, ""), expect_count); 1.137 +} 1.138 + 1.139 +// This is probably equivalent to os::snprintf, but we're being 1.140 +// explicit about what we're testing here. 1.141 +static int vsnprintf_wrapper(char* buf, size_t len, const char* fmt, ...) { 1.142 + va_list args; 1.143 + va_start(args, fmt); 1.144 + int result = os::vsnprintf(buf, len, fmt, args); 1.145 + va_end(args); 1.146 + return result; 1.147 +} 1.148 + 1.149 +// These are declared in jvm.h; test here, with related functions. 1.150 +extern "C" { 1.151 +int jio_vsnprintf(char*, size_t, const char*, va_list); 1.152 +int jio_snprintf(char*, size_t, const char*, ...); 1.153 +} 1.154 + 1.155 +// This is probably equivalent to jio_snprintf, but we're being 1.156 +// explicit about what we're testing here. 1.157 +static int jio_vsnprintf_wrapper(char* buf, size_t len, const char* fmt, ...) { 1.158 + va_list args; 1.159 + va_start(args, fmt); 1.160 + int result = jio_vsnprintf(buf, len, fmt, args); 1.161 + va_end(args); 1.162 + return result; 1.163 +} 1.164 + 1.165 +void test_snprintf() { 1.166 + test_snprintf(vsnprintf_wrapper, true); 1.167 + test_snprintf(os::snprintf, true); 1.168 + test_snprintf(jio_vsnprintf_wrapper, false); // jio_vsnprintf returns -1 on error including exceeding buffer size 1.169 + test_snprintf(jio_snprintf, false); // jio_snprintf calls jio_vsnprintf 1.170 +} 1.171 #endif // PRODUCT 1.172 1.173 fileStream::fileStream(const char* file_name) {