@@ -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' )
696814def 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