8220394: bufferedStream does not honor size limit

Reviewed-by: dholmes, clanger
This commit is contained in:
Thomas Stuefe 2019-05-24 09:02:33 +02:00
parent fd67f8ee69
commit a46a6bcfeb
3 changed files with 84 additions and 6 deletions

View File

@ -939,6 +939,7 @@ bufferedStream::bufferedStream(size_t initial_size, size_t bufmax) : outputStrea
buffer_pos = 0;
buffer_fixed = false;
buffer_max = bufmax;
truncated = false;
}
bufferedStream::bufferedStream(char* fixed_buffer, size_t fixed_buffer_size, size_t bufmax) : outputStream() {
@ -947,12 +948,17 @@ bufferedStream::bufferedStream(char* fixed_buffer, size_t fixed_buffer_size, siz
buffer_pos = 0;
buffer_fixed = true;
buffer_max = bufmax;
truncated = false;
}
void bufferedStream::write(const char* s, size_t len) {
if (truncated) {
return;
}
if(buffer_pos + len > buffer_max) {
flush();
flush(); // Note: may be a noop.
}
size_t end = buffer_pos + len;
@ -960,19 +966,42 @@ void bufferedStream::write(const char* s, size_t len) {
if (buffer_fixed) {
// if buffer cannot resize, silently truncate
len = buffer_length - buffer_pos - 1;
truncated = true;
} else {
// For small overruns, double the buffer. For larger ones,
// increase to the requested size.
if (end < buffer_length * 2) {
end = buffer_length * 2;
}
buffer = REALLOC_C_HEAP_ARRAY(char, buffer, end, mtInternal);
buffer_length = end;
// Impose a cap beyond which the buffer cannot grow - a size which
// in all probability indicates a real error, e.g. faulty printing
// code looping, while not affecting cases of just-very-large-but-its-normal
// output.
const size_t reasonable_cap = MAX2(100 * M, buffer_max * 2);
if (end > reasonable_cap) {
// In debug VM, assert right away.
assert(false, "Exceeded max buffer size for this string.");
// Release VM: silently truncate. We do this since these kind of errors
// are both difficult to predict with testing (depending on logging content)
// and usually not serious enough to kill a production VM for it.
end = reasonable_cap;
size_t remaining = end - buffer_pos;
if (len >= remaining) {
len = remaining - 1;
truncated = true;
}
}
if (buffer_length < end) {
buffer = REALLOC_C_HEAP_ARRAY(char, buffer, end, mtInternal);
buffer_length = end;
}
}
}
memcpy(buffer + buffer_pos, s, len);
buffer_pos += len;
update_position(s, len);
if (len > 0) {
memcpy(buffer + buffer_pos, s, len);
buffer_pos += len;
update_position(s, len);
}
}
char* bufferedStream::as_string() {

View File

@ -267,6 +267,7 @@ class bufferedStream : public outputStream {
size_t buffer_max;
size_t buffer_length;
bool buffer_fixed;
bool truncated;
public:
bufferedStream(size_t initial_bufsize = 256, size_t bufmax = 1024*1024*10);
bufferedStream(char* fixed_buffer, size_t fixed_buffer_size, size_t bufmax = 1024*1024*10);

View File

@ -67,3 +67,51 @@ TEST_VM(ostream, stringStream_dynamic_realloc_1) {
TEST_VM(ostream, stringStream_dynamic_realloc_2) {
do_test_stringStream_dynamic_realloc(true);
}
TEST_VM(ostream, bufferedStream_static) {
char buf[100];
bufferedStream bs(buf, sizeof(buf));
size_t written = 0;
for (int i = 0; i < 100; i ++) {
written += print_lorem(&bs, true);
if (written < sizeof(buf)) {
ASSERT_EQ(bs.size(), written);
} else {
ASSERT_EQ(bs.size(), sizeof(buf) - 1);
}
}
}
TEST_VM(ostream, bufferedStream_dynamic_small) {
bufferedStream bs(1); // small to excercise realloc.
size_t written = 0;
// The max cap imposed is 100M, we should be safely below this in this test.
for (int i = 0; i < 10; i ++) {
written += print_lorem(&bs, true);
ASSERT_EQ(bs.size(), written);
}
}
/* Activate to manually test bufferedStream dynamic cap.
TEST_VM(ostream, bufferedStream_dynamic_large) {
bufferedStream bs(1); // small to excercise realloc.
size_t written = 0;
// The max cap imposed is 100M. Writing this much should safely hit it.
// Note that this will assert in debug builds which is the expected behavior.
size_t expected_cap_at = 100 * M;
for (int i = 0; i < 10000000; i ++) {
written += print_lorem(&bs, false);
if (written < expected_cap_at) {
ASSERT_EQ(bs.size(), written);
} else {
ASSERT_EQ(bs.size(), expected_cap_at - 1);
}
}
}
*/