Calculates maximum stack height for given code section. According to EIP5450 https://eips.ethereum.org/EIPS/eip-5450
| 1033 | |
| 1034 | // Calculates maximum stack height for given code section. According to EIP5450 https://eips.ethereum.org/EIPS/eip-5450 |
| 1035 | uint16_t calculateMaxStackHeight(Assembly::CodeSection const& _section) |
| 1036 | { |
| 1037 | static auto constexpr UNVISITED = std::numeric_limits<size_t>::max(); |
| 1038 | |
| 1039 | AssemblyItems const& items = _section.items; |
| 1040 | solAssert(!items.empty()); |
| 1041 | uint16_t overallMaxHeight = _section.inputs; |
| 1042 | std::stack<size_t> worklist; |
| 1043 | std::vector<size_t> maxStackHeights(items.size(), UNVISITED); |
| 1044 | |
| 1045 | // Init first item stack height to number of inputs to the code section |
| 1046 | // maxStackHeights stores stack height for an item before the item execution |
| 1047 | maxStackHeights[0] = _section.inputs; |
| 1048 | // Push first item index to the worklist |
| 1049 | worklist.push(0u); |
| 1050 | while (!worklist.empty()) |
| 1051 | { |
| 1052 | size_t idx = worklist.top(); |
| 1053 | worklist.pop(); |
| 1054 | AssemblyItem const& item = items[idx]; |
| 1055 | size_t stackHeightChange = item.deposit(); |
| 1056 | size_t currentMaxHeight = maxStackHeights[idx]; |
| 1057 | solAssert(currentMaxHeight != UNVISITED); |
| 1058 | |
| 1059 | std::vector<size_t> successors; |
| 1060 | |
| 1061 | // Add next instruction to successors for non-control-flow-changing instructions |
| 1062 | if ( |
| 1063 | !(item.hasInstruction() && SemanticInformation::terminatesControlFlow(item.instruction())) && |
| 1064 | item.type() != RelativeJump && |
| 1065 | item.type() != RetF && |
| 1066 | item.type() != JumpF |
| 1067 | ) |
| 1068 | { |
| 1069 | solAssert(idx < items.size() - 1, "No terminating instruction."); |
| 1070 | successors.emplace_back(idx + 1); |
| 1071 | } |
| 1072 | |
| 1073 | // Add jumps destinations to successors |
| 1074 | // TODO: Remember to add RJUMPV when it is supported. |
| 1075 | if (item.type() == RelativeJump || item.type() == ConditionalRelativeJump) |
| 1076 | { |
| 1077 | auto const tagIt = std::find(items.begin(), items.end(), item.tag()); |
| 1078 | solAssert(tagIt != items.end(), "Tag not found."); |
| 1079 | successors.emplace_back(static_cast<size_t>(std::distance(items.begin(), tagIt))); |
| 1080 | // TODO: This assert fails until the code is not topologically sorted. Uncomment when sorting introduced. |
| 1081 | // If backward jump the successor must be already visited. |
| 1082 | // solAssert(idx <= successors.back() || maxStackHeights[successors.back()] != UNVISITED); |
| 1083 | } |
| 1084 | |
| 1085 | solRequire( |
| 1086 | currentMaxHeight + stackHeightChange <= std::numeric_limits<uint16_t>::max(), |
| 1087 | AssemblyException, |
| 1088 | "Stack overflow in EOF function." |
| 1089 | ); |
| 1090 | overallMaxHeight = std::max(overallMaxHeight, static_cast<uint16_t>(currentMaxHeight + stackHeightChange)); |
| 1091 | currentMaxHeight += stackHeightChange; |
| 1092 |
no test coverage detected