aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorOrlando Arbildo <oarbildo@google.com>2022-08-09 22:24:27 +0000
committerOrlando Arbildo <oarbildo@google.com>2022-09-08 19:58:36 +0000
commit7ac8b7983f78a8d511f527f5f78e3a5f9593b719 (patch)
tree20c3666846dbb74cf34eed4fd8e3517a47be2a4a /lib
parentc5edec8b78f992781e456a21d5e610ea6dce4e85 (diff)
downloadcommon-7ac8b7983f78a8d511f527f5f78e3a5f9593b719.tar.gz
[lib][libc] Improving log filtering capabilities
Adding modifiers to override filtering. We are using the same modifier used by printk in the linux kernel to override filtering of pointers (%px), and extending it to also %dx, %ux and %xx. We are also removing the override of RELEASE_BUILD on code because this is now taken care on test build makefiles. Bug: 234061145 Test: Added host unit tests for both test-debug and release like builds. Change-Id: I120cd7ef6664ec02ec02c2324cfa9bac3445e6a6
Diffstat (limited to 'lib')
-rw-r--r--lib/libc/printf.c49
-rw-r--r--lib/libc/test_common/libc_printf_tests.cpp129
2 files changed, 170 insertions, 8 deletions
diff --git a/lib/libc/printf.c b/lib/libc/printf.c
index 0ac64798..9723196e 100644
--- a/lib/libc/printf.c
+++ b/lib/libc/printf.c
@@ -28,14 +28,6 @@
#include <stdio.h>
#include <string.h>
-/*
-* We are overriding the RELEASE_BUILD behavior on this file to always disable filtering on test builds.
-*/
-#if TEST_BUILD
-#undef RELEASE_BUILD
-#define RELEASE_BUILD 0
-#endif
-
#ifdef UTEST_BUILD
#include "test_includes/printf_test.h"
#endif
@@ -467,6 +459,44 @@ __NO_INLINE static char *double_to_hexstring(char *buf, size_t len, double d, ui
#endif // FLOAT_PRINTF
+/* Currently only doing a 1 char lookahead for the modifiers*/
+static void parse_extra_modifiers(const char **format_string, int *flags, bool use_filter_modifiers)
+{
+ char currChar;
+
+ /* Because this function is called only when we are parsing
+ * and actual format specifier, this value will either point
+ * to the printable string or at most to the NULL terminator.
+ */
+ currChar = **format_string;
+ if (currChar == 0) {
+ return;
+ }
+ /* This is a not filtered call, we should not "eat" the extra x.*/
+ if (!use_filter_modifiers) {
+ return;
+ }
+ switch(currChar) {
+ case 'x':
+ /* Found an x modifier; we really want to print this value.*/
+ *flags &= ~FILTERED_ON_RELEASE;
+ /* We are consuming this character, advance format string.
+ * Advancing is safe because the current character is a
+ * printable one, so worst case we will advance to the end
+ * of the string and the original algorithm was prepared to
+ * handling advancing to end of string before starting to
+ * parse.
+ */
+ (*format_string)++;
+ break;
+ default:
+ /* We didn't understood the next character,
+ * normal parsing code will take care of it
+ */
+ break;
+ }
+}
+
static int _printf_engine_internal(_printf_engine_output_func out, void *state, const char *fmt, va_list ap, bool filtered)
{
int err = 0;
@@ -582,6 +612,7 @@ next_format:
(flags & PTRDIFFFLAG) ? va_arg(ap, ptrdiff_t) :
va_arg(ap, int));
flags |= SIGNEDFLAG;
+ parse_extra_modifiers(&fmt, &flags, filtered);
s = longlong_to_string(num_buffer, n, sizeof(num_buffer), flags, &signchar);
goto _output_string;
case 'u':
@@ -593,6 +624,7 @@ next_format:
(flags & INTMAXFLAG) ? va_arg(ap, uintmax_t) :
(flags & PTRDIFFFLAG) ? (uintptr_t)va_arg(ap, ptrdiff_t) :
va_arg(ap, unsigned int));
+ parse_extra_modifiers(&fmt, &flags, filtered);
s = longlong_to_string(num_buffer, n, sizeof(num_buffer), flags, &signchar);
goto _output_string;
case 'p':
@@ -611,6 +643,7 @@ hex:
(flags & INTMAXFLAG) ? va_arg(ap, uintmax_t) :
(flags & PTRDIFFFLAG) ? (uintptr_t)va_arg(ap, ptrdiff_t) :
va_arg(ap, unsigned int);
+ parse_extra_modifiers(&fmt, &flags, filtered);
s = longlong_to_hexstring(num_buffer, n, sizeof(num_buffer), flags);
if (flags & ALTFLAG) {
OUTPUT_CHAR('0');
diff --git a/lib/libc/test_common/libc_printf_tests.cpp b/lib/libc/test_common/libc_printf_tests.cpp
index fc6fb1d7..9debbe01 100644
--- a/lib/libc/test_common/libc_printf_tests.cpp
+++ b/lib/libc/test_common/libc_printf_tests.cpp
@@ -211,3 +211,132 @@ TEST(PrintfTest, SmallHexTest) {
snprintf_filtered(buffer, BUFFER_SIZE, "unsigned integer: 0x%x", 0x1000);
EXPECT_STREQ(buffer, "unsigned integer: 0x1000");
}
+
+TEST(PrintfTest, PointerUnsignedOneLineFilterOne) {
+ char buffer[BUFFER_SIZE];
+
+ snprintf_filtered(buffer, BUFFER_SIZE, "pointer1: %px number: %u", 0x5000, 10000);
+ EXPECT_STREQ_COND(buffer, "pointer1: 0x5000 number: ***", "pointer1: 0x5000 number: 10000", RELEASE_BUILD);
+}
+
+TEST(PrintfTest, PointerUnsignedOneLineFilterOneInverse) {
+ char buffer[BUFFER_SIZE];
+
+ snprintf_filtered(buffer, BUFFER_SIZE, "pointer1: %p number: %ux", 0x5000, 10000);
+ EXPECT_STREQ_COND(buffer, "pointer1: 0x*** number: 10000", "pointer1: 0x5000 number: 10000", RELEASE_BUILD);
+}
+
+TEST(PrintfTest, PointerUnsignedHexOneLineFilterOne) {
+ char buffer[BUFFER_SIZE];
+
+ snprintf_filtered(buffer, BUFFER_SIZE, "pointer1: %px number: %u hex: %xx", 0x5000, 10000, 0X7000);
+ EXPECT_STREQ_COND(buffer, "pointer1: 0x5000 number: *** hex: 7000", "pointer1: 0x5000 number: 10000 hex: 7000", RELEASE_BUILD);
+}
+
+TEST(PrintfTest, PointerUnsignedHexOneLineFilterOneInverse) {
+ char buffer[BUFFER_SIZE];
+
+ snprintf_filtered(buffer, BUFFER_SIZE, "pointer1: %p number: %ux hex: %x", 0x5000, 10000, 0X7000);
+ EXPECT_STREQ_COND(buffer, "pointer1: 0x*** number: 10000 hex: ***", "pointer1: 0x5000 number: 10000 hex: 7000", RELEASE_BUILD);
+}
+
+TEST(PrintfTest, ReleaseUnfilteredPointerPrintTest) {
+ char buffer[BUFFER_SIZE];
+
+ snprintf_filtered(buffer, BUFFER_SIZE, "pointer: %px", (void*)0x5000);
+ EXPECT_STREQ(buffer, "pointer: 0x5000");
+}
+
+TEST(PrintfTest, ReleaseUnfilteredLargNegIntTest) {
+ char buffer[BUFFER_SIZE];
+
+ snprintf_filtered(buffer, BUFFER_SIZE, "integer: %dx", -4097);
+ EXPECT_STREQ(buffer, "integer: -4097");
+}
+
+TEST(PrintfTest, ReleaseUnfilteredLargerHexTest) {
+ char buffer[BUFFER_SIZE];
+
+ snprintf_filtered(buffer, BUFFER_SIZE, "unsigned integer: 0x%xx", 0x1001);
+ EXPECT_STREQ(buffer, "unsigned integer: 0x1001");
+}
+
+TEST(PrintfTest, ReleaseUnfilteredLargerUintTest) {
+ char buffer[BUFFER_SIZE];
+
+ snprintf_filtered(buffer, BUFFER_SIZE, "unsigned integer: %ux", 4097);
+ EXPECT_STREQ(buffer, "unsigned integer: 4097");
+}
+
+TEST(PrintfTest, ReleaseUnfilteredLargerUintXAtEndTest) {
+ char buffer[BUFFER_SIZE];
+
+ snprintf_filtered(buffer, BUFFER_SIZE, "unsigned integer: %uxx", 34127);
+ EXPECT_STREQ(buffer, "unsigned integer: 34127x");
+}
+
+TEST(PrintfTest, ReleaseUnfilteredPrintfBufferLargeEnoughTest) {
+ char buffer[BUFFER_SIZE];
+ memset(buffer, 0, BUFFER_SIZE);
+ buffer[5] = '@';
+
+ snprintf_filtered(buffer, 5, "%xx", 0x3000);
+ EXPECT_STREQ(buffer, "3000");
+ EXPECT_EQ(buffer[5], '@');
+}
+
+TEST(PrintfTest, ReleaseUnfilteredPrintfBufferLargeEnoughForReleaseTest) {
+ char buffer[BUFFER_SIZE];
+ memset(buffer, 0, BUFFER_SIZE);
+ buffer[4] = '@';
+
+ snprintf_filtered(buffer, 4, "%xx", 0x3000);
+ EXPECT_STREQ(buffer,"300");
+ EXPECT_EQ(buffer[4], '@');
+}
+
+TEST(PrintfTest, ReleaseUnfilteredPrintfBufferTooSmallForReleaseTest) {
+ char buffer[BUFFER_SIZE];
+ memset(buffer, 0, BUFFER_SIZE);
+ buffer[3] = '@';
+
+ snprintf_filtered(buffer, 3, "%xx", 0x3000);
+ EXPECT_STREQ(buffer, "30");
+ EXPECT_EQ(buffer[3], '@');
+}
+
+TEST(PrintfTest, ReleaseUnfilteredPrintfStringXPrintsTest) {
+ char buffer[BUFFER_SIZE];
+
+ snprintf_filtered(buffer, BUFFER_SIZE, "%sx", "hello");
+ EXPECT_STREQ(buffer, "hellox");
+}
+
+TEST(PrintfTest, ThreeModifierTogetherOneNotFilteredTest) {
+ char buffer[BUFFER_SIZE];
+
+ snprintf_filtered(buffer, BUFFER_SIZE, "%d%xx%u", 98765, 0x43210, 123456);
+ EXPECT_STREQ_COND(buffer, "***43210***", "9876543210123456", RELEASE_BUILD);
+}
+
+TEST(PrintfTest, ThreeModifierTogetherOneNotFilteredInverseTest) {
+ char buffer[BUFFER_SIZE];
+
+ snprintf_filtered(buffer, BUFFER_SIZE, "%dx%x%ux", 98765, 0x43210, 123456);
+ EXPECT_STREQ_COND(buffer, "98765***123456", "9876543210123456", RELEASE_BUILD);
+}
+
+TEST(PrintfTest, ReleaseUnfilteredThreeModifiersTest) {
+ char buffer[BUFFER_SIZE];
+
+ snprintf_filtered(buffer, BUFFER_SIZE, "pointer: %px unsigned: %ux signed: %dx", (void*)0x5000, 7000, 80000);
+ EXPECT_STREQ(buffer, "pointer: 0x5000 unsigned: 7000 signed: 80000");
+}
+
+TEST(PrintfTest, SnprintfModifierNotUsedTest) {
+ char buffer[BUFFER_SIZE];
+
+ snprintf(buffer, BUFFER_SIZE, "hex: %xx pointer: %px unsigned: %ux signed: %dx", 2, (void*) 3, 4, 5);
+
+ EXPECT_STREQ(buffer, "hex: 2x pointer: 0x3x unsigned: 4x signed: 5x");
+}