Skip to content

Pointer format %p fails (Win32) #45

@csoroz

Description

@csoroz

The value is taken from va_arg initially here:

printf/printf.c

Line 1058 in bd89cc7

uintptr_t value = (uintptr_t)va_arg(va, void*);

When sizeof(uintptr_t) != sizeof(long long) (i.e. Win32) it tries to read va_arg again:

printf/printf.c

Line 1071 in bd89cc7

idx = print_integer(out, buffer, idx, maxlen, (PRINTF_INTEGER_VALUE_TYPE)((uintptr_t)va_arg(va, void*)), false, BASE_HEX, precision, width, flags);

which is wrong. The case when is_ll is true does it right:

printf/printf.c

Line 1067 in bd89cc7

idx = print_integer(out, buffer, idx, maxlen, (PRINTF_INTEGER_VALUE_TYPE) value, false, BASE_HEX, precision, width, flags);

If the else case is corrected, it would do the same. Then this conditional compilation is not necessary:
#if PRINTF_SUPPORT_LONG_LONG

printf/printf.c

Lines 1055 to 1078 in bd89cc7

case 'p' : {
width = sizeof(void*) * 2U + 2; // 2 hex chars per byte + the "0x" prefix
flags |= FLAGS_ZEROPAD | FLAGS_POINTER;
uintptr_t value = (uintptr_t)va_arg(va, void*);
if (value == (uintptr_t) NULL) {
idx = _out_rev(out, buffer, idx, maxlen, ")lin(", 5, width, flags);
}
else {
#if PRINTF_SUPPORT_LONG_LONG
const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
if (is_ll) {
idx = print_integer(out, buffer, idx, maxlen, (PRINTF_INTEGER_VALUE_TYPE) value, false, BASE_HEX, precision, width, flags);
}
else {
#endif
idx = print_integer(out, buffer, idx, maxlen, (PRINTF_INTEGER_VALUE_TYPE)((uintptr_t)va_arg(va, void*)), false, BASE_HEX, precision, width, flags);
#if PRINTF_SUPPORT_LONG_LONG
}
#endif
}
format++;
break;
}

Compiling with MSVC (VS2017) this issue makes this test cases fail:
Screenshot 2021-09-21 at 17 49 03

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions