# Check for overlapping memory areas?

**URL:** <https://ziggit.dev/t/check-for-overlapping-memory-areas/6362>\
**Category:** Help\
**Tags:** standard-library\
**Created:** [October 14, 2024, 1:18am UTC](https://ziggit.dev/t/check-for-overlapping-memory-areas/6362 "2024-10-14T01:18:47Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![jeffective](https://ziggit.dev/user_avatar/ziggit.dev/jeffective/32/3116_2.png) [@jeffective](https://ziggit.dev/u/jeffective)\
**Post date:** [October 14, 2024, 1:18am UTC](https://ziggit.dev/t/check-for-overlapping-memory-areas/6362/1 "2024-10-14T01:18:47Z")

</div>

Given two slices, is there a method in the standard library to check if they overlap (point to the same memory)?

---

<div class="post-metadata">

**Author:** ![mnemnion](https://ziggit.dev/user_avatar/ziggit.dev/mnemnion/32/2478_2.png) [@mnemnion](https://ziggit.dev/u/mnemnion)\
**Post date:** [October 14, 2024, 1:35am UTC](https://ziggit.dev/t/check-for-overlapping-memory-areas/6362/2 "2024-10-14T01:35:44Z")

</div>

Don’t think so, it would be in `std.mem` and doesn’t appear to be.

Not especially difficult to write,

```zig
const a_start = slice_a.ptr;
const a_end = slice_a[slice_a.len..].ptr;
const b_start = slice_b.ptr;
const b_end = slice_b[slice_b.len..].ptr;

```

Then you cast them to `usize` with `@intFromPtr` and just check if either end is between the other pair.

---

<div class="post-metadata">

**Author:** ![jeffective](https://ziggit.dev/user_avatar/ziggit.dev/jeffective/32/3116_2.png) [@jeffective](https://ziggit.dev/u/jeffective)\
**Post date:** [October 14, 2024, 1:37am UTC](https://ziggit.dev/t/check-for-overlapping-memory-areas/6362/3 "2024-10-14T01:37:30Z")

</div>

Doesn’t this assume a “linear memory model”?

Is this a valid assumption?

---

<div class="post-metadata">

**Author:** ![mnemnion](https://ziggit.dev/user_avatar/ziggit.dev/mnemnion/32/2478_2.png) [@mnemnion](https://ziggit.dev/u/mnemnion)\
**Post date:** [October 15, 2024, 2:09am UTC](https://ziggit.dev/t/check-for-overlapping-memory-areas/6362/4 "2024-10-15T02:09:11Z")

</div>

8 posts were split to a new topic: [Unified memory models and AddressSpace](https://ziggit.dev/t/unified-memory-models-and-addressspace/6379)

---

<div class="post-metadata">

**Author:** ![jeffective](https://ziggit.dev/user_avatar/ziggit.dev/jeffective/32/3116_2.png) [@jeffective](https://ziggit.dev/u/jeffective)\
**Post date:** [October 14, 2024, 2:26am UTC](https://ziggit.dev/t/check-for-overlapping-memory-areas/6362/5 "2024-10-14T02:26:50Z")

</div>

I believe this is the relevant issue:

> <https://github.com/ziglang/zig/issues/17613>
>
> See:
>               
> \> In addition to the problems identified in this review, t…he entire idea of checking whether aliasing is occurring in userland is flawed. You already noticed that it cannot be done at compile time, but there is more. This would wreck pointer provenance-based optimizations in ReleaseSafe mode because of the \`@intFromPtr\` calls.
> \>
> \> I think general-purpose alias checking needs to be done via a language builtin instead.
> 
> \_Originally posted by @andrewrk in https://github.com/ziglang/zig/pull/17544#pullrequestreview-1686340050\_
> 
> Essentially, for safety reasons being able to explicitly determine if slices alias an be useful in some situations. However, there are limitations to doig this in userspace which a builtin would be the best way to address.

---

<div class="post-metadata">

**Author:** ![jeffective](https://ziggit.dev/user_avatar/ziggit.dev/jeffective/32/3116_2.png) [@jeffective](https://ziggit.dev/u/jeffective)\
**Post date:** [October 14, 2024, 2:36am UTC](https://ziggit.dev/t/check-for-overlapping-memory-areas/6362/6 "2024-10-14T02:36:35Z")

</div>

and this doesn’t appear to work:

```zig
const std = @import("std");
fn assertNonOverlapping(noalias slice1: []u8, noalias slice2: []u8) void {
    _ = slice1;
    _ = slice2;
}

test "check for overlaps" {
    var buf = [3]u8{ 1, 2, 3 };
    const second_slice: []u8 = buf[1..2];

    assertNonOverlapping(&buf, second_slice);
}

```

---

<div class="post-metadata">

**Author:** ![mnemnion](https://ziggit.dev/user_avatar/ziggit.dev/mnemnion/32/2478_2.png) [@mnemnion](https://ziggit.dev/u/mnemnion)\
**Post date:** [October 14, 2024, 9:55pm UTC](https://ziggit.dev/t/check-for-overlapping-memory-areas/6362/13 "2024-10-14T21:55:49Z")

</div>

> [@jeffective](#):
>
> Doesn’t this assume a “linear memory model”?
> 
> Is this a valid assumption?

No, it assumes something weaker: that valid memory in a process always has unique addresses.

If you think about it, every pointer in a slice must be valid, and unique. Nothing could possibly work if this wasn’t true. Valid means the number you have points to the address, unique means only that number (in your process) _can_ point to that address.

A linear memory model would mean that there’s real actual addresses between pointer A and pointer B, and that’s not a safe assumption, each page is randomized but every page offset given to a process is unique. It has to be.

So what _is_ safe is that if the ranges of the start and end pointer do not overlap, the memory doesn’t overlap, and if they do, it does.

---

<div class="post-metadata">

**Author:** ![jeffective](https://ziggit.dev/user_avatar/ziggit.dev/jeffective/32/3116_2.png) [@jeffective](https://ziggit.dev/u/jeffective)\
**Post date:** [September 10, 2026, 4:12am UTC](https://ziggit.dev/t/check-for-overlapping-memory-areas/6362/14 "2026-09-10T04:12:50Z")

</div>

This was actually a huge pain to implement

```zig
/// returns true if two memory areas alias
/// zero len slices never alias anything
pub fn alias(comptime T: type, a: []const T, b: []const T) bool {
    if (a.len == 0 or b.len == 0) return false;

    const a_start = @intFromPtr(a.ptr);
    const b_start = @intFromPtr(b.ptr);
    const a_end = @intFromPtr(a[a.len - 1 ..].ptr);
    const b_end = @intFromPtr(b[b.len - 1 ..].ptr);

    return a_start <= b_end and b_start <= a_end;
}

test alias {
    const a: [10]u16 = undefined;

    try std.testing.expect(alias(u16, a[9..10], a[9..10]));
    // |----|
    // |--|
    try std.testing.expect(alias(u16, a[0..5], a[1..2]));

    // |----|
    // |---|
    try std.testing.expect(alias(u16, a[0..5], a[1..5]));

    // |----|
    // |----|
    try std.testing.expect(alias(u16, a[0..5], a[1..6]));

    // |----|
    // |---|
    try std.testing.expect(alias(u16, a[0..5], a[0..4]));

    // |----|
    // |----|
    try std.testing.expect(alias(u16, a[0..5], a[0..5]));

    // |----|
    // |-----|
    try std.testing.expect(alias(u16, a[0..5], a[0..6]));

    // |---|
    // |---|
    try std.testing.expect(alias(u16, a[1..5], a[0..4]));

    // |---|
    // |----|
    try std.testing.expect(alias(u16, a[1..5], a[0..5]));

    // |---|
    // |-----|
    try std.testing.expect(alias(u16, a[1..5], a[0..6]));

    // |---|
    // |-----|
    try std.testing.expect(alias(u16, a[0..5], a[4..6]));

    // |-----|
    // |---|
    try std.testing.expect(alias(u16, a[4..6], a[0..5]));

    // |-----|
    // |---|
    try std.testing.expect(!alias(u16, a[4..6], a[0..4]));

    // |-----|
    // |---|
    try std.testing.expect(!alias(u16, a[4..6], a[0..3]));

    // |---|
    // |-----|
    try std.testing.expect(!alias(u16, a[0..4], a[4..6]));

    // |---|
    // |-----|
    try std.testing.expect(!alias(u16, a[0..3], a[4..6]));

    try std.testing.expect(!alias(u16, a[0..0], a[0..0]));
    try std.testing.expect(!alias(u16, a[0..0], a[1..2]));
    try std.testing.expect(!alias(u16, a[1..2], a[1..1]));
}

```
