Skip to content

Commit 13c817e

Browse files
committed
py/objmodule: Add a table of built-in modules with delegation.
This replaces the previous QSTR_null entry in the globals dict which could leak out to Python (e.g. via iteration of mod.__dict__) and could lead to crashes. It results in smaller code size at the expense of turning a lookup into a loop, but the list it is looping over likely only contains one or two elements. To allow a module to register its custom attr function it can use the new `MP_REGISTER_MODULE_DELEGATION` macro. This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
1 parent eb85f4d commit 13c817e

9 files changed

+67
-36
lines changed

py/builtin.h

+2
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ extern const mp_obj_module_t mp_module___main__;
132132
extern const mp_obj_module_t mp_module_builtins;
133133
extern const mp_obj_module_t mp_module_sys;
134134

135+
void mp_module_sys_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest);
136+
135137
// Modules needed by the parser when MICROPY_COMP_MODULE_CONST is enabled.
136138
extern const mp_obj_module_t mp_module_errno;
137139
extern const mp_obj_module_t mp_module_uctypes;

py/builtinhelp.c

+1-6
Original file line numberDiff line numberDiff line change
@@ -151,12 +151,7 @@ STATIC void mp_help_print_obj(const mp_obj_t obj) {
151151
if (map != NULL) {
152152
for (uint i = 0; i < map->alloc; i++) {
153153
mp_obj_t key = map->table[i].key;
154-
if (key != MP_OBJ_NULL
155-
#if MICROPY_MODULE_ATTR_DELEGATION
156-
// MP_MODULE_ATTR_DELEGATION_ENTRY entries have MP_QSTRnull as qstr key.
157-
&& key != MP_OBJ_NEW_QSTR(MP_QSTRnull)
158-
#endif
159-
) {
154+
if (key != MP_OBJ_NULL) {
160155
mp_help_print_info_about_object(key, map->table[i].value);
161156
}
162157
}

py/makemoduledefs.py

+23-4
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,16 @@
2222
import argparse
2323

2424

25-
pattern = re.compile(
25+
register_pattern = re.compile(
2626
r"\s*(MP_REGISTER_MODULE|MP_REGISTER_EXTENSIBLE_MODULE)\(MP_QSTR_(.*?),\s*(.*?)\);",
2727
flags=re.DOTALL,
2828
)
2929

30+
delegation_pattern = re.compile(
31+
r"\s*(?:MP_REGISTER_MODULE_DELEGATION)\((.*?),\s*(.*?)\);",
32+
flags=re.DOTALL,
33+
)
34+
3035

3136
def find_module_registrations(filename):
3237
"""Find any MP_REGISTER_MODULE definitions in the provided file.
@@ -37,7 +42,8 @@ def find_module_registrations(filename):
3742
global pattern
3843

3944
with io.open(filename, encoding="utf-8") as c_file_obj:
40-
return set(re.findall(pattern, c_file_obj.read()))
45+
c = c_file_obj.read()
46+
return set(re.findall(register_pattern, c)), set(re.findall(delegation_pattern, c))
4147

4248

4349
def generate_module_table_header(modules):
@@ -50,7 +56,6 @@ def generate_module_table_header(modules):
5056
# Print header file for all external modules.
5157
mod_defs = set()
5258
extensible_mod_defs = set()
53-
print("// Automatically generated by makemoduledefs.py.\n")
5459
for macro_name, module_name, obj_module in modules:
5560
mod_def = "MODULE_DEF_{}".format(module_name.upper())
5661
if macro_name == "MP_REGISTER_MODULE":
@@ -97,13 +102,27 @@ def generate_module_table_header(modules):
97102
print("// MICROPY_REGISTERED_EXTENSIBLE_MODULES")
98103

99104

105+
def generate_module_delegations(delegations):
106+
print("\n#define MICROPY_MODULE_DELEGATIONS \\")
107+
for obj_module, fun_name in delegations:
108+
print(
109+
" {{ MP_ROM_PTR(&{obj_module}), {fun_name} }},".format(
110+
obj_module=obj_module, fun_name=fun_name
111+
)
112+
)
113+
print("// MICROPY_MODULE_DELEGATIONS")
114+
115+
100116
def main():
101117
parser = argparse.ArgumentParser()
102118
parser.add_argument("file", nargs=1, help="file with MP_REGISTER_MODULE definitions")
103119
args = parser.parse_args()
104120

105-
modules = find_module_registrations(args.file[0])
121+
print("// Automatically generated by makemoduledefs.py.\n")
122+
123+
modules, delegations = find_module_registrations(args.file[0])
106124
generate_module_table_header(sorted(modules))
125+
generate_module_delegations(sorted(delegations))
107126

108127

109128
if __name__ == "__main__":

py/makeqstrdefs.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,9 @@ def process_file(f):
9393
elif args.mode == _MODE_COMPRESS:
9494
re_match = re.compile(r'MP_COMPRESSED_ROM_TEXT\("([^"]*)"\)')
9595
elif args.mode == _MODE_MODULE:
96-
re_match = re.compile(r"MP_REGISTER_(?:EXTENSIBLE_)?MODULE\(.*?,\s*.*?\);")
96+
re_match = re.compile(
97+
r"(?:MP_REGISTER_MODULE|MP_REGISTER_EXTENSIBLE_MODULE|MP_REGISTER_MODULE_DELEGATION)\(.*?,\s*.*?\);"
98+
)
9799
elif args.mode == _MODE_ROOT_POINTER:
98100
re_match = re.compile(r"MP_REGISTER_ROOT_POINTER\(.*?\);")
99101
output = []

py/modsys.c

+2-6
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ STATIC const uint16_t sys_mutable_keys[] = {
207207
MP_QSTRnull,
208208
};
209209

210-
STATIC void mp_module_sys_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
210+
void mp_module_sys_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
211211
MP_STATIC_ASSERT(MP_ARRAY_SIZE(sys_mutable_keys) == MP_SYS_MUTABLE_NUM + 1);
212212
MP_STATIC_ASSERT(MP_ARRAY_SIZE(MP_STATE_VM(sys_mutable)) == MP_SYS_MUTABLE_NUM);
213213
mp_module_generic_attr(attr, dest, sys_mutable_keys, MP_STATE_VM(sys_mutable));
@@ -280,11 +280,6 @@ STATIC const mp_rom_map_elem_t mp_module_sys_globals_table[] = {
280280
#if MICROPY_PY_SYS_ATEXIT
281281
{ MP_ROM_QSTR(MP_QSTR_atexit), MP_ROM_PTR(&mp_sys_atexit_obj) },
282282
#endif
283-
284-
#if MICROPY_PY_SYS_ATTR_DELEGATION
285-
// Delegation of attr lookup.
286-
MP_MODULE_ATTR_DELEGATION_ENTRY(&mp_module_sys_attr),
287-
#endif
288283
};
289284

290285
STATIC MP_DEFINE_CONST_DICT(mp_module_sys_globals, mp_module_sys_globals_table);
@@ -317,6 +312,7 @@ MP_REGISTER_ROOT_POINTER(mp_obj_t sys_exitfunc);
317312
#if MICROPY_PY_SYS_ATTR_DELEGATION
318313
// Contains mutable sys attributes.
319314
MP_REGISTER_ROOT_POINTER(mp_obj_t sys_mutable[MP_SYS_MUTABLE_NUM]);
315+
MP_REGISTER_MODULE_DELEGATION(mp_module_sys, &mp_module_sys_attr);
320316
#endif
321317

322318
#endif // MICROPY_PY_SYS

py/mpconfig.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -839,8 +839,8 @@ typedef double mp_float_t;
839839
#define MICROPY_STREAMS_POSIX_API (0)
840840
#endif
841841

842-
// Whether modules can use MP_MODULE_ATTR_DELEGATION_ENTRY() to delegate failed
843-
// attribute lookups.
842+
// Whether modules can use MP_REGISTER_MODULE_DELEGATION() to delegate failed
843+
// attribute lookups to a custom handler function.
844844
#ifndef MICROPY_MODULE_ATTR_DELEGATION
845845
#define MICROPY_MODULE_ATTR_DELEGATION (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
846846
#endif

py/obj.h

+4
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,10 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t;
437437
// As above, but allow this module to be extended from the filesystem.
438438
#define MP_REGISTER_EXTENSIBLE_MODULE(module_name, obj_module)
439439

440+
// Add a custom handler for a builtin module that will be called to delegate
441+
// failed attribute lookups.
442+
#define MP_REGISTER_MODULE_DELEGATION(obj_module, fun_name)
443+
440444
// Declare a root pointer (to avoid garbage collection of a global static variable).
441445
// param variable_declaration: a valid C variable declaration
442446
#define MP_REGISTER_ROOT_POINTER(variable_declaration)

py/objmodule.c

+30-14
Original file line numberDiff line numberDiff line change
@@ -63,20 +63,7 @@ STATIC void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kin
6363
mp_printf(print, "<module '%s'>", module_name);
6464
}
6565

66-
STATIC void module_attr_try_delegation(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
67-
#if MICROPY_MODULE_ATTR_DELEGATION
68-
// Delegate lookup to a module's custom attr method (found in last lot of globals dict).
69-
mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in);
70-
mp_map_t *map = &self->globals->map;
71-
if (map->table[map->alloc - 1].key == MP_OBJ_NEW_QSTR(MP_QSTRnull)) {
72-
((mp_attr_fun_t)MP_OBJ_TO_PTR(map->table[map->alloc - 1].value))(self_in, attr, dest);
73-
}
74-
#else
75-
(void)self_in;
76-
(void)attr;
77-
(void)dest;
78-
#endif
79-
}
66+
STATIC void module_attr_try_delegation(mp_obj_t self_in, qstr attr, mp_obj_t *dest);
8067

8168
STATIC void module_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
8269
mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in);
@@ -177,6 +164,18 @@ STATIC const mp_rom_map_elem_t mp_builtin_extensible_module_table[] = {
177164
};
178165
MP_DEFINE_CONST_MAP(mp_builtin_extensible_module_map, mp_builtin_extensible_module_table);
179166

167+
#if MICROPY_MODULE_ATTR_DELEGATION && defined(MICROPY_MODULE_DELEGATIONS)
168+
typedef struct _mp_module_delegation_entry_t {
169+
mp_rom_obj_t mod;
170+
mp_attr_fun_t fun;
171+
} mp_module_delegation_entry_t;
172+
173+
STATIC const mp_module_delegation_entry_t mp_builtin_module_delegation_table[] = {
174+
// delegation entries declared with MP_REGISTER_MODULE_DELEGATION()
175+
MICROPY_MODULE_DELEGATIONS
176+
};
177+
#endif
178+
180179
// Attempts to find (and initialise) a built-in, otherwise returns
181180
// MP_OBJ_NULL.
182181
mp_obj_t mp_module_get_builtin(qstr module_name, bool extensible) {
@@ -230,6 +229,23 @@ mp_obj_t mp_module_get_builtin(qstr module_name, bool extensible) {
230229
return elem->value;
231230
}
232231

232+
STATIC void module_attr_try_delegation(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
233+
#if MICROPY_MODULE_ATTR_DELEGATION
234+
// Delegate lookup to a module's custom attr method.
235+
size_t n = MP_ARRAY_SIZE(mp_builtin_module_delegation_table);
236+
for (size_t i = 0; i < n; ++i) {
237+
if (*(mp_obj_t *)(&mp_builtin_module_delegation_table[i].mod) == self_in) {
238+
mp_builtin_module_delegation_table[i].fun(self_in, attr, dest);
239+
break;
240+
}
241+
}
242+
#else
243+
(void)self_in;
244+
(void)attr;
245+
(void)dest;
246+
#endif
247+
}
248+
233249
void mp_module_generic_attr(qstr attr, mp_obj_t *dest, const uint16_t *keys, mp_obj_t *values) {
234250
for (size_t i = 0; keys[i] != MP_QSTRnull; ++i) {
235251
if (attr == keys[i]) {

py/objmodule.h

-3
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@
2828

2929
#include "py/obj.h"
3030

31-
// Place at the very end of a module's globals_table.
32-
#define MP_MODULE_ATTR_DELEGATION_ENTRY(ptr) { MP_ROM_QSTR(MP_QSTRnull), MP_ROM_PTR(ptr) }
33-
3431
extern const mp_map_t mp_builtin_module_map;
3532
extern const mp_map_t mp_builtin_extensible_module_map;
3633

0 commit comments

Comments
 (0)