Skip to content

Commit 094e5bd

Browse files
authored
Extract setup_santizers function. NFC (#25712)
The phase_linker_setup function is enormous so I'm trying to split it up a little.
1 parent cc359e6 commit 094e5bd

File tree

1 file changed

+119
-112
lines changed

1 file changed

+119
-112
lines changed

tools/link.py

Lines changed: 119 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,124 @@ def check_settings():
692692
exit_with_error(msg)
693693

694694

695+
@ToolchainProfiler.profile()
696+
def setup_sanitizers(options):
697+
assert(options.sanitize)
698+
699+
if settings.WASM_WORKERS:
700+
exit_with_error('WASM_WORKERS is not currently compatible with `-fsanitize` tools')
701+
# These symbols are needed by `withBuiltinMalloc` which used to implement
702+
# the `__noleakcheck` attribute. However this dependency is not yet represented in the JS
703+
# symbol graph generated when we run the compiler with `--symbols-only`.
704+
settings.REQUIRED_EXPORTS += [
705+
'malloc',
706+
'calloc',
707+
'realloc',
708+
'memalign',
709+
'free',
710+
'emscripten_builtin_malloc',
711+
'emscripten_builtin_calloc',
712+
'emscripten_builtin_realloc',
713+
'emscripten_builtin_memalign',
714+
'emscripten_builtin_free',
715+
]
716+
717+
if ('leak' in options.sanitize or 'address' in options.sanitize) and not settings.ALLOW_MEMORY_GROWTH:
718+
# Increase the minimum memory requirements to account for extra memory
719+
# that the sanitizers might need (in addition to the shadow memory
720+
# requirements handled below).
721+
# These values are designed be an over-estimate of the actual requirements and
722+
# are based on experimentation with different tests/programs under asan and
723+
# lsan.
724+
inc_initial_memory(50 * 1024 * 1024)
725+
if settings.PTHREADS:
726+
inc_initial_memory(50 * 1024 * 1024)
727+
728+
if options.sanitize & UBSAN_SANITIZERS:
729+
if options.sanitize_minimal_runtime:
730+
settings.UBSAN_RUNTIME = 1
731+
else:
732+
settings.UBSAN_RUNTIME = 2
733+
734+
if 'leak' in options.sanitize:
735+
settings.USE_LSAN = 1
736+
default_setting('EXIT_RUNTIME', 1)
737+
738+
if 'address' in options.sanitize:
739+
settings.USE_ASAN = 1
740+
default_setting('EXIT_RUNTIME', 1)
741+
if not settings.UBSAN_RUNTIME:
742+
settings.UBSAN_RUNTIME = 2
743+
744+
settings.REQUIRED_EXPORTS += emscripten.ASAN_C_HELPERS
745+
746+
if settings.ASYNCIFY and not settings.ASYNCIFY_ONLY:
747+
# we do not want asyncify to instrument these helpers - they just access
748+
# memory as small getters/setters, so they cannot pause anyhow, and also
749+
# we access them in the runtime as we prepare to rewind, which would hit
750+
# an asyncify assertion, if asyncify instrumented them.
751+
#
752+
# note that if ASYNCIFY_ONLY was set by the user then we do not need to
753+
# do anything (as the user's list won't contain these functions), and if
754+
# we did add them, the pass would assert on incompatible lists, hence the
755+
# condition in the above if.
756+
settings.ASYNCIFY_REMOVE.append("__asan_*")
757+
758+
if settings.ASAN_SHADOW_SIZE != -1:
759+
diagnostics.warning('emcc', 'ASAN_SHADOW_SIZE is ignored and will be removed in a future release')
760+
761+
if 'GLOBAL_BASE' in user_settings:
762+
exit_with_error("ASan does not support custom GLOBAL_BASE")
763+
764+
# Increase the INITIAL_MEMORY and shift GLOBAL_BASE to account for
765+
# the ASan shadow region which starts at address zero.
766+
# The shadow region is 1/8th the size of the total memory and is
767+
# itself part of the total memory.
768+
# We use the following variables in this calculation:
769+
# - user_mem : memory usable/visible by the user program.
770+
# - shadow_size : memory used by asan for shadow memory.
771+
# - total_mem : the sum of the above. this is the size of the wasm memory (and must be aligned to WASM_PAGE_SIZE)
772+
user_mem = settings.MAXIMUM_MEMORY
773+
if not settings.ALLOW_MEMORY_GROWTH and settings.INITIAL_MEMORY != -1:
774+
user_mem = settings.INITIAL_MEMORY
775+
776+
# Given the know value of user memory size we can work backwards
777+
# to find the total memory and the shadow size based on the fact
778+
# that the user memory is 7/8ths of the total memory.
779+
# (i.e. user_mem == total_mem * 7 / 8
780+
# TODO-Bug?: this does not look to handle 4GB MAXIMUM_MEMORY correctly.
781+
total_mem = user_mem * 8 / 7
782+
783+
# But we might need to re-align to wasm page size
784+
total_mem = int(align_to_wasm_page_boundary(total_mem))
785+
786+
# The shadow size is 1/8th the resulting rounded up size
787+
shadow_size = total_mem // 8
788+
789+
# We start our global data after the shadow memory.
790+
# We don't need to worry about alignment here. wasm-ld will take care of that.
791+
settings.GLOBAL_BASE = shadow_size
792+
793+
# Adjust INITIAL_MEMORY (if needed) to account for the shifted global base.
794+
if settings.INITIAL_MEMORY != -1:
795+
if settings.ALLOW_MEMORY_GROWTH:
796+
settings.INITIAL_MEMORY += align_to_wasm_page_boundary(shadow_size)
797+
else:
798+
settings.INITIAL_MEMORY = total_mem
799+
800+
if settings.SAFE_HEAP:
801+
# SAFE_HEAP instruments ASan's shadow memory accesses.
802+
# Since the shadow memory starts at 0, the act of accessing the shadow memory is detected
803+
# by SAFE_HEAP as a null pointer dereference.
804+
exit_with_error('ASan does not work with SAFE_HEAP')
805+
806+
if settings.MEMORY64:
807+
exit_with_error('MEMORY64 does not yet work with ASAN')
808+
809+
if settings.GENERATE_SOURCE_MAP:
810+
settings.LOAD_SOURCE_MAP = 1
811+
812+
695813
@ToolchainProfiler.profile_block('linker_setup')
696814
def phase_linker_setup(options, linker_args): # noqa: C901, PLR0912, PLR0915
697815
"""Future modifications should consider refactoring to reduce complexity.
@@ -1549,123 +1667,12 @@ def limit_incoming_module_api():
15491667
diagnostics.warning('emcc', 'JavaScript output suffix requested, but wasm side modules are just wasm files; emitting only a .wasm, no .js')
15501668

15511669
if options.sanitize:
1552-
if settings.WASM_WORKERS:
1553-
exit_with_error('WASM_WORKERS is not currently compatible with `-fsanitize` tools')
1554-
# These symbols are needed by `withBuiltinMalloc` which used to implement
1555-
# the `__noleakcheck` attribute. However this dependency is not yet represented in the JS
1556-
# symbol graph generated when we run the compiler with `--symbols-only`.
1557-
settings.REQUIRED_EXPORTS += [
1558-
'malloc',
1559-
'calloc',
1560-
'realloc',
1561-
'memalign',
1562-
'free',
1563-
'emscripten_builtin_malloc',
1564-
'emscripten_builtin_calloc',
1565-
'emscripten_builtin_realloc',
1566-
'emscripten_builtin_memalign',
1567-
'emscripten_builtin_free',
1568-
]
1569-
1570-
if ('leak' in options.sanitize or 'address' in options.sanitize) and not settings.ALLOW_MEMORY_GROWTH:
1571-
# Increase the minimum memory requirements to account for extra memory
1572-
# that the sanitizers might need (in addition to the shadow memory
1573-
# requirements handled below).
1574-
# These values are designed be an over-estimate of the actual requirements and
1575-
# are based on experimentation with different tests/programs under asan and
1576-
# lsan.
1577-
inc_initial_memory(50 * 1024 * 1024)
1578-
if settings.PTHREADS:
1579-
inc_initial_memory(50 * 1024 * 1024)
1580-
1581-
if options.sanitize & UBSAN_SANITIZERS:
1582-
if options.sanitize_minimal_runtime:
1583-
settings.UBSAN_RUNTIME = 1
1584-
else:
1585-
settings.UBSAN_RUNTIME = 2
1586-
1587-
if 'leak' in options.sanitize:
1588-
settings.USE_LSAN = 1
1589-
default_setting('EXIT_RUNTIME', 1)
1590-
1591-
if 'address' in options.sanitize:
1592-
settings.USE_ASAN = 1
1593-
default_setting('EXIT_RUNTIME', 1)
1594-
if not settings.UBSAN_RUNTIME:
1595-
settings.UBSAN_RUNTIME = 2
1596-
1597-
settings.REQUIRED_EXPORTS += emscripten.ASAN_C_HELPERS
1598-
1599-
if settings.ASYNCIFY and not settings.ASYNCIFY_ONLY:
1600-
# we do not want asyncify to instrument these helpers - they just access
1601-
# memory as small getters/setters, so they cannot pause anyhow, and also
1602-
# we access them in the runtime as we prepare to rewind, which would hit
1603-
# an asyncify assertion, if asyncify instrumented them.
1604-
#
1605-
# note that if ASYNCIFY_ONLY was set by the user then we do not need to
1606-
# do anything (as the user's list won't contain these functions), and if
1607-
# we did add them, the pass would assert on incompatible lists, hence the
1608-
# condition in the above if.
1609-
settings.ASYNCIFY_REMOVE.append("__asan_*")
1610-
1611-
if settings.ASAN_SHADOW_SIZE != -1:
1612-
diagnostics.warning('emcc', 'ASAN_SHADOW_SIZE is ignored and will be removed in a future release')
1613-
1614-
if 'GLOBAL_BASE' in user_settings:
1615-
exit_with_error("ASan does not support custom GLOBAL_BASE")
1616-
1617-
# Increase the INITIAL_MEMORY and shift GLOBAL_BASE to account for
1618-
# the ASan shadow region which starts at address zero.
1619-
# The shadow region is 1/8th the size of the total memory and is
1620-
# itself part of the total memory.
1621-
# We use the following variables in this calculation:
1622-
# - user_mem : memory usable/visible by the user program.
1623-
# - shadow_size : memory used by asan for shadow memory.
1624-
# - total_mem : the sum of the above. this is the size of the wasm memory (and must be aligned to WASM_PAGE_SIZE)
1625-
user_mem = settings.MAXIMUM_MEMORY
1626-
if not settings.ALLOW_MEMORY_GROWTH and settings.INITIAL_MEMORY != -1:
1627-
user_mem = settings.INITIAL_MEMORY
1628-
1629-
# Given the know value of user memory size we can work backwards
1630-
# to find the total memory and the shadow size based on the fact
1631-
# that the user memory is 7/8ths of the total memory.
1632-
# (i.e. user_mem == total_mem * 7 / 8
1633-
# TODO-Bug?: this does not look to handle 4GB MAXIMUM_MEMORY correctly.
1634-
total_mem = user_mem * 8 / 7
1635-
1636-
# But we might need to re-align to wasm page size
1637-
total_mem = int(align_to_wasm_page_boundary(total_mem))
1638-
1639-
# The shadow size is 1/8th the resulting rounded up size
1640-
shadow_size = total_mem // 8
1641-
1642-
# We start our global data after the shadow memory.
1643-
# We don't need to worry about alignment here. wasm-ld will take care of that.
1644-
settings.GLOBAL_BASE = shadow_size
1645-
1646-
# Adjust INITIAL_MEMORY (if needed) to account for the shifted global base.
1647-
if settings.INITIAL_MEMORY != -1:
1648-
if settings.ALLOW_MEMORY_GROWTH:
1649-
settings.INITIAL_MEMORY += align_to_wasm_page_boundary(shadow_size)
1650-
else:
1651-
settings.INITIAL_MEMORY = total_mem
1652-
1653-
if settings.SAFE_HEAP:
1654-
# SAFE_HEAP instruments ASan's shadow memory accesses.
1655-
# Since the shadow memory starts at 0, the act of accessing the shadow memory is detected
1656-
# by SAFE_HEAP as a null pointer dereference.
1657-
exit_with_error('ASan does not work with SAFE_HEAP')
1658-
1659-
if settings.MEMORY64:
1660-
exit_with_error('MEMORY64 does not yet work with ASAN')
1670+
setup_sanitizers(options)
16611671

16621672
if settings.USE_ASAN or settings.SAFE_HEAP:
16631673
# ASan and SAFE_HEAP check address 0 themselves
16641674
settings.CHECK_NULL_WRITES = 0
16651675

1666-
if options.sanitize and settings.GENERATE_SOURCE_MAP:
1667-
settings.LOAD_SOURCE_MAP = 1
1668-
16691676
if 'GLOBAL_BASE' not in user_settings and not settings.SHRINK_LEVEL and not settings.OPT_LEVEL and not settings.USE_ASAN:
16701677
# When optimizing for size it helps to put static data first before
16711678
# the stack (since this makes instructions for accessing this data

0 commit comments

Comments
 (0)