Skip to content

Commit ceb41cf

Browse files
authored
Use python context manager when reading webassembly modules (#17516)
Fixes: #17452
1 parent fafcc86 commit ceb41cf

File tree

7 files changed

+114
-102
lines changed

7 files changed

+114
-102
lines changed

emscripten.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -306,11 +306,13 @@ def emscript(in_wasm, out_wasm, outfile_js, memfile):
306306
update_settings_glue(out_wasm, metadata)
307307

308308
if not settings.WASM_BIGINT and metadata['emJsFuncs']:
309-
module = webassembly.Module(in_wasm)
310-
types = module.get_types()
311309
import_map = {}
312-
for imp in module.get_imports():
313-
import_map[imp.field] = imp
310+
311+
with webassembly.Module(in_wasm) as module:
312+
types = module.get_types()
313+
for imp in module.get_imports():
314+
import_map[imp.field] = imp
315+
314316
for em_js_func, raw in metadata.get('emJsFuncs', {}).items():
315317
c_sig = raw.split('<::>')[0].strip('()')
316318
if not c_sig or c_sig == 'void':

emsymbolizer.py

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -183,28 +183,28 @@ def symbolize_address_sourcemap(module, address, force_file):
183183

184184

185185
def main(args):
186-
module = webassembly.Module(args.wasm_file)
187-
base = 16 if args.address.lower().startswith('0x') else 10
188-
address = int(args.address, base)
189-
symbolized = 0
190-
191-
if args.addrtype == 'code':
192-
address += get_codesec_offset(module)
193-
194-
if ((has_debug_line_section(module) and not args.source) or
195-
'dwarf' in args.source):
196-
symbolize_address_dwarf(module, address)
197-
symbolized += 1
198-
199-
if ((get_sourceMappingURL_section(module) and not args.source) or
200-
'sourcemap' in args.source):
201-
symbolize_address_sourcemap(module, address, args.file)
202-
symbolized += 1
203-
204-
if not symbolized:
205-
raise Error('No .debug_line or sourceMappingURL section found in '
206-
f'{module.filename}.'
207-
" I don't know how to symbolize this file yet")
186+
with webassembly.Module(args.wasm_file) as module:
187+
base = 16 if args.address.lower().startswith('0x') else 10
188+
address = int(args.address, base)
189+
symbolized = 0
190+
191+
if args.addrtype == 'code':
192+
address += get_codesec_offset(module)
193+
194+
if ((has_debug_line_section(module) and not args.source) or
195+
'dwarf' in args.source):
196+
symbolize_address_dwarf(module, address)
197+
symbolized += 1
198+
199+
if ((get_sourceMappingURL_section(module) and not args.source) or
200+
'sourcemap' in args.source):
201+
symbolize_address_sourcemap(module, address, args.file)
202+
symbolized += 1
203+
204+
if not symbolized:
205+
raise Error('No .debug_line or sourceMappingURL section found in '
206+
f'{module.filename}.'
207+
" I don't know how to symbolize this file yet")
208208

209209

210210
def get_args():

tests/test_core.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7229,7 +7229,8 @@ def test_demangle_stacks(self, extra_args):
72297229
self.do_core_test('test_demangle_stacks.cpp', assert_returncode=NON_ZERO)
72307230

72317231
# there should be a name section in the file
7232-
self.assertTrue(webassembly.Module('test_demangle_stacks.wasm').has_name_section())
7232+
with webassembly.Module('test_demangle_stacks.wasm') as m:
7233+
self.assertTrue(m.has_name_section())
72337234

72347235
print('without assertions, the stack is not printed, but a message suggesting assertions is')
72357236
self.set_setting('ASSERTIONS', 0)
@@ -8117,7 +8118,8 @@ def test_asyncify_lists(self, args, should_pass, response=None):
81178118
filename = 'test_asyncify_lists.wasm'
81188119
# there should be no name section. sanitizers, however, always enable that
81198120
if not is_sanitizing(self.emcc_args) and '--profiling-funcs' not in self.emcc_args:
8120-
self.assertFalse(webassembly.Module(filename).has_name_section())
8121+
with webassembly.Module(filename) as m:
8122+
self.assertFalse(m.has_name_section())
81218123
# in a fully-optimized build, imports and exports are minified too and we
81228124
# can verify that our function names appear nowhere
81238125
if '-O3' in self.emcc_args:

tests/test_other.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8680,14 +8680,14 @@ def test_separate_dwarf(self):
86808680
self.assertNotIn(bytes(os.path.join('subdir', 'output.wasm.debug.wasm'), 'ascii'), wasm)
86818681

86828682
# Check that the dwarf file has only dwarf, name, and non-code sections
8683-
debug_wasm = webassembly.Module('subdir/output.wasm.debug.wasm')
8684-
if not debug_wasm.has_name_section():
8685-
self.fail('name section not found in separate dwarf file')
8686-
for sec in debug_wasm.sections():
8687-
if sec.type == webassembly.SecType.CODE:
8688-
self.fail(f'section of type "{sec.type}" found in separate dwarf file')
8689-
if sec.name and sec.name != 'name' and not sec.name.startswith('.debug'):
8690-
self.fail(f'non-debug section "{sec.name}" found in separate dwarf file')
8683+
with webassembly.Module('subdir/output.wasm.debug.wasm') as debug_wasm:
8684+
if not debug_wasm.has_name_section():
8685+
self.fail('name section not found in separate dwarf file')
8686+
for sec in debug_wasm.sections():
8687+
if sec.type == webassembly.SecType.CODE:
8688+
self.fail(f'section of type "{sec.type}" found in separate dwarf file')
8689+
if sec.name and sec.name != 'name' and not sec.name.startswith('.debug'):
8690+
self.fail(f'non-debug section "{sec.name}" found in separate dwarf file')
86918691

86928692
# Check that dwarfdump can dump the debug info
86938693
dwdump = self.run_process(

tools/building.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1354,12 +1354,12 @@ def is_wasm_dylib(filename):
13541354
"""Detect wasm dynamic libraries by the presence of the "dylink" custom section."""
13551355
if not is_wasm(filename):
13561356
return False
1357-
module = webassembly.Module(filename)
1358-
section = next(module.sections())
1359-
if section.type == webassembly.SecType.CUSTOM:
1360-
module.seek(section.offset)
1361-
if module.read_string() in ('dylink', 'dylink.0'):
1362-
return True
1357+
with webassembly.Module(filename) as module:
1358+
section = next(module.sections())
1359+
if section.type == webassembly.SecType.CUSTOM:
1360+
module.seek(section.offset)
1361+
if module.read_string() in ('dylink', 'dylink.0'):
1362+
return True
13631363
return False
13641364

13651365

tools/extract_metadata.py

Lines changed: 55 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -227,15 +227,15 @@ def update_metadata(filename, metadata):
227227
declares = []
228228
invoke_funcs = []
229229
em_js_funcs = set(metadata['emJsFuncs'])
230-
module = webassembly.Module(filename)
231-
for i in module.get_imports():
232-
if i.kind == webassembly.ExternType.FUNC:
233-
if i.field.startswith('invoke_'):
234-
invoke_funcs.append(i.field)
235-
elif i.field not in em_js_funcs:
236-
declares.append(i.field)
237-
238-
exports = [e.name for e in module.get_exports() if e.kind in [webassembly.ExternType.FUNC, webassembly.ExternType.TAG]]
230+
with webassembly.Module(filename) as module:
231+
for i in module.get_imports():
232+
if i.kind == webassembly.ExternType.FUNC:
233+
if i.field.startswith('invoke_'):
234+
invoke_funcs.append(i.field)
235+
elif i.field not in em_js_funcs:
236+
declares.append(i.field)
237+
238+
exports = [e.name for e in module.get_exports() if e.kind in [webassembly.ExternType.FUNC, webassembly.ExternType.TAG]]
239239
metadata['declares'] = declares
240240
metadata['exports'] = exports
241241
metadata['invokeFuncs'] = invoke_funcs
@@ -249,53 +249,54 @@ def get_string_at(module, address):
249249

250250

251251
def extract_metadata(filename):
252-
module = webassembly.Module(filename)
253252
export_names = []
254253
declares = []
255254
invoke_funcs = []
256255
global_imports = []
257256
em_js_funcs = {}
258-
exports = module.get_exports()
259-
imports = module.get_imports()
260-
261-
for i in imports:
262-
if i.kind == webassembly.ExternType.GLOBAL:
263-
global_imports.append(i.field)
264-
265-
export_map = {e.name: e for e in exports}
266-
for e in exports:
267-
if e.kind == webassembly.ExternType.GLOBAL and e.name.startswith('__em_js__'):
268-
name = e.name[len('__em_js__'):]
269-
globl = module.get_global(e.index)
270-
string_address = get_global_value(globl)
271-
em_js_funcs[name] = get_string_at(module, string_address)
272-
273-
for i in imports:
274-
if i.kind == webassembly.ExternType.FUNC:
275-
if i.field.startswith('invoke_'):
276-
invoke_funcs.append(i.field)
277-
elif i.field not in em_js_funcs:
278-
declares.append(i.field)
279-
280-
export_names = [e.name for e in exports if e.kind in [webassembly.ExternType.FUNC, webassembly.ExternType.TAG]]
281-
282-
features = module.parse_features_section()
283-
features = ['--enable-' + f[1] for f in features if f[0] == '+']
284-
features = [f.replace('--enable-atomics', '--enable-threads') for f in features]
285-
features = [f.replace('--enable-simd128', '--enable-simd') for f in features]
286-
features = [f.replace('--enable-nontrapping-fptoint', '--enable-nontrapping-float-to-int') for f in features]
287-
288-
# If main does not read its parameters, it will just be a stub that
289-
# calls __original_main (which has no parameters).
290-
metadata = {}
291-
metadata['asmConsts'] = get_asm_strings(module, export_map)
292-
metadata['declares'] = declares
293-
metadata['emJsFuncs'] = em_js_funcs
294-
metadata['exports'] = export_names
295-
metadata['features'] = features
296-
metadata['globalImports'] = global_imports
297-
metadata['invokeFuncs'] = invoke_funcs
298-
metadata['mainReadsParams'] = get_main_reads_params(module, export_map)
299-
metadata['namedGlobals'] = get_named_globals(module, exports)
300-
# print("Metadata parsed: " + pprint.pformat(metadata))
301-
return metadata
257+
258+
with webassembly.Module(filename) as module:
259+
exports = module.get_exports()
260+
imports = module.get_imports()
261+
262+
for i in imports:
263+
if i.kind == webassembly.ExternType.GLOBAL:
264+
global_imports.append(i.field)
265+
266+
export_map = {e.name: e for e in exports}
267+
for e in exports:
268+
if e.kind == webassembly.ExternType.GLOBAL and e.name.startswith('__em_js__'):
269+
name = e.name[len('__em_js__'):]
270+
globl = module.get_global(e.index)
271+
string_address = get_global_value(globl)
272+
em_js_funcs[name] = get_string_at(module, string_address)
273+
274+
for i in imports:
275+
if i.kind == webassembly.ExternType.FUNC:
276+
if i.field.startswith('invoke_'):
277+
invoke_funcs.append(i.field)
278+
elif i.field not in em_js_funcs:
279+
declares.append(i.field)
280+
281+
export_names = [e.name for e in exports if e.kind in [webassembly.ExternType.FUNC, webassembly.ExternType.TAG]]
282+
283+
features = module.parse_features_section()
284+
features = ['--enable-' + f[1] for f in features if f[0] == '+']
285+
features = [f.replace('--enable-atomics', '--enable-threads') for f in features]
286+
features = [f.replace('--enable-simd128', '--enable-simd') for f in features]
287+
features = [f.replace('--enable-nontrapping-fptoint', '--enable-nontrapping-float-to-int') for f in features]
288+
289+
# If main does not read its parameters, it will just be a stub that
290+
# calls __original_main (which has no parameters).
291+
metadata = {}
292+
metadata['asmConsts'] = get_asm_strings(module, export_map)
293+
metadata['declares'] = declares
294+
metadata['emJsFuncs'] = em_js_funcs
295+
metadata['exports'] = export_names
296+
metadata['features'] = features
297+
metadata['globalImports'] = global_imports
298+
metadata['invokeFuncs'] = invoke_funcs
299+
metadata['mainReadsParams'] = get_main_reads_params(module, export_map)
300+
metadata['namedGlobals'] = get_named_globals(module, exports)
301+
# print("Metadata parsed: " + pprint.pformat(metadata))
302+
return metadata

tools/webassembly.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,15 @@ def __init__(self, filename):
192192
self._cache = {}
193193

194194
def __del__(self):
195+
assert not self.buf, '`__exit__` should have already been called, please use context manager'
196+
197+
def __enter__(self):
198+
return self
199+
200+
def __exit__(self, exc_type, exc_val, exc_tb): # noqa
195201
if self.buf:
196202
self.buf.close()
203+
self.buf = None
197204

198205
def read_at(self, offset, count):
199206
self.buf.seek(offset)
@@ -532,15 +539,15 @@ def get_global(self, idx):
532539

533540

534541
def parse_dylink_section(wasm_file):
535-
module = Module(wasm_file)
536-
return module.parse_dylink_section()
542+
with Module(wasm_file) as module:
543+
return module.parse_dylink_section()
537544

538545

539546
def get_exports(wasm_file):
540-
module = Module(wasm_file)
541-
return module.get_exports()
547+
with Module(wasm_file) as module:
548+
return module.get_exports()
542549

543550

544551
def get_imports(wasm_file):
545-
module = Module(wasm_file)
546-
return module.get_imports()
552+
with Module(wasm_file) as module:
553+
return module.get_imports()

0 commit comments

Comments
 (0)