diff options
author | Daniel Dunbar <daniel@zuster.org> | 2009-08-23 20:31:39 +0000 |
---|---|---|
committer | Daniel Dunbar <daniel@zuster.org> | 2009-08-23 20:31:39 +0000 |
commit | 9441cfe4880018a85af9710ad405d4f2e522acc2 (patch) | |
tree | ce52791943346ccf557a8aa28979b3f157d58f4e /include | |
parent | a235d13217ff14621a88f3ea96a8a3b980c56d02 (diff) | |
download | external_llvm-9441cfe4880018a85af9710ad405d4f2e522acc2.zip external_llvm-9441cfe4880018a85af9710ad405d4f2e522acc2.tar.gz external_llvm-9441cfe4880018a85af9710ad405d4f2e522acc2.tar.bz2 |
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
Diffstat (limited to 'include')
-rw-r--r-- | include/llvm/Support/Format.h | 61 |
1 files changed, 27 insertions, 34 deletions
diff --git a/include/llvm/Support/Format.h b/include/llvm/Support/Format.h index 2ab097f..df03f66 100644 --- a/include/llvm/Support/Format.h +++ b/include/llvm/Support/Format.h @@ -36,6 +36,10 @@ class format_object_base { protected: const char *Fmt; virtual void home(); // Out of line virtual method. + + /// snprint - Call snprintf() for this object, on the given buffer and size. + virtual int snprint(char *Buffer, unsigned BufferSize) const = 0; + public: format_object_base(const char *fmt) : Fmt(fmt) {} virtual ~format_object_base() {} @@ -43,7 +47,23 @@ public: /// print - Format the object into the specified buffer. On success, this /// returns the length of the formatted string. If the buffer is too small, /// this returns a length to retry with, which will be larger than BufferSize. - virtual unsigned print(char *Buffer, unsigned BufferSize) const = 0; + unsigned print(char *Buffer, unsigned BufferSize) const { + assert(BufferSize && "Invalid buffer size!"); + + // Print the string, leaving room for the terminating null. + int N = snprint(Buffer, BufferSize); + + // VC++ and old GlibC return negative on overflow, just double the size. + if (N < 0) + return BufferSize*2; + + // Other impls yield number of bytes needed, not including the final '\0'. + if (unsigned(N) >= BufferSize) + return N+1; + + // Otherwise N is the length of output (not including the final '\0'). + return N; + } }; /// format_object1 - This is a templated helper class used by the format @@ -58,17 +78,8 @@ public: : format_object_base(fmt), Val(val) { } - /// print - Format the object into the specified buffer. On success, this - /// returns the length of the formatted string. If the buffer is too small, - /// this returns a length to retry with, which will be larger than BufferSize. - virtual unsigned print(char *Buffer, unsigned BufferSize) const { - int N = snprintf(Buffer, BufferSize-1, Fmt, Val); - if (N < 0) // VC++ and old GlibC return negative on overflow. - return BufferSize*2; - if (unsigned(N) >= BufferSize-1)// Other impls yield number of bytes needed. - return N+1; - // If N is positive and <= BufferSize-1, then the string fit, yay. - return N; + virtual int snprint(char *Buffer, unsigned BufferSize) const { + return snprintf(Buffer, BufferSize, Fmt, Val); } }; @@ -85,17 +96,8 @@ public: : format_object_base(fmt), Val1(val1), Val2(val2) { } - /// print - Format the object into the specified buffer. On success, this - /// returns the length of the formatted string. If the buffer is too small, - /// this returns a length to retry with, which will be larger than BufferSize. - virtual unsigned print(char *Buffer, unsigned BufferSize) const { - int N = snprintf(Buffer, BufferSize-1, Fmt, Val1, Val2); - if (N < 0) // VC++ and old GlibC return negative on overflow. - return BufferSize*2; - if (unsigned(N) >= BufferSize-1)// Other impls yield number of bytes needed. - return N+1; - // If N is positive and <= BufferSize-1, then the string fit, yay. - return N; + virtual int snprint(char *Buffer, unsigned BufferSize) const { + return snprintf(Buffer, BufferSize, Fmt, Val1, Val2); } }; @@ -113,17 +115,8 @@ public: : format_object_base(fmt), Val1(val1), Val2(val2), Val3(val3) { } - /// print - Format the object into the specified buffer. On success, this - /// returns the length of the formatted string. If the buffer is too small, - /// this returns a length to retry with, which will be larger than BufferSize. - virtual unsigned print(char *Buffer, unsigned BufferSize) const { - int N = snprintf(Buffer, BufferSize-1, Fmt, Val1, Val2, Val3); - if (N < 0) // VC++ and old GlibC return negative on overflow. - return BufferSize*2; - if (unsigned(N) >= BufferSize-1)// Other impls yield number of bytes needed. - return N+1; - // If N is positive and <= BufferSize-1, then the string fit, yay. - return N; + virtual int snprint(char *Buffer, unsigned BufferSize) const { + return snprintf(Buffer, BufferSize, Fmt, Val1, Val2, Val3); } }; |