This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Add thread safety to some environment accesses
[perl5.git] / inline.h
index f52d4e5..20aae02 100644 (file)
--- a/inline.h
+++ b/inline.h
@@ -6,7 +6,7 @@
  *    License or the Artistic License, as specified in the README file.
  *
  *    This file contains tables and code adapted from
- *    http://bjoern.hoehrmann.de/utf-8/decoder/dfa/, which requires this
+ *    https://bjoern.hoehrmann.de/utf-8/decoder/dfa/, which requires this
  *    copyright notice:
 
 Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
@@ -195,6 +195,14 @@ Perl_ReANY(const REGEXP * const re)
 
 /* ------------------------------- sv.h ------------------------------- */
 
+PERL_STATIC_INLINE bool
+Perl_SvTRUE(pTHX_ SV *sv) {
+    if (!LIKELY(sv))
+        return FALSE;
+    SvGETMAGIC(sv);
+    return SvTRUE_nomg_NN(sv);
+}
+
 PERL_STATIC_INLINE SV *
 Perl_SvREFCNT_inc(SV *sv)
 {
@@ -533,24 +541,7 @@ Perl_variant_byte_number(PERL_UINTMAX_T word)
     /* Get just the msb bits of each byte */
     word &= PERL_VARIANTS_WORD_MASK;
 
-#  ifdef USING_MSVC6    /* VC6 has some issues with the normal code, and the
-                           easiest thing is to hide that from the callers */
-    {
-        unsigned int i;
-        const U8 * s = (U8 *) &word;
-        dTHX;
-
-        for (i = 0; i < sizeof(word); i++ ) {
-            if (s[i]) {
-                return i;
-            }
-        }
-
-        Perl_croak(aTHX_ "panic: %s: %d: unexpected zero word\n",
-                                 __FILE__, __LINE__);
-    }
-
-#  elif BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
+#  if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
 
     /* Bytes are stored like
      *  Byte8 ... Byte2 Byte1
@@ -1060,7 +1051,7 @@ machines) is a valid UTF-8 character.
 =cut
 
 This uses an adaptation of the table and algorithm given in
-http://bjoern.hoehrmann.de/utf-8/decoder/dfa/, which provides comprehensive
+https://bjoern.hoehrmann.de/utf-8/decoder/dfa/, which provides comprehensive
 documentation of the original version.  A copyright notice for the original
 version is given at the beginning of this file.  The Perl adapation is
 documented at the definition of PL_extended_utf8_dfa_tab[].
@@ -1134,7 +1125,7 @@ C<L</is_strict_utf8_string_loclen>> to check entire strings.
 =cut
 
 This uses an adaptation of the tables and algorithm given in
-http://bjoern.hoehrmann.de/utf-8/decoder/dfa/, which provides comprehensive
+https://bjoern.hoehrmann.de/utf-8/decoder/dfa/, which provides comprehensive
 documentation of the original version.  A copyright notice for the original
 version is given at the beginning of this file.  The Perl adapation is
 documented at the definition of strict_extended_utf8_dfa_tab[].
@@ -1200,7 +1191,7 @@ C<L</is_c9strict_utf8_string_loclen>> to check entire strings.
 =cut
 
 This uses an adaptation of the tables and algorithm given in
-http://bjoern.hoehrmann.de/utf-8/decoder/dfa/, which provides comprehensive
+https://bjoern.hoehrmann.de/utf-8/decoder/dfa/, which provides comprehensive
 documentation of the original version.  A copyright notice for the original
 version is given at the beginning of this file.  The Perl adapation is
 documented at the definition of PL_c9_utf8_dfa_tab[].
@@ -1619,7 +1610,7 @@ Perl_utf8_hop_back(const U8 *s, SSize_t off, const U8 *start)
             s--;
         } while (UTF8_IS_CONTINUATION(*s) && s > start);
     }
-    
+
     GCC_DIAG_IGNORE(-Wcast-qual)
     return (U8 *)s;
     GCC_DIAG_RESTORE
@@ -1812,7 +1803,7 @@ Perl_utf8n_to_uvchr_msgs(const U8 *s,
      * will need to be called.
      *
      * This is an adaptation of the tables and algorithm given in
-     * http://bjoern.hoehrmann.de/utf-8/decoder/dfa/, which provides
+     * https://bjoern.hoehrmann.de/utf-8/decoder/dfa/, which provides
      * comprehensive documentation of the original version.  A copyright notice
      * for the original version is given at the beginning of this file.  The
      * Perl adapation is documented at the definition of PL_strict_utf8_dfa_tab[].
@@ -1996,6 +1987,36 @@ S_lossless_NV_to_IV(const NV nv, IV *ivp)
 
 #endif
 
+/* ------------------ regcomp.c, toke.c ------------ */
+
+#if defined(PERL_IN_REGCOMP_C) || defined(PERL_IN_TOKE_C)
+
+/*
+ - regcurly - a little FSA that accepts {\d+,?\d*}
+    Pulled from reg.c.
+ */
+PERL_STATIC_INLINE bool
+S_regcurly(const char *s)
+{
+    PERL_ARGS_ASSERT_REGCURLY;
+
+    if (*s++ != '{')
+       return FALSE;
+    if (!isDIGIT(*s))
+       return FALSE;
+    while (isDIGIT(*s))
+       s++;
+    if (*s == ',') {
+       s++;
+       while (isDIGIT(*s))
+           s++;
+    }
+
+    return *s == '}';
+}
+
+#endif
+
 /* ------------------ pp.c, regcomp.c, toke.c, universal.c ------------ */
 
 #if defined(PERL_IN_PP_C) || defined(PERL_IN_REGCOMP_C) || defined(PERL_IN_TOKE_C) || defined(PERL_IN_UNIVERSAL_C)
@@ -2512,6 +2533,36 @@ Perl_foldEQ_locale(const char *s1, const char *s2, I32 len)
     return 1;
 }
 
+/*
+=for apidoc my_strnlen
+
+The C library C<strnlen> if available, or a Perl implementation of it.
+
+C<my_strnlen()> computes the length of the string, up to C<maxlen>
+characters.  It will will never attempt to address more than C<maxlen>
+characters, making it suitable for use with strings that are not
+guaranteed to be NUL-terminated.
+
+=cut
+
+Description stolen from http://man.openbsd.org/strnlen.3,
+implementation stolen from PostgreSQL.
+*/
+#ifndef HAS_STRNLEN
+
+PERL_STATIC_INLINE Size_t
+Perl_my_strnlen(const char *str, Size_t maxlen)
+{
+    const char *end = (char *) memchr(str, '\0', maxlen);
+
+    PERL_ARGS_ASSERT_MY_STRNLEN;
+
+    if (end == NULL) return maxlen;
+    return end - str;
+}
+
+#endif
+
 #if ! defined (HAS_MEMRCHR) && (defined(PERL_CORE) || defined(PERL_EXT))
 
 PERL_STATIC_INLINE void *
@@ -2535,6 +2586,59 @@ S_my_memrchr(const char * s, const char c, const STRLEN len)
 
 #endif
 
+PERL_STATIC_INLINE char *
+Perl_mortal_getenv(const char * str)
+{
+    /* This implements a (mostly) thread-safe, sequential-call-safe getenv().
+     *
+     * It's (mostly) thread-safe because it uses a mutex to prevent
+     * simultaneous access from other threads that use the same mutex, and
+     * makes a copy of the result before releasing that mutex.  All of the Perl
+     * core uses that mutex, but, like all mutexes, everything has to cooperate
+     * for it to completely work.  It is possible for code from, say XS, to not
+     * use this mutex, defeating the safety.
+     *
+     * On some platforms, getenv() is not sequential-call-safe, because
+     * subsequent calls destroy the static storage inside the C library
+     * returned by an earlier call.  The result must be copied or completely
+     * acted upon before a subsequent getenv call.  Those calls could come from
+     * another thread.  Again, making a copy while controlling the mutex
+     * prevents these problems..
+     *
+     * To prevent leaks, the copy is made by creating a new SV containing it,
+     * mortalizing the SV, and returning the SV's string (the copy).  Thus this
+     * is a drop-in replacement for getenv().
+     *
+     * A complication is that this can be called during phases where the
+     * mortalization process isn't available.  These are in interpreter
+     * destruction or early in construction.  khw believes that at these times
+     * there shouldn't be anything else going on, so plain getenv is safe AS
+     * LONG AS the caller acts on the return before calling it again. */
+
+    char * ret;
+    dTHX;
+
+    PERL_ARGS_ASSERT_MORTAL_GETENV;
+
+    /* Can't mortalize without stacks.  khw believes that no other threads
+     * should be running, so no need to lock things, and this may be during a
+     * phase when locking isn't even available */
+    if (UNLIKELY(PL_scopestack_ix == 0)) {
+        return getenv(str);
+    }
+
+    ENV_LOCK;
+
+    ret = getenv(str);
+
+    if (ret != NULL) {
+        ret = SvPVX(sv_2mortal(newSVpv(ret, 0)));
+    }
+
+    ENV_UNLOCK;
+    return ret;
+}
+
 /*
  * ex: set ts=8 sts=4 sw=4 et:
  */