src/share/vm/utilities/ostream.cpp

changeset 9478
f3108e56b502
parent 9327
f96fcd9e1e1b
child 9572
624a0741915c
child 9904
4698900b8221
     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) {

mercurial