nothings / stb

stb single-file public domain libraries for C/C++

Home Page:https://twitter.com/nothings

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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

stefano-zanotti-88 opened this issue · comments

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:

CHECK4("-1 2 -3", "%ji %zi %ti", (intmax_t)-1, (ssize_t)2, (ptrdiff_t)-3);

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:

stb/stb_sprintf.h

Lines 543 to 551 in beebb24

case 'j':
fl |= (sizeof(size_t) == 8) ? STBSP__INTMAX : 0;
++f;
break;
// are we 64-bit on size_t or ptrdiff_t? (c99)
case 'z':
fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0;
++f;
break;

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: #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
#632
#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.