This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
dquote.c: Use memchr() instead of strchr()
authorKarl Williamson <khw@cpan.org>
Sat, 25 Mar 2017 17:39:05 +0000 (11:39 -0600)
committerKarl Williamson <khw@cpan.org>
Mon, 6 Nov 2017 21:31:45 +0000 (14:31 -0700)
This allows \x and \o to work properly in the face of embedded NULs.
A limit parameter is added to each function, and that is passed to
memchr (which replaces strchr).  See the branch merge message for more
information.

dquote.c
embed.fnc
embed.h
proto.h
regcomp.c
toke.c

index 19a7a37..6913ca5 100644 (file)
--- a/dquote.c
+++ b/dquote.c
@@ -56,7 +56,8 @@ Perl_grok_bslash_c(pTHX_ const char source, const bool output_warning)
 }
 
 bool
-Perl_grok_bslash_o(pTHX_ char **s, UV *uv, const char** error_msg,
+Perl_grok_bslash_o(pTHX_ char **s, const char * const send, UV *uv,
+                      const char** error_msg,
                       const bool output_warning, const bool strict,
                       const bool silence_non_portable,
                       const bool UTF)
@@ -68,13 +69,16 @@ Perl_grok_bslash_o(pTHX_ char **s, UV *uv, const char** error_msg,
  *  It guarantees that the returned codepoint, *uv, when expressed as
  *  utf8 bytes, would fit within the skipped "\o{...}" bytes.
  *  On input:
- *     s   is the address of a pointer to a NULL terminated string that begins
- *         with 'o', and the previous character was a backslash.  At exit, *s
- *         will be advanced to the byte just after those absorbed by this
- *         function.  Hence the caller can continue parsing from there.  In
- *         the case of an error, this routine has generally positioned *s to
- *         point just to the right of the first bad spot, so that a message
- *         that has a "<--" to mark the spot will be correctly positioned.
+ *     s   is the address of a pointer to a string.  **s is 'o', and the
+ *         previous character was a backslash.  At exit, *s will be advanced
+ *         to the byte just after those absorbed by this function.  Hence the
+ *         caller can continue parsing from there.  In the case of an error,
+ *         this routine has generally positioned *s to point just to the right
+ *         of the first bad spot, so that a message that has a "<--" to mark
+ *         the spot will be correctly positioned.
+ *     send - 1  gives a limit in *s that this function is not permitted to
+ *         look beyond.  That is, the function may look at bytes only in the
+ *         range *s..send-1
  *     uv  points to a UV that will hold the output value, valid only if the
  *         return from the function is TRUE
  *      error_msg is a pointer that will be set to an internal buffer giving an
@@ -107,7 +111,7 @@ Perl_grok_bslash_o(pTHX_ char **s, UV *uv, const char** error_msg,
        return FALSE;
     }
 
-    e = strchr(*s, '}');
+    e = (char *) memchr(*s, '}', send - *s);
     if (!e) {
         (*s)++;  /* Move past the '{' */
         while (isOCTAL(**s)) { /* Position beyond the legal digits */
@@ -158,7 +162,8 @@ Perl_grok_bslash_o(pTHX_ char **s, UV *uv, const char** error_msg,
 }
 
 bool
-Perl_grok_bslash_x(pTHX_ char **s, UV *uv, const char** error_msg,
+Perl_grok_bslash_x(pTHX_ char **s, const char * const send, UV *uv,
+                      const char** error_msg,
                       const bool output_warning, const bool strict,
                       const bool silence_non_portable,
                       const bool UTF)
@@ -171,13 +176,16 @@ Perl_grok_bslash_x(pTHX_ char **s, UV *uv, const char** error_msg,
  *  utf8 bytes, would fit within the skipped "\x{...}" bytes.
  *
  *  On input:
- *     s   is the address of a pointer to a NULL terminated string that begins
- *         with 'x', and the previous character was a backslash.  At exit, *s
- *         will be advanced to the byte just after those absorbed by this
- *         function.  Hence the caller can continue parsing from there.  In
- *         the case of an error, this routine has generally positioned *s to
- *         point just to the right of the first bad spot, so that a message
- *         that has a "<--" to mark the spot will be correctly positioned.
+ *     s   is the address of a pointer to a string.  **s is 'x', and the
+ *         previous character was a backslash.  At exit, *s will be advanced
+ *         to the byte just after those absorbed by this function.  Hence the
+ *         caller can continue parsing from there.  In the case of an error,
+ *         this routine has generally positioned *s to point just to the right
+ *         of the first bad spot, so that a message that has a "<--" to mark
+ *         the spot will be correctly positioned.
+ *     send - 1  gives a limit in *s that this function is not permitted to
+ *         look beyond.  That is, the function may look at bytes only in the
+ *         range *s..send-1
  *     uv  points to a UV that will hold the output value, valid only if the
  *         return from the function is TRUE
  *      error_msg is a pointer that will be set to an internal buffer giving an
@@ -226,7 +234,7 @@ Perl_grok_bslash_x(pTHX_ char **s, UV *uv, const char** error_msg,
        return TRUE;
     }
 
-    e = strchr(*s, '}');
+    e = (char *) memchr(*s, '}', send - *s);
     if (!e) {
         (*s)++;  /* Move past the '{' */
         while (isXDIGIT(**s)) { /* Position beyond the legal digits */
index 3860958..ef43922 100644 (file)
--- a/embed.fnc
+++ b/embed.fnc
@@ -918,14 +918,18 @@ p |OP*    |localize       |NN OP *o|I32 lex
 ApdR   |I32    |looks_like_number|NN SV *const sv
 Apd    |UV     |grok_bin       |NN const char* start|NN STRLEN* len_p|NN I32* flags|NULLOK NV *result
 #if defined(PERL_IN_REGCOMP_C) || defined(PERL_IN_TOKE_C) || defined(PERL_IN_DQUOTE_C)
-EMpRX  |bool   |grok_bslash_x  |NN char** s|NN UV* uv           \
+EMpRX  |bool   |grok_bslash_x  |NN char** s             \
+                               |NN const char* const send       \
+                               |NN UV* uv                       \
                                |NN const char** error_msg       \
                                |const bool output_warning       \
                                |const bool strict               \
                                |const bool silence_non_portable \
                                |const bool utf8
 EMpRX  |char   |grok_bslash_c  |const char source|const bool output_warning
-EMpRX  |bool   |grok_bslash_o  |NN char** s|NN UV* uv           \
+EMpRX  |bool   |grok_bslash_o  |NN char** s             \
+                               |NN const char* const send       \
+                               |NN UV* uv                       \
                                |NN const char** error_msg       \
                                |const bool output_warning       \
                                |const bool strict               \
diff --git a/embed.h b/embed.h
index 5900678..34af92d 100644 (file)
--- a/embed.h
+++ b/embed.h
 #  if defined(PERL_IN_REGCOMP_C) || defined(PERL_IN_TOKE_C) || defined(PERL_IN_DQUOTE_C)
 #define form_short_octal_warning(a,b)  S_form_short_octal_warning(aTHX_ a,b)
 #define grok_bslash_c(a,b)     Perl_grok_bslash_c(aTHX_ a,b)
-#define grok_bslash_o(a,b,c,d,e,f,g)   Perl_grok_bslash_o(aTHX_ a,b,c,d,e,f,g)
-#define grok_bslash_x(a,b,c,d,e,f,g)   Perl_grok_bslash_x(aTHX_ a,b,c,d,e,f,g)
+#define grok_bslash_o(a,b,c,d,e,f,g,h) Perl_grok_bslash_o(aTHX_ a,b,c,d,e,f,g,h)
+#define grok_bslash_x(a,b,c,d,e,f,g,h) Perl_grok_bslash_x(aTHX_ a,b,c,d,e,f,g,h)
 #define regcurly               S_regcurly
 #  endif
 #  if defined(PERL_IN_REGCOMP_C) || defined(PERL_IN_UTF8_C)
diff --git a/proto.h b/proto.h
index 72c3a60..2547cec 100644 (file)
--- a/proto.h
+++ b/proto.h
@@ -5398,15 +5398,15 @@ PERL_STATIC_INLINE char*        S_form_short_octal_warning(pTHX_ const char * const s,
 PERL_CALLCONV char     Perl_grok_bslash_c(pTHX_ const char source, const bool output_warning)
                        __attribute__warn_unused_result__;
 
-PERL_CALLCONV bool     Perl_grok_bslash_o(pTHX_ char** s, UV* uv, const char** error_msg, const bool output_warning, const bool strict, const bool silence_non_portable, const bool utf8)
+PERL_CALLCONV bool     Perl_grok_bslash_o(pTHX_ char** s, const char* const send, UV* uv, const char** error_msg, const bool output_warning, const bool strict, const bool silence_non_portable, const bool utf8)
                        __attribute__warn_unused_result__;
 #define PERL_ARGS_ASSERT_GROK_BSLASH_O \
-       assert(s); assert(uv); assert(error_msg)
+       assert(s); assert(send); assert(uv); assert(error_msg)
 
-PERL_CALLCONV bool     Perl_grok_bslash_x(pTHX_ char** s, UV* uv, const char** error_msg, const bool output_warning, const bool strict, const bool silence_non_portable, const bool utf8)
+PERL_CALLCONV bool     Perl_grok_bslash_x(pTHX_ char** s, const char* const send, UV* uv, const char** error_msg, const bool output_warning, const bool strict, const bool silence_non_portable, const bool utf8)
                        __attribute__warn_unused_result__;
 #define PERL_ARGS_ASSERT_GROK_BSLASH_X \
-       assert(s); assert(uv); assert(error_msg)
+       assert(s); assert(send); assert(uv); assert(error_msg)
 
 #ifndef PERL_NO_INLINE_FUNCTIONS
 PERL_STATIC_INLINE I32 S_regcurly(const char *s)
index af1ec37..892aed8 100644 (file)
--- a/regcomp.c
+++ b/regcomp.c
@@ -13354,6 +13354,7 @@ S_regatom(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, U32 depth)
                            const char* error_msg;
 
                            bool valid = grok_bslash_o(&p,
+                                                       RExC_end,
                                                       &result,
                                                       &error_msg,
                                                       PASS2, /* out warnings */
@@ -13380,6 +13381,7 @@ S_regatom(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, U32 depth)
                            const char* error_msg;
 
                            bool valid = grok_bslash_x(&p,
+                                                       RExC_end,
                                                       &result,
                                                       &error_msg,
                                                       PASS2, /* out warnings */
@@ -16525,6 +16527,7 @@ S_regclass(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, U32 depth,
                {
                    const char* error_msg;
                    bool valid = grok_bslash_o(&RExC_parse,
+                                               RExC_end,
                                               &value,
                                               &error_msg,
                                                PASS2,   /* warnings only in
@@ -16543,6 +16546,7 @@ S_regclass(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, U32 depth,
                {
                    const char* error_msg;
                    bool valid = grok_bslash_x(&RExC_parse,
+                                               RExC_end,
                                               &value,
                                               &error_msg,
                                               PASS2, /* Output warnings */
diff --git a/toke.c b/toke.c
index 734b02c..159e2ae 100644 (file)
--- a/toke.c
+++ b/toke.c
@@ -3508,7 +3508,8 @@ S_scan_const(pTHX_ char *start)
                {
                    const char* error;
 
-                   bool valid = grok_bslash_o(&s, &uv, &error,
+                   bool valid = grok_bslash_o(&s, PL_bufend,
+                                               &uv, &error,
                                                TRUE, /* Output warning */
                                                FALSE, /* Not strict */
                                                TRUE, /* Output warnings for
@@ -3526,7 +3527,8 @@ S_scan_const(pTHX_ char *start)
                {
                    const char* error;
 
-                   bool valid = grok_bslash_x(&s, &uv, &error,
+                   bool valid = grok_bslash_x(&s, PL_bufend,
+                                               &uv, &error,
                                                TRUE, /* Output warning */
                                                FALSE, /* Not strict */
                                                TRUE,  /* Output warnings for