Skip to content

Commit 99a3dbc

Browse files
committed
Merge branch 'PHP-8.0'
* PHP-8.0: Don't check for throwing calls in sccp function evaluation
2 parents 30c8916 + 0ce9b5f commit 99a3dbc

File tree

1 file changed

+121
-200
lines changed

1 file changed

+121
-200
lines changed

ext/opcache/Optimizer/sccp.c

Lines changed: 121 additions & 200 deletions
Original file line numberDiff line numberDiff line change
@@ -781,253 +781,174 @@ static inline int ct_eval_array_key_exists(zval *result, zval *op1, zval *op2) {
781781
return SUCCESS;
782782
}
783783

784-
/* The functions chosen here are simple to implement and either likely to affect a branch,
785-
* or just happened to be commonly used with constant operands in WP (need to test other
786-
* applications as well, of course). */
787-
static inline int ct_eval_func_call(
788-
zval *result, zend_string *name, uint32_t num_args, zval **args) {
789-
uint32_t i;
790-
zend_execute_data *execute_data, *prev_execute_data;
791-
zend_function *func;
792-
bool overflow;
793-
794-
if (num_args == 0) {
795-
if (zend_string_equals_literal(name, "php_sapi_name")
796-
|| zend_string_equals_literal(name, "imagetypes")
797-
|| zend_string_equals_literal(name, "phpversion")) {
798-
/* pass */
799-
} else {
800-
return FAILURE;
801-
}
802-
} else if (num_args == 1) {
803-
if (zend_string_equals_literal(name, "chr")) {
804-
zend_long c;
805-
if (Z_TYPE_P(args[0]) != IS_LONG) {
806-
return FAILURE;
807-
}
808-
809-
c = Z_LVAL_P(args[0]) & 0xff;
810-
ZVAL_CHAR(result, c);
811-
return SUCCESS;
812-
} else if (zend_string_equals_literal(name, "count")) {
813-
if (Z_TYPE_P(args[0]) != IS_ARRAY) {
814-
return FAILURE;
815-
}
816-
817-
ZVAL_LONG(result, zend_hash_num_elements(Z_ARRVAL_P(args[0])));
818-
return SUCCESS;
819-
} else if (zend_string_equals_literal(name, "ini_get")) {
820-
zend_ini_entry *ini_entry;
821-
822-
if (Z_TYPE_P(args[0]) != IS_STRING) {
823-
return FAILURE;
824-
}
825-
826-
ini_entry = zend_hash_find_ptr(EG(ini_directives), Z_STR_P(args[0]));
827-
if (!ini_entry) {
828-
ZVAL_FALSE(result);
829-
} else if (ini_entry->modifiable != ZEND_INI_SYSTEM) {
830-
return FAILURE;
831-
} else if (ini_entry->value) {
832-
ZVAL_STR_COPY(result, ini_entry->value);
833-
} else {
834-
ZVAL_EMPTY_STRING(result);
835-
}
836-
return SUCCESS;
837-
} else if (zend_string_equals_literal(name, "trim")
838-
|| zend_string_equals_literal(name, "rtrim")
839-
|| zend_string_equals_literal(name, "ltrim")
840-
|| zend_string_equals_literal(name, "str_split")
841-
|| zend_string_equals_literal(name, "preg_quote")
842-
|| zend_string_equals_literal(name, "base64_encode")
843-
|| zend_string_equals_literal(name, "base64_decode")
844-
|| zend_string_equals_literal(name, "urlencode")
845-
|| zend_string_equals_literal(name, "urldecode")
846-
|| zend_string_equals_literal(name, "rawurlencode")
847-
|| zend_string_equals_literal(name, "rawurldecode")
848-
|| zend_string_equals_literal(name, "php_uname")) {
849-
if (Z_TYPE_P(args[0]) != IS_STRING) {
850-
return FAILURE;
851-
}
852-
/* pass */
853-
} else if (zend_string_equals_literal(name, "array_keys")
854-
|| zend_string_equals_literal(name, "array_values")) {
855-
if (Z_TYPE_P(args[0]) != IS_ARRAY) {
856-
return FAILURE;
857-
}
858-
/* pass */
859-
} else if (zend_string_equals_literal(name, "array_flip")) {
784+
static zend_bool can_ct_eval_func_call(zend_string *name, uint32_t num_args, zval **args) {
785+
/* Functions that can be evaluated independently of what the arguments are.
786+
* It's okay if these functions throw on invalid arguments, but they should not warn. */
787+
if (false
788+
|| zend_string_equals_literal(name, "array_diff")
789+
|| zend_string_equals_literal(name, "array_diff_assoc")
790+
|| zend_string_equals_literal(name, "array_diff_key")
791+
|| zend_string_equals_literal(name, "array_key_exists")
792+
|| zend_string_equals_literal(name, "array_keys")
793+
|| zend_string_equals_literal(name, "array_merge")
794+
|| zend_string_equals_literal(name, "array_merge_recursive")
795+
|| zend_string_equals_literal(name, "array_replace")
796+
|| zend_string_equals_literal(name, "array_replace_recursive")
797+
|| zend_string_equals_literal(name, "array_values")
798+
|| zend_string_equals_literal(name, "base64_decode")
799+
|| zend_string_equals_literal(name, "base64_encode")
800+
|| zend_string_equals_literal(name, "imagetypes")
801+
|| zend_string_equals_literal(name, "in_array")
802+
|| zend_string_equals_literal(name, "ltrim")
803+
|| zend_string_equals_literal(name, "php_sapi_name")
804+
|| zend_string_equals_literal(name, "php_uname")
805+
|| zend_string_equals_literal(name, "phpversion")
806+
|| zend_string_equals_literal(name, "pow")
807+
|| zend_string_equals_literal(name, "preg_quote")
808+
|| zend_string_equals_literal(name, "rawurldecode")
809+
|| zend_string_equals_literal(name, "rawurlencode")
810+
|| zend_string_equals_literal(name, "rtrim")
811+
|| zend_string_equals_literal(name, "serialize")
812+
|| zend_string_equals_literal(name, "str_contains")
813+
|| zend_string_equals_literal(name, "str_ends_with")
814+
|| zend_string_equals_literal(name, "str_split")
815+
|| zend_string_equals_literal(name, "str_split")
816+
|| zend_string_equals_literal(name, "str_starts_with")
817+
|| zend_string_equals_literal(name, "strpos")
818+
|| zend_string_equals_literal(name, "substr")
819+
|| zend_string_equals_literal(name, "trim")
820+
|| zend_string_equals_literal(name, "urldecode")
821+
|| zend_string_equals_literal(name, "urlencode")
822+
|| zend_string_equals_literal(name, "version_compare")
823+
) {
824+
return true;
825+
}
826+
827+
/* For the following functions we need to check arguments to prevent warnings during
828+
* evaluation. */
829+
if (num_args == 1) {
830+
if (zend_string_equals_literal(name, "array_flip")) {
860831
zval *entry;
861832

862833
if (Z_TYPE_P(args[0]) != IS_ARRAY) {
863-
return FAILURE;
834+
return false;
864835
}
865836
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args[0]), entry) {
837+
/* Throws warning for non int/string values. */
866838
if (Z_TYPE_P(entry) != IS_LONG && Z_TYPE_P(entry) != IS_STRING) {
867-
return FAILURE;
839+
return false;
868840
}
869841
} ZEND_HASH_FOREACH_END();
870-
/* pass */
871-
} else if (zend_string_equals_literal(name, "implode")) {
842+
return true;
843+
}
844+
if (zend_string_equals_literal(name, "implode")) {
872845
zval *entry;
873846

874847
if (Z_TYPE_P(args[0]) != IS_ARRAY) {
875-
return FAILURE;
848+
return false;
876849
}
877850

878851
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args[0]), entry) {
852+
/* May throw warning during conversion to string. */
879853
if (Z_TYPE_P(entry) > IS_STRING) {
880-
return FAILURE;
854+
return false;
881855
}
882856
} ZEND_HASH_FOREACH_END();
883-
/* pass */
884-
} else if (zend_string_equals_literal(name, "serialize")) {
885-
/* pass */
886-
} else {
887-
return FAILURE;
857+
return true;
888858
}
889-
} else if (num_args == 2) {
890-
if (zend_string_equals_literal(name, "in_array")) {
891-
if (Z_TYPE_P(args[1]) != IS_ARRAY) {
892-
return FAILURE;
893-
}
894-
/* pass */
895-
} else if (zend_string_equals_literal(name, "str_split")) {
896-
if (Z_TYPE_P(args[0]) != IS_STRING
897-
|| Z_TYPE_P(args[1]) != IS_LONG
898-
|| Z_LVAL_P(args[1]) <= 0) {
899-
return FAILURE;
900-
}
901-
/* pass */
902-
} else if (zend_string_equals_literal(name, "array_key_exists")) {
903-
if (Z_TYPE_P(args[1]) != IS_ARRAY
904-
|| (Z_TYPE_P(args[0]) != IS_LONG
905-
&& Z_TYPE_P(args[0]) != IS_STRING
906-
&& Z_TYPE_P(args[0]) != IS_NULL)) {
907-
return FAILURE;
908-
}
909-
/* pass */
910-
} else if (zend_string_equals_literal(name, "trim")
911-
|| zend_string_equals_literal(name, "rtrim")
912-
|| zend_string_equals_literal(name, "ltrim")
913-
|| zend_string_equals_literal(name, "preg_quote")) {
914-
if (Z_TYPE_P(args[0]) != IS_STRING
915-
|| Z_TYPE_P(args[1]) != IS_STRING) {
916-
return FAILURE;
917-
}
918-
/* pass */
919-
} else if (zend_string_equals_literal(name, "str_repeat")) {
920-
if (Z_TYPE_P(args[0]) != IS_STRING
921-
|| Z_TYPE_P(args[1]) != IS_LONG
922-
|| zend_safe_address(Z_STRLEN_P(args[0]), Z_LVAL_P(args[1]), 0, &overflow) > 64 * 1024
923-
|| overflow) {
924-
return FAILURE;
925-
}
926-
/* pass */
927-
} else if (zend_string_equals_literal(name, "array_merge")
928-
|| zend_string_equals_literal(name, "array_replace")
929-
|| zend_string_equals_literal(name, "array_merge_recursive")
930-
|| zend_string_equals_literal(name, "array_replace_recursive")
931-
|| zend_string_equals_literal(name, "array_diff")
932-
|| zend_string_equals_literal(name, "array_diff_assoc")
933-
|| zend_string_equals_literal(name, "array_diff_key")) {
934-
for (i = 0; i < num_args; i++) {
935-
if (Z_TYPE_P(args[i]) != IS_ARRAY) {
936-
return FAILURE;
937-
}
938-
}
939-
/* pass */
859+
return false;
860+
}
861+
862+
if (num_args == 2) {
863+
if (zend_string_equals_literal(name, "str_repeat")) {
864+
/* Avoid creating overly large strings at compile-time. */
865+
bool overflow;
866+
return Z_TYPE_P(args[0]) == IS_STRING
867+
&& Z_TYPE_P(args[1]) == IS_LONG
868+
&& zend_safe_address(Z_STRLEN_P(args[0]), Z_LVAL_P(args[1]), 0, &overflow) < 64 * 1024
869+
&& !overflow;
940870
} else if (zend_string_equals_literal(name, "implode")) {
941871
zval *entry;
942872

943873
if ((Z_TYPE_P(args[0]) != IS_STRING || Z_TYPE_P(args[1]) != IS_ARRAY)
944874
&& (Z_TYPE_P(args[0]) != IS_ARRAY || Z_TYPE_P(args[1]) != IS_STRING)) {
945-
return FAILURE;
875+
return false;
946876
}
947877

878+
/* May throw warning during conversion to string. */
948879
if (Z_TYPE_P(args[0]) == IS_ARRAY) {
949880
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args[0]), entry) {
950881
if (Z_TYPE_P(entry) > IS_STRING) {
951-
return FAILURE;
882+
return false;
952883
}
953884
} ZEND_HASH_FOREACH_END();
954885
} else {
955886
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args[1]), entry) {
956887
if (Z_TYPE_P(entry) > IS_STRING) {
957-
return FAILURE;
888+
return false;
958889
}
959890
} ZEND_HASH_FOREACH_END();
960891
}
961-
/* pass */
962-
} else if (zend_string_equals_literal(name, "strpos")
963-
|| zend_string_equals_literal(name, "str_contains")
964-
|| zend_string_equals_literal(name, "str_starts_with")
965-
|| zend_string_equals_literal(name, "str_ends_with")
966-
|| zend_string_equals_literal(name, "version_compare")) {
967-
if (Z_TYPE_P(args[0]) != IS_STRING
968-
|| Z_TYPE_P(args[1]) != IS_STRING) {
969-
return FAILURE;
970-
}
971-
/* pass */
972-
} else if (zend_string_equals_literal(name, "substr")) {
973-
if (Z_TYPE_P(args[0]) != IS_STRING
974-
|| Z_TYPE_P(args[1]) != IS_LONG) {
975-
return FAILURE;
976-
}
977-
/* pass */
978-
} else if (zend_string_equals_literal(name, "pow")) {
979-
if ((Z_TYPE_P(args[0]) != IS_LONG && Z_TYPE_P(args[0]) != IS_DOUBLE)
980-
|| (Z_TYPE_P(args[1]) != IS_LONG && Z_TYPE_P(args[1]) != IS_DOUBLE)) {
981-
return FAILURE;
982-
}
983-
/* pass */
984-
} else {
985-
return FAILURE;
892+
return true;
986893
}
987-
} else if (num_args == 3) {
988-
if (zend_string_equals_literal(name, "in_array")) {
989-
if (Z_TYPE_P(args[1]) != IS_ARRAY
990-
|| (Z_TYPE_P(args[2]) != IS_FALSE
991-
&& Z_TYPE_P(args[2]) != IS_TRUE)) {
894+
return false;
895+
}
896+
897+
return false;
898+
}
899+
900+
/* The functions chosen here are simple to implement and either likely to affect a branch,
901+
* or just happened to be commonly used with constant operands in WP (need to test other
902+
* applications as well, of course). */
903+
static inline int ct_eval_func_call(
904+
zval *result, zend_string *name, uint32_t num_args, zval **args) {
905+
uint32_t i;
906+
zend_execute_data *execute_data, *prev_execute_data;
907+
zend_function *func = zend_hash_find_ptr(CG(function_table), name);
908+
if (!func || func->type != ZEND_INTERNAL_FUNCTION) {
909+
return FAILURE;
910+
}
911+
912+
if (num_args == 1) {
913+
/* Handle a few functions for which we manually implement evaluation here. */
914+
if (zend_string_equals_literal(name, "chr")) {
915+
zend_long c;
916+
if (Z_TYPE_P(args[0]) != IS_LONG) {
992917
return FAILURE;
993918
}
994-
/* pass */
995-
} else if (zend_string_equals_literal(name, "array_merge")
996-
|| zend_string_equals_literal(name, "array_replace")
997-
|| zend_string_equals_literal(name, "array_merge_recursive")
998-
|| zend_string_equals_literal(name, "array_replace_recursive")
999-
|| zend_string_equals_literal(name, "array_diff")
1000-
|| zend_string_equals_literal(name, "array_diff_assoc")
1001-
|| zend_string_equals_literal(name, "array_diff_key")) {
1002-
for (i = 0; i < num_args; i++) {
1003-
if (Z_TYPE_P(args[i]) != IS_ARRAY) {
1004-
return FAILURE;
1005-
}
919+
920+
c = Z_LVAL_P(args[0]) & 0xff;
921+
ZVAL_CHAR(result, c);
922+
return SUCCESS;
923+
} else if (zend_string_equals_literal(name, "count")) {
924+
if (Z_TYPE_P(args[0]) != IS_ARRAY) {
925+
return FAILURE;
1006926
}
1007-
/* pass */
1008-
} else if (zend_string_equals_literal(name, "version_compare")) {
1009-
if (Z_TYPE_P(args[0]) != IS_STRING
1010-
|| Z_TYPE_P(args[1]) != IS_STRING
1011-
|| Z_TYPE_P(args[2]) != IS_STRING) {
927+
928+
ZVAL_LONG(result, zend_hash_num_elements(Z_ARRVAL_P(args[0])));
929+
return SUCCESS;
930+
} else if (zend_string_equals_literal(name, "ini_get")) {
931+
zend_ini_entry *ini_entry;
932+
933+
if (Z_TYPE_P(args[0]) != IS_STRING) {
1012934
return FAILURE;
1013935
}
1014-
/* pass */
1015-
} else if (zend_string_equals_literal(name, "substr")) {
1016-
if (Z_TYPE_P(args[0]) != IS_STRING
1017-
|| Z_TYPE_P(args[1]) != IS_LONG
1018-
|| Z_TYPE_P(args[2]) != IS_LONG) {
936+
937+
ini_entry = zend_hash_find_ptr(EG(ini_directives), Z_STR_P(args[0]));
938+
if (!ini_entry) {
939+
ZVAL_FALSE(result);
940+
} else if (ini_entry->modifiable != ZEND_INI_SYSTEM) {
1019941
return FAILURE;
942+
} else if (ini_entry->value) {
943+
ZVAL_STR_COPY(result, ini_entry->value);
944+
} else {
945+
ZVAL_EMPTY_STRING(result);
1020946
}
1021-
/* pass */
1022-
} else {
1023-
return FAILURE;
947+
return SUCCESS;
1024948
}
1025-
} else {
1026-
return FAILURE;
1027949
}
1028950

1029-
func = zend_hash_find_ptr(CG(function_table), name);
1030-
if (!func || func->type != ZEND_INTERNAL_FUNCTION) {
951+
if (!can_ct_eval_func_call(name, num_args, args)) {
1031952
return FAILURE;
1032953
}
1033954

0 commit comments

Comments
 (0)