zig icon indicating copy to clipboard operation
zig copied to clipboard

LLVM crash when using argument of naked function

Open filasieno opened this issue 1 year ago • 9 comments

Zig Version

0.13

Steps to Reproduce and Observed Behavior

While playing with inline ASM I get a SEGFAULT in release. The following code does not do anything and is totally wrong, but the compiler should not SEGFAULT.

This program segfaults the compiler with exit code 139.

zig build-exe sample.zig -OReleaseSafe --> segfaults zig build-exe sample.zig -OReleaseFast --> segfaults zig build-exe sample.zig --> OK

// Type your code here, or load an example.
const std = @import("std");

fn hello(counter: *i32) callconv(.Naked) void {
    counter.* = counter.* +% 1;
    call(@ptrCast(&hello), counter);
    // call("example.hello", counter);
}

inline fn call(tcfn: *const void, arg1: *i32) void {
    asm volatile (
        \\jmp *%[f]
        :
        : [f] "{rax}" (tcfn),
          [arg1] "{esi}" (arg1),
    );
}

fn square(num: i32) i32 {
    var i: i32 = 0;
    call(@ptrCast(&hello), &i);
    // hello(0);
    return num * num;
}

pub fn main() !void {
    _ = square(100);
}


Expected Behavior

Anything but a SEGFAULT.

filasieno avatar Sep 01 '24 22:09 filasieno

Repros on 0.14.0-dev.1338+93cb44c80 targeting x86_64-linux. LLVM error:

Can't get register for value!
UNREACHABLE executed at /home/mlugg/llvm/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp:1920!

mlugg avatar Sep 01 '24 23:09 mlugg

LLVM IR reduction:

target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; Function Attrs: naked
define void @empty.hello(ptr %0) #0 {
Entry:
  %1 = load i32, ptr %0, align 4
  ret void
}

attributes #0 = { naked }

doesn't need -O3 to trigger.

Rexicon226 avatar Sep 01 '24 23:09 Rexicon226

Lovely, mind filing an upstream issue @Rexicon226?

mlugg avatar Sep 01 '24 23:09 mlugg

oh, wait, maybe verify it's not fixed on llvm 19 first lol

mlugg avatar Sep 01 '24 23:09 mlugg

oh, wait, maybe verify it's not fixed on llvm 19 first lol

It's not:

❯ ~/local/llvm19-debug/bin/llc test.ll
Can't get register for value!
UNREACHABLE executed at /Users/david/Code/llvm-project/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp:1959!
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.

Lovely, mind filing an upstream issue @Rexicon226?

Can do in a minute.

Rexicon226 avatar Sep 01 '24 23:09 Rexicon226

Well actually, it seems they fixed it at some point between 19-master: https://zig.godbolt.org/z/63oWfMh9G

Why do we allow arguments in naked functions again?

Rexicon226 avatar Sep 01 '24 23:09 Rexicon226

IIRC naked functions are a little up in the air ATM. @alexrp has talked about constraining them to effectively only contain asm statements.

mlugg avatar Sep 01 '24 23:09 mlugg

The bug here is that we allow people to reference arguments in a naked function in Sema.

LLVM is basically right to either reject or not handle IR that does this because, in the general case, there is no way to make it work in a naked function.

alexrp avatar Sep 01 '24 23:09 alexrp

My change to allow arguments in naked functions should be reverted, you can name the arguments when you cast:

pub const foo: *const fn (helpful_name: u32) callconv(.C) u32 = @ptrCast(&fooNaked);

I'd also argue that you should be required to use a return type of noreturn for all naked functions since they are not callable and cannot contain return statements.

jacobly0 avatar Sep 02 '24 01:09 jacobly0