summaryrefslogtreecommitdiff
path: root/pp_ctl.c
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2013-11-28 16:46:15 +0000
committerDavid Mitchell <davem@iabyn.com>2013-11-28 17:03:49 +0000
commit5d37acd6b65eb421e938a3fde62cc1edde467dae (patch)
tree905d9b7ae0be58425baa6f089e070f0cde45e713 /pp_ctl.c
parentb56aac20bc53699e4a5ea975542404fb371cf085 (diff)
downloadperl-5d37acd6b65eb421e938a3fde62cc1edde467dae.tar.gz
silence -Wformat-nonliteral compiler warnings
Due to the security risks associated with user-supplied formats being passed to C-level printf() style functions (eg %n), gcc has a -Wformat-nonliteral warning that complains whenever such a function is passed a non-literal format string. This commit silences all such warnings in core and ext/. The main changes are 1) the 'f' (format) flag in embed.fnc is now handled slightly more cleverly. Rather than just applying to functions whose last arg is '...' (and where the format arg is assumed to be the previous arg), it can now handle non-'...' functions: arg checking is disabled, but format checking is sill done: it works by assuming that an arg called 'fmt', 'pat' or 'f' is the format string (and dies if fails to find exactly one such arg). 2) with the new embed.fnc functionally, more functions have been marked with the 'f' flag. When such a function passes its fmt arg onto an inner printf-like function, we simply disable the warning for that call using GCC_DIAG_IGNORE(-Wformat-nonliteral), since we know that the caller must have already checked it. 3) In quite a few places the format string isn't literal, but it *is* constant (e.g. PL_warn_uninit_sv). For those cases, again disable the warning. 4) In pp_formline(), a particular format was was one of several different literal strings depending on circumstances. Rather than assigning this string to a temporary variable, incorporate the ?: branches directly in the function call arg. gcc is clever enough to decide the arg is then always literal.
Diffstat (limited to 'pp_ctl.c')
-rw-r--r--pp_ctl.c51
1 files changed, 29 insertions, 22 deletions
diff --git a/pp_ctl.c b/pp_ctl.c
index 95727f201a..01b3b9cd1e 100644
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -479,7 +479,6 @@ PP(pp_formline)
STRLEN linemax; /* estimate of output size in bytes */
bool item_is_utf8 = FALSE;
bool targ_is_utf8 = FALSE;
- const char *fmt;
MAGIC *mg = NULL;
U8 *source; /* source of bytes to append */
STRLEN to_copy; /* how may bytes to append */
@@ -795,28 +794,13 @@ PP(pp_formline)
}
case FF_0DECIMAL: /* like FF_DECIMAL but for 0### */
- arg = *fpc++;
-#if defined(USE_LONG_DOUBLE)
- fmt = (const char *)
- ((arg & FORM_NUM_POINT) ?
- "%#0*.*" PERL_PRIfldbl : "%0*.*" PERL_PRIfldbl);
-#else
- fmt = (const char *)
- ((arg & FORM_NUM_POINT) ?
- "%#0*.*f" : "%0*.*f");
-#endif
- goto ff_dec;
-
case FF_DECIMAL: /* do @##, ^##, where <arg>=(precision|flags) */
+ {
+ I32 form_num_point;
+
arg = *fpc++;
-#if defined(USE_LONG_DOUBLE)
- fmt = (const char *)
- ((arg & FORM_NUM_POINT) ? "%#*.*" PERL_PRIfldbl : "%*.*" PERL_PRIfldbl);
-#else
- fmt = (const char *)
- ((arg & FORM_NUM_POINT) ? "%#*.*f" : "%*.*f");
-#endif
- ff_dec:
+ form_num_point = (arg & FORM_NUM_POINT);
+
/* If the field is marked with ^ and the value is undefined,
blank it out. */
if ((arg & FORM_NUM_BLANK) && !SvOK(sv)) {
@@ -838,11 +822,34 @@ PP(pp_formline)
{
STORE_NUMERIC_STANDARD_SET_LOCAL();
arg &= ~(FORM_NUM_POINT|FORM_NUM_BLANK);
- my_snprintf(t, SvLEN(PL_formtarget) - (t - SvPVX(PL_formtarget)), fmt, (int) fieldsize, (int) arg, value);
+ my_snprintf(t,
+ SvLEN(PL_formtarget) - (t - SvPVX(PL_formtarget)),
+ (fpc[-2] == FF_0DECIMAL)
+ ?
+ form_num_point
+#if defined(USE_LONG_DOUBLE)
+ ? "%#0*.*" PERL_PRIfldbl
+ : "%0*.*" PERL_PRIfldbl
+#else
+ ? "%#0*.*f"
+ : "%0*.*f"
+#endif
+ :
+ form_num_point
+#if defined(USE_LONG_DOUBLE)
+ ? "%#*.*" PERL_PRIfldbl
+ : "%*.*" PERL_PRIfldbl
+#else
+ ? "%#*.*f"
+ : "%*.*f"
+#endif
+ , (int) fieldsize, (int) arg, value);
+
RESTORE_NUMERIC_STANDARD();
}
t += fieldsize;
break;
+ }
case FF_NEWLINE: /* delete trailing spaces, then append \n */
f++;