Skip to content

slicing with comptime start and end indexes results in pointer-to-array #4752

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

Merged
merged 20 commits into from
Mar 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
2182d28
slicing with comptime start and end results in array
andrewrk Mar 16, 2020
0707be8
fixes in semantic analysis needed to support this feature
andrewrk Mar 17, 2020
c896c50
fix slice of string literal having the wrong type
andrewrk Mar 17, 2020
8d0ac6d
`@ptrCast` supports casting a slice to pointer
andrewrk Mar 17, 2020
8ea0a00
improve std lib code for the new semantics
andrewrk Mar 17, 2020
2b41344
fix alignment when slicing with comptime start and end index
andrewrk Mar 17, 2020
4435b05
fix regression when slicing 0-bit pointers
andrewrk Mar 18, 2020
72a261b
fix runtime slice of pointer not setting length
andrewrk Mar 18, 2020
e947f0c
0-bit array type does not resolve child type
andrewrk Mar 18, 2020
8688c43
when result loc is a slice, avoid evaluating lazy start..end
andrewrk Mar 18, 2020
2164b51
partial revert of an improvement this branch made
andrewrk Mar 18, 2020
b5dba70
fixes to std.meta
andrewrk Mar 18, 2020
7fa88cc
std lib fixups for new semantics
andrewrk Mar 19, 2020
61266d2
test & docs fixups to work with new semantics
andrewrk Mar 19, 2020
f824658
slicing sentinel-terminated slice without end
andrewrk Mar 19, 2020
8ddf9d8
add behavior tests for slicing with comptime indexes
andrewrk Mar 19, 2020
1d7861a
fix incorrect sentinel check
andrewrk Mar 19, 2020
f614d94
update std lib to take advantage of slicing with comptime indexes
andrewrk Mar 19, 2020
6b6f2fc
std.net: remove the hack from earlier in the branch
andrewrk Mar 19, 2020
160367e
fix compile error for reading past end of pointer casted array
andrewrk Mar 19, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 16 additions & 20 deletions doc/langref.html.in
Original file line number Diff line number Diff line change
Expand Up @@ -2093,8 +2093,9 @@ var foo: u8 align(4) = 100;
test "global variable alignment" {
assert(@TypeOf(&foo).alignment == 4);
assert(@TypeOf(&foo) == *align(4) u8);
const slice = @as(*[1]u8, &foo)[0..];
assert(@TypeOf(slice) == []align(4) u8);
const as_pointer_to_array: *[1]u8 = &foo;
const as_slice: []u8 = as_pointer_to_array;
assert(@TypeOf(as_slice) == []align(4) u8);
}

fn derp() align(@sizeOf(usize) * 2) i32 { return 1234; }
Expand Down Expand Up @@ -2187,7 +2188,8 @@ test "basic slices" {
// a slice is that the array's length is part of the type and known at
// compile-time, whereas the slice's length is known at runtime.
// Both can be accessed with the `len` field.
const slice = array[0..array.len];
var known_at_runtime_zero: usize = 0;
const slice = array[known_at_runtime_zero..array.len];
assert(&slice[0] == &array[0]);
assert(slice.len == array.len);

Expand All @@ -2207,13 +2209,15 @@ test "basic slices" {
{#code_end#}
<p>This is one reason we prefer slices to pointers.</p>
{#code_begin|test|slices#}
const assert = @import("std").debug.assert;
const mem = @import("std").mem;
const fmt = @import("std").fmt;
const std = @import("std");
const assert = std.debug.assert;
const mem = std.mem;
const fmt = std.fmt;

test "using slices for strings" {
// Zig has no concept of strings. String literals are arrays of u8, and
// in general the string type is []u8 (slice of u8).
// Zig has no concept of strings. String literals are const pointers to
// arrays of u8, and by convention parameters that are "strings" are
// expected to be UTF-8 encoded slices of u8.
// Here we coerce [5]u8 to []const u8
const hello: []const u8 = "hello";
const world: []const u8 = "世界";
Expand All @@ -2222,7 +2226,7 @@ test "using slices for strings" {
// You can use slice syntax on an array to convert an array into a slice.
const all_together_slice = all_together[0..];
// String concatenation example.
const hello_world = try fmt.bufPrint(all_together_slice, "{} {}", .{hello, world});
const hello_world = try fmt.bufPrint(all_together_slice, "{} {}", .{ hello, world });

// Generally, you can use UTF-8 and not worry about whether something is a
// string. If you don't need to deal with individual characters, no need
Expand All @@ -2239,23 +2243,15 @@ test "slice pointer" {
slice[2] = 3;
assert(slice[2] == 3);
// The slice is mutable because we sliced a mutable pointer.
assert(@TypeOf(slice) == []u8);
// Furthermore, it is actually a pointer to an array, since the start
// and end indexes were both comptime-known.
assert(@TypeOf(slice) == *[5]u8);

// You can also slice a slice:
const slice2 = slice[2..3];
assert(slice2.len == 1);
assert(slice2[0] == 3);
}

test "slice widening" {
// Zig supports slice widening and slice narrowing. Cast a slice of u8
// to a slice of anything else, and Zig will perform the length conversion.
const array align(@alignOf(u32)) = [_]u8{ 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13 };
const slice = mem.bytesAsSlice(u32, array[0..]);
assert(slice.len == 2);
assert(slice[0] == 0x12121212);
assert(slice[1] == 0x13131313);
}
{#code_end#}
{#see_also|Pointers|for|Arrays#}

Expand Down
38 changes: 19 additions & 19 deletions lib/std/crypto/aes.zig
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ fn rotw(w: u32) u32 {

// Encrypt one block from src into dst, using the expanded key xk.
fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {
var s0 = mem.readIntSliceBig(u32, src[0..4]);
var s1 = mem.readIntSliceBig(u32, src[4..8]);
var s2 = mem.readIntSliceBig(u32, src[8..12]);
var s3 = mem.readIntSliceBig(u32, src[12..16]);
var s0 = mem.readIntBig(u32, src[0..4]);
var s1 = mem.readIntBig(u32, src[4..8]);
var s2 = mem.readIntBig(u32, src[8..12]);
var s3 = mem.readIntBig(u32, src[12..16]);

// First round just XORs input with key.
s0 ^= xk[0];
Expand Down Expand Up @@ -58,18 +58,18 @@ fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {
s2 ^= xk[k + 2];
s3 ^= xk[k + 3];

mem.writeIntSliceBig(u32, dst[0..4], s0);
mem.writeIntSliceBig(u32, dst[4..8], s1);
mem.writeIntSliceBig(u32, dst[8..12], s2);
mem.writeIntSliceBig(u32, dst[12..16], s3);
mem.writeIntBig(u32, dst[0..4], s0);
mem.writeIntBig(u32, dst[4..8], s1);
mem.writeIntBig(u32, dst[8..12], s2);
mem.writeIntBig(u32, dst[12..16], s3);
}

// Decrypt one block from src into dst, using the expanded key xk.
pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {
var s0 = mem.readIntSliceBig(u32, src[0..4]);
var s1 = mem.readIntSliceBig(u32, src[4..8]);
var s2 = mem.readIntSliceBig(u32, src[8..12]);
var s3 = mem.readIntSliceBig(u32, src[12..16]);
var s0 = mem.readIntBig(u32, src[0..4]);
var s1 = mem.readIntBig(u32, src[4..8]);
var s2 = mem.readIntBig(u32, src[8..12]);
var s3 = mem.readIntBig(u32, src[12..16]);

// First round just XORs input with key.
s0 ^= xk[0];
Expand Down Expand Up @@ -109,10 +109,10 @@ pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {
s2 ^= xk[k + 2];
s3 ^= xk[k + 3];

mem.writeIntSliceBig(u32, dst[0..4], s0);
mem.writeIntSliceBig(u32, dst[4..8], s1);
mem.writeIntSliceBig(u32, dst[8..12], s2);
mem.writeIntSliceBig(u32, dst[12..16], s3);
mem.writeIntBig(u32, dst[0..4], s0);
mem.writeIntBig(u32, dst[4..8], s1);
mem.writeIntBig(u32, dst[8..12], s2);
mem.writeIntBig(u32, dst[12..16], s3);
}

fn xorBytes(dst: []u8, a: []const u8, b: []const u8) usize {
Expand Down Expand Up @@ -154,8 +154,8 @@ fn AES(comptime keysize: usize) type {
var n: usize = 0;
while (n < src.len) {
ctx.encrypt(keystream[0..], ctrbuf[0..]);
var ctr_i = std.mem.readIntSliceBig(u128, ctrbuf[0..]);
std.mem.writeIntSliceBig(u128, ctrbuf[0..], ctr_i +% 1);
var ctr_i = std.mem.readIntBig(u128, ctrbuf[0..]);
std.mem.writeIntBig(u128, ctrbuf[0..], ctr_i +% 1);

n += xorBytes(dst[n..], src[n..], &keystream);
}
Expand Down Expand Up @@ -251,7 +251,7 @@ fn expandKey(key: []const u8, enc: []u32, dec: []u32) void {
var i: usize = 0;
var nk = key.len / 4;
while (i < nk) : (i += 1) {
enc[i] = mem.readIntSliceBig(u32, key[4 * i .. 4 * i + 4]);
enc[i] = mem.readIntBig(u32, key[4 * i ..][0..4]);
}
while (i < enc.len) : (i += 1) {
var t = enc[i - 1];
Expand Down
11 changes: 4 additions & 7 deletions lib/std/crypto/blake2.zig
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,7 @@ fn Blake2s(comptime out_len: usize) type {
const rr = d.h[0 .. out_len / 32];

for (rr) |s, j| {
// TODO https://github.com/ziglang/zig/issues/863
mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s);
mem.writeIntLittle(u32, out[4 * j ..][0..4], s);
}
}

Expand All @@ -135,8 +134,7 @@ fn Blake2s(comptime out_len: usize) type {
var v: [16]u32 = undefined;

for (m) |*r, i| {
// TODO https://github.com/ziglang/zig/issues/863
r.* = mem.readIntSliceLittle(u32, b[4 * i .. 4 * i + 4]);
r.* = mem.readIntLittle(u32, b[4 * i ..][0..4]);
}

var k: usize = 0;
Expand Down Expand Up @@ -358,8 +356,7 @@ fn Blake2b(comptime out_len: usize) type {
const rr = d.h[0 .. out_len / 64];

for (rr) |s, j| {
// TODO https://github.com/ziglang/zig/issues/863
mem.writeIntSliceLittle(u64, out[8 * j .. 8 * j + 8], s);
mem.writeIntLittle(u64, out[8 * j ..][0..8], s);
}
}

Expand All @@ -370,7 +367,7 @@ fn Blake2b(comptime out_len: usize) type {
var v: [16]u64 = undefined;

for (m) |*r, i| {
r.* = mem.readIntSliceLittle(u64, b[8 * i .. 8 * i + 8]);
r.* = mem.readIntLittle(u64, b[8 * i ..][0..8]);
}

var k: usize = 0;
Expand Down
61 changes: 30 additions & 31 deletions lib/std/crypto/chacha20.zig
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ fn salsa20_wordtobyte(out: []u8, input: [16]u32) void {
}

for (x) |_, i| {
// TODO https://github.com/ziglang/zig/issues/863
mem.writeIntSliceLittle(u32, out[4 * i .. 4 * i + 4], x[i] +% input[i]);
mem.writeIntLittle(u32, out[4 * i ..][0..4], x[i] +% input[i]);
}
}

Expand All @@ -73,10 +72,10 @@ fn chaCha20_internal(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) vo

const c = "expand 32-byte k";
const constant_le = [_]u32{
mem.readIntSliceLittle(u32, c[0..4]),
mem.readIntSliceLittle(u32, c[4..8]),
mem.readIntSliceLittle(u32, c[8..12]),
mem.readIntSliceLittle(u32, c[12..16]),
mem.readIntLittle(u32, c[0..4]),
mem.readIntLittle(u32, c[4..8]),
mem.readIntLittle(u32, c[8..12]),
mem.readIntLittle(u32, c[12..16]),
};

mem.copy(u32, ctx[0..], constant_le[0..4]);
Expand Down Expand Up @@ -120,19 +119,19 @@ pub fn chaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce:
var k: [8]u32 = undefined;
var c: [4]u32 = undefined;

k[0] = mem.readIntSliceLittle(u32, key[0..4]);
k[1] = mem.readIntSliceLittle(u32, key[4..8]);
k[2] = mem.readIntSliceLittle(u32, key[8..12]);
k[3] = mem.readIntSliceLittle(u32, key[12..16]);
k[4] = mem.readIntSliceLittle(u32, key[16..20]);
k[5] = mem.readIntSliceLittle(u32, key[20..24]);
k[6] = mem.readIntSliceLittle(u32, key[24..28]);
k[7] = mem.readIntSliceLittle(u32, key[28..32]);
k[0] = mem.readIntLittle(u32, key[0..4]);
k[1] = mem.readIntLittle(u32, key[4..8]);
k[2] = mem.readIntLittle(u32, key[8..12]);
k[3] = mem.readIntLittle(u32, key[12..16]);
k[4] = mem.readIntLittle(u32, key[16..20]);
k[5] = mem.readIntLittle(u32, key[20..24]);
k[6] = mem.readIntLittle(u32, key[24..28]);
k[7] = mem.readIntLittle(u32, key[28..32]);

c[0] = counter;
c[1] = mem.readIntSliceLittle(u32, nonce[0..4]);
c[2] = mem.readIntSliceLittle(u32, nonce[4..8]);
c[3] = mem.readIntSliceLittle(u32, nonce[8..12]);
c[1] = mem.readIntLittle(u32, nonce[0..4]);
c[2] = mem.readIntLittle(u32, nonce[4..8]);
c[3] = mem.readIntLittle(u32, nonce[8..12]);
chaCha20_internal(out, in, k, c);
}

Expand All @@ -147,19 +146,19 @@ pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32]
var k: [8]u32 = undefined;
var c: [4]u32 = undefined;

k[0] = mem.readIntSliceLittle(u32, key[0..4]);
k[1] = mem.readIntSliceLittle(u32, key[4..8]);
k[2] = mem.readIntSliceLittle(u32, key[8..12]);
k[3] = mem.readIntSliceLittle(u32, key[12..16]);
k[4] = mem.readIntSliceLittle(u32, key[16..20]);
k[5] = mem.readIntSliceLittle(u32, key[20..24]);
k[6] = mem.readIntSliceLittle(u32, key[24..28]);
k[7] = mem.readIntSliceLittle(u32, key[28..32]);
k[0] = mem.readIntLittle(u32, key[0..4]);
k[1] = mem.readIntLittle(u32, key[4..8]);
k[2] = mem.readIntLittle(u32, key[8..12]);
k[3] = mem.readIntLittle(u32, key[12..16]);
k[4] = mem.readIntLittle(u32, key[16..20]);
k[5] = mem.readIntLittle(u32, key[20..24]);
k[6] = mem.readIntLittle(u32, key[24..28]);
k[7] = mem.readIntLittle(u32, key[28..32]);

c[0] = @truncate(u32, counter);
c[1] = @truncate(u32, counter >> 32);
c[2] = mem.readIntSliceLittle(u32, nonce[0..4]);
c[3] = mem.readIntSliceLittle(u32, nonce[4..8]);
c[2] = mem.readIntLittle(u32, nonce[0..4]);
c[3] = mem.readIntLittle(u32, nonce[4..8]);

const block_size = (1 << 6);
// The full block size is greater than the address space on a 32bit machine
Expand Down Expand Up @@ -463,8 +462,8 @@ pub fn chacha20poly1305Seal(dst: []u8, plaintext: []const u8, data: []const u8,
mac.update(zeros[0..padding]);
}
var lens: [16]u8 = undefined;
mem.writeIntSliceLittle(u64, lens[0..8], data.len);
mem.writeIntSliceLittle(u64, lens[8..16], plaintext.len);
mem.writeIntLittle(u64, lens[0..8], data.len);
mem.writeIntLittle(u64, lens[8..16], plaintext.len);
mac.update(lens[0..]);
mac.final(dst[plaintext.len..]);
}
Expand Down Expand Up @@ -500,8 +499,8 @@ pub fn chacha20poly1305Open(dst: []u8, msgAndTag: []const u8, data: []const u8,
mac.update(zeros[0..padding]);
}
var lens: [16]u8 = undefined;
mem.writeIntSliceLittle(u64, lens[0..8], data.len);
mem.writeIntSliceLittle(u64, lens[8..16], ciphertext.len);
mem.writeIntLittle(u64, lens[0..8], data.len);
mem.writeIntLittle(u64, lens[8..16], ciphertext.len);
mac.update(lens[0..]);
var computedTag: [16]u8 = undefined;
mac.final(computedTag[0..]);
Expand Down
3 changes: 1 addition & 2 deletions lib/std/crypto/md5.zig
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,7 @@ pub const Md5 = struct {
d.round(d.buf[0..]);

for (d.s) |s, j| {
// TODO https://github.com/ziglang/zig/issues/863
mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s);
mem.writeIntLittle(u32, out[4 * j ..][0..4], s);
}
}

Expand Down
29 changes: 14 additions & 15 deletions lib/std/crypto/poly1305.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
// https://monocypher.org/

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

const Endian = builtin.Endian;
const readIntSliceLittle = std.mem.readIntSliceLittle;
const writeIntSliceLittle = std.mem.writeIntSliceLittle;
const readIntLittle = std.mem.readIntLittle;
const writeIntLittle = std.mem.writeIntLittle;

pub const Poly1305 = struct {
const Self = @This();
Expand Down Expand Up @@ -59,19 +59,19 @@ pub const Poly1305 = struct {
{
var i: usize = 0;
while (i < 1) : (i += 1) {
ctx.r[0] = readIntSliceLittle(u32, key[0..4]) & 0x0fffffff;
ctx.r[0] = readIntLittle(u32, key[0..4]) & 0x0fffffff;
}
}
{
var i: usize = 1;
while (i < 4) : (i += 1) {
ctx.r[i] = readIntSliceLittle(u32, key[i * 4 .. i * 4 + 4]) & 0x0ffffffc;
ctx.r[i] = readIntLittle(u32, key[i * 4 ..][0..4]) & 0x0ffffffc;
}
}
{
var i: usize = 0;
while (i < 4) : (i += 1) {
ctx.pad[i] = readIntSliceLittle(u32, key[i * 4 + 16 .. i * 4 + 16 + 4]);
ctx.pad[i] = readIntLittle(u32, key[i * 4 + 16 ..][0..4]);
}
}

Expand Down Expand Up @@ -168,10 +168,10 @@ pub const Poly1305 = struct {
const nb_blocks = nmsg.len >> 4;
var i: usize = 0;
while (i < nb_blocks) : (i += 1) {
ctx.c[0] = readIntSliceLittle(u32, nmsg[0..4]);
ctx.c[1] = readIntSliceLittle(u32, nmsg[4..8]);
ctx.c[2] = readIntSliceLittle(u32, nmsg[8..12]);
ctx.c[3] = readIntSliceLittle(u32, nmsg[12..16]);
ctx.c[0] = readIntLittle(u32, nmsg[0..4]);
ctx.c[1] = readIntLittle(u32, nmsg[4..8]);
ctx.c[2] = readIntLittle(u32, nmsg[8..12]);
ctx.c[3] = readIntLittle(u32, nmsg[12..16]);
polyBlock(ctx);
nmsg = nmsg[16..];
}
Expand Down Expand Up @@ -210,11 +210,10 @@ pub const Poly1305 = struct {
const uu2 = (uu1 >> 32) + ctx.h[2] + ctx.pad[2]; // <= 2_00000000
const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000

// TODO https://github.com/ziglang/zig/issues/863
writeIntSliceLittle(u32, out[0..], @truncate(u32, uu0));
writeIntSliceLittle(u32, out[4..], @truncate(u32, uu1));
writeIntSliceLittle(u32, out[8..], @truncate(u32, uu2));
writeIntSliceLittle(u32, out[12..], @truncate(u32, uu3));
writeIntLittle(u32, out[0..4], @truncate(u32, uu0));
writeIntLittle(u32, out[4..8], @truncate(u32, uu1));
writeIntLittle(u32, out[8..12], @truncate(u32, uu2));
writeIntLittle(u32, out[12..16], @truncate(u32, uu3));

ctx.secureZero();
}
Expand Down
3 changes: 1 addition & 2 deletions lib/std/crypto/sha1.zig
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,7 @@ pub const Sha1 = struct {
d.round(d.buf[0..]);

for (d.s) |s, j| {
// TODO https://github.com/ziglang/zig/issues/863
mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s);
mem.writeIntBig(u32, out[4 * j ..][0..4], s);
}
}

Expand Down
Loading