diff --git a/test/tools/ossfuzz/protoToYul.cpp b/test/tools/ossfuzz/protoToYul.cpp index 3dc6d78ee..345797afb 100644 --- a/test/tools/ossfuzz/protoToYul.cpp +++ b/test/tools/ossfuzz/protoToYul.cpp @@ -21,7 +21,6 @@ #include #include -#include #include #include @@ -1385,6 +1384,14 @@ void ProtoConverter::visit(PopStmt const& _x) m_output << ")\n"; } +string ProtoConverter::getObjectIdentifier(ObjectId const& _x) +{ + unsigned currentId = currentObjectId(); + yulAssert(m_objectScopeTree.size() > currentId, "Proto fuzzer: Error referencing object"); + std::vector objectIdsInScope = m_objectScopeTree[currentId]; + return objectIdsInScope[_x.id() % objectIdsInScope.size()]; +} + void ProtoConverter::visit(Code const& _x) { m_output << "code {\n"; @@ -1394,7 +1401,8 @@ void ProtoConverter::visit(Code const& _x) void ProtoConverter::visit(Data const& _x) { - m_output << "data \"datablock\" hex\"" << createHex(_x.hex()) << "\"\n"; + // TODO: Generate random data block identifier + m_output << "data \"" << s_dataIdentifier << "\" hex\"" << createHex(_x.hex()) << "\"\n"; } void ProtoConverter::visit(Object const& _x) @@ -1406,11 +1414,33 @@ void ProtoConverter::visit(Object const& _x) visit(_x.code()); if (_x.has_data()) visit(_x.data()); - if (_x.has_obj()) - visit(_x.obj()); + if (_x.has_sub_obj()) + visit(_x.sub_obj()); m_output << "}\n"; } +void ProtoConverter::buildObjectScopeTree(Object const& _x) +{ + // Identifies object being visited + string objectId = newObjectId(false); + vector node{objectId}; + if (_x.has_data()) + node.push_back(s_dataIdentifier); + if (_x.has_sub_obj()) + { + // Identifies sub object whose numeric suffix is + // m_objectId + string subObjectId = "object" + to_string(m_objectId); + node.push_back(subObjectId); + // TODO: Add sub-object to object's ancestors once + // nested access is implemented. + m_objectScopeTree.push_back(node); + buildObjectScopeTree(_x.sub_obj()); + } + else + m_objectScopeTree.push_back(node); +} + void ProtoConverter::visit(Program const& _x) { // Initialize input size @@ -1427,6 +1457,9 @@ void ProtoConverter::visit(Program const& _x) break; case Program::kObj: m_isObject = true; + buildObjectScopeTree(_x.obj()); + // Reset object id counter + m_objectId = 0; visit(_x.obj()); break; case Program::PROGRAM_ONEOF_NOT_SET: diff --git a/test/tools/ossfuzz/protoToYul.h b/test/tools/ossfuzz/protoToYul.h index 49a34a8fd..ef149d198 100644 --- a/test/tools/ossfuzz/protoToYul.h +++ b/test/tools/ossfuzz/protoToYul.h @@ -26,8 +26,10 @@ #include #include + #include #include +#include namespace yul { @@ -240,6 +242,11 @@ private: /// Removes entry from m_functionMap and m_functionName void updateFunctionMaps(std::string const& _x); + /// Build a tree of objects that contains the object/data + /// identifiers that are in scope in a given object. + /// @param _x root object of the yul protobuf specification. + void buildObjectScopeTree(Object const& _x); + /// Returns a pseudo-random dictionary token. /// @param _p Enum that decides if the returned token is hex prefixed ("0x") or not /// @return Dictionary token at the index computed using a @@ -263,23 +270,28 @@ private: return "foo_" + functionTypeToString(_type) + "_" + std::to_string(counter()); } - /// Returns current object identifier as string. Input parameter - /// is ignored. - std::string getObjectIdentifier(ObjectId const&) - { - // TODO: Return a pseudo randomly chosen object identifier - // that is in scope as string. - // At the moment, we simply return the identifier that - // corresponds to the currently visited object. - return "object" + std::to_string(m_objectId - 1); - } + /// Returns a pseudo-randomly chosen object identifier that is in the + /// scope of the Yul object being visited. + std::string getObjectIdentifier(ObjectId const& _x); /// Return new object identifier as string. Identifier string /// is a template of the form "\"object\"" where is /// a monotonically increasing object ID counter. - std::string newObjectId() + /// @param _decorate If true (default value), object ID is + /// enclosed within double quotes. + std::string newObjectId(bool _decorate = true) { - return "\"object" + std::to_string(m_objectId++) + "\""; + return dev::Whiskers(R"("object")") + ("decorate", _decorate) + ("id", std::to_string(m_objectId++)) + .render(); + } + + /// Returns the object counter value corresponding to the object + /// being visited. + unsigned currentObjectId() + { + return m_objectId - 1; } std::ostringstream m_output; @@ -297,9 +309,13 @@ private: std::stack> m_switchLiteralSetPerScope; // Look-up table per function type that holds the number of input (output) function parameters std::map> m_functionSigMap; + /// Tree of objects and their scopes + std::vector> m_objectScopeTree; // mod input/output parameters impose an upper bound on the number of input/output parameters a function may have. static unsigned constexpr s_modInputParams = 5; static unsigned constexpr s_modOutputParams = 5; + /// Hard-coded identifier for a Yul object's data block + static auto constexpr s_dataIdentifier = "datablock"; /// Predicate to keep track of for body scope. If true, break/continue /// statements can not be created. bool m_inForBodyScope; diff --git a/test/tools/ossfuzz/yulProto.proto b/test/tools/ossfuzz/yulProto.proto index 54befeeb9..6871a63ac 100644 --- a/test/tools/ossfuzz/yulProto.proto +++ b/test/tools/ossfuzz/yulProto.proto @@ -207,9 +207,9 @@ message ExtCodeCopy { required Expression size = 4; } -/// TODO: Add a field that may be used for referencing -/// a pseudo random object identifier at run time. -message ObjectId {} +message ObjectId { + required uint64 id = 1; +} message DataSize { required ObjectId identifier = 1; @@ -388,7 +388,7 @@ message Block { message Object { required Code code = 1; optional Data data = 2; - optional Object obj = 3; + optional Object sub_obj = 3; } message Code {