Skip to content

An in-place wrapper around a pure function can introduce a memory aliasing bug #7625

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
passionsocks opened this issue Dec 31, 2020 · 2 comments
Milestone

Comments

@passionsocks
Copy link

This snippet of code demonstrates the bug, as observed in Zig 0.7.1

// unexpected_aliasing.zig
const std = @import("std");

// pure complex multiplication -- returns a * b
fn complexPureMult(a: [2]f32, b: [2]f32) [2]f32 {
    return [2]f32{
        a[0] * b[0] - a[1] * b[1],
        a[0] * b[1] + a[1] * b[0],
    };
}

// inplace complex multiplication -- a *= b;
fn complexInplaceMult(a: *[2]f32, b: [2]f32) void {
    a.* = complexPureMult(a.*, b);
}

test "inplace_product_result_alias_bug_in_debug" {
    const identity = [2]f32{ 1, 0 };
    const nonidentity = [2]f32{ 4, 5 };

    const pure_result = complexPureMult(identity, nonidentity);
    std.testing.expectEqual(nonidentity[0], pure_result[0]);
    std.testing.expectEqual(nonidentity[1], pure_result[1]);

    var inplace_result = identity;
    complexInplaceMult(&inplace_result, nonidentity);
    std.testing.expectEqual(nonidentity[0], inplace_result[0]);
    std.testing.expectEqual(nonidentity[1], inplace_result[1]); // "expected 5.0e+00, found 2.0e+01"
}

Running the test in the default (-O Debug) build mode gives the indicated error with the inplace result on my x86_64-linux desktop machine.

$ zig version
0.7.1
$ zig test unexpected_aliasing.zip
Test [1/1] test "inplace_product_result_alias_bug"... expected 5.0e+00, found 2.0e+01
[...]

The generated code for complexPureMult shows that it does not expect the destination for the result to be an alias for the first argument, as it computes the first term (reading memory for all four values) and writes it to the destination before computing the second term (rereading all four values).

However complexInplaceMult violates the assumption, so the computed value is incorrect.

@travisstaloch
Copy link
Contributor

#4021 maybe.

@daurnimator
Copy link
Contributor

Closing as dupe of #3696

@andrewrk andrewrk added this to the 0.8.0 milestone Jan 3, 2021
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

No branches or pull requests

4 participants