@@ -69,56 +69,75 @@ typedef struct struct_dep {
6969} s_struct_dep ;
7070
7171/**
72- * Find all the dependencies from a given structure
72+ * Add a struct to the dependency list if not already present
7373 *
74- * @param[out] deps_count count of how many struct dependency pointers
75- * @param[in] first_dep pointer to the first dependency pointer
76- * @param[in] struct_ptr pointer to the struct we are getting the dependencies of
77- * @return pointer to the first found dependency, \ref NULL otherwise
74+ * @param[in,out] first_dep pointer to the head of the dependency list
75+ * @param[in] s pointer to the struct to add
76+ * @return \ref true on success, \ref false on memory allocation failure
7877 */
79- static bool get_struct_dependencies (s_struct_dep * * first_dep , const s_struct_712 * struct_ptr ) {
80- const s_struct_712_field * field_ptr ;
81- const char * arg_structname ;
82- const s_struct_712 * arg_struct_ptr ;
78+ static bool add_dep_if_new (s_struct_dep * * first_dep , const s_struct_712 * s ) {
8379 s_struct_dep * tmp ;
8480 s_struct_dep * new_dep ;
8581
82+ for (tmp = * first_dep ; tmp != NULL ; tmp = (s_struct_dep * ) ((flist_node_t * ) tmp )-> next ) {
83+ if (tmp -> s == s ) return true;
84+ }
85+ if ((new_dep = APP_MEM_ALLOC (sizeof (* new_dep ))) == NULL ) {
86+ apdu_response_code = SWO_INSUFFICIENT_MEMORY ;
87+ return false;
88+ }
89+ new_dep -> s = s ;
90+ flist_push_back ((flist_node_t * * ) first_dep , (flist_node_t * ) new_dep );
91+ return true;
92+ }
93+
94+ /**
95+ * Scan all fields of a struct and add any unknown TYPE_CUSTOM dependencies
96+ *
97+ * @param[in,out] first_dep pointer to the head of the dependency list
98+ * @param[in] struct_ptr pointer to the struct whose fields are scanned
99+ * @return \ref true on success, \ref false on error
100+ */
101+ static bool collect_direct_deps (s_struct_dep * * first_dep , const s_struct_712 * struct_ptr ) {
102+ const s_struct_712_field * field_ptr ;
103+ const s_struct_712 * dep ;
104+ const char * dep_name ;
105+
86106 for (field_ptr = struct_ptr -> fields ; field_ptr != NULL ;
87107 field_ptr = (s_struct_712_field * ) ((flist_node_t * ) field_ptr )-> next ) {
88- if (field_ptr -> type == TYPE_CUSTOM ) {
89- // get struct name
90- arg_structname = get_struct_field_typename (field_ptr );
91- // from its name, get the pointer to its definition
92- if ((arg_struct_ptr = get_structn (arg_structname , strlen (arg_structname ))) == NULL ) {
93- PRINTF ("Error: could not find EIP-712 dependency struct \"" );
94- for (int i = 0 ; i < (int ) strlen (arg_structname ); ++ i )
95- PRINTF ("%c" , arg_structname [i ]);
96- PRINTF ("\" during type_hash\n" );
97- return false;
98- }
99-
100- // check if it is not already present in the dependencies array
101- for (tmp = * first_dep ; tmp != NULL ;
102- tmp = (s_struct_dep * ) ((flist_node_t * ) tmp )-> next ) {
103- // it's a match!
104- if (tmp -> s == arg_struct_ptr ) {
105- break ;
106- }
107- }
108- // if it's not present in the array, add it and recurse into it
109- if (tmp == NULL ) {
110- if (APP_MEM_CALLOC ((void * * ) & new_dep , sizeof (s_struct_dep )) == false) {
111- apdu_response_code = SWO_INSUFFICIENT_MEMORY ;
112- return false;
113- }
114- new_dep -> s = arg_struct_ptr ;
115- flist_push_back ((flist_node_t * * ) first_dep , (flist_node_t * ) new_dep );
116- // TODO: Move away from recursive calls
117- if (!get_struct_dependencies (first_dep , arg_struct_ptr )) {
118- return false;
119- }
120- }
108+ if (field_ptr -> type != TYPE_CUSTOM ) continue ;
109+
110+ dep_name = get_struct_field_typename (field_ptr );
111+ if ((dep = get_structn (dep_name , strlen (dep_name ))) == NULL ) {
112+ PRINTF ("Error: could not find EIP-712 dependency struct \"" );
113+ for (size_t i = 0 ; i < strlen (dep_name ); ++ i ) PRINTF ("%c" , dep_name [i ]);
114+ PRINTF ("\" during type_hash\n" );
115+ return false;
121116 }
117+ if (!add_dep_if_new (first_dep , dep )) return false;
118+ }
119+ return true;
120+ }
121+
122+ /**
123+ * Find all the transitive dependencies of a given structure
124+ *
125+ * Uses the dependency list itself as a worklist: new entries are appended at
126+ * the back while the cursor advances forward, so newly discovered dependencies
127+ * are processed without recursion and without extra allocations.
128+ *
129+ * @param[out] first_dep pointer to the head of the dependency list
130+ * @param[in] struct_ptr pointer to the struct we are getting the dependencies of
131+ * @return \ref true on success, \ref false on error
132+ */
133+ static bool get_struct_dependencies (s_struct_dep * * first_dep , const s_struct_712 * struct_ptr ) {
134+ s_struct_dep * cursor ;
135+
136+ if (!collect_direct_deps (first_dep , struct_ptr )) return false;
137+
138+ for (cursor = * first_dep ; cursor != NULL ;
139+ cursor = (s_struct_dep * ) ((flist_node_t * ) cursor )-> next ) {
140+ if (!collect_direct_deps (first_dep , cursor -> s )) return false;
122141 }
123142 return true;
124143}
0 commit comments