Skip to content

Data written at runtime is wrongly classified as const (phase1) #7894

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
iglosiggio opened this issue Jan 27, 2021 · 2 comments
Closed

Data written at runtime is wrongly classified as const (phase1) #7894

iglosiggio opened this issue Jan 27, 2021 · 2 comments
Labels
bug Observed behavior contradicts documented or intended behavior stage1 The process of building from source via WebAssembly and the C backend.
Milestone

Comments

@iglosiggio
Copy link

I think this is the problem behind #6043 and #7878

Example code:

// Writes to rodata
export fn tuple(v: u64) void {
    const bug = .{ .{ v } };
}

// Writes to rodata
export fn anon_struct(v: u64) void {
    const bug = .{ .v = .{ .v = v } };
}

const InnerData = struct {
    v: u64
};
// Writes to rodata
export fn known_inner_struct(v: u64) void {
    const bug = .{ .v = InnerData { .v = v } };
}

const OuterData = struct {
    v: InnerData
};
// Works
export fn known_outer_struct(v: u64) void {
    const works = OuterData { .v = .{ .v = v } };
}

// Works
export fn known_both_structs(v: u64) void {
    const works = OuterData { .v = InnerData { .v = v} };
}

pub fn panic(msg: []const u8, error_return_trace: ?*@import("std").builtin.StackTrace) noreturn {
    @breakpoint();
    unreachable;
}

A snippet of the generated code for the first example (output from objdump because it's a bit less noisy than -femit-asm):

0000000000000030 <tuple>:
  30:	55                   	push   rbp
  31:	48 89 e5             	mov    rbp,rsp
  34:	50                   	push   rax
  35:	48 89 7d f8          	mov    QWORD PTR [rbp-0x8],rdi
  39:	48 8b 45 f8          	mov    rax,QWORD PTR [rbp-0x8]
  3d:	48 89 04 25 00 00 00 	mov    QWORD PTR ds:0x0,rax
  44:	00 
			41: R_X86_64_32S	.rodata.cst8
  45:	48 83 c4 08          	add    rsp,0x8
  49:	5d                   	pop    rbp
  4a:	c3                   	ret    
  4b:	0f 1f 44 00 00       	nop    DWORD PTR [rax+rax*1+0x0]

ds:0x0 is the relocation to be filled with the pointer of .rodata.cst8

IR generation log for the same function:

{
  const bug = {{v    }    };
}
fn tuple() { // (IR)
Entry_0:
  #1  | SrcResetResult        | (unknown)   | - | ResetResult(none)
  #2  | SrcResetResult        | (unknown)   | - | ResetResult(none)
  #3  | SrcConst              | bool        | 2 | false
  #4  | SrcAlloca             | (unknown)   | 1 | Alloca(align=(null),name=bug)
  #5  | SrcResetResult        | (unknown)   | - | ResetResult(var(#4))
  #6  | SrcResolveResult      | (unknown)   | 2 | ResolveResult(var(#4))
  #7  | SrcConst              | usize       | 1 | 0
  #8  | SrcElemPtr            | (unknown)   | 2 | &#6[#7] // no safety
  #9  | SrcResetResult        | (unknown)   | - | ResetResult(inst(#8))
  #10 | SrcResolveResult      | (unknown)   | 2 | ResolveResult(inst(#8))
  #11 | SrcConst              | usize       | 1 | 0
  #12 | SrcElemPtr            | (unknown)   | 2 | &#10[#11] // no safety
  #13 | SrcResetResult        | (unknown)   | - | ResetResult(inst(#12))
  #14 | SrcVarPtr             | (unknown)   | 1 | &v
  #15 | SrcLoadPtr            | (unknown)   | 1 | #14.*
  #16 | SrcEndExpr            | (unknown)   | - | EndExpr(result=inst(#12),value=#15)
  #17 | SrcContainerInitList  | (unknown)   | 1 | {#12}result=#10
  #18 | SrcEndExpr            | (unknown)   | - | EndExpr(result=inst(#8),value=#17)
  #19 | SrcContainerInitList  | (unknown)   | 1 | {#8}result=#6
  #20 | SrcEndExpr            | (unknown)   | - | EndExpr(result=var(#4),value=#19)
  #21 | SrcDeclVar            | (unknown)   | - | const bug = #4 // comptime = #3
  #22 | SrcConst              | void        | 0 | {}
  #23 | SrcConst              | void        | 4 | {}
  #24 | SrcEndExpr            | (unknown)   | - | EndExpr(result=none,value=#23)
  #25 | SrcAddImplicitReturnType| (unknown)   | - | @addImplicitReturnType(#23)
  #26 | SrcResetResult        | (unknown)   | - | ResetResult(return)
  #27 | SrcEndExpr            | (unknown)   | - | EndExpr(result=return,value=#23)
  #28 | SrcReturn             | noreturn    | - | return #23
}
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:1:30
~ #1  | SrcResetResult        | (unknown)   | - | ResetResult(none)
-> #2  | GenConst              | void        | 0 | {}
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:2:5
~ #2  | SrcResetResult        | (unknown)   | - | ResetResult(none)
-> #3  | GenConst              | void        | 0 | {}
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:2:5
~ #3  | SrcConst              | bool        | 2 | false
-> #4  | GenConst              | bool        | 0 | false
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:2:5
~ #4  | SrcAlloca             | (unknown)   | 1 | Alloca(align=(null),name=bug)
-> (null~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:2:5
~ #5  | SrcResetResult        | (unknown)   | - | ResetResult(var(#4))
-> #5  | GenConst              | void        | 0 | {}
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:2:18
~ #6  | SrcResolveResult      | (unknown)   | 2 | ResolveResult(var(#4))
-> #6  | GenAlloca             | *struct:2:18| 0 | Alloca(align=0,name=bug)
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:2:21
~ #7  | SrcConst              | usize       | 1 | 0
-> #7  | GenConst              | usize       | 0 | 0
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:2:21
~ #8  | SrcElemPtr            | (unknown)   | 2 | &#6[#7] // no safety
-> #8  | GenCast               | (* field '0' of struct:2:18)| 0 | NoOp cast #6
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:2:21
~ #9  | SrcResetResult        | (unknown)   | - | ResetResult(inst(#8))
-> #9  | GenConst              | void        | 0 | {}
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:2:21
~ #10 | SrcResolveResult      | (unknown)   | 2 | ResolveResult(inst(#8))
-> #11 | GenStructFieldPtr     | *struct:2:21| 0 | @StructFieldPtr(&#10.0)
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:2:23
~ #11 | SrcConst              | usize       | 1 | 0
-> #12 | GenConst              | usize       | 0 | 0
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:2:23
~ #12 | SrcElemPtr            | (unknown)   | 2 | &#10[#11] // no safety
-> #13 | GenCast               | (* field '0' of struct:2:21)| 0 | NoOp cast #11
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:2:23
~ #13 | SrcResetResult        | (unknown)   | - | ResetResult(inst(#12))
-> #14 | GenConst              | void        | 0 | {}
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:2:23
~ #14 | SrcVarPtr             | (unknown)   | 1 | &v
-> #15 | GenVarPtr             | *const u64  | 0 | &v
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:2:23
~ #15 | SrcLoadPtr            | (unknown)   | 1 | #14.*
-> #16 | GenLoadPtr            | u64         | 0 | loadptr(#15)result=(null)
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:2:23
~ #16 | SrcEndExpr            | (unknown)   | - | EndExpr(result=inst(#12),value=#15)
-> #19 | GenConst              | void        | 0 | {}
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:2:21
~ #17 | SrcContainerInitList  | (unknown)   | 1 | {#12}result=#10
-> #20 | GenLoadPtr            | struct:2:21 | 0 | loadptr(#11)result=(null)
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:2:21
~ #18 | SrcEndExpr            | (unknown)   | - | EndExpr(result=inst(#8),value=#17)
-> #21 | GenConst              | void        | 0 | {}
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:2:18
~ #19 | SrcContainerInitList  | (unknown)   | 1 | {#8}result=#6
-> #22 | GenConst              | struct:2:18 | 0 | (struct struct:2:18 constant)
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:2:18
~ #20 | SrcEndExpr            | (unknown)   | - | EndExpr(result=var(#4),value=#19)
-> #23 | GenConst              | void        | 0 | {}
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:2:5
~ #21 | SrcDeclVar            | (unknown)   | - | const bug = #4 // comptime = #3
-> #24 | GenDeclVar            | void        | - | const bug: struct:2:18 align(8) = #6
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:1:30
~ #23 | SrcConst              | void        | 4 | {}
-> #25 | GenConst              | void        | 0 | {}
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:1:30
~ #24 | SrcEndExpr            | (unknown)   | - | EndExpr(result=none,value=#23)
-> #26 | GenConst              | void        | 0 | {}
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:1:30
~ #25 | SrcAddImplicitReturnType| (unknown)   | - | @addImplicitReturnType(#23)
-> #27 | GenConst              | void        | 0 | {}
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:1:30
~ #26 | SrcResetResult        | (unknown)   | - | ResetResult(return)
-> #28 | GenConst              | void        | 0 | {}
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:1:30
~ #27 | SrcEndExpr            | (unknown)   | - | EndExpr(result=return,value=#23)
-> #30 | GenConst              | void        | 0 | {}
~ /home/ilosiggio/experimentos/zig/zig/build/test/report.zig:1:30
~ #28 | SrcReturn             | noreturn    | - | return #23
append new bb Entry_0
-> (noreturn)
fn tuple() { // (analyzed)
Entry_0:
  #1  | GenReturnPtr          | *void       | 0 | @ReturnPtr
  #8  | GenCast               | (* field '0' of struct:2:18)| 0 | NoOp cast #6
  :6  | GenAlloca             | *struct:2:18| 2 | Alloca(align=0,name=bug)
  #11 | GenStructFieldPtr     | *struct:2:21| 2 | @StructFieldPtr(&#10.0)
  :10 | GenConst              | *struct:2:18| 1 | *(struct struct:2:18 constant)
  #13 | GenCast               | (* field '0' of struct:2:21)| 1 | NoOp cast #11
  #15 | GenVarPtr             | *const u64  | 1 | &v
  #16 | GenLoadPtr            | u64         | 1 | loadptr(#15)result=(null)
  #17 | GenStructFieldPtr     | *u64        | 1 | @StructFieldPtr(&#13.0)
  #18 | GenStorePtr           | void        | - | *#17 = #16
  #20 | GenLoadPtr            | struct:2:21 | 0 | loadptr(#11)result=(null)
  #24 | GenDeclVar            | void        | - | const bug: struct:2:18 align(8) = #6
  #31 | GenReturn             | noreturn    | - | return #25
  :25 | GenConst              | void        | 1 | {}
}

After debugging a lot of hours i think the problem is on translating #10 (SrcResolveResult) into #11 GenStructFieldPtr and :10 (GenConst). Maybe this is an aliasing problem (#18 (GenStorePtr) is marked as ConstValSpecialRuntime but neither #13 (GenCast) nor #11 (GenStructFieldPtr) get recognized as such.

Any guidance on how to understand better the problem is welcome. I know phase1 is not the current focus so i hope this issue doesn't add a lot of noise :)

@iglosiggio
Copy link
Author

Seems to be a dupe of #3915

@SpexGuy SpexGuy added bug Observed behavior contradicts documented or intended behavior stage1 The process of building from source via WebAssembly and the C backend. labels Mar 17, 2021
@Vexu Vexu added this to the 0.9.0 milestone Mar 19, 2021
@andrewrk andrewrk modified the milestones: 0.9.0, 0.10.0 May 19, 2021
@mikdusan
Copy link
Member

mikdusan commented Jan 2, 2023

looks like no more .rodata in function:

$ zig version
0.11.0-dev.1026+4172c2916

$ zig build-obj bug1.zig

$ objdump -M intel -d bug1.o | sed -n '/<tuple>/,/^$/p'
0000000000000000 <tuple>:
   0:	55                   	push   rbp
   1:	48 89 e5             	mov    rbp,rsp
   4:	48 83 ec 18          	sub    rsp,0x18
   8:	48 89 7d e8          	mov    QWORD PTR [rbp-0x18],rdi
   c:	48 89 7d f0          	mov    QWORD PTR [rbp-0x10],rdi
  10:	48 8b 45 f0          	mov    rax,QWORD PTR [rbp-0x10]
  14:	48 89 45 f8          	mov    QWORD PTR [rbp-0x8],rax
  18:	48 83 c4 18          	add    rsp,0x18
  1c:	5d                   	pop    rbp
  1d:	c3                   	ret
  1e:	66 90                	xchg   ax,ax

@mikdusan mikdusan closed this as completed Jan 2, 2023
@andrewrk andrewrk modified the milestones: 0.12.0, 0.11.0 Jan 3, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Observed behavior contradicts documented or intended behavior stage1 The process of building from source via WebAssembly and the C backend.
Projects
None yet
Development

No branches or pull requests

5 participants