nothings / stb

stb single-file public domain libraries for C/C++
https://twitter.com/nothings
Other
25.83k stars 7.66k forks source link

stb_sprintf: not working with 'j' 'z' modifiers #1575

Open stefano-zanotti-88 opened 8 months ago

stefano-zanotti-88 commented 8 months ago

Describe the bug Modifiers 'j' and 'z' do not work properly on some architecture, because the arguments have a size different from that inferred by the library, which results in wrong data being read from the varargs list.

To Reproduce stb_sprintf(buff, "%ji %zi %ti", (intmax_t)-1, (ssize_t)2, (ptrdiff_t)-3); taken from the test: https://github.com/nothings/stb/blob/beebb24b945efdea3b9bba23affb8eb3ba8982e7/tests/test_sprintf.c#L75 To be executed on a platform with:

sizeof(intmax_t) == 8
sizeof(size_t) == 4
sizeof(ptrdiff_t) == 4

e.g. a 32-bit architecture like ARM Cortex-M

Fix This: https://github.com/nothings/stb/blob/beebb24b945efdea3b9bba23affb8eb3ba8982e7/stb_sprintf.h#L543-L551 should be changed to have:

case 'j': ... sizeof(intmax_t)
case 'z': ... sizeof(size_t)

Since intmax_t is not available for this library (see the discussion here: https://github.com/nothings/stb/pull/633), something else should be used, e.g. assume that it is always 8, or do this:

#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#include <stdint.h> // for intmax_t
#endif
...
case 'j':
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
fl |= (sizeof(intmax_t) == 8) ? STBSP__INTMAX : 0;
#else
fl |= STBSP__INTMAX;
#endif

Related https://github.com/nothings/stb/issues/632 https://github.com/nothings/stb/pull/633

The proper handling was already suggested before (see #633 above), but since it was manually merged, also with the goal of minimizing dependencies, the wrong types were used.