Source-linked AI summary

MallocSan: A Memory Safety Tool for Native Closed-Source Applications

Adel Belkhiri, Michel Dagenais, Maxime Lamothe

arXiv:2609.38499v1cs.SE

TL;DR

Deterministic memory-safety checking is difficult to deploy when existing approaches require source access, specialized hardware, or costly translation. MallocSan tags protected heap pointers and uses fault-driven runtime patching for per-object checks; it reports lower execution-time overhead than Memcheck across the evaluated benchmarks while retaining detection and scaling results within its stated scope.

  • Problem

    Deterministic identity-based spatial checking is difficult to deploy on closed-source native applications without source access, recompilation, specialized hardware, or expensive whole-program translation.

    Source: §1 · pp. 1, 3
  • Method

    MallocSan interposes on heap allocation, encodes object identifiers in protected pointers, and uses noncanonical-address faults to trigger per-object checks and runtime patching.

    Source: §3 · p. 5
  • Results

    4.82× versus 18.55× geometric-mean execution-time factors for MallocSan and Memcheck across seven SPEC CPU 2017 benchmarks; Juliet detection was complete without false reports, and both evaluated workloads scaled substantially.

    Source: §10 · pp. 26–27
  • Takeaways & Limitations

    The supported conclusion is deterministic per-object spatial checking for protected heaps in unmodified x86-64 Linux binaries.

    Source: §10 · p. 26

    Objects not returned through interposed allocation functions, including custom-allocator, mmap, and brk allocations, may go undetected; stack and global variables are outside its heap-protection scope.

    Source: §8.2 · p. 24

Abstract

from arXiv · show

Memory-corruption errors remain a leading cause of high-impact vulnerabilities in C and C++ software. Deterministic detection, however, remains difficult to deploy: compiler-based sanitizers require source code and control of the build pipeline, hardware-assisted schemes depend on specific platforms, and dynamic binary translation can impose order-of-magnitude slowdowns. This paper presents MallocSan, a heap sanitizer for native, potentially closed-source x86-64 Linux applications that requires no source access, recompilation, or specialized hardware. MallocSan interposes on memory allocation through LD_PRELOAD and embeds an object identifier in the unused high bits of each protected pointer. Dereferencing the resulting noncanonical pointer faults at the offending instruction, which MallocSan decodes and patches at runtime so that subsequent executions perform per-object bounds checks entirely in userspace. Sites that cannot be patched fall back to in-handler emulation or single-stepping, while an optional profile-guided pass rewrites frequently executed residual sites offline. MallocSan also extends identity-based checking to vector gather/scatter instructions and supports policy-scoped coverage. Across seven SPEC CPU 2017 benchmarks, MallocSan outperforms Valgrind Memcheck on five, with a geometric-mean execution-time factor of 4.82x relative to native execution, compared with 18.55x for Memcheck, while preserving substantial parallel scaling on both evaluated multithreaded workloads: 644.nab_s and pigz. On the in-scope Juliet tests, MallocSan detects all seeded violations with no false reports on the good executions. It also detects heap-buffer errors in real-world applications, including a known one-byte overread in LibTIFF's tiffcrop utility.

1 Introduction

C and C++ memory safety remains difficult because object bounds and lifetimes are not consistently enforced, while existing detection approaches trade strength against deployability. MallocSan addresses this gap with deterministic heap checking for unmodified binaries and runtime mechanisms designed to make it practical.

Motivation

  • Native pointers permit unchecked arithmetic and dereferencing, so object boundaries and lifetimes are not consistently enforced.Invalid accesses can silently corrupt state and surface later, complicating diagnosis.Source: §1 · p. 1

Research gap

  • Existing tools either lack deterministic identity-based spatial checking or require source access, specialized hardware, or expensive whole-program translation.MallocSan is presented as a response to this deployment gap.Source: §1 · p. 2

Approach

  • MallocSan interposes on allocations, tags protected pointers with object identifiers, and checks each dereference against its allocation’s recorded bounds.A noncanonical tagged-pointer dereference faults at the access, allowing runtime decoding and patching to move recurring checks into userspace.Source: §1 · p. 2

Design choices

  • Protection can be scoped by allocation properties or caller origin, and an optional guard-page backend trades memory and precision for avoiding per-access instrumentation on selected large allocations.The design also validates active vector gather/scatter lanes against the identified object’s bounds.Source: §1 · pp. 2–3

Contributions

  • The paper contributes a heap sanitizer for unmodified x86-64 Linux binaries, identity-based machine-code checking mechanisms, optional guard-page and profile-guided optimizations, and accuracy, overhead, and scaling evaluations.The evaluations include Juliet tests, selected SPEC CPU 2017 workloads, OpenMP 644.nab_s, and pigz.Source: §1 · p. 3

2 Background

The background establishes the paper’s heap-safety scope and the trade-offs among detection models and binary instrumentation approaches. It then distinguishes offline rewriting from runtime patching and explains their redirection encodings.

2.1 Memory Safety: Scope and Detection Model

  • The paper focuses on heap-resident spatial and temporal errors, assessed in terms of detection timing, precision, coverage, and execution-time and space overhead.Location-based methods can miss nonlinear or inter-object jumps, while identity-based methods track referents but require richer metadata and propagation.Source: §2.1 · pp. 3–4

2.2 Binary and Runtime Patching

  • Compiler instrumentation requires compilation-pipeline access, dynamic binary instrumentation translates executed code, and binary patching redirects selected sites without translating all executed code.Patching overhead depends primarily on the frequency and cost of patched sites.Source: §2.2 · p. 4

2.2.1 Static Binary Patching.

  • Static rewriting determines patch sites and redirections offline, paying construction costs once but requiring separately handled shared libraries and plugins and a runtime mechanism for generated code.MallocSan’s profile-guided phase uses E9Patch to install redirections while preserving original instruction addresses.Source: §2.2.1 · pp. 4–5

2.2.2 Runtime Patching.

  • Runtime patching can reach loaded and later-discovered code; JUMP redirects sites with enough space, NOP-bridge uses nearby padding for shorter sites, and TRAP is the fallback when safe redirection is unavailable.TRAP incurs signal delivery on each execution, whereas JUMP avoids repeated signal delivery; libpatch supplies these runtime mechanisms.Source: Figure 1 · p. 4, §2.2 · p. 4, §2.2.2 · p. 5

3 MallocSan Overview

MallocSan tags selected heap pointers with object identifiers and uses faults on noncanonical tagged addresses to intercept protected accesses. Runtime patching makes later checks userspace operations where possible, with slower alternatives for unpatchable sites.

Pointer tagging and object tracking

  • Through LD_PRELOAD, MallocSan assigns protected allocations object identifiers encoded in pointer high bits, with object-table entries recording allocation base and size.The OID identifies the bounds record used to validate each protected access; optional use-after-free tracking retains and marks freed entries.Source: §3 · p. 5

Fault interception and steady state

  • A first dereference faults at the instruction, where MallocSan decodes its operands and dependencies and installs a patch when possible.The patched path strips the OID, checks the canonical address against the object table, then restores the protected pointer.Source: §3 · p. 5

Fallback paths

  • Unpatchable sites use in-handler emulation when the instruction is simple enough, or single-stepping otherwise; overlapping patches can recover many sites relocated to out-of-line buffers.These alternatives preserve checking but are slower than the patched userspace path.Source: §3 · p. 5

4 MallocSan Design

MallocSan protects selected heap allocations by tagging pointers with object identities and faulting on dereference, then checking accesses against per-object bounds. Its design extends checking to REP and vector-indexed operations while controlling which allocations are protected.

4 MallocSan Design

  • MallocSan combines object tracking, coverage controls, first-fault instruction analysis, runtime patching, and specialized handling for REP and VSIB accesses.Its design also includes overlapping patches, post-handler optimizations, boundary handling, thread safety, and an optional guard-page backend.Source: §4 · pp. 5–6

4.1 Pointer Tagging and Object Table

  • Each protected allocation receives an OID tag that indexes its recorded base, size, and allocation site for per-object bounds checks.The 15 usable tag bits provide up to 32,767 identifiers; optional use-after-free tracking retains freed entries for explicit classification.Source: §4.1 · p. 6
  • Immediate OID reuse can let a stale pointer pass validation if reassignment occurs before dereference and the accessed range fits the new object.Use-after-free tracking avoids this ambiguity for retained freed objects but increases pressure on the finite OID space.Source: §4.1 · p. 6

4.2 Protection Coverage Control

  • Protection can be scoped by allocation size, order, and concurrent-object limits, while caller-origin filters allow selected executables and libraries to be tagged.Unprotected allocations retain the original malloc path; the configurable library allowlist also avoids faults in code incompatible with tagged pointers.Source: §4.2 · pp. 6–7

4.3 First-Fault Handling and Instruction Analysis

  • A tagged-pointer fault is handled on an alternate signal stack, and decoded instruction metadata is cached by address for later executions.The handler defers decoding to a trampoline because the disassembly library is not async-signal-safe; instruction-table states coordinate concurrent first-fault analysis.Source: §4.3 · p. 7

4.3.1 REP String Instructions.

  • Fixed-count REP operations are checked before execution by deriving their full memory footprints, including separate source and destination intervals.For zero iterations no check is needed; overflow in span computation saturates so an oversized count is reported out of bounds.Source: §4.3.1 · pp. 7–8, Figure 3 · p. 8
  • For data-dependent REP scans, MallocSan checks the first element before execution, then validates the actual interval recovered from updated pointer registers.This deferred check handles the actual scan extent rather than treating rcx's upper bound as the iteration count, and restores the pointer tag afterward.Source: §4.3.1 · p. 8, Figure 4 · p. 8

4.3.2 VSIB Instructions.

  • VSIB handling checks each active vector lane against the object referenced by the tagged base, while leaving inactive lanes unchecked.The instruction metadata records lane count and index width; a violating lane is reported with its number and computed address.Source: §4.3.2 · pp. 8–9, Figure 5 · p. 9

4.4 Runtime Patching and Fallback Paths

MallocSan redirects patchable faulting instructions through user-space handlers that validate accesses before executing the original operation. When ordinary patching is unavailable, it uses ordered fallbacks and extends patching to relocated instructions through overlapping patches.

4.4 Runtime Patching and Fallback Paths

  • A JUMP patch redirects a faulting instruction to handler code and an out-of-line buffer; its 5-byte form is preferred when the site permits it.Patch installation is delegated to a worker thread after the process becomes multithreaded because libpatch is not thread-safe.Source: §4.4 · p. 9
  • Patched paths strip OIDs, validate the access, execute on canonical addresses, and restore tags when pointer registers remain live.If JUMP patching is unavailable, MallocSan tries in-handler emulation, then TRAP patches, and finally single-stepping; most sites receive JUMP patches.Source: §4.4 · pp. 9–10

4.5 Overlapping Patches for Relocated Instructions

  • Relocated instructions can fault inside an out-of-line buffer, where direct patching is unavailable and repeated single-stepping would burden hot loops.This motivates support for overlapping patches.Source: §4.4 · p. 9, §4.5 · pp. 10–11
  • When an instruction overwrites tagged register values before any further pointer use, MallocSan omits the post-handler to avoid unnecessary or incorrect restoration.The pre-handler still removes tags and validates the access.Source: Figure 7 · p. 11
  • Overlapping patches register a relocated instruction as a child, rebuild the parent buffer with its handlers, and atomically publish the new buffer.Concurrent execution sees either valid buffer; eligible children are displaced non-head instructions, and failed child creation falls back to single-stepping.Source: §4.5 · p. 11

4.6 Post-Handler Elimination and Deferral

MallocSan reduces recurring handler overhead by eliminating unnecessary post-handlers and deferring necessary restoration to later safe sites. Its scans preserve safety through bounds validation and conservative rules for pointer use and control flow.

4.6 Post-Handler Elimination and Deferral

  • Post-handlers are eliminated when tagged values become dead or are fully overwritten, because restoring their OIDs is then unnecessary or incorrect.The pre-handler still removes tags and validates the access.Source: §4.6 · pp. 11–12
  • When restoration remains necessary, a forward scan selects a later safe site, stopping at unsafe control flow or tagged-register interactions.If a preferred site cannot host the required 5-byte jump, bounded tail-fallback candidates are considered; otherwise restoration remains immediate.Source: §4.6 · pp. 11–12
  • Accepted accesses through the tagged register are added to a widened footprint, which the originating pre-handler revalidates against current object bounds on every execution.Constant pointer walks are folded into per-register deltas when checking subsequent accesses.Source: §4.6 · p. 12
  • Deferral can cross a loop back-edge only for a constrained single-exit shape satisfying five control-flow, register-use, address, and restoration-site conditions.This avoids restoring the tag and faulting again on every iteration.Source: §4.6 · p. 12
  • For an eligible loop with a loop-invariant address, one entry check covers all iterations and a single exit post-handler restores the tag.Multiple protected sites in the loop can share the exit post-handler.Source: §4.6 · p. 12
  • Repeat-prefixed string instructions are excluded from both optimizations, and data-dependent CMPS and SCAS checks remain at the instruction site.Their implicit pointer updates require re-tagging, while exact footprints for CMPS and SCAS are known only after execution.Source: §4.6 · p. 12

4.7 C Library and Kernel Boundaries

MallocSan wraps selected libc and pthread entry points to manage tagged pointers across library and kernel boundaries. The wrappers also enable scoped protection while preventing internal allocations from being tagged recursively.

4.7 C Library and Kernel Boundaries

  • Wrappers strip tags from pointer arguments at library and kernel boundaries, then restore tags to returned or derived pointers that remain associated with protected objects.This handling is needed because library routines may manipulate pointers internally or pass user buffers to the kernel.Source: §4.7 · pp. 13–14
  • Selective wrapping or exclusion scopes protection to application components while leaving standard shared libraries uninstrumented.A thread-local reentrancy guard temporarily disables protection for internal allocations and restores its prior state on exit.Source: §4.7 · p. 14

4.8 Concurrency and Thread Safety

MallocSan separates shared instruction metadata from per-thread execution state and coordinates instruction decoding and patching across threads. Its optional guard-page backend protects selected allocations without per-access instrumentation, trading some precision and memory for lower checking overhead on large objects.

4.8 Concurrency and Thread Safety

  • Instruction metadata is immutable after creation, while temporary register values reside in thread-local state; atomic entry creation and serialized patch requests coordinate concurrent execution.A dedicated worker performs patching, and instruction analysis occurs outside signal handlers because Capstone is not async-signal-safe.Source: §4.8 · p. 14

4.9 Guard-Page Protection Backend

  • The guard-page backend places eligible objects before an inaccessible page, so page-crossing overflows fault at the offending access without per-access instrumentation.The alignment gap is canary-filled and checked at deallocation.Source: §4.9 · p. 14, Figure 8 · p. 15
  • Guard pages miss small trailing reads within the alignment gap and underflows, while OID checking detects these cases at access time.Guarding is capped and gated by a minimum allocation size; other or declined requests fall back to OID tagging, and large objects are favored to limit proportional page-rounding cost.Source: §4.9 · pp. 14–15

5 Implementation Details

MallocSan's implementation is divided into runtime, instruction-analysis, patching, and wrapper modules. It uses binary-patching, disassembly, and ELF/DWARF-introspection libraries, and records instruction statistics for profile-guided optimization.

5 Implementation Details

  • Four runtime modules handle initialization and policy, instruction analysis and handlers, binary patching, and allocation and library-boundary wrappers.The wrapper module tags protected allocations and strips or restores tags at library and kernel boundaries.Source: §5 · p. 15
  • The implementation exceeds 10,000 lines of C and depends on libpatch, Capstone, libdw, and libunwind.Per-instruction hit counts and patching metadata are emitted at process exit to drive the profile-guided optimization pass.Source: §5 · p. 15

6 Profile-Guided Hot-Path Optimization

MallocSan profiles residual TRAP sites and optionally rewrites frequently executed eligible sites offline into JUMP-based redirections. The fast path preserves the original checking logic while reducing steady-state overhead at hot sites.

6 Profile-Guided Hot-Path Optimization

  • Frequent TRAP invocations incur signal delivery, handler dispatch, and context recovery, which can dominate execution time inside hot loops.The optional profile-guided pipeline targets these sites for offline rewriting.Source: §6 · p. 15
  • Using E9Patch, the rewriting phase replaces selected TRAP sites with JUMP-based redirections that perform the same OID stripping, bounds check, and tag restoration.Sites must exceed a user-specified execution threshold and have a safe rewrite window of at least five bytes.Source: §6 · pp. 15–16
  • Rewritten sites reuse the TRAP path’s checking logic, while ineligible instructions retain the signal-based fallback.The approach trades one profiling run for lower steady-state overhead on hot sites in subsequent executions.Source: §6 · p. 16

7 Evaluation

The evaluation tests heap-boundary detection, single-thread overhead, profile-guided rewriting, and multithreaded scaling. Across selected SPEC CPU 2017 benchmarks, MallocSan has lower geometric-mean execution-time and MRSS factors than Memcheck.

7.1 Detection Effectiveness (RQ1)

  • On the scored Juliet population, MallocSan recorded 2,195 true positives and 2,766 true negatives, with no false positives or false negatives, and detected LibTIFF’s one-byte overread.The result excludes 152 bad runs where the defect did not manifest, 383 stack-destination violations, and 36 intra-object violations.Source: Table 1 · p. 17, §7.1 · p. 17

7.3 Single-Thread Overhead (RQ2)

  • Across seven selected SPEC benchmarks, MallocSan’s geometric-mean execution-time factor was 4.82× versus 18.55× for Memcheck, and geometric-mean MRSS factor was 1.62× versus 2.50×.MallocSan had a lower execution-time factor on five benchmarks and lower mean MRSS on all seven.Source: Figure 9 · p. 18, Figure 10 · p. 18, §7.3 · p. 19

7.2 Performance Methodology

  • The single-thread SPEC evaluation used seven selected compatible workloads, protected every eligible heap allocation, and averaged ten runs after verifying output correctness.The measured factors use Native as the 1.0× baseline; the selected workloads do not represent the entire SPEC CPU 2017 suite.Source: §7.2 · pp. 17–19

7.4 Effect of Profile-Guided Rewriting (RQ3)

  • Offline rewriting reduced execution-time factors by 15.8% on 605.mcf_s and 48.6% on 619.lbm_s, a two-workload geometric-mean reduction of 34.2%.Both rewritten factors remained above Memcheck’s corresponding factors.Source: §7.4 · p. 20

7.5 Multithreaded Scaling (RQ4)

  • MallocSan preserved substantial scaling on both evaluated workloads: 644.nab_s reached 10.48× speedup versus Native’s 10.34×, while pigz reached 19.56× versus Native’s 13.61×.At 18 pigz compression threads, MallocSan’s execution-time factor was 1.20× Native; the results cover only the tested workloads, inputs, thread ranges, and machine.Source: Figure 12 · p. 21, §7.5 · pp. 21–22

8 General Discussion

The discussion frames MallocSan and Memcheck as tools for different operating points: MallocSan targets lower-overhead, policy-scoped per-object checks, while Memcheck offers broader process checking at higher cost. The evaluation and limitations qualify that tradeoff by workload, application compatibility, and the scope of the evidence.

8.1 Evaluation Findings and Design Tradeoffs

  • Replacing eligible hot TRAP sites with direct JUMP-based redirection can recover some fallback cost, but residual TRAP sites and checks on rewritten paths constrain the benefit.The attainable improvement depends on eligible sites’ dynamic coverage and the remaining cost of OID stripping, bounds validation, and tag restoration.Source: §8.1 · p. 23
  • MallocSan’s runtime state is prominent relative to 648.exchange2_s’s exceptionally small Native footprint but contributes little in relative terms on workloads with large Native footprints.Its persistent state includes a bounded object table, an instruction table that grows with distinct protected sites, and fixed-capacity trampoline and OLX pools.Source: §8.1 · p. 23
  • Memcheck serializes client-thread execution, whereas MallocSan runs application threads concurrently and serializes patch installation only once per newly encountered instruction site.MallocSan handles faults on the faulting thread and uses thread-local state for steady-state checking.Source: §8.1 · p. 23
  • At 18 compression threads on pigz, MallocSan achieved 19.56× speedup versus Native’s 13.61×, while taking 1.20× as long.The higher relative speedup is consistent with first-fault analysis overlapping useful compression work; it does not mean lower absolute execution time.Source: §8.1 · p. 23
  • MallocSan concentrates checks on protected heap accesses, while Memcheck performs broad process-wide addressability checking; narrowing MallocSan’s policy reduces both cost and coverage.The evaluation protects every eligible heap allocation, representing MallocSan’s widest OID-tagging policy; broader protection costs more.Source: §8.1 · pp. 22–23
  • The application class best suited to MallocSan is dynamically linked x86-64 Linux software using supported allocation interfaces and not repurposing the selected pointer tag bits.Its protection requirements must also align with allocation-granularity heap checking.Source: §8.1 · p. 24

8.2 Limitations and Threats to Validity

  • MallocSan’s assumptions about virtual-address layout, allocation interfaces, and pointer-bit use may limit protected objects, omit allocations from coverage, or make an application incompatible.On five-level paging, the available nonzero OIDs fall from 32,767 to 127; custom arenas, pools, mmap, and brk allocations bypass interposed entry points, while stack and global objects are out of scope.Source: §8.2 · p. 24
  • Scaling evidence covers two workloads on one heterogeneous processor and does not establish the same behavior for other workload classes, inputs, settings, or hardware topologies.Aggregate timings also do not isolate the contribution of concurrent first-fault analysis and its overlap with useful work.Source: §8.2 · p. 24

9 Related Work

The related work compares memory-safety approaches by detection strength, deployment requirements, and runtime cost. It positions MallocSan’s interposition and runtime patching as a way to provide deterministic per-object spatial checking for selected heap accesses in unmodified binaries.

9.1 Static Detection of Memory Errors

  • Static and learning-based detectors avoid runtime enforcement but face limits in detection, scalability, generalization, or operational false-positive burden.Evaluated static-analysis configurations achieved a 25.67% robust detection rate on Toyota ITC, and Cppcheck or Flawfinder alerts changed for 22 of 159 vulnerability fixes.Source: §9.1 · pp. 24–25

9.2 Compiler-Based Dynamic Enforcement

  • Compiler-based sanitizers provide dynamic checks but require instrumentation, while identity-based schemes such as SoftBound and CETS depend on compiler support.ASan reports 73% average slowdown and approximately 3.4× memory overhead; the software-only SoftBoundCETS prototype averages 72% overhead across SPEC benchmarks.Source: §9.2 · p. 25

9.3 Hardware-Assisted Detection

  • Hardware-assisted approaches can reduce enforcement cost, but depend on specialized processors, operating systems, ABIs, or ISA features.CHERI reports single-digit percentage overhead but requires a CHERI platform and software stack; No-FAT reports 8% overhead on SPEC CPU 2017.Source: §9.3 · p. 25

9.4 Binary-Level Instrumentation

  • Binary-level tools can accept unmodified executables, but DBT carries substantial overhead and static rewriting can require relocation information or well-structured compiler output.Memcheck’s translation pipeline imposes a 17–40× slowdown; MTSan’s results also illustrate limits involving custom allocators and sub-object overflows.Source: §9.4 · p. 26

9.5 Runtime Interposition and Allocator-Based Defenses

  • Allocator interposition deploys on prebuilt binaries, but prior systems offer probabilistic spatial protection, temporal-only protection, or compiler-dependent tracking rather than identity-based deterministic spatial checks.MallocSan uses LD_PRELOAD on commodity x86-64 systems and validates protected accesses against per-object bounds; allocations bypassing the interposed interface remain outside its scope.Source: §9.5 · p. 26

10 Conclusion

MallocSan combines allocator interposition, pointer OIDs, and runtime binary patching to check protected heap accesses in unmodified x86-64 Linux binaries. The evaluation reports lower execution-time overhead than Memcheck across the selected SPEC benchmarks, while the conclusion limits its scope to supported heap allocations and identifies extensions needed for broader applicability.

10 Conclusion

  • MallocSan assigns protected allocations OIDs and uses first-fault interception to validate accesses, then patches sites for later checks, with emulation or single-stepping for sites that cannot use direct redirection.It requires no source access, recompilation, or specialized hardware, and offers policy-scoped heap protection and optional use-after-free reporting.Source: §10 · p. 26
  • Across seven selected SPEC CPU 2017 benchmarks, MallocSan’s execution-time geometric-mean factor was 4.82×, compared with Memcheck’s 18.55×.On the in-scope Juliet tests, MallocSan detected every manifested violation and issued no reports on good executions; it also preserved substantial parallel scaling on both evaluated multithreaded workloads.Source: §10 · pp. 26–27
  • MallocSan protects heap allocations obtained through interposed interfaces on x86-64 Linux; stack and global objects, unsupported custom allocation paths, and applications repurposing selected pointer bits fall outside its scope.The conclusion identifies extending direct redirection, broadening emulation coverage, and reducing recurring checking cost as future work.Source: §10 · p. 27
Loading 2609.38499v1…