Repository navigation
Conversation
…ensor An address computed from loaded values, such as `tl.load(a_ptr + idx)` with `idx` loaded from memory, is concretized before it is checked: `_materialize_memory_operand` replaces the whole pointer subtree with its concrete addresses, which drops `a_ptr`. `_resolve_tensor` then took the tensor that the first address falls in. An access from `a_ptr` whose addresses all fall inside another argument `b` was not reported, and one whose first address falls inside `b` was checked against, and attributed to, `b`. Before the full replacement, `_pointer_base` follows the pointer-valued operands of the address down to the pointer argument, and the concrete pointer keeps it as `origin_base`, which `_collect_tensor_base` and the expression signature use. A pointer loaded from memory or cast from an integer has no such base and is still resolved from its value. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Performance Benchmark
Iterations: 1 warmup + 20 measured |
`replace_subtree()` replaces subtrees in place, so concretizing one access's address also turned the shared parts of later addresses into constants without a base. With a pointer tile built before a loop and offsets loaded in it, the first iteration's concretization dropped the base for every later iteration, which then fell back to the tensor of the first concrete address: an iteration whose addresses all fall inside another argument was not reported. Before the full replacement, every pointer node that `_pointer_base` follows now keeps `origin_base`, and `replace_subtree` carries it to the constant that replaces a node. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The sanitizer checks an access against the tensor its pointer comes from, so that an access that leaves tensor A and lands inside tensor B is reported. When the offsets are loaded from memory, it does not:
An address computed from loaded values is concretized before it is checked.
_materialize_memory_operandfirst replaces the loaded subtree with its values, which keepsa_ptr + <values>, and then, when the pointer holds a vector constant, replaces the whole pointer with its concrete addresses, which dropsa_ptr._resolve_tensorthen took the tensor that the first concrete address falls in (_collect_tensor_basereturns the address list). With offsets intob:a_ptr + idxaba_ptra, the rest inba_ptra_ptrb, the rest inab_ptra_ptrb, two pastbb_ptr(the lanes inbpass)a_ptrLoads and stores behave alike.
This PR keeps the pointer argument:
SymbolicClient._pointer_basefollows only the pointer-valued operands of an address (pointer arithmetic, splats and broadcasts, selects), skipping type-spec children, down to a scalar pointer constant. A pointer that comes out of a load, or is cast from an integer, has no such base and returns None._materialize_memory_operandtakes the address's base and stores it asorigin_baseon every pointer node on the way (_mark_pointer_base), andreplace_subtreecarriesorigin_baseto the constant that replaces a node.replace_subtree()works in place, so the subtrees it replaces may be shared with later accesses: with a pointer tile built before a loop and offsets loaded in the loop, the first iteration's concretization would otherwise leave the later iterations without a base (the second commit; the loop test below fails without it)._collect_tensor_basereturnsorigin_basewhen a concrete pointer has one, so the concrete-address route, the deferred loop checks, and reporting all usea_ptr's tensor.signature()includesorigin_base, so that two concrete pointers with the same addresses but different bases are not deduplicated into one check.A pointer loaded from a pointer table is still resolved from its value, as before. A table entry that points to a tensor that is not a kernel argument is still reported, since the sanitizer knows no bounds for it; this PR does not change that.
Tests
tests/end_to_end/test_sanitizer.py:test_sanitizer_checks_loaded_offsets_against_their_base_tensor: the five cases above, for a load and a store (10 cases). The kernels are defined per test, so that no launch repeats an earlier one ([BUG] Sanitizer skips re-launches whose addresses, masks, or branches depend on loaded values #517 is not merged on main). The 6 cases that should be reported ona_ptrbut are not fail on main.test_sanitizer_checks_loaded_offsets_in_a_loop_against_their_base_tensor: a pointer tile built before a loop, offsets loaded in it; the second iteration lands entirely inb. Not reported on main, nor with only the first commit.test_sanitizer_resolves_a_loaded_pointer_from_its_value: a pointer loaded from a table into a tensor that is a kernel argument, in bounds; not reported, with and without this PR.pytest tests/: 366 passed, 6 skipped on main; 378 passed, 6 skipped with this PR (Python 3.12, Triton 3.8.0).ruff checkandruff format --check(v0.1.9) pass on the changed files.🤖 Generated with Claude Code