937 buffer_length = initial_size; |
937 buffer_length = initial_size; |
938 buffer = NEW_C_HEAP_ARRAY(char, buffer_length, mtInternal); |
938 buffer = NEW_C_HEAP_ARRAY(char, buffer_length, mtInternal); |
939 buffer_pos = 0; |
939 buffer_pos = 0; |
940 buffer_fixed = false; |
940 buffer_fixed = false; |
941 buffer_max = bufmax; |
941 buffer_max = bufmax; |
|
942 truncated = false; |
942 } |
943 } |
943 |
944 |
944 bufferedStream::bufferedStream(char* fixed_buffer, size_t fixed_buffer_size, size_t bufmax) : outputStream() { |
945 bufferedStream::bufferedStream(char* fixed_buffer, size_t fixed_buffer_size, size_t bufmax) : outputStream() { |
945 buffer_length = fixed_buffer_size; |
946 buffer_length = fixed_buffer_size; |
946 buffer = fixed_buffer; |
947 buffer = fixed_buffer; |
947 buffer_pos = 0; |
948 buffer_pos = 0; |
948 buffer_fixed = true; |
949 buffer_fixed = true; |
949 buffer_max = bufmax; |
950 buffer_max = bufmax; |
|
951 truncated = false; |
950 } |
952 } |
951 |
953 |
952 void bufferedStream::write(const char* s, size_t len) { |
954 void bufferedStream::write(const char* s, size_t len) { |
953 |
955 |
|
956 if (truncated) { |
|
957 return; |
|
958 } |
|
959 |
954 if(buffer_pos + len > buffer_max) { |
960 if(buffer_pos + len > buffer_max) { |
955 flush(); |
961 flush(); // Note: may be a noop. |
956 } |
962 } |
957 |
963 |
958 size_t end = buffer_pos + len; |
964 size_t end = buffer_pos + len; |
959 if (end >= buffer_length) { |
965 if (end >= buffer_length) { |
960 if (buffer_fixed) { |
966 if (buffer_fixed) { |
961 // if buffer cannot resize, silently truncate |
967 // if buffer cannot resize, silently truncate |
962 len = buffer_length - buffer_pos - 1; |
968 len = buffer_length - buffer_pos - 1; |
|
969 truncated = true; |
963 } else { |
970 } else { |
964 // For small overruns, double the buffer. For larger ones, |
971 // For small overruns, double the buffer. For larger ones, |
965 // increase to the requested size. |
972 // increase to the requested size. |
966 if (end < buffer_length * 2) { |
973 if (end < buffer_length * 2) { |
967 end = buffer_length * 2; |
974 end = buffer_length * 2; |
968 } |
975 } |
969 buffer = REALLOC_C_HEAP_ARRAY(char, buffer, end, mtInternal); |
976 // Impose a cap beyond which the buffer cannot grow - a size which |
970 buffer_length = end; |
977 // in all probability indicates a real error, e.g. faulty printing |
971 } |
978 // code looping, while not affecting cases of just-very-large-but-its-normal |
972 } |
979 // output. |
973 memcpy(buffer + buffer_pos, s, len); |
980 const size_t reasonable_cap = MAX2(100 * M, buffer_max * 2); |
974 buffer_pos += len; |
981 if (end > reasonable_cap) { |
975 update_position(s, len); |
982 // In debug VM, assert right away. |
|
983 assert(false, "Exceeded max buffer size for this string."); |
|
984 // Release VM: silently truncate. We do this since these kind of errors |
|
985 // are both difficult to predict with testing (depending on logging content) |
|
986 // and usually not serious enough to kill a production VM for it. |
|
987 end = reasonable_cap; |
|
988 size_t remaining = end - buffer_pos; |
|
989 if (len >= remaining) { |
|
990 len = remaining - 1; |
|
991 truncated = true; |
|
992 } |
|
993 } |
|
994 if (buffer_length < end) { |
|
995 buffer = REALLOC_C_HEAP_ARRAY(char, buffer, end, mtInternal); |
|
996 buffer_length = end; |
|
997 } |
|
998 } |
|
999 } |
|
1000 if (len > 0) { |
|
1001 memcpy(buffer + buffer_pos, s, len); |
|
1002 buffer_pos += len; |
|
1003 update_position(s, len); |
|
1004 } |
976 } |
1005 } |
977 |
1006 |
978 char* bufferedStream::as_string() { |
1007 char* bufferedStream::as_string() { |
979 char* copy = NEW_RESOURCE_ARRAY(char, buffer_pos+1); |
1008 char* copy = NEW_RESOURCE_ARRAY(char, buffer_pos+1); |
980 strncpy(copy, buffer, buffer_pos); |
1009 strncpy(copy, buffer, buffer_pos); |