From 9b1069fc2deca0b91a819a6d6b847cc7b6ba0e44 Mon Sep 17 00:00:00 2001 From: Adam Harvey Date: Mon, 19 Aug 2013 15:14:19 -0700 Subject: [PATCH 1/5] Ensure the exception string is constructed in a binary-safe manner. --- Zend/zend_exceptions.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 14ae75e38d09..15f00fdea4ba 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -617,10 +617,26 @@ ZEND_METHOD(exception, __toString) } if (Z_STRLEN(message) > 0) { - len = zend_spprintf(&str, 0, "exception '%s' with message '%s' in %s:%ld\nStack trace:\n%s%s%s", - Z_OBJCE_P(exception)->name, Z_STRVAL(message), Z_STRVAL(file), Z_LVAL(line), - (trace && Z_STRLEN_P(trace)) ? Z_STRVAL_P(trace) : "#0 {main}\n", - len ? "\n\nNext " : "", prev_str); + char *prefix, *suffix; + int prefix_len, suffix_len; + + prefix_len = zend_spprintf(&prefix, 0, "exception '%s' with message '", + Z_OBJCE_P(exception)->name); + + suffix_len = zend_spprintf(&suffix, 0, "' in %s:%ld\nStack trace:\n%s%s%s", + Z_STRVAL(file), Z_LVAL(line), + (trace && Z_STRLEN_P(trace)) ? Z_STRVAL_P(trace) : "#0 {main}\n", + len ? "\n\nNext " : "", prev_str); + + len = prefix_len + Z_STRLEN(message) + suffix_len; + str = emalloc(len + 1); + memcpy(str, prefix, prefix_len); + memcpy(str + prefix_len, Z_STRVAL(message), Z_STRLEN(message)); + memcpy(str + prefix_len + Z_STRLEN(message), suffix, suffix_len); + str[len] = '\0'; + + efree(prefix); + efree(suffix); } else { len = zend_spprintf(&str, 0, "exception '%s' in %s:%ld\nStack trace:\n%s%s%s", Z_OBJCE_P(exception)->name, Z_STRVAL(file), Z_LVAL(line), @@ -643,7 +659,7 @@ ZEND_METHOD(exception, __toString) /* We store the result in the private property string so we can access * the result in uncaught exception handlers without memleaks. */ - zend_update_property_string(default_exception_ce, getThis(), "string", sizeof("string")-1, str TSRMLS_CC); + zend_update_property_stringl(default_exception_ce, getThis(), "string", sizeof("string")-1, str, len TSRMLS_CC); RETURN_STRINGL(str, len, 0); } @@ -807,7 +823,11 @@ ZEND_API void zend_exception_error(zval *exception, int severity TSRMLS_DC) /* { if (Z_TYPE_P(str) != IS_STRING) { zend_error(E_WARNING, "%s::__toString() must return a string", ce_exception->name); } else { - zend_update_property_string(default_exception_ce, exception, "string", sizeof("string")-1, EG(exception) ? ce_exception->name : Z_STRVAL_P(str) TSRMLS_CC); + if (EG(exception)) { + zend_update_property_string(default_exception_ce, exception, "string", sizeof("string")-1, ce_exception->name TSRMLS_CC); + } else { + zend_update_property_stringl(default_exception_ce, exception, "string", sizeof("string")-1, Z_STRVAL_P(str), Z_STRLEN_P(str) TSRMLS_CC); + } } } zval_ptr_dtor(&str); @@ -836,7 +856,7 @@ ZEND_API void zend_exception_error(zval *exception, int severity TSRMLS_DC) /* { convert_to_string(file); convert_to_long(line); - zend_error_va(severity, (Z_STRLEN_P(file) > 0) ? Z_STRVAL_P(file) : NULL, Z_LVAL_P(line), "Uncaught %s\n thrown", Z_STRVAL_P(str)); + zend_error_va(severity, (Z_STRLEN_P(file) > 0) ? Z_STRVAL_P(file) : NULL, Z_LVAL_P(line), "Uncaught %Z\n thrown", str); } else { zend_error(severity, "Uncaught exception '%s'", ce_exception->name); } From e7ece29032b2cafe2dbaedd1e62dac1f6dd63ef4 Mon Sep 17 00:00:00 2001 From: Adam Harvey Date: Mon, 19 Aug 2013 15:22:13 -0700 Subject: [PATCH 2/5] Update the default error handler to be binary-safe. --- main/main.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/main/main.c b/main/main.c index 2f56afa03a3f..08b881572e69 100644 --- a/main/main.c +++ b/main/main.c @@ -1087,9 +1087,14 @@ static void php_error_cb(int type, const char *error_filename, const uint error_ size_t len; char *buf = php_escape_html_entities(buffer, buffer_len, &len, 0, ENT_COMPAT, NULL TSRMLS_CC); php_printf("%s
\n%s: %s in %s on line %d
\n%s", STR_PRINT(prepend_string), error_type_str, buf, error_filename, error_lineno, STR_PRINT(append_string)); + php_printf("%s
\n%s: ", STR_PRINT(prepend_string), error_type_str); + PHPWRITE(buf, len); + php_printf(" in %s on line %d
\n%s", error_filename, error_lineno, STR_PRINT(append_string)); efree(buf); } else { - php_printf("%s
\n%s: %s in %s on line %d
\n%s", STR_PRINT(prepend_string), error_type_str, buffer, error_filename, error_lineno, STR_PRINT(append_string)); + php_printf("%s
\n%s: ", STR_PRINT(prepend_string), error_type_str); + PHPWRITE(buffer, buffer_len); + php_printf(" in %s on line %d
\n%s", error_filename, error_lineno, STR_PRINT(append_string)); } } else { /* Write CLI/CGI errors to stderr if display_errors = "stderr" */ @@ -1097,13 +1102,19 @@ static void php_error_cb(int type, const char *error_filename, const uint error_ PG(display_errors) == PHP_DISPLAY_ERRORS_STDERR ) { #ifdef PHP_WIN32 - fprintf(stderr, "%s: %s in %s on line %d\n", error_type_str, buffer, error_filename, error_lineno); + fprintf(stderr, "%s: ", error_type_str); + fwrite(buffer, buffer_len, 1, stderr); + fprintf(stderr, " in %s on line %d\n", error_filename, error_lineno); fflush(stderr); #else - fprintf(stderr, "%s: %s in %s on line %d\n", error_type_str, buffer, error_filename, error_lineno); + fprintf(stderr, "%s\n%s: ", STR_PRINT(prepend_string), error_type_str); + fwrite(buffer, buffer_len, 1, stderr); + fprintf(stderr, " in %s on line %d\n%s", error_filename, error_lineno, STR_PRINT(append_string)); #endif } else { - php_printf("%s\n%s: %s in %s on line %d\n%s", STR_PRINT(prepend_string), error_type_str, buffer, error_filename, error_lineno, STR_PRINT(append_string)); + php_printf("%s\n%s: ", STR_PRINT(prepend_string), error_type_str); + PHPWRITE(buffer, buffer_len); + php_printf(" in %s on line %d\n%s", error_filename, error_lineno, STR_PRINT(append_string)); } } } From 38b70e5d0c44f28b863b6b506d3ade790f42cd56 Mon Sep 17 00:00:00 2001 From: Adam Harvey Date: Mon, 19 Aug 2013 15:27:37 -0700 Subject: [PATCH 3/5] Fix CLI error output to stderr. For whatever reason, prepend and append strings don't get prepended and appended when the error output is to stderr. This retains that behaviour in the new code. --- main/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/main.c b/main/main.c index 08b881572e69..84a2437d543c 100644 --- a/main/main.c +++ b/main/main.c @@ -1107,9 +1107,9 @@ static void php_error_cb(int type, const char *error_filename, const uint error_ fprintf(stderr, " in %s on line %d\n", error_filename, error_lineno); fflush(stderr); #else - fprintf(stderr, "%s\n%s: ", STR_PRINT(prepend_string), error_type_str); + fprintf(stderr, "%s: ", error_type_str); fwrite(buffer, buffer_len, 1, stderr); - fprintf(stderr, " in %s on line %d\n%s", error_filename, error_lineno, STR_PRINT(append_string)); + fprintf(stderr, " in %s on line %d\n", error_filename, error_lineno); #endif } else { php_printf("%s\n%s: ", STR_PRINT(prepend_string), error_type_str); From 7684d20882b0c44f147b22550a5b0881979ec7a9 Mon Sep 17 00:00:00 2001 From: Adam Harvey Date: Mon, 19 Aug 2013 15:33:41 -0700 Subject: [PATCH 4/5] Add a test for binary-safe exception messages and error output. --- Zend/tests/exception_011.phpt | Bin 0 -> 252 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Zend/tests/exception_011.phpt diff --git a/Zend/tests/exception_011.phpt b/Zend/tests/exception_011.phpt new file mode 100644 index 0000000000000000000000000000000000000000..02bab1d11e3b756ae46d3a738ffedf01d2b4e174 GIT binary patch literal 252 zcmYk1K}*9x5Jo-kulT5x*uz54QS3oBQ1Bo$f(I|tIA#~q*|3=sMf~qhsfzb`?|b8Y z8+NVtu8k$nNqUfg-#Z>PWx<>@LXN|L{fF{|B+$q>@HA1+&iiJ2AB?`)jB$k1lLW#u z!mr|L@tX7VdQWAsx^|meW5UxzxN953Tti9&xRhLKJW5B$KI*^y>d#Z1TYi>Nnf1b? n)hTH?)yo&RQ|jKJg*vX? Date: Mon, 19 Aug 2013 15:35:06 -0700 Subject: [PATCH 5/5] Remove duplicate line. --- main/main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/main/main.c b/main/main.c index 84a2437d543c..6e8db5f1429a 100644 --- a/main/main.c +++ b/main/main.c @@ -1086,7 +1086,6 @@ static void php_error_cb(int type, const char *error_filename, const uint error_ if (type == E_ERROR || type == E_PARSE) { size_t len; char *buf = php_escape_html_entities(buffer, buffer_len, &len, 0, ENT_COMPAT, NULL TSRMLS_CC); - php_printf("%s
\n%s: %s in %s on line %d
\n%s", STR_PRINT(prepend_string), error_type_str, buf, error_filename, error_lineno, STR_PRINT(append_string)); php_printf("%s
\n%s: ", STR_PRINT(prepend_string), error_type_str); PHPWRITE(buf, len); php_printf(" in %s on line %d
\n%s", error_filename, error_lineno, STR_PRINT(append_string));