parent
b971bea8aa
commit
c3e751aac6
53 changed files with 1012 additions and 1028 deletions
@ -1,176 +0,0 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2012 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// from google3/base/stringprintf.cc
|
||||
|
||||
#include "google/protobuf/stubs/stringprintf.h" |
||||
|
||||
#include <errno.h> |
||||
#include <stdarg.h> // For va_list and related operations |
||||
#include <stdio.h> // MSVC requires this for _vsnprintf |
||||
|
||||
#include <vector> |
||||
|
||||
#include "google/protobuf/stubs/common.h" |
||||
#include "google/protobuf/stubs/logging.h" |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
|
||||
#ifdef _MSC_VER |
||||
#ifndef va_copy |
||||
// Define va_copy for MSVC. This is a hack, assuming va_list is simply a
|
||||
// pointer into the stack and is safe to copy.
|
||||
#define va_copy(dest, src) ((dest) = (src)) |
||||
#endif |
||||
#endif |
||||
|
||||
void StringAppendV(std::string* dst, const char* format, va_list ap) { |
||||
// First try with a small fixed size buffer
|
||||
static const int kSpaceLength = 1024; |
||||
char space[kSpaceLength]; |
||||
|
||||
// It's possible for methods that use a va_list to invalidate
|
||||
// the data in it upon use. The fix is to make a copy
|
||||
// of the structure before using it and use that copy instead.
|
||||
va_list backup_ap; |
||||
va_copy(backup_ap, ap); |
||||
int result = vsnprintf(space, kSpaceLength, format, backup_ap); |
||||
va_end(backup_ap); |
||||
|
||||
if (result < kSpaceLength) { |
||||
if (result >= 0) { |
||||
// Normal case -- everything fit.
|
||||
dst->append(space, result); |
||||
return; |
||||
} |
||||
|
||||
#ifdef _MSC_VER |
||||
{ |
||||
// Error or MSVC running out of space. MSVC 8.0 and higher
|
||||
// can be asked about space needed with the special idiom below:
|
||||
va_copy(backup_ap, ap); |
||||
result = vsnprintf(nullptr, 0, format, backup_ap); |
||||
va_end(backup_ap); |
||||
} |
||||
#endif |
||||
|
||||
if (result < 0) { |
||||
// Just an error.
|
||||
return; |
||||
} |
||||
} |
||||
|
||||
// Increase the buffer size to the size requested by vsnprintf,
|
||||
// plus one for the closing \0.
|
||||
int length = result+1; |
||||
char* buf = new char[length]; |
||||
|
||||
// Restore the va_list before we use it again
|
||||
va_copy(backup_ap, ap); |
||||
result = vsnprintf(buf, length, format, backup_ap); |
||||
va_end(backup_ap); |
||||
|
||||
if (result >= 0 && result < length) { |
||||
// It fit
|
||||
dst->append(buf, result); |
||||
} |
||||
delete[] buf; |
||||
} |
||||
|
||||
std::string StringPrintf(const char* format, ...) { |
||||
va_list ap; |
||||
va_start(ap, format); |
||||
std::string result; |
||||
StringAppendV(&result, format, ap); |
||||
va_end(ap); |
||||
return result; |
||||
} |
||||
|
||||
const std::string& SStringPrintf(std::string* dst, const char* format, ...) { |
||||
va_list ap; |
||||
va_start(ap, format); |
||||
dst->clear(); |
||||
StringAppendV(dst, format, ap); |
||||
va_end(ap); |
||||
return *dst; |
||||
} |
||||
|
||||
void StringAppendF(std::string* dst, const char* format, ...) { |
||||
va_list ap; |
||||
va_start(ap, format); |
||||
StringAppendV(dst, format, ap); |
||||
va_end(ap); |
||||
} |
||||
|
||||
// Max arguments supported by StringPrintVector
|
||||
const int kStringPrintfVectorMaxArgs = 32; |
||||
|
||||
// An empty block of zero for filler arguments. This is const so that if
|
||||
// printf tries to write to it (via %n) then the program gets a SIGSEGV
|
||||
// and we can fix the problem or protect against an attack.
|
||||
static const char string_printf_empty_block[256] = { '\0' }; |
||||
|
||||
std::string StringPrintfVector(const char* format, |
||||
const std::vector<std::string>& v) { |
||||
GOOGLE_CHECK_LE(v.size(), kStringPrintfVectorMaxArgs) |
||||
<< "StringPrintfVector currently only supports up to " |
||||
<< kStringPrintfVectorMaxArgs << " arguments. " |
||||
<< "Feel free to add support for more if you need it."; |
||||
|
||||
// Add filler arguments so that bogus format+args have a harder time
|
||||
// crashing the program, corrupting the program (%n),
|
||||
// or displaying random chunks of memory to users.
|
||||
|
||||
const char* cstr[kStringPrintfVectorMaxArgs]; |
||||
for (int i = 0; i < v.size(); ++i) { |
||||
cstr[i] = v[i].c_str(); |
||||
} |
||||
for (int i = v.size(); i < kStringPrintfVectorMaxArgs; ++i) { |
||||
cstr[i] = &string_printf_empty_block[0]; |
||||
} |
||||
|
||||
// I do not know any way to pass kStringPrintfVectorMaxArgs arguments,
|
||||
// or any way to build a va_list by hand, or any API for printf
|
||||
// that accepts an array of arguments. The best I can do is stick
|
||||
// this COMPILE_ASSERT right next to the actual statement.
|
||||
|
||||
static_assert(kStringPrintfVectorMaxArgs == 32, "arg_count_mismatch"); |
||||
return StringPrintf(format, |
||||
cstr[0], cstr[1], cstr[2], cstr[3], cstr[4], |
||||
cstr[5], cstr[6], cstr[7], cstr[8], cstr[9], |
||||
cstr[10], cstr[11], cstr[12], cstr[13], cstr[14], |
||||
cstr[15], cstr[16], cstr[17], cstr[18], cstr[19], |
||||
cstr[20], cstr[21], cstr[22], cstr[23], cstr[24], |
||||
cstr[25], cstr[26], cstr[27], cstr[28], cstr[29], |
||||
cstr[30], cstr[31]); |
||||
} |
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -1,87 +0,0 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2012 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// from google3/base/stringprintf.h
|
||||
//
|
||||
// Printf variants that place their output in a C++ string.
|
||||
//
|
||||
// Usage:
|
||||
// string result = StringPrintf("%d %s\n", 10, "hello");
|
||||
// SStringPrintf(&result, "%d %s\n", 10, "hello");
|
||||
// StringAppendF(&result, "%d %s\n", 20, "there");
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H |
||||
#define GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H |
||||
|
||||
#include <stdarg.h> |
||||
|
||||
#include <string> |
||||
#include <vector> |
||||
|
||||
#include "google/protobuf/stubs/common.h" |
||||
|
||||
// Must be last.
|
||||
#include "google/protobuf/port_def.inc" // NOLINT |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
|
||||
// Return a C++ string
|
||||
PROTOBUF_EXPORT extern std::string StringPrintf(const char* format, ...); |
||||
|
||||
// Store result into a supplied string and return it
|
||||
PROTOBUF_EXPORT extern const std::string& SStringPrintf(std::string* dst, |
||||
const char* format, |
||||
...); |
||||
|
||||
// Append result to a supplied string
|
||||
PROTOBUF_EXPORT extern void StringAppendF(std::string* dst, const char* format, |
||||
...); |
||||
|
||||
// Lower-level routine that takes a va_list and appends to a specified
|
||||
// string. All other routines are just convenience wrappers around it.
|
||||
PROTOBUF_EXPORT extern void StringAppendV(std::string* dst, const char* format, |
||||
va_list ap); |
||||
|
||||
// The max arguments supported by StringPrintfVector
|
||||
PROTOBUF_EXPORT extern const int kStringPrintfVectorMaxArgs; |
||||
|
||||
// You can use this version when all your arguments are strings, but
|
||||
// you don't know how many arguments you'll have at compile time.
|
||||
// StringPrintfVector will LOG(FATAL) if v.size() > kStringPrintfVectorMaxArgs
|
||||
PROTOBUF_EXPORT extern std::string StringPrintfVector( |
||||
const char* format, const std::vector<std::string>& v); |
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc" |
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H
|
@ -1,157 +0,0 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2012 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// from google3/base/stringprintf_unittest.cc
|
||||
|
||||
#include "google/protobuf/stubs/stringprintf.h" |
||||
|
||||
#include <gtest/gtest.h> |
||||
|
||||
#include <array> |
||||
#include <cerrno> |
||||
#include <string> |
||||
|
||||
#include "google/protobuf/testing/googletest.h" |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace { |
||||
|
||||
TEST(StringPrintfTest, Empty) { |
||||
#if 0 |
||||
// gcc 2.95.3, gcc 4.1.0, and gcc 4.2.2 all warn about this:
|
||||
// warning: zero-length printf format string.
|
||||
// so we do not allow them in google3.
|
||||
EXPECT_EQ("", StringPrintf("")); |
||||
#endif |
||||
EXPECT_EQ("", StringPrintf("%s", std::string().c_str())); |
||||
EXPECT_EQ("", StringPrintf("%s", "")); |
||||
} |
||||
|
||||
TEST(StringPrintfTest, Misc) { |
||||
// MSVC and mingw does not support $ format specifier.
|
||||
#if !defined(_MSC_VER) && !defined(__MINGW32__) |
||||
EXPECT_EQ("123hello w", StringPrintf("%3$d%2$s %1$c", 'w', "hello", 123)); |
||||
#endif // !_MSC_VER
|
||||
} |
||||
|
||||
TEST(StringAppendFTest, Empty) { |
||||
std::string value("Hello"); |
||||
const char* empty = ""; |
||||
StringAppendF(&value, "%s", empty); |
||||
EXPECT_EQ("Hello", value); |
||||
} |
||||
|
||||
TEST(StringAppendFTest, EmptyString) { |
||||
std::string value("Hello"); |
||||
StringAppendF(&value, "%s", ""); |
||||
EXPECT_EQ("Hello", value); |
||||
} |
||||
|
||||
TEST(StringAppendFTest, String) { |
||||
std::string value("Hello"); |
||||
StringAppendF(&value, " %s", "World"); |
||||
EXPECT_EQ("Hello World", value); |
||||
} |
||||
|
||||
TEST(StringAppendFTest, Int) { |
||||
std::string value("Hello"); |
||||
StringAppendF(&value, " %d", 123); |
||||
EXPECT_EQ("Hello 123", value); |
||||
} |
||||
|
||||
TEST(StringPrintfTest, Multibyte) { |
||||
// If we are in multibyte mode and feed invalid multibyte sequence,
|
||||
// StringPrintf should return an empty string instead of running
|
||||
// out of memory while trying to determine destination buffer size.
|
||||
// see b/4194543.
|
||||
|
||||
char* old_locale_c = setlocale(LC_CTYPE, nullptr); |
||||
ASSERT_TRUE(old_locale_c != nullptr); |
||||
std::string old_locale = old_locale_c; |
||||
// Push locale with multibyte mode
|
||||
setlocale(LC_CTYPE, "en_US.utf8"); |
||||
|
||||
const char kInvalidCodePoint[] = "\375\067s"; |
||||
std::string value = StringPrintf("%.*s", 3, kInvalidCodePoint); |
||||
|
||||
// In some versions of glibc (e.g. eglibc-2.11.1, aka GRTEv2), snprintf
|
||||
// returns error given an invalid codepoint. Other versions
|
||||
// (e.g. eglibc-2.15, aka pre-GRTEv3) emit the codepoint verbatim.
|
||||
// We test that the output is one of the above.
|
||||
EXPECT_TRUE(value.empty() || value == kInvalidCodePoint); |
||||
|
||||
// Repeat with longer string, to make sure that the dynamically
|
||||
// allocated path in StringAppendV is handled correctly.
|
||||
const size_t n = 2048; |
||||
std::array<char, n + 1> buf; |
||||
memset(&buf[0], ' ', n - 3); |
||||
memcpy(&buf[0] + n - 3, kInvalidCodePoint, 4); |
||||
value = StringPrintf("%.*s", n, &buf[0]); |
||||
// See GRTEv2 vs. GRTEv3 comment above.
|
||||
EXPECT_TRUE(value.empty() || value == &buf[0]); |
||||
|
||||
setlocale(LC_CTYPE, old_locale.c_str()); |
||||
} |
||||
|
||||
TEST(StringPrintfTest, NoMultibyte) { |
||||
// No multibyte handling, but the string contains funny chars.
|
||||
char* old_locale_c = setlocale(LC_CTYPE, nullptr); |
||||
ASSERT_TRUE(old_locale_c != nullptr); |
||||
std::string old_locale = old_locale_c; |
||||
setlocale(LC_CTYPE, "POSIX"); |
||||
std::string value = StringPrintf("%.*s", 3, "\375\067s"); |
||||
setlocale(LC_CTYPE, old_locale.c_str()); |
||||
EXPECT_EQ("\375\067s", value); |
||||
} |
||||
|
||||
TEST(StringPrintfTest, DontOverwriteErrno) { |
||||
// Check that errno isn't overwritten unless we're printing
|
||||
// something significantly larger than what people are normally
|
||||
// printing in their badly written PLOG() statements.
|
||||
errno = ECHILD; |
||||
std::string value = StringPrintf("Hello, %s!", "World"); |
||||
EXPECT_EQ(ECHILD, errno); |
||||
} |
||||
|
||||
TEST(StringPrintfTest, LargeBuf) { |
||||
// Check that the large buffer is handled correctly.
|
||||
int n = 2048; |
||||
char* buf = new char[n+1]; |
||||
memset(buf, ' ', n); |
||||
buf[n] = 0; |
||||
std::string value = StringPrintf("%s", buf); |
||||
EXPECT_EQ(buf, value); |
||||
delete[] buf; |
||||
} |
||||
|
||||
} // anonymous namespace
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
Loading…
Reference in new issue