// Copyright 2022 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef UI_ACCESSIBILITY_AX_TREE_FUZZER_UTIL_H_ #define UI_ACCESSIBILITY_AX_TREE_FUZZER_UTIL_H_ #include "ui/accessibility/ax_tree.h" #include "ui/accessibility/ax_tree_data.h" #include "ui/accessibility/ax_tree_id.h" #include "ui/accessibility/ax_tree_update.h" #include "ui/accessibility/test_ax_tree_manager.h" // TODO(janewman): Replace usage with ...FuzzedDataProvider... class FuzzerData { public: FuzzerData(const unsigned char* data, size_t size); size_t RemainingBytes(); unsigned char NextByte(); const unsigned char* NextBytes(size_t amount); private: const unsigned char* data_; const size_t data_size_; size_t data_index_; }; class AXTreeFuzzerGenerator { public: AXTreeFuzzerGenerator() = default; ~AXTreeFuzzerGenerator() = default; ui::AXTree* GetTree(); void GenerateInitialUpdate(FuzzerData& fuzz_data, int node_count); bool GenerateTreeUpdate(FuzzerData& fuzz_data, size_t node_count); ui::AXNodeID GetMaxAssignedID() const; // This must be kept in sync with the minimum amount of data needed to create // any node. Any optional node data should check to ensure there is space. static constexpr size_t kMinimumNewNodeFuzzDataSize = 5; static constexpr size_t kMinTextFuzzDataSize = 10; static constexpr size_t kMaxTextFuzzDataSize = 200; // When creating a node, we allow for the next node to be a sibling of an // ancestor, this constant determines the maximum nodes we will pop when // building the tree. static constexpr size_t kMaxAncestorPopCount = 3; private: enum NextNodeRelationship { // Next node is a child of this node. (This node is a parent.) kChild, // Next node is sibling to this node. (This node is a leaf.) kSibling, // Next node is sibling to an ancestor. (This node is a leaf.) kSiblingToAncestor, }; enum TreeUpdateOperation { kAddChild, kRemoveNode, kTextChange, kNoOperation }; void RecursiveGenerateUpdate(const ui::AXNode* node, ui::AXTreeUpdate& tree_update, FuzzerData& fuzz_data, std::set& updated_nodes); // TODO(janewman): Many of these can be made static. ui::AXNodeData CreateChildNodeData(ui::AXNodeData& parent, ui::AXNodeID new_node_id); NextNodeRelationship DetermineNextNodeRelationship(ax::mojom::Role role, unsigned char byte); TreeUpdateOperation DetermineTreeUpdateOperation(const ui::AXNode* node, unsigned char byte); void AddRoleSpecificProperties(FuzzerData& fuzz_data, ui::AXNodeData& node, const std::string& parentName, size_t extra_data_size); ax::mojom::Role GetInterestingRole(unsigned char byte, ax::mojom::Role parent_role); bool CanHaveChildren(ax::mojom::Role role); bool CanHaveText(ax::mojom::Role role); std::u16string GenerateInterestingText(const unsigned char* data, size_t size); ui::AXNodeID max_assigned_node_id_; ui::TestAXTreeManager tree_manager_; }; #endif // UI_ACCESSIBILITY_AX_TREE_FUZZER_UTIL_H_