Skip to content

Commit a683fa5

Browse files
committed
snprintf() calls need to have proper radix
Calls to libc snprintf() were neglected to be changed when perl was fixed to change the radix character to the proper one based on whether or not 'use locale' is in effect. Perl-level code is unaffected, but core and XS code is. This commit changes to wrap snprintf() calls with the macros designed for the purpose, long used for similar situations elsewhere in the code. Doing this requires the thread context. I achieved this in a few places by a dTHX, instead of assuming a caller would have the context already available, and adding a pTHX_ parameter. I tried doing it the other way, and got a few breakages in our test suite. Formatting already requires significant CPU time, so this addition should just be in the noise This bug was found by new tests that will be added in a future commit.
1 parent a170805 commit a683fa5

File tree

3 files changed

+54
-14
lines changed

3 files changed

+54
-14
lines changed

perl.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2283,7 +2283,7 @@ my_snprintf()
22832283

22842284
#define PERL_SNPRINTF_CHECK(len, max, api) STMT_START { if ((max) > 0 && (Size_t)len > (max)) Perl_croak_nocontext("panic: %s buffer overflow", STRINGIFY(api)); } STMT_END
22852285

2286-
#ifdef USE_QUADMATH
2286+
#if defined(USE_LOCALE_NUMERIC) || defined(USE_QUADMATH)
22872287
# define my_snprintf Perl_my_snprintf
22882288
# define PERL_MY_SNPRINTF_GUARDED
22892289
#elif defined(HAS_SNPRINTF) && defined(HAS_C99_VARIADIC_MACROS) && !(defined(DEBUGGING) && !defined(PERL_USE_GCC_BRACE_GROUPS)) && !defined(PERL_GCC_PEDANTIC)
@@ -2300,9 +2300,16 @@ my_snprintf()
23002300

23012301
/* There is no quadmath_vsnprintf, and therefore my_vsnprintf()
23022302
* dies if called under USE_QUADMATH. */
2303-
#if defined(HAS_VSNPRINTF) && defined(HAS_C99_VARIADIC_MACROS) && !(defined(DEBUGGING) && !defined(PERL_USE_GCC_BRACE_GROUPS)) && !defined(PERL_GCC_PEDANTIC)
2303+
#if ! defined(USE_LOCALE_NUMERIC) \
2304+
&& defined(HAS_VSNPRINTF) \
2305+
&& defined(HAS_C99_VARIADIC_MACROS) \
2306+
&& ! (defined(DEBUGGING) && ! defined(PERL_USE_GCC_BRACE_GROUPS)) \
2307+
&& ! defined(PERL_GCC_PEDANTIC)
23042308
# ifdef PERL_USE_GCC_BRACE_GROUPS
2305-
# define my_vsnprintf(buffer, max, ...) ({ int len = vsnprintf(buffer, max, __VA_ARGS__); PERL_SNPRINTF_CHECK(len, max, vsnprintf); len; })
2309+
# define my_vsnprintf(buffer, max, ...) \
2310+
({ int len = vsnprintf(buffer, max, __VA_ARGS__); \
2311+
PERL_SNPRINTF_CHECK(len, max, vsnprintf); \
2312+
len; })
23062313
# define PERL_MY_VSNPRINTF_GUARDED
23072314
# else
23082315
# define my_vsnprintf(buffer, max, ...) vsnprintf(buffer, max, __VA_ARGS__)

perlio.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,10 @@ PerlIO_debug(const char *fmt, ...)
369369
should be, otherwise the system isn't likely to support quadmath.
370370
Nothing should be calling PerlIO_debug() with floating point anyway.
371371
*/
372+
DECLARATION_FOR_LC_NUMERIC_MANIPULATION;
373+
STORE_LC_NUMERIC_SET_TO_NEEDED();
372374
const STRLEN len2 = vsnprintf(buffer + len1, sizeof(buffer) - len1, fmt, ap);
375+
RESTORE_LC_NUMERIC();
373376
# else
374377
STATIC_ASSERT_STMT(0);
375378
# endif

util.c

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5194,11 +5194,14 @@ getting C<vsnprintf>.
51945194
51955195
=cut
51965196
*/
5197+
51975198
int
51985199
Perl_my_snprintf(char *buffer, const Size_t len, const char *format, ...)
51995200
{
52005201
int retval = -1;
52015202
va_list ap;
5203+
dTHX;
5204+
52025205
PERL_ARGS_ASSERT_MY_SNPRINTF;
52035206
#ifndef HAS_VSNPRINTF
52045207
PERL_UNUSED_VAR(len);
@@ -5207,9 +5210,12 @@ Perl_my_snprintf(char *buffer, const Size_t len, const char *format, ...)
52075210
#ifdef USE_QUADMATH
52085211
{
52095212
bool quadmath_valid = FALSE;
5213+
52105214
if (quadmath_format_valid(format)) {
52115215
/* If the format looked promising, use it as quadmath. */
5212-
retval = quadmath_snprintf(buffer, len, format, va_arg(ap, NV));
5216+
WITH_LC_NUMERIC_SET_TO_NEEDED(
5217+
retval = quadmath_snprintf(buffer, len, format, va_arg(ap, NV));
5218+
);
52135219
if (retval == -1) {
52145220
Perl_croak_nocontext("panic: quadmath_snprintf failed, format \"%s\"", format);
52155221
}
@@ -5241,12 +5247,20 @@ Perl_my_snprintf(char *buffer, const Size_t len, const char *format, ...)
52415247

52425248
}
52435249
#endif
5244-
if (retval == -1)
5250+
if (retval == -1) {
5251+
52455252
#ifdef HAS_VSNPRINTF
5246-
retval = vsnprintf(buffer, len, format, ap);
5253+
WITH_LC_NUMERIC_SET_TO_NEEDED(
5254+
retval = vsnprintf(buffer, len, format, ap);
5255+
);
52475256
#else
5248-
retval = vsprintf(buffer, format, ap);
5257+
WITH_LC_NUMERIC_SET_TO_NEEDED(
5258+
retval = vsprintf(buffer, format, ap);
5259+
);
52495260
#endif
5261+
5262+
}
5263+
52505264
va_end(ap);
52515265
/* vsprintf() shows failure with < 0 */
52525266
if (retval < 0
@@ -5271,6 +5285,7 @@ C<sv_vcatpvf> instead, or getting C<vsnprintf>.
52715285
52725286
=cut
52735287
*/
5288+
52745289
int
52755290
Perl_my_vsnprintf(char *buffer, const Size_t len, const char *format, va_list ap)
52765291
{
@@ -5284,27 +5299,36 @@ Perl_my_vsnprintf(char *buffer, const Size_t len, const char *format, va_list ap
52845299
return 0;
52855300
#else
52865301
int retval;
5302+
dTHX;
52875303

52885304
# ifdef NEED_VA_COPY
52895305
va_list apc;
52905306

52915307
PERL_ARGS_ASSERT_MY_VSNPRINTF;
52925308
Perl_va_copy(ap, apc);
52935309
# ifdef HAS_VSNPRINTF
5294-
retval = vsnprintf(buffer, len, format, apc);
5295-
# else
52965310

5311+
WITH_LC_NUMERIC_SET_TO_NEEDED(
5312+
retval = vsnprintf(buffer, len, format, apc);
5313+
);
5314+
# else
52975315
PERL_UNUSED_ARG(len);
5298-
retval = vsprintf(buffer, format, apc);
5316+
WITH_LC_NUMERIC_SET_TO_NEEDED(
5317+
retval = vsprintf(buffer, format, apc);
5318+
);
52995319
# endif
53005320

53015321
va_end(apc);
53025322
# else
53035323
# ifdef HAS_VSNPRINTF
5304-
retval = vsnprintf(buffer, len, format, ap);
5324+
WITH_LC_NUMERIC_SET_TO_NEEDED(
5325+
retval = vsnprintf(buffer, len, format, ap);
5326+
);
53055327
# else
53065328
PERL_UNUSED_ARG(len);
5307-
retval = vsprintf(buffer, format, ap);
5329+
WITH_LC_NUMERIC_SET_TO_NEEDED(
5330+
retval = vsprintf(buffer, format, ap);
5331+
);
53085332
# endif
53095333
# endif /* #ifdef NEED_VA_COPY */
53105334

@@ -5317,6 +5341,7 @@ Perl_my_vsnprintf(char *buffer, const Size_t len, const char *format, va_list ap
53175341
# endif
53185342
)
53195343
Perl_croak_nocontext("panic: my_vsnprintf buffer overflow");
5344+
53205345
return retval;
53215346
#endif
53225347
}
@@ -6159,8 +6184,13 @@ static void atos_symbolize(atos_context* ctx,
61596184
return;
61606185
}
61616186
}
6162-
cnt = snprintf(cmd, sizeof(cmd), ctx->format,
6163-
ctx->fname, ctx->object_base_addr, raw_frame);
6187+
6188+
dTHX;
6189+
WITH_LC_NUMERIC_SET_TO_NEEDED(
6190+
cnt = snprintf(cmd, sizeof(cmd), ctx->format,
6191+
ctx->fname, ctx->object_base_addr, raw_frame);
6192+
);
6193+
61646194
if (cnt < sizeof(cmd)) {
61656195
/* Undo nostdio.h #defines that disable stdio.
61666196
* This is somewhat naughty, but is used elsewhere

0 commit comments

Comments
 (0)