Skip to content
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

wasm miscompilation without LLVM: can modify const value #22617

Open
knexator opened this issue Jan 26, 2025 · 0 comments
Open

wasm miscompilation without LLVM: can modify const value #22617

knexator opened this issue Jan 26, 2025 · 0 comments
Labels
arch-wasm 32-bit and 64-bit WebAssembly backend-self-hosted bug Observed behavior contradicts documented or intended behavior miscompilation The compiler reports success but produces semantically incorrect code.
Milestone

Comments

@knexator
Copy link

knexator commented Jan 26, 2025

Zig Version

0.14.0-dev.2647+5322459a0

Steps to Reproduce and Observed Behavior

Create an array of Foo (a struct with a single usize field), take the first element as a const value, and then modify the array. The const element has changed!

main.zig:

const std = @import("std");

// Without a custom log fn, it doesn't compile
pub const std_options = std.Options{
    .logFn = myLogFn,
};
fn myLogFn(
    comptime message_level: std.log.Level,
    comptime scope: @Type(.enum_literal),
    comptime format: []const u8,
    args: anytype,
) void {
    _ = message_level;
    _ = scope;
    _ = format;
    _ = args;
}

extern fn logInt(arg: usize) void;

export fn _start() void {
    bug() catch unreachable;
}

fn bug() !void {
    const Foo = struct {
        k: usize,
    };
    var gpa = std.heap.GeneralPurposeAllocator(.{}).init;
    const alloc = gpa.allocator();
    var foos = std.ArrayList(Foo).init(alloc);
    try foos.append(.{ .k = 0 });
    try foos.append(.{ .k = 1 });
    const first_foo = foos.items[0];
    logInt(first_foo.k);
    _ = foos.orderedRemove(0);
    // The bug persists if we change the above line to:
    // foos.items[0] = foos.items[1];
    logInt(first_foo.k);
}

build.zig:

const std = @import("std");

// JS helper to run the wasm module
const main_js_contents =
    \\const fs = require("fs");
    \\(async () => {
    \\  const wasmBuffer = fs.readFileSync(process.argv[2]);
    \\  const wasmModule = await WebAssembly.instantiate(wasmBuffer, {
    \\    env: { logInt: (arg) => console.log(arg) },
    \\  });
    \\  wasmModule.instance.exports._start();
    \\})();
;

pub fn build(b: *std.Build) void {
    const use_llvm = b.option(bool, "llvm", "use llvm and lld");
    const optimize = b.standardOptimizeOption(.{});
    const exe = b.addExecutable(.{
        .name = "wasm_bug",
        .root_source_file = b.path("main.zig"),
        .optimize = optimize,
        .target = b.resolveTargetQuery(.{
            .cpu_arch = .wasm32,
            .os_tag = .freestanding,
        }),
        .use_llvm = use_llvm,
    });
    exe.import_symbols = true;
    b.installArtifact(exe);

    const write_file_step = b.addWriteFiles();
    const main_js = write_file_step.add("main.js", main_js_contents);
    const launch_node = b.addSystemCommand(&.{"node"});
    launch_node.addFileArg(main_js);
    launch_node.addFileArg(exe.getEmittedBin());
    launch_node.step.dependOn(b.getInstallStep());

    const run_launch_node_step = b.step("run", "run the wasm module");
    run_launch_node_step.dependOn(&launch_node.step);
}

zig build run -Dllmv=false outputs, on my machine, "0 1"

(note that the run is provided only for convenience and requires node installed; feel free to run the .wasm in any other way.)

Expected Behavior

The output should be "0 0", and in fact that's what we see when running zig build run -Dllmv=true.

I've also tried on 0.14.0-dev.2851+b074fb7dd but I can't get it working there; it fails on WebAssembly.instantiate()

@knexator knexator added the bug Observed behavior contradicts documented or intended behavior label Jan 26, 2025
@andrewrk andrewrk added arch-wasm 32-bit and 64-bit WebAssembly miscompilation The compiler reports success but produces semantically incorrect code. backend-self-hosted labels Jan 27, 2025
@andrewrk andrewrk added this to the 0.15.0 milestone Jan 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
arch-wasm 32-bit and 64-bit WebAssembly backend-self-hosted bug Observed behavior contradicts documented or intended behavior miscompilation The compiler reports success but produces semantically incorrect code.
Projects
None yet
Development

No branches or pull requests

2 participants