Skip to content

feat(Singlepass): add config for strict memory boundary checking#6351

Open
marxin wants to merge 5 commits intomainfrom
singlepass-riscv-memory-boundary-checking
Open

feat(Singlepass): add config for strict memory boundary checking#6351
marxin wants to merge 5 commits intomainfrom
singlepass-riscv-memory-boundary-checking

Conversation

@marxin
Copy link
Copy Markdown
Contributor

@marxin marxin commented Mar 25, 2026

So far, we've been using the strict boundary checking for the RISC-V target of the Singlepass compiler. Works fine, however, it makes the memory operations rather slow and so, similarly to other targets, let's rely on the access violation memory signals.

@tsahee @wakabat
For preserving the old behavior, I added a new config option strict_memory_boundary_checks.

@marxin marxin requested a review from syrusakbary as a code owner March 25, 2026 10:52
Copilot AI review requested due to automatic review settings March 25, 2026 10:52
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a configurable “strict memory boundary checks” mode for the Singlepass compiler, allowing RISC-V Singlepass to default to the faster signal-based OOB behavior while preserving the previous always-check behavior behind a flag.

Changes:

  • Introduce strict_memory_boundary_checks on Singlepass config (default false) and document it.
  • Plumb the flag through Singlepass codegen so memory ops can request explicit bounds checks even for static memories.
  • Update RISC-V Singlepass memory codegen to honor need_check, plus adjust tests/ignores accordingly.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
lib/compiler-singlepass/src/config.rs Adds the new config field + builder-style setter.
lib/compiler-singlepass/src/codegen.rs Uses the config flag to force need_check for memory ops.
lib/compiler-singlepass/src/machine_riscv.rs Makes bounds checking conditional on need_check for RISC-V memory ops.
tests/compilers/issues.rs Adds a regression test intended to validate strict bounds behavior.
tests/ignores.txt Adds RISC-V Singlepass ignores for spec tests affected by relaxed boundary behavior; tweaks comment text.
lib/compiler-singlepass/README.md Documents the new option and updates supported target list.
Comments suppressed due to low confidence (1)

lib/compiler-singlepass/src/machine_riscv.rs:1048

  • cond (aliased to tmp_base) is released via release_gpr(cond) and then immediately reused as a scratch register for the alignment check (emit_and(..., Location::GPR(cond))). This breaks the register-usage bookkeeping and is fragile if future changes allocate temps between these points. Delay releasing cond until after the alignment-check block (or acquire a fresh temp for the alignment check).
        self.release_gpr(tmp_bound);
        self.release_gpr(cond);

        let align = value_size as u32;
        if check_alignment && align != 1 {
            self.assembler.emit_and(
                Size::S64,
                Location::GPR(tmp_addr),
                Location::Imm64((align - 1) as u64),
                Location::GPR(cond),

marxin and others added 2 commits March 25, 2026 12:12
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@marxin marxin added this to the v7.2 milestone Mar 25, 2026
}
}

/// Configure whether Singlepass should always emit strict memory boundary
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't a major behavior change like this use the old behaviour by default?

We could switch the default with the next major version?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the change is tightly communicated with our customer, we can do it. Moreover, it's going to align with other Singlepass platforms.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our customers are a limited subset of our users though.

In general I'm against significant behaviour changes in minor versions.

Guess should have @syrusakbary chime in.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, that’s a good point! Keep in mind that the current RISC-V port of Singlepass is still considered experimental, so we may have some flexibility to make this change.

As for minor versions, it’s a bit tricky. On one hand, we aim to do a major release once a year, but in reality, many minor releases introduce breaking changes and arguably should be treated as major versions. This might be worth discussing further.

@marxin marxin requested a review from theduke March 31, 2026 12:39
Copy link
Copy Markdown
Member

@syrusakbary syrusakbary left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The strict memory boundary checking is what MemoryStyle::Dynamic implies.

All MemoryStyle::Dynamic memories must do strict memory boundary checking, so we don't need an extra setting?

@marxin
Copy link
Copy Markdown
Contributor Author

marxin commented Apr 8, 2026

The strict memory boundary checking is what MemoryStyle::Dynamic implies.

Yes, that behavior has been preserved.

All MemoryStyle::Dynamic memories must perform strict boundary checking, so we don’t need an extra setting?

The situation comes from a divergence in the original Singlepass RISC-V implementation compared to x86_64 and AArch64. On those architectures, MemoryStyle::Static relies on signal handling to catch out-of-bounds accesses.

When I added rv64gc support, I mistakenly enabled strict boundary checking by default to comply with the spec. The newly introduced strict_memory_boundary_checks flag is still useful, though - particularly for scenarios like running modules on bare metal (e.g., Offchain use cases).

@marxin marxin requested a review from syrusakbary April 8, 2026 11:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants