diff --git a/libc/bionic/debug_format.cpp b/libc/bionic/debug_format.cpp index eeed3ac0d..793f8b19f 100644 --- a/libc/bionic/debug_format.cpp +++ b/libc/bionic/debug_format.cpp @@ -26,11 +26,7 @@ * SUCH DAMAGE. */ -// Temporarily disable _FORTIFY_SOURCE to get this code to -// compile under GCC 4.7 -#undef _FORTIFY_SOURCE - -#include "debug_format.h" +#include <../private/debug_format.h> // Relative path so we can #include this for testing. #include #include @@ -40,11 +36,6 @@ #include #include -/* define UNIT_TESTS to build this file as a single executable that runs - * the formatter's unit tests - */ -#define xxUNIT_TESTS - /*** Generic output sink ***/ @@ -134,12 +125,12 @@ buf_out_length(BufOut *bo) } static int -vformat_buffer(char *buff, size_t buffsize, const char *format, va_list args) +vformat_buffer(char *buff, size_t buf_size, const char *format, va_list args) { BufOut bo; Out *out; - out = buf_out_init(&bo, buff, buffsize); + out = buf_out_init(&bo, buff, buf_size); if (out == NULL) return 0; @@ -291,7 +282,7 @@ parse_decimal(const char *format, int *ppos) // Writes number 'value' in base 'base' into buffer 'buf' of size 'buf_size' bytes. // Assumes that buf_size > 0. -static void format_number(char* buf, size_t buf_size, uint64_t value, int base, bool caps) { +static void format_unsigned(char* buf, size_t buf_size, uint64_t value, int base, bool caps) { char* p = buf; char* end = buf + buf_size - 1; @@ -327,27 +318,26 @@ static void format_number(char* buf, size_t buf_size, uint64_t value, int base, } } -/* Write an integer (octal or decimal) into a buffer, assumes buffsize > 2 */ -static void -format_integer(char *buffer, size_t buffsize, uint64_t value, int base, int isSigned) -{ - // TODO: this is incorrect for MIN_INT. - if (isSigned && (int64_t)value < 0) { - buffer[0] = '-'; - buffer += 1; - buffsize -= 1; - value = (uint64_t)(-(int64_t)value); - } +static void format_integer(char* buf, size_t buf_size, uint64_t value, char conversion) { + // Decode the conversion specifier. + int is_signed = (conversion == 'd' || conversion == 'i' || conversion == 'o'); + int base = 10; + if (conversion == 'x' || conversion == 'X') { + base = 16; + } else if (conversion == 'o') { + base = 8; + } + bool caps = (conversion == 'X'); - format_number(buffer, buffsize, value, base, false); + if (is_signed && static_cast(value) < 0) { + buf[0] = '-'; + buf += 1; + buf_size -= 1; + value = static_cast(-static_cast(value)); + } + format_unsigned(buf, buf_size, value, base, caps); } -// Assumes buf_size > 2. -static void format_hex(char* buf, size_t buf_size, uint64_t value, bool caps) { - format_number(buf, buf_size, value, 16, caps); -} - - /* Perform formatted output to an output target 'o' */ static void out_vformat(Out *o, const char *format, va_list args) @@ -362,7 +352,6 @@ out_vformat(Out *o, const char *format, va_list args) int width = -1; int prec = -1; size_t bytelen = sizeof(int); - const char* str; int slen; char buffer[32]; /* temporary buffer used to format numbers */ @@ -457,6 +446,7 @@ out_vformat(Out *o, const char *format, va_list args) } /* conversion specifier */ + const char* str = buffer; if (c == 's') { /* string */ str = va_arg(args, const char*); @@ -468,17 +458,15 @@ out_vformat(Out *o, const char *format, va_list args) /* NOTE: char is promoted to int when passed through the stack */ buffer[0] = (char) va_arg(args, int); buffer[1] = '\0'; - str = buffer; } else if (c == 'p') { uint64_t value = (uintptr_t) va_arg(args, void*); buffer[0] = '0'; buffer[1] = 'x'; - format_hex(buffer + 2, sizeof buffer-2, value, false); - str = buffer; - } else { + format_integer(buffer + 2, sizeof(buffer) - 2, value, 'x'); + } else if (c == 'd' || c == 'i' || c == 'o' || c == 'x' || c == 'X') { /* integers - first read value from stack */ uint64_t value; - int isSigned = (c == 'd' || c == 'i' || c == 'o'); + int is_signed = (c == 'd' || c == 'i' || c == 'o'); /* NOTE: int8_t and int16_t are promoted to int when passed * through the stack @@ -492,27 +480,18 @@ out_vformat(Out *o, const char *format, va_list args) } /* sign extension, if needed */ - if (isSigned) { + if (is_signed) { int shift = 64 - 8*bytelen; value = (uint64_t)(((int64_t)(value << shift)) >> shift); } /* format the number properly into our buffer */ - switch (c) { - case 'i': case 'd': - format_integer(buffer, sizeof buffer, value, 10, isSigned); - break; - case 'o': - format_integer(buffer, sizeof buffer, value, 8, isSigned); - break; - case 'x': case 'X': - format_hex(buffer, sizeof buffer, value, (c == 'X')); - break; - default: - buffer[0] = '\0'; - } - /* then point to it */ - str = buffer; + format_integer(buffer, sizeof(buffer), value, c); + } else if (c == '%') { + buffer[0] = '%'; + buffer[1] = '\0'; + } else { + __assert(__FILE__, __LINE__, "conversion specifier unsupported"); } /* if we are here, 'str' points to the content that must be @@ -537,101 +516,3 @@ out_vformat(Out *o, const char *format, va_list args) } } } - - -#ifdef UNIT_TESTS - -#include - -static int gFails = 0; - -#define MARGIN 40 - -#define UTEST_CHECK(condition,message) \ - printf("Checking %-*s: ", MARGIN, message); fflush(stdout); \ - if (!(condition)) { \ - printf("KO\n"); \ - gFails += 1; \ - } else { \ - printf("ok\n"); \ - } - -static void -utest_BufOut(void) -{ - char buffer[16]; - BufOut bo[1]; - Out* out; - int ret; - - buffer[0] = '1'; - out = buf_out_init(bo, buffer, sizeof buffer); - UTEST_CHECK(buffer[0] == '\0', "buf_out_init clears initial byte"); - out_send(out, "abc", 3); - UTEST_CHECK(!memcmp(buffer, "abc", 4), "out_send() works with BufOut"); - out_send_repeat(out, 'X', 4); - UTEST_CHECK(!memcmp(buffer, "abcXXXX", 8), "out_send_repeat() works with BufOut"); - buffer[sizeof buffer-1] = 'x'; - out_send_repeat(out, 'Y', 2*sizeof(buffer)); - UTEST_CHECK(buffer[sizeof buffer-1] == '\0', "overflows always zero-terminates"); - - out = buf_out_init(bo, buffer, sizeof buffer); - out_send_repeat(out, 'X', 2*sizeof(buffer)); - ret = buf_out_length(bo); - UTEST_CHECK(ret == 2*sizeof(buffer), "correct size returned on overflow"); -} - -static void -utest_expect(const char* result, const char* format, ...) -{ - va_list args; - BufOut bo[1]; - char buffer[256]; - Out* out = buf_out_init(bo, buffer, sizeof buffer); - - printf("Checking %-*s: ", MARGIN, format); fflush(stdout); - va_start(args, format); - out_vformat(out, format, args); - va_end(args); - - if (strcmp(result, buffer)) { - printf("KO. got '%s' expecting '%s'\n", buffer, result); - gFails += 1; - } else { - printf("ok. got '%s'\n", result); - } -} - -int main(void) -{ - utest_BufOut(); - utest_expect("", ""); - utest_expect("a", "a"); - utest_expect("01234", "01234", ""); - utest_expect("01234", "%s", "01234"); - utest_expect("aabbcc", "aa%scc", "bb"); - utest_expect("a", "%c", 'a'); - utest_expect("1234", "%d", 1234); - utest_expect("-8123", "%d", -8123); - utest_expect("16", "%hd", 0x7fff0010); - utest_expect("16", "%hhd", 0x7fffff10); - utest_expect("68719476736", "%lld", 0x1000000000LL); - utest_expect("70000", "%ld", 70000); - utest_expect("0xb0001234", "%p", (void*)0xb0001234); - utest_expect("12ab", "%x", 0x12ab); - utest_expect("12AB", "%X", 0x12ab); - utest_expect("00123456", "%08x", 0x123456); - utest_expect("01234", "0%d", 1234); - utest_expect(" 1234", "%5d", 1234); - utest_expect("01234", "%05d", 1234); - utest_expect(" 1234", "%8d", 1234); - utest_expect("1234 ", "%-8d", 1234); - utest_expect("abcdef ", "%-11s", "abcdef"); - utest_expect("something:1234", "%s:%d", "something", 1234); - utest_expect("005:5:05", "%03d:%d:%02d", 5, 5, 5); - utest_expect("5,0x0", "%d,%p", 5, NULL); - utest_expect("68719476736,6,7,8", "%lld,%d,%d,%d", 0x1000000000LL, 6, 7, 8); - return gFails != 0; -} - -#endif /* UNIT_TESTS */ diff --git a/libc/include/signal.h b/libc/include/signal.h index 0770b0f75..8c9b170b9 100644 --- a/libc/include/signal.h +++ b/libc/include/signal.h @@ -59,7 +59,7 @@ extern const char* const sys_signame[]; static __inline__ int sigismember(const sigset_t* set, int signum) { int bit = signum - 1; // Signal numbers start at 1, but bit positions start at 0. - if (set == NULL || bit < 0 || bit >= 8*sizeof(sigset_t)) { + if (set == NULL || bit < 0 || bit >= (int) (8*sizeof(sigset_t))) { errno = EINVAL; return -1; } @@ -69,7 +69,7 @@ static __inline__ int sigismember(const sigset_t* set, int signum) { static __inline__ int sigaddset(sigset_t* set, int signum) { int bit = signum - 1; // Signal numbers start at 1, but bit positions start at 0. - if (set == NULL || bit < 0 || bit >= 8*sizeof(sigset_t)) { + if (set == NULL || bit < 0 || bit >= (int) (8*sizeof(sigset_t))) { errno = EINVAL; return -1; } @@ -80,7 +80,7 @@ static __inline__ int sigaddset(sigset_t* set, int signum) { static __inline__ int sigdelset(sigset_t* set, int signum) { int bit = signum - 1; // Signal numbers start at 1, but bit positions start at 0. - if (set == NULL || bit < 0 || bit >= 8*sizeof(sigset_t)) { + if (set == NULL || bit < 0 || bit >= (int) (8*sizeof(sigset_t))) { errno = EINVAL; return -1; } diff --git a/libc/include/stdio.h b/libc/include/stdio.h index cd04d9cbe..62882dba7 100644 --- a/libc/include/stdio.h +++ b/libc/include/stdio.h @@ -523,13 +523,13 @@ char *fgets(char *dest, int size, FILE *stream) // Compiler can prove, at compile time, that the passed in size // is always <= the actual object size. Don't call __fgets_chk - if (__builtin_constant_p(size) && (size <= bos)) { + if (__builtin_constant_p(size) && (size <= (int) bos)) { return __fgets_real(dest, size, stream); } // Compiler can prove, at compile time, that the passed in size // is always > the actual object size. Force a compiler error. - if (__builtin_constant_p(size) && (size > bos)) { + if (__builtin_constant_p(size) && (size > (int) bos)) { __fgets_too_big_error(); } diff --git a/tests/Android.mk b/tests/Android.mk index 25da12084..0685d4a13 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -53,6 +53,7 @@ test_c_flags = \ -Werror \ test_src_files = \ + debug_format_test.cpp \ dirent_test.cpp \ fenv_test.cpp \ getauxval_test.cpp \ diff --git a/tests/debug_format_test.cpp b/tests/debug_format_test.cpp new file mode 100644 index 000000000..8419e4afc --- /dev/null +++ b/tests/debug_format_test.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#if defined(__BIONIC__) + +#include "../libc/bionic/debug_format.cpp" + +extern int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...); + +TEST(debug_format, smoke) { + char buf[BUFSIZ]; + + __libc_format_buffer(buf, sizeof(buf), "a"); + EXPECT_STREQ("a", buf); + + __libc_format_buffer(buf, sizeof(buf), "%%"); + EXPECT_STREQ("%", buf); + + __libc_format_buffer(buf, sizeof(buf), "01234"); + EXPECT_STREQ("01234", buf); + + __libc_format_buffer(buf, sizeof(buf), "a%sb", "01234"); + EXPECT_STREQ("a01234b", buf); + + char* s = NULL; + __libc_format_buffer(buf, sizeof(buf), "a%sb", s); + EXPECT_STREQ("a(null)b", buf); + + __libc_format_buffer(buf, sizeof(buf), "aa%scc", "bb"); + EXPECT_STREQ("aabbcc", buf); + + __libc_format_buffer(buf, sizeof(buf), "a%cc", 'b'); + EXPECT_STREQ("abc", buf); + + __libc_format_buffer(buf, sizeof(buf), "a%db", 1234); + EXPECT_STREQ("a1234b", buf); + + __libc_format_buffer(buf, sizeof(buf), "a%db", -8123); + EXPECT_STREQ("a-8123b", buf); + + __libc_format_buffer(buf, sizeof(buf), "a%hdb", 0x7fff0010); + EXPECT_STREQ("a16b", buf); + + __libc_format_buffer(buf, sizeof(buf), "a%hhdb", 0x7fffff10); + EXPECT_STREQ("a16b", buf); + + __libc_format_buffer(buf, sizeof(buf), "a%lldb", 0x1000000000LL); + EXPECT_STREQ("a68719476736b", buf); + + __libc_format_buffer(buf, sizeof(buf), "a%ldb", 70000L); + EXPECT_STREQ("a70000b", buf); + + __libc_format_buffer(buf, sizeof(buf), "a%pb", reinterpret_cast(0xb0001234)); + EXPECT_STREQ("a0xb0001234b", buf); + + __libc_format_buffer(buf, sizeof(buf), "a%xz", 0x12ab); + EXPECT_STREQ("a12abz", buf); + + __libc_format_buffer(buf, sizeof(buf), "a%Xz", 0x12ab); + EXPECT_STREQ("a12ABz", buf); + + __libc_format_buffer(buf, sizeof(buf), "a%08xz", 0x123456); + EXPECT_STREQ("a00123456z", buf); + + __libc_format_buffer(buf, sizeof(buf), "a%5dz", 1234); + EXPECT_STREQ("a 1234z", buf); + + __libc_format_buffer(buf, sizeof(buf), "a%05dz", 1234); + EXPECT_STREQ("a01234z", buf); + + __libc_format_buffer(buf, sizeof(buf), "a%8dz", 1234); + EXPECT_STREQ("a 1234z", buf); + + __libc_format_buffer(buf, sizeof(buf), "a%-8dz", 1234); + EXPECT_STREQ("a1234 z", buf); + + __libc_format_buffer(buf, sizeof(buf), "A%-11sZ", "abcdef"); + EXPECT_STREQ("Aabcdef Z", buf); + + __libc_format_buffer(buf, sizeof(buf), "A%s:%dZ", "hello", 1234); + EXPECT_STREQ("Ahello:1234Z", buf); + + __libc_format_buffer(buf, sizeof(buf), "a%03d:%d:%02dz", 5, 5, 5); + EXPECT_STREQ("a005:5:05z", buf); + + void* p = NULL; + __libc_format_buffer(buf, sizeof(buf), "a%d,%pz", 5, p); + EXPECT_STREQ("a5,0x0z", buf); + + __libc_format_buffer(buf, sizeof(buf), "a%lld,%d,%d,%dz", 0x1000000000LL, 6, 7, 8); + EXPECT_STREQ("a68719476736,6,7,8z", buf); +} + +TEST(debug_format, d_INT_MAX) { + char buf[BUFSIZ]; + __libc_format_buffer(buf, sizeof(buf), "%d", INT_MAX); + EXPECT_STREQ("2147483647", buf); +} + +TEST(debug_format, d_INT_MIN) { + char buf[BUFSIZ]; + __libc_format_buffer(buf, sizeof(buf), "%d", INT_MIN); + EXPECT_STREQ("-2147483648", buf); +} + +TEST(debug_format, ld_LONG_MAX) { + char buf[BUFSIZ]; + __libc_format_buffer(buf, sizeof(buf), "%ld", LONG_MAX); + EXPECT_STREQ("2147483647", buf); +} + +TEST(debug_format, ld_LONG_MIN) { + char buf[BUFSIZ]; + __libc_format_buffer(buf, sizeof(buf), "%ld", LONG_MIN); + EXPECT_STREQ("-2147483648", buf); +} + +TEST(debug_format, lld_LLONG_MAX) { + char buf[BUFSIZ]; + __libc_format_buffer(buf, sizeof(buf), "%lld", LLONG_MAX); + EXPECT_STREQ("9223372036854775807", buf); +} + +TEST(debug_format, lld_LLONG_MIN) { + char buf[BUFSIZ]; + __libc_format_buffer(buf, sizeof(buf), "%lld", LLONG_MIN); + EXPECT_STREQ("-9223372036854775808", buf); +} + +#endif