ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
34.8k stars 2.54k forks source link

advanced control flow analysis: compile error for returning slice of local array from function #506

Open ghost opened 7 years ago

ghost commented 7 years ago
const io = @import("std").io;

fn array(comptime T: type, a: []const T) {
    for (a) |v| {
        %%io.stdout.printf("{} ", v);
    }
    %%io.stdout.printf("\n");
}

fn right_encode(n: u64) -> []u8 {
    var r = []u8{0} ** 9;
    var i: u8 = 8;
    var x: u64 = n;
    while (x > 0) : (x /= 256) {
        i -= 1;
        r[i] = @truncate(u8, x);
    }
    r[8] = 8 - i;
    //%%io.stdout.printf("\n");
    array(u8, r[i..]);
    return r[i..];
}

test "ok" {
    %%io.stdout.printf("\n");
    var r: []u8 = undefined;
    r = right_encode(12345678910111213);
    array(u8, r[0..]);
}
[root@archlinux ~]# zig test gg.zig
Test 1/1 ok...
43 220 84 93 242 189 237 7
43 220 84 93 242 189 0 0
OK
[root@archlinux ~]# zig test gg.zig --release-fast
Test 1/1 ok...
43 220 84 93 242 189 237 7
43 220 84 93 242 189 237 7
OK

if remove comment on line //%%io.stdout.printf("\n"); both mode works:

[root@archlinux ~]# zig test gg.zig
Test 1/1 ok...

43 220 84 93 242 189 237 7
43 220 84 93 242 189 237 7
OK
[root@archlinux ~]# zig test gg.zig --release-fast
Test 1/1 ok...

43 220 84 93 242 189 237 7
43 220 84 93 242 189 237 7
OK

Uptodate environment:

[root@archlinux ~]# uname -a
Linux archlinux 4.13.3-1-ARCH #1 SMP PREEMPT Thu Sep 21 20:33:16 CEST 2017 x86_64 GNU/Linux
[root@archlinux ~]# pacman -Q | egrep "zig|^ll"
lld 5.0.0-1
llvm 5.0.0-1
llvm-libs 5.0.0-1
zig-git 0.0.0r1678.3fe50cb1-1
thejoshwolfe commented 7 years ago

return r[i..];

This is undefined behavior, since r is a local variable array. The slice you're returning includes a pointer to your local variable, which goes out of scope when you return, which means the pointer becomes invalid.

andrewrk commented 7 years ago

Now the question is, is there something zig could have done to catch this at runtime? Is this #211 ? Edit: oops, no it's not #211.

andrewrk commented 7 years ago

We have a compile error if you directly return an address of a local variable, using the runtime value hint system. I think it can be expanded to work for this situation.

ghost commented 7 years ago

@thejoshwolfe How to rewrite code to be correct?

thejoshwolfe commented 7 years ago

How to rewrite code to be correct?

There are lots of places to put the array. The easiest one in my opinion is to make a local variable in the caller to right_encode and pass in a slice for right_encode to fill.

Or perhaps right_encode is going to be a method on an object that can keep its own buffer as a field. The best answer to this question depends on what's really going on in your software.

ghost commented 7 years ago

@thejoshwolfe Thanks, I will play around.