Refactor BufferOutputStream.

- Rewrite BufferOutputStream to handle 0 sized buffers and to get rid
  of an unnecessary loop.
- Add tests to verify overflow corner cases.
- Implement async_safe_format_buffer to call async_safe_format_buffer_va_list
  instead of duplicate the code.

Test: Ran new unit tests, booted on angler.
Change-Id: I7fb13e209f5b7443d212f55aab4b05ff2e0e8219
This commit is contained in:
Christopher Ferris 2017-08-22 11:24:09 -07:00
parent 3ce8834e53
commit 9247640711
2 changed files with 39 additions and 36 deletions

View File

@ -60,43 +60,36 @@ enum AndroidEventLogType {
struct BufferOutputStream {
public:
BufferOutputStream(char* buffer, size_t size) : total(0) {
buffer_ = buffer;
end_ = buffer + size - 1;
pos_ = buffer_;
pos_[0] = '\0';
BufferOutputStream(char* buffer, size_t size) : total(0), pos_(buffer), avail_(size) {
if (avail_ > 0) pos_[0] = '\0';
}
~BufferOutputStream() {}
~BufferOutputStream() = default;
void Send(const char* data, int len) {
if (len < 0) {
len = strlen(data);
}
total += len;
while (len > 0) {
int avail = end_ - pos_;
if (avail == 0) {
return;
}
if (avail > len) {
avail = len;
}
memcpy(pos_, data, avail);
pos_ += avail;
pos_[0] = '\0';
len -= avail;
if (avail_ <= 1) {
// No space to put anything else.
return;
}
if (static_cast<size_t>(len) >= avail_) {
len = avail_ - 1;
}
memcpy(pos_, data, len);
pos_ += len;
pos_[0] = '\0';
avail_ -= len;
}
size_t total;
private:
char* buffer_;
char* pos_;
char* end_;
size_t avail_;
};
struct FdOutputStream {
@ -107,16 +100,15 @@ struct FdOutputStream {
if (len < 0) {
len = strlen(data);
}
total += len;
while (len > 0) {
int rc = TEMP_FAILURE_RETRY(write(fd_, data, len));
if (rc == -1) {
ssize_t bytes = TEMP_FAILURE_RETRY(write(fd_, data, len));
if (bytes == -1) {
return;
}
data += rc;
len -= rc;
data += bytes;
len -= bytes;
}
}
@ -409,15 +401,6 @@ static void out_vformat(Out& o, const char* format, va_list args) {
}
}
int async_safe_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) {
BufferOutputStream os(buffer, buffer_size);
va_list args;
va_start(args, format);
out_vformat(os, format, args);
va_end(args);
return os.total;
}
int async_safe_format_buffer_va_list(char* buffer, size_t buffer_size, const char* format,
va_list args) {
BufferOutputStream os(buffer, buffer_size);
@ -425,6 +408,14 @@ int async_safe_format_buffer_va_list(char* buffer, size_t buffer_size, const cha
return os.total;
}
int async_safe_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) {
va_list args;
va_start(args, format);
int buffer_len = async_safe_format_buffer_va_list(buffer, buffer_size, format, args);
va_end(args);
return buffer_len;
}
int async_safe_format_fd(int fd, const char* format, ...) {
FdOutputStream os(fd);
va_list args;

View File

@ -181,8 +181,20 @@ TEST(async_safe_log, buffer_overrun) {
char buf[BUFSIZ];
ASSERT_EQ(11, async_safe_format_buffer(buf, sizeof(buf), "hello %s", "world"));
EXPECT_STREQ("hello world", buf);
ASSERT_EQ(11, async_safe_format_buffer(buf, 8, "hello %s", "world"));
EXPECT_STREQ("hello w", buf);
ASSERT_EQ(11, async_safe_format_buffer(buf, 6, "hello %s", "world"));
EXPECT_STREQ("hello", buf);
ASSERT_EQ(4, async_safe_format_buffer(nullptr, 0, "xxxx"));
ASSERT_EQ(4, async_safe_format_buffer(buf, 1, "xxxx"));
EXPECT_STREQ("", buf);
ASSERT_EQ(4, async_safe_format_buffer(buf, 2, "xxxx"));
EXPECT_STREQ("x", buf);
#else // __BIONIC__
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif // __BIONIC__