[string] Remove reuse of va_list in AppendVarargs

va_list are not guarenteed to maintain their values after being used.
With clang on Linux, args is undefined after fetching length and will print
"(null)".
Copy args into another va_list before getting length to prevent this.
Add tests.
This commit is contained in:
Sandy Carter 2019-01-27 10:10:04 -05:00
parent 6c58b3b13d
commit c97c4dbeac
2 changed files with 15 additions and 3 deletions

View File

@ -64,7 +64,10 @@ void StringBuffer::AppendFormat(const char* format, ...) {
}
void StringBuffer::AppendVarargs(const char* format, va_list args) {
int length = vsnprintf(nullptr, 0, format, args);
va_list size_args;
va_copy(size_args, args); // arg is indeterminate after the return so copy it
int length = vsnprintf(nullptr, 0, format, size_args);
va_end(size_args);
Grow(length + 1);
vsnprintf(buffer_ + buffer_offset_, buffer_capacity_, format, args);
buffer_offset_ += length;

View File

@ -8,6 +8,7 @@
*/
#include "xenia/base/string.h"
#include "xenia/base/string_buffer.h"
#include "third_party/catch/include/catch.hpp"
@ -16,8 +17,16 @@ namespace base {
namespace test {
TEST_CASE("StringBuffer") {
// TODO(bwrsandman):
REQUIRE(false);
StringBuffer sb;
uint32_t module_flags = 0x1000000;
std::string path_(R"(\Device\Cdrom0\default.xex)");
sb.AppendFormat("Module %s:\n", path_.c_str());
REQUIRE(sb.to_string() == "Module \\Device\\Cdrom0\\default.xex:\n");
sb.AppendFormat(" Module Flags: %.8X\n", module_flags);
REQUIRE(
sb.to_string() ==
"Module \\Device\\Cdrom0\\default.xex:\n Module Flags: 01000000\n");
}
} // namespace test