d_sigprocmask=''
d_sigsetjmp=''
usesitecustomize=''
+d_snprintf=''
+d_vsnprintf=''
d_sockatmark=''
d_sockatmarkproto=''
d_ip_mreq=''
eval $setvar
$rm_try
+: see if snprintf exists
+set snprintf d_snprintf
+eval $inlibc
+
+: see if vsnprintf exists
+set vsnprintf d_vsnprintf
+eval $inlibc
+
+case "$d_snprintf-$d_vsnprintf" in
+"$define-$define")
+ $cat <<EOM
+Checking whether your snprintf() and vsnprintf() work okay...
+EOM
+ $cat >try.c <<'EOCP'
+/* v?snprintf testing logic courtesy of Russ Allbery.
+ * According to C99:
+ * - if the buffer is too short it still must be \0-terminated
+ * - if the buffer is too short the potentially required length
+ * must be returned and not -1
+ * - if the buffer is NULL the potentially required length
+ * must be returned and not -1 or core dump
+ */
+#include <stdio.h>
+#include <stdarg.h>
+
+char buf[2];
+
+int test (char *format, ...)
+{
+ va_list args;
+ int count;
+
+ va_start (args, format);
+ count = vsnprintf (buf, sizeof buf, format, args);
+ va_end (args);
+ return count;
+}
+
+int main ()
+{
+ return ((test ("%s", "abcd") == 4 && buf[0] == 'a' && buf[1] == '\0'
+ && snprintf (NULL, 0, "%s", "abcd") == 4) ? 0 : 1);
+}
+EOCP
+ set try
+ if eval $compile; then
+ `$run ./try`
+ case "$?" in
+ 0) echo "Your snprintf() and vsnprintf() seem to be working okay." ;;
+ *) cat <<EOM >&4
+Your snprintf() and snprintf() don't seem to be working okay.
+EOM
+ d_snprintf="$undef"
+ d_vsnprintf="$undef"
+ ;;
+ esac
+ else
+ echo "(I can't seem to compile the test program--assuming they don't)"
+ d_snprintf="$undef"
+ d_vsnprintf="$undef"
+ fi
+ $rm_try
+ ;;
+esac
+
: see if sockatmark exists
set sockatmark d_sockatmark
eval $inlibc
d_sigsetjmp='$d_sigsetjmp'
d_sin6_scope_id='$d_sin6_scope_id'
d_sitearch='$d_sitearch'
+d_snprintf='$d_snprintf'
d_sockaddr_in6='$d_sockaddr_in6'
d_sockaddr_sa_len='$d_sockaddr_sa_len'
d_sockatmark='$d_sockatmark'
d_void_closedir='$d_void_closedir'
d_voidsig='$d_voidsig'
d_voidtty='$d_voidtty'
+d_vsnprintf='$d_vsnprintf'
d_wait4='$d_wait4'
d_waitpid='$d_waitpid'
d_wcscmp='$d_wcscmp'
d_sigsetjmp='define'
d_sin6_scope_id='undef'
d_sitearch='define'
+d_snprintf='undef'
d_sockaddr_in6='undef'
d_sockaddr_sa_len='undef'
d_sockatmark='undef'
d_void_closedir='undef'
d_voidsig='define'
d_voidtty=''
+d_vsnprintf='define'
d_wait4='define'
d_waitpid='define'
d_wcscmp='undef'
d_sigsetjmp='define'
d_sin6_scope_id='undef'
d_sitearch='define'
+d_snprintf='undef'
d_sockaddr_in6='undef'
d_sockaddr_sa_len='undef'
d_sockatmark='undef'
d_void_closedir='undef'
d_voidsig='define'
d_voidtty=''
+d_vsnprintf='define'
d_wait4='define'
d_waitpid='define'
d_wcscmp='undef'
d_sigsetjmp='undef'
d_sin6_scope_id='undef'
d_sitearch='undef'
+d_snprintf='undef'
d_sockaddr_in6='undef'
d_sockaddr_sa_len='undef'
d_sockatmark='undef'
d_void_closedir='undef'
d_voidsig='define'
d_voidtty=''
+d_vsnprintf='undef'
d_wait4='undef'
d_waitpid='define'
d_wcscmp='undef'
of architecture-dependent library files for $package. If
$sitearch is the same as $archlib, then this is set to undef.
+d_snprintf (d_snprintf.U):
+ This variable conditionally defines the HAS_SNPRINTF symbol, which
+ indicates to the C program that the snprintf () library function
+ is available.
+
d_sockaddr_in6 (d_socket.U):
This variable conditionally defines the HAS_SOCKADDR_IN6 symbol, which
indicates the availability of a struct sockaddr_in6.
Otherwise (on USG probably), it is enough to close the standard file
descriptors and do a setpgrp().
+d_vsnprintf (d_snprintf.U):
+ This variable conditionally defines the HAS_VSNPRINTF symbol, which
+ indicates to the C program that the vsnprintf () library function
+ is available.
+
d_wait4 (d_wait4.U):
This variable conditionally defines the HAS_WAIT4 symbol, which
indicates the wait4() routine is available.
d_sigsetjmp='define'
d_sin6_scope_id='define'
d_sitearch='define'
+d_snprintf='define'
d_sockaddr_in6='define'
d_sockaddr_sa_len='undef'
d_sockatmark='define'
d_void_closedir='undef'
d_voidsig='define'
d_voidtty=''
+d_vsnprintf='define'
d_wait4='define'
d_waitpid='define'
d_wcscmp='define'
/*#define USE_SITECUSTOMIZE / **/
#endif
+/* HAS_SNPRINTF:
+ * This symbol, if defined, indicates that the snprintf () library
+ * function is available for use.
+ */
+/* HAS_VSNPRINTF:
+ * This symbol, if defined, indicates that the vsnprintf () library
+ * function is available for use.
+ */
+#define HAS_SNPRINTF /**/
+#define HAS_VSNPRINTF /**/
+
/* HAS_SOCKATMARK:
* This symbol, if defined, indicates that the sockatmark routine is
* available to test whether a socket is at the out-of-band mark.
#$usesitecustomize USE_SITECUSTOMIZE /**/
#endif
+/* HAS_SNPRINTF:
+ * This symbol, if defined, indicates that the snprintf () library
+ * function is available for use.
+ */
+/* HAS_VSNPRINTF:
+ * This symbol, if defined, indicates that the vsnprintf () library
+ * function is available for use.
+ */
+#$d_snprintf HAS_SNPRINTF /**/
+#$d_vsnprintf HAS_VSNPRINTF /**/
+
/* HAS_SOCKATMARK:
* This symbol, if defined, indicates that the sockatmark routine is
* available to test whether a socket is at the out-of-band mark.
$ d_setgrent = "define"
$ d_ttyname_r = "define"
$ ttyname_r_proto = "1"
+$ d_snprintf = "define"
+$ d_vsnprintf = "define"
$!
$! VMS V7.3-2 powered options
$! We know that it is only available for V7.3-2 and later on 64 bit platforms.
$ WC "d_void_closedir='define'"
$ WC "d_voidsig='undef'"
$ WC "d_voidtty='" + "'"
+$ WC "d_vsnprintf='" + d_vsnprintf + "'"
$ WC "d_wait4='" + d_wait4 + "'"
$ WC "d_waitpid='define'"
$ WC "d_wcscmp='define'"
$ WC "d_setprotoent_r='undef'"
$ WC "d_setpwent_r='undef'"
$ WC "d_setservent_r='undef'"
+$ WC "d_snprintf='" + d_snprintf + "'"
$ WC "d_srand48_r='undef'"
$ WC "d_srandom_r='undef'"
$ WC "d_strerror_l='undef'"
*/
/* Note that we do not check against snprintf()/vsnprintf() returning
- * negative values because that is non-standard behaviour and we now
- * assume a working C89 implementation. */
+ * negative values because that is non-standard behaviour and we use
+ * snprintf/vsnprintf only iff HAS_VSNPRINTF has been defined, and
+ * that should be true only if the snprintf()/vsnprintf() are true
+ * to the standard. */
#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
#ifdef USE_QUADMATH
# define my_snprintf Perl_my_snprintf
# define PERL_MY_SNPRINTF_GUARDED
-#elif defined(HAS_C99_VARIADIC_MACROS) && !(defined(DEBUGGING) && !defined(PERL_USE_GCC_BRACE_GROUPS)) && !defined(PERL_GCC_PEDANTIC)
+#elif defined(HAS_SNPRINTF) && defined(HAS_C99_VARIADIC_MACROS) && !(defined(DEBUGGING) && !defined(PERL_USE_GCC_BRACE_GROUPS)) && !defined(PERL_GCC_PEDANTIC)
# ifdef PERL_USE_GCC_BRACE_GROUPS
# define my_snprintf(buffer, max, ...) ({ int len = snprintf(buffer, max, __VA_ARGS__); PERL_SNPRINTF_CHECK(len, max, snprintf); len; })
# define PERL_MY_SNPRINTF_GUARDED
/* There is no quadmath_vsnprintf, and therefore my_vsnprintf()
* dies if called under USE_QUADMATH. */
-#if defined(HAS_C99_VARIADIC_MACROS) && !(defined(DEBUGGING) && !defined(PERL_USE_GCC_BRACE_GROUPS)) && !defined(PERL_GCC_PEDANTIC)
+#if defined(HAS_VSNPRINTF) && defined(HAS_C99_VARIADIC_MACROS) && !(defined(DEBUGGING) && !defined(PERL_USE_GCC_BRACE_GROUPS)) && !defined(PERL_GCC_PEDANTIC)
# ifdef PERL_USE_GCC_BRACE_GROUPS
# define my_vsnprintf(buffer, max, ...) ({ int len = vsnprintf(buffer, max, __VA_ARGS__); PERL_SNPRINTF_CHECK(len, max, vsnprintf); len; })
# define PERL_MY_VSNPRINTF_GUARDED
d_sigsetjmp='define'
d_sin6_scope_id='undef'
d_sitearch='define'
+d_snprintf='undef'
d_sockaddr_in6='undef'
d_sockaddr_sa_len='undef'
d_sockatmark='undef'
d_void_closedir='undef'
d_voidsig='define'
d_voidtty=''
+d_vsnprintf='undef'
d_wait4='undef'
d_waitpid='define'
d_wcscmp='undef'
allocate at least one byte. (In general you should rarely need to work
at this low level, but instead use the various malloc wrappers.)
+=item *
+
+snprintf() - the return type is unportable. Use my_snprintf() instead.
+
=back
=head2 Security problems
Do not use sprintf() or vsprintf()
-If you really want just plain byte strings, use snprintf() and
-vsnprintf() instead. If you want something
+If you really want just plain byte strings, use my_snprintf() and
+my_vsnprintf() instead, which will try to use snprintf() and
+vsnprintf() if those safer APIs are available. If you want something
fancier than a plain byte string, use
L<C<Perl_form>()|perlapi/form> or SVs and
L<C<Perl_sv_catpvf()>|perlapi/sv_catpvf>.
+Note that glibc C<printf()>, C<sprintf()>, etc. are buggy before glibc
+version 2.17. They won't allow a C<%.s> format with a precision to
+create a string that isn't valid UTF-8 if the current underlying locale
+of the program is UTF-8. What happens is that the C<%s> and its operand are
+simply skipped without any notice.
+L<https://sourceware.org/bugzilla/show_bug.cgi?id=6530>.
+
=item *
Do not use atoi()
d_sitearch='define'
d_sitecustomize='undef'
d_sitecustomize='undef'
+d_snprintf='undef'
d_sockaddr_in6='undef'
d_sockaddr_sa_len='undef'
d_sockatmark='undef'
d_void_closedir='undef'
d_voidsig='undef'
d_voidtty=''
+d_vsnprintf='undef'
d_wait4='undef'
d_waitpid='undef'
d_wcscmp='undef'
/*#define USE_SITECUSTOMIZE / **/
#endif
+/* HAS_SNPRINTF:
+ * This symbol, if defined, indicates that the snprintf () library
+ * function is available for use.
+ */
+/* HAS_VSNPRINTF:
+ * This symbol, if defined, indicates that the vsnprintf () library
+ * function is available for use.
+ */
+/*#define HAS_SNPRINTF / **/
+/*#define HAS_VSNPRINTF / **/
+
/* HAS_SOCKATMARK:
* This symbol, if defined, indicates that the sockatmark routine is
* available to test whether a socket is at the out-of-band mark.
#endif
/* Generated from:
- * 7913b611cab4bc7877d2d75fa7ebdacc195e251c150ec7bf4bec7cc4e558b971 config_h.SH
- * aa2ab1991bf5916d4b01b69ed4108a49a96fdf763ef66dda095036df8b63af48 uconfig.sh
+ * 84ef0e3b4e27374e35a7ac6726cf1c0149b1d4ba726bd58e06d9a9ce18acbb04 config_h.SH
+ * 9df6179826b20eb8e1d8db749dfd77913897fae551371f686571273075f78092 uconfig.sh
* ex: set ro: */
d_sigsetjmp='undef'
d_sin6_scope_id='undef'
d_sitearch='undef'
+d_snprintf='undef'
d_sockaddr_in6='undef'
d_sockaddr_sa_len='undef'
d_sockatmark='undef'
d_void_closedir='undef'
d_voidsig='undef'
d_voidtty=''
+d_vsnprintf='undef'
d_wait4='undef'
d_waitpid='undef'
d_wcscmp='undef'
d_sigsetjmp='undef'
d_sin6_scope_id='undef'
d_sitearch='undef'
+d_snprintf='undef'
d_sockaddr_in6='undef'
d_sockaddr_sa_len='undef'
d_sockatmark='undef'
d_void_closedir='undef'
d_voidsig='undef'
d_voidtty=''
+d_vsnprintf='undef'
d_wait4='undef'
d_waitpid='undef'
d_wcscmp='undef'
/*
=for apidoc my_snprintf
-The C library C<snprintf> functionality (using C<vsnprintf>).
-Consider using C<sv_vcatpvf> instead.
+The C library C<snprintf> functionality, if available and
+standards-compliant (uses C<vsnprintf>, actually). However, if the
+C<vsnprintf> is not available, will unfortunately use the unsafe
+C<vsprintf> which can overrun the buffer (there is an overrun check,
+but that may be too late). Consider using C<sv_vcatpvf> instead, or
+getting C<vsnprintf>.
=cut
*/
int retval = -1;
va_list ap;
PERL_ARGS_ASSERT_MY_SNPRINTF;
+#ifndef HAS_VSNPRINTF
+ PERL_UNUSED_VAR(len);
+#endif
va_start(ap, format);
#ifdef USE_QUADMATH
{
* Handling the "Q-less" cases right would require walking
* through the va_list and rewriting the format, calling
* quadmath for the NVs, building a new va_list, and then
- * letting vsnprintf to take care of the other
+ * letting vsnprintf/vsprintf to take care of the other
* arguments. This may be doable.
*
* We do not attempt that now. But for paranoia, we here try
* to detect some common (but not all) cases where the
* "Q-less" %[efgaEFGA] formats are present, and die if
* detected. This doesn't fix the problem, but it stops the
- * vsnprintf pulling doubles off the va_list when
+ * vsnprintf/vsprintf pulling doubles off the va_list when
* __float128 NVs should be pulled off instead.
*
* If quadmath_format_needed() returns false, we are reasonably
}
#endif
if (retval == -1)
+#ifdef HAS_VSNPRINTF
retval = vsnprintf(buffer, len, format, ap);
+#else
+ retval = vsprintf(buffer, format, ap);
+#endif
va_end(ap);
+ /* vsprintf() shows failure with < 0 */
+ if (retval < 0
+#ifdef HAS_VSNPRINTF
/* vsnprintf() shows failure with >= len */
- if (len > 0 && (Size_t)retval >= len)
+ ||
+ (len > 0 && (Size_t)retval >= len)
+#endif
+ )
Perl_croak_nocontext("panic: my_snprintf buffer overflow");
return retval;
}
/*
=for apidoc my_vsnprintf
-The C library C<vsnprintf>. Consider using C<sv_vcatpvf> instead.
+The C library C<vsnprintf> if available and standards-compliant.
+However, if if the C<vsnprintf> is not available, will unfortunately
+use the unsafe C<vsprintf> which can overrun the buffer (there is an
+overrun check, but that may be too late). Consider using
+C<sv_vcatpvf> instead, or getting C<vsnprintf>.
=cut
*/
PERL_ARGS_ASSERT_MY_VSNPRINTF;
Perl_va_copy(ap, apc);
+# ifdef HAS_VSNPRINTF
retval = vsnprintf(buffer, len, format, apc);
+# else
+ PERL_UNUSED_ARG(len);
+ retval = vsprintf(buffer, format, apc);
+# endif
va_end(apc);
#else
+# ifdef HAS_VSNPRINTF
retval = vsnprintf(buffer, len, format, ap);
+# else
+ PERL_UNUSED_ARG(len);
+ retval = vsprintf(buffer, format, ap);
+# endif
#endif /* #ifdef NEED_VA_COPY */
+ /* vsprintf() shows failure with < 0 */
+ if (retval < 0
+#ifdef HAS_VSNPRINTF
/* vsnprintf() shows failure with >= len */
- if (len > 0 && (Size_t)retval >= len)
+ ||
+ (len > 0 && (Size_t)retval >= len)
+#endif
+ )
Perl_croak_nocontext("panic: my_vsnprintf buffer overflow");
return retval;
#endif
d_sigsetjmp='undef'
d_sin6_scope_id='undef'
d_sitearch='define'
+d_snprintf='undef'
d_sockaddr_in6='undef'
d_sockaddr_sa_len='undef'
d_sockatmark='undef'
d_void_closedir='undef'
d_voidsig='define'
d_voidtty=''
+d_vsnprintf='undef'
d_wait4='undef'
d_waitpid='define'
d_wcscmp='undef'
d_sigsetjmp='undef'
d_sin6_scope_id='define'
d_sitearch='define'
+d_snprintf='define'
d_sockaddr_in6='undef'
d_sockaddr_sa_len='undef'
d_sockatmark='undef'
d_void_closedir='undef'
d_voidsig='define'
d_voidtty=''
+d_vsnprintf='define'
d_wait4='undef'
d_waitpid='define'
d_wcscmp='define'
/*#define USE_SITECUSTOMIZE / **/
#endif
+/* HAS_SNPRINTF:
+ * This symbol, if defined, indicates that the snprintf () library
+ * function is available for use.
+ */
+/* HAS_VSNPRINTF:
+ * This symbol, if defined, indicates that the vsnprintf () library
+ * function is available for use.
+ */
+#define HAS_SNPRINTF /**/
+#define HAS_VSNPRINTF /**/
+
/* HAS_SOCKATMARK:
* This symbol, if defined, indicates that the sockatmark routine is
* available to test whether a socket is at the out-of-band mark.
/*#define USE_SITECUSTOMIZE / **/
#endif
+/* HAS_SNPRINTF:
+ * This symbol, if defined, indicates that the snprintf () library
+ * function is available for use.
+ */
+/* HAS_VSNPRINTF:
+ * This symbol, if defined, indicates that the vsnprintf () library
+ * function is available for use.
+ */
+#define HAS_SNPRINTF /**/
+#define HAS_VSNPRINTF /**/
+
/* HAS_SOCKATMARK:
* This symbol, if defined, indicates that the sockatmark routine is
* available to test whether a socket is at the out-of-band mark.