llvm.org GIT mirror llvm / 9441cfe
Fix off-by-one in llvm::Format::print. - This also shortens the Format.h implementation, and uses the print buffer fully (it was wasting a character). - This manifested as llvm-test failures, because one side effect was that raw_ostream would write garbage '\x00' values into the output stream if it happened that the string was at the end of the buffer. This meant that grep would report 'Binary file matches', which meant the silly pattern matching llvm-test eventually does would fail. Cute. :) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79862 91177308-0d34-0410-b5e6-96231b3b80d8 Daniel Dunbar 10 years ago
3 changed file(s) with 59 addition(s) and 39 deletion(s). Raw diff Collapse all Expand all
3535 protected:
3636 const char *Fmt;
3737 virtual void home(); // Out of line virtual method.
38
39 /// snprint - Call snprintf() for this object, on the given buffer and size.
40 virtual int snprint(char *Buffer, unsigned BufferSize) const = 0;
41
3842 public:
3943 format_object_base(const char *fmt) : Fmt(fmt) {}
4044 virtual ~format_object_base() {}
4246 /// print - Format the object into the specified buffer. On success, this
4347 /// returns the length of the formatted string. If the buffer is too small,
4448 /// this returns a length to retry with, which will be larger than BufferSize.
45 virtual unsigned print(char *Buffer, unsigned BufferSize) const = 0;
49 unsigned print(char *Buffer, unsigned BufferSize) const {
50 assert(BufferSize && "Invalid buffer size!");
51
52 // Print the string, leaving room for the terminating null.
53 int N = snprint(Buffer, BufferSize);
54
55 // VC++ and old GlibC return negative on overflow, just double the size.
56 if (N < 0)
57 return BufferSize*2;
58
59 // Other impls yield number of bytes needed, not including the final '\0'.
60 if (unsigned(N) >= BufferSize)
61 return N+1;
62
63 // Otherwise N is the length of output (not including the final '\0').
64 return N;
65 }
4666 };
4767
4868 /// format_object1 - This is a templated helper class used by the format
5777 : format_object_base(fmt), Val(val) {
5878 }
5979
60 /// print - Format the object into the specified buffer. On success, this
61 /// returns the length of the formatted string. If the buffer is too small,
62 /// this returns a length to retry with, which will be larger than BufferSize.
63 virtual unsigned print(char *Buffer, unsigned BufferSize) const {
64 int N = snprintf(Buffer, BufferSize-1, Fmt, Val);
65 if (N < 0) // VC++ and old GlibC return negative on overflow.
66 return BufferSize*2;
67 if (unsigned(N) >= BufferSize-1)// Other impls yield number of bytes needed.
68 return N+1;
69 // If N is positive and <= BufferSize-1, then the string fit, yay.
70 return N;
80 virtual int snprint(char *Buffer, unsigned BufferSize) const {
81 return snprintf(Buffer, BufferSize, Fmt, Val);
7182 }
7283 };
7384
8495 : format_object_base(fmt), Val1(val1), Val2(val2) {
8596 }
8697
87 /// print - Format the object into the specified buffer. On success, this
88 /// returns the length of the formatted string. If the buffer is too small,
89 /// this returns a length to retry with, which will be larger than BufferSize.
90 virtual unsigned print(char *Buffer, unsigned BufferSize) const {
91 int N = snprintf(Buffer, BufferSize-1, Fmt, Val1, Val2);
92 if (N < 0) // VC++ and old GlibC return negative on overflow.
93 return BufferSize*2;
94 if (unsigned(N) >= BufferSize-1)// Other impls yield number of bytes needed.
95 return N+1;
96 // If N is positive and <= BufferSize-1, then the string fit, yay.
97 return N;
98 virtual int snprint(char *Buffer, unsigned BufferSize) const {
99 return snprintf(Buffer, BufferSize, Fmt, Val1, Val2);
98100 }
99101 };
100102
112114 : format_object_base(fmt), Val1(val1), Val2(val2), Val3(val3) {
113115 }
114116
115 /// print - Format the object into the specified buffer. On success, this
116 /// returns the length of the formatted string. If the buffer is too small,
117 /// this returns a length to retry with, which will be larger than BufferSize.
118 virtual unsigned print(char *Buffer, unsigned BufferSize) const {
119 int N = snprintf(Buffer, BufferSize-1, Fmt, Val1, Val2, Val3);
120 if (N < 0) // VC++ and old GlibC return negative on overflow.
121 return BufferSize*2;
122 if (unsigned(N) >= BufferSize-1)// Other impls yield number of bytes needed.
123 return N+1;
124 // If N is positive and <= BufferSize-1, then the string fit, yay.
125 return N;
117 virtual int snprint(char *Buffer, unsigned BufferSize) const {
118 return snprintf(Buffer, BufferSize, Fmt, Val1, Val2, Val3);
126119 }
127120 };
128121
252252 // If we have more than a few bytes left in our output buffer, try
253253 // formatting directly onto its end.
254254 size_t NextBufferSize = 127;
255 if (OutBufEnd-OutBufCur > 3) {
256 size_t BufferBytesLeft = OutBufEnd-OutBufCur;
255 size_t BufferBytesLeft = OutBufEnd - OutBufCur;
256 if (BufferBytesLeft > 3) {
257257 size_t BytesUsed = Fmt.print(OutBufCur, BufferBytesLeft);
258258
259259 // Common case is that we have plenty of space.
260 if (BytesUsed < BufferBytesLeft) {
260 if (BytesUsed <= BufferBytesLeft) {
261261 OutBufCur += BytesUsed;
262262 return *this;
263263 }
276276 V.resize(NextBufferSize);
277277
278278 // Try formatting into the SmallVector.
279 size_t BytesUsed = Fmt.print(&V[0], NextBufferSize);
279 size_t BytesUsed = Fmt.print(V.data(), NextBufferSize);
280280
281281 // If BytesUsed fit into the vector, we win.
282282 if (BytesUsed <= NextBufferSize)
283 return write(&V[0], BytesUsed);
283 return write(V.data(), BytesUsed);
284284
285285 // Otherwise, try again with a new size.
286286 assert(BytesUsed > NextBufferSize && "Didn't grow buffer!?");
77 //===----------------------------------------------------------------------===//
88
99 #include "gtest/gtest.h"
10 #include "llvm/ADT/SmallString.h"
11 #include "llvm/Support/Format.h"
1012 #include "llvm/Support/raw_ostream.h"
1113
1214 using namespace llvm;
1719 std::string res;
1820 llvm::raw_string_ostream(res) << Value;
1921 return res;
22 }
23
24 /// printToString - Print the given value to a stream which only has \arg
25 /// BytesLeftInBuffer bytes left in the buffer. This is useful for testing edge
26 /// cases in the buffer handling logic.
27 template std::string printToString(const T &Value,
28 unsigned BytesLeftInBuffer) {
29 // FIXME: This is relying on internal knowledge of how raw_ostream works to
30 // get the buffer position right.
31 SmallString<256> SVec;
32 assert(BytesLeftInBuffer < 256 && "Invalid buffer count!");
33 llvm::raw_svector_ostream OS(SVec);
34 unsigned StartIndex = 256 - BytesLeftInBuffer;
35 for (unsigned i = 0; i != StartIndex; ++i)
36 OS << '?';
37 OS << Value;
38 return OS.str().substr(StartIndex);
2039 }
2140
2241 template std::string printToStringUnbuffered(const T &Value) {
89108 EXPECT_EQ("-9223372036854775808", printToStringUnbuffered(INT64_MIN));
90109 }
91110
111 TEST(raw_ostreamTest, BufferEdge) {
112 EXPECT_EQ("1.20", printToString(format("%.2f", 1.2), 1));
113 EXPECT_EQ("1.20", printToString(format("%.2f", 1.2), 2));
114 EXPECT_EQ("1.20", printToString(format("%.2f", 1.2), 3));
115 EXPECT_EQ("1.20", printToString(format("%.2f", 1.2), 4));
116 EXPECT_EQ("1.20", printToString(format("%.2f", 1.2), 10));
92117 }
118
119 }