From 613768f08ed471fe7a0fdfd5eeb44aa48c21074b Mon Sep 17 00:00:00 2001 From: Stanislav Eismont Date: Tue, 20 Dec 2022 09:51:01 +0300 Subject: [PATCH 1/3] add recursion depth limit in to_array_debug() --- runtime/runtime.cmake | 1 + runtime/to-array-processor.cpp | 7 +++++ runtime/to-array-processor.h | 51 ++++++++++++++++++++++++++++------ 3 files changed, 50 insertions(+), 9 deletions(-) create mode 100644 runtime/to-array-processor.cpp diff --git a/runtime/runtime.cmake b/runtime/runtime.cmake index bf6df3dcde..78706e19d2 100644 --- a/runtime/runtime.cmake +++ b/runtime/runtime.cmake @@ -102,6 +102,7 @@ prepend(KPHP_RUNTIME_SOURCES ${BASE_DIR}/runtime/ string_buffer.cpp string_cache.cpp string_functions.cpp + to-array-processor.cpp tl/rpc_tl_query.cpp tl/rpc_response.cpp tl/rpc_server.cpp diff --git a/runtime/to-array-processor.cpp b/runtime/to-array-processor.cpp new file mode 100644 index 0000000000..751a278d17 --- /dev/null +++ b/runtime/to-array-processor.cpp @@ -0,0 +1,7 @@ +// Compiler for PHP (aka KPHP) +// Copyright (c) 2020 LLC «V Kontakte» +// Distributed under the GPL v3 License, see LICENSE.notice.txt + +#include "runtime/to-array-processor.h" + +bool ArrayProcessorError::recursion_depth_exeeded = false; diff --git a/runtime/to-array-processor.h b/runtime/to-array-processor.h index 1b3ce768d9..cd756583df 100644 --- a/runtime/to-array-processor.h +++ b/runtime/to-array-processor.h @@ -5,6 +5,8 @@ #pragma once #include +#include +#include #include "common/mixin/not_copyable.h" #include "common/smart_ptrs/singleton.h" @@ -35,8 +37,9 @@ class ShapeKeyDemangle : vk::not_copyable { class ToArrayVisitor { public: - explicit ToArrayVisitor(bool with_class_names) - : with_class_names_(with_class_names) {} + explicit ToArrayVisitor(bool with_class_names, std::size_t depth) + : with_class_names_(with_class_names) + , depth_(++depth) {} array flush_result() && noexcept { return std::move(result_); @@ -83,12 +86,12 @@ class ToArrayVisitor { template void process_impl(const char *field_name, const class_instance &instance) { - add_value(field_name, instance.is_null() ? mixed{} : f$to_array_debug(instance, with_class_names_)); + add_value(field_name, instance.is_null() ? mixed{} : to_array_debug_impl(instance, with_class_names_, depth_)); } template void process_impl(const char *field_name, const std::tuple &value) { - ToArrayVisitor tuple_processor{with_class_names_}; + ToArrayVisitor tuple_processor{with_class_names_, 0}; tuple_processor.result_.reserve(sizeof...(Args), 0, true); process_tuple(value, tuple_processor, std::index_sequence_for{}); @@ -97,7 +100,7 @@ class ToArrayVisitor { template void process_impl(const char *field_name, const shape, T...> &value) { - ToArrayVisitor shape_processor{with_class_names_}; + ToArrayVisitor shape_processor{with_class_names_, 0}; shape_processor.result_.reserve(sizeof...(Is), 0, true); process_shape(value, shape_processor); @@ -115,17 +118,26 @@ class ToArrayVisitor { array result_; bool with_class_names_{false}; + std::size_t depth_{0}; +}; + +struct ArrayProcessorError { + static bool recursion_depth_exeeded; }; template -array f$to_array_debug(const class_instance &klass, bool with_class_names = false) { +array to_array_debug_impl(const class_instance &klass, bool with_class_names = false, std::size_t depth = 0) { array result; + if (depth > 64) { + ArrayProcessorError::recursion_depth_exeeded = true; + return result; + } if (klass.is_null()) { return result; } if constexpr (!std::is_empty_v) { - ToArrayVisitor visitor{with_class_names}; + ToArrayVisitor visitor{with_class_names, depth}; klass.get()->accept(visitor); result = std::move(visitor).flush_result(); } @@ -136,17 +148,38 @@ array f$to_array_debug(const class_instance &klass, bool with_class_na return result; } +template +array f$to_array_debug(const class_instance &klass, bool with_class_names = false) { + ArrayProcessorError::recursion_depth_exeeded = false; + auto result = to_array_debug_impl(klass, with_class_names); + if (ArrayProcessorError::recursion_depth_exeeded) { + ArrayProcessorError::recursion_depth_exeeded = false; + return {}; + } + return result; +} + template array f$to_array_debug(const std::tuple &tuple, bool with_class_names = false) { - ToArrayVisitor visitor{with_class_names}; + ArrayProcessorError::recursion_depth_exeeded = false; + ToArrayVisitor visitor{with_class_names, 0}; ToArrayVisitor::process_tuple(tuple, visitor, std::index_sequence_for{}); + if (ArrayProcessorError::recursion_depth_exeeded) { + ArrayProcessorError::recursion_depth_exeeded = false; + return {}; + } return std::move(visitor).flush_result(); } template array f$to_array_debug(const shape, T...> &shape, bool with_class_names = false) { - ToArrayVisitor visitor{with_class_names}; + ArrayProcessorError::recursion_depth_exeeded = false; + ToArrayVisitor visitor{with_class_names, 0}; ToArrayVisitor::process_shape(shape, visitor); + if (ArrayProcessorError::recursion_depth_exeeded) { + ArrayProcessorError::recursion_depth_exeeded = false; + return {}; + } return std::move(visitor).flush_result(); } From 96a46705553b73da168df3f599423853ea846454 Mon Sep 17 00:00:00 2001 From: Stanislav Eismont Date: Tue, 20 Dec 2022 10:24:47 +0300 Subject: [PATCH 2/3] add test --- .../dl/1042_to_array_debug_reursion_limit.php | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 tests/phpt/dl/1042_to_array_debug_reursion_limit.php diff --git a/tests/phpt/dl/1042_to_array_debug_reursion_limit.php b/tests/phpt/dl/1042_to_array_debug_reursion_limit.php new file mode 100644 index 0000000000..ad35f50341 --- /dev/null +++ b/tests/phpt/dl/1042_to_array_debug_reursion_limit.php @@ -0,0 +1,33 @@ +@ok +next = new Chain; + var_dump(instance_to_array($obj)); +} + +function test_max_depth_level() { + $obj = new Chain; + $ptr = $obj; + for ($i = 0; $i < 64; ++$i) { + $ptr->next = new Chain; + $ptr = $ptr->next; + } + + // 64 lvl depth is ok + var_dump(count(instance_to_array($obj))); + + $ptr->next = new Chain; + + // allowed depth exceeded + var_dump(instance_to_array($obj)); +} + +test_chain_objects(); +test_max_depth_level(); From 7aa43dd9e0a7547fda9c74489f591ba64938ce5c Mon Sep 17 00:00:00 2001 From: Stanislav Eismont Date: Tue, 20 Dec 2022 10:54:05 +0300 Subject: [PATCH 3/3] fix unrelated tests --- tests/phpt/dl/1034_to_array_debug_shape.php | 8 -------- tests/phpt/dl/1035_to_array_debug_tuple.php | 8 -------- 2 files changed, 16 deletions(-) diff --git a/tests/phpt/dl/1034_to_array_debug_shape.php b/tests/phpt/dl/1034_to_array_debug_shape.php index 231a37cb37..105fa9ac67 100644 --- a/tests/phpt/dl/1034_to_array_debug_shape.php +++ b/tests/phpt/dl/1034_to_array_debug_shape.php @@ -20,15 +20,7 @@ function __construct() { function to_array_debug_shape(bool $with_class_names) { $shape = shape(['foo' => 42, 'bar' => new A]); - $dump = to_array_debug($shape, $with_class_names); - #ifndef KPHP - $dump = ['foo' => 42, 'bar' => ['a_obj' => ['i' => 88, 'b_shape' => ['baz' => 'qax']]]]; - if ($with_class_names) { - $dump['bar']['__class_name'] = 'A'; - $dump['bar']['a_obj']['__class_name'] = 'B'; - } - #endif var_dump($dump); } diff --git a/tests/phpt/dl/1035_to_array_debug_tuple.php b/tests/phpt/dl/1035_to_array_debug_tuple.php index 666c994b11..cc6e5a26ce 100644 --- a/tests/phpt/dl/1035_to_array_debug_tuple.php +++ b/tests/phpt/dl/1035_to_array_debug_tuple.php @@ -20,15 +20,7 @@ function __construct() { function to_array_debug_tuple(bool $with_class_names) { $tuple = tuple(42, new A); - $dump = to_array_debug($tuple, $with_class_names); - #ifndef KPHP - $dump = [42, ['a_obj' => ['i' => 88, 'b_tuple' => [77, 'qax']]]]; - if ($with_class_names) { - $dump[1]['__class_name'] = 'A'; - $dump[1]['a_obj']['__class_name'] = 'B'; - } - #endif var_dump($dump); }