authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-04 11:58:31-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-04 11:58:31-04:00
logdbde8254d02241d893140cb499ad25e8cbb3438a
treeaf5be3723d32a378891fac4320e6a4b9a4edd674
parentf7f11e237c96a357e9a5e8b4a8ce2c6a7499de3b
parent2bd2a8ea3430b92f0c41d602d12982f776a9a524
signaturelock-open Commit is signed but in an unrecognized format.

Merge remote-tracking branch 'origin/master' into llvm7


62 files changed, 4721 insertions(+), 964 deletions(-)

CMakeLists.txt+6-2
...@@ -447,13 +447,17 @@ set(ZIG_STD_FILES...@@ -447,13 +447,17 @@ set(ZIG_STD_FILES
447 "c/index.zig"447 "c/index.zig"
448 "c/linux.zig"448 "c/linux.zig"
449 "c/windows.zig"449 "c/windows.zig"
450 "coff.zig"
450 "crypto/blake2.zig"451 "crypto/blake2.zig"
452 "crypto/chacha20.zig"
451 "crypto/hmac.zig"453 "crypto/hmac.zig"
452 "crypto/index.zig"454 "crypto/index.zig"
453 "crypto/md5.zig"455 "crypto/md5.zig"
454 "crypto/sha1.zig"456 "crypto/sha1.zig"
455 "crypto/sha2.zig"457 "crypto/sha2.zig"
456 "crypto/sha3.zig"458 "crypto/sha3.zig"
459 "crypto/poly1305.zig"
460 "crypto/x25519.zig"
457 "cstr.zig"461 "cstr.zig"
458 "debug/failing_allocator.zig"462 "debug/failing_allocator.zig"
459 "debug/index.zig"463 "debug/index.zig"
...@@ -579,12 +583,12 @@ set(ZIG_STD_FILES...@@ -579,12 +583,12 @@ set(ZIG_STD_FILES
579 "os/windows/error.zig"583 "os/windows/error.zig"
580 "os/windows/index.zig"584 "os/windows/index.zig"
581 "os/windows/kernel32.zig"585 "os/windows/kernel32.zig"
586 "os/windows/ntdll.zig"
582 "os/windows/ole32.zig"587 "os/windows/ole32.zig"
583 "os/windows/shell32.zig"588 "os/windows/shell32.zig"
584 "os/windows/shlwapi.zig"
585 "os/windows/user32.zig"
586 "os/windows/util.zig"589 "os/windows/util.zig"
587 "os/zen.zig"590 "os/zen.zig"
591 "pdb.zig"
588 "rand/index.zig"592 "rand/index.zig"
589 "rand/ziggurat.zig"593 "rand/ziggurat.zig"
590 "segmented_list.zig"594 "segmented_list.zig"
doc/docgen.zig+2-2
...@@ -40,11 +40,11 @@ pub fn main() !void {...@@ -40,11 +40,11 @@ pub fn main() !void {
40 var out_file = try os.File.openWrite(out_file_name);40 var out_file = try os.File.openWrite(out_file_name);
41 defer out_file.close();41 defer out_file.close();
4242
43 var file_in_stream = io.FileInStream.init(&in_file);43 var file_in_stream = io.FileInStream.init(in_file);
4444
45 const input_file_bytes = try file_in_stream.stream.readAllAlloc(allocator, max_doc_file_size);45 const input_file_bytes = try file_in_stream.stream.readAllAlloc(allocator, max_doc_file_size);
4646
47 var file_out_stream = io.FileOutStream.init(&out_file);47 var file_out_stream = io.FileOutStream.init(out_file);
48 var buffered_out_stream = io.BufferedOutStream(io.FileOutStream.Error).init(&file_out_stream.stream);48 var buffered_out_stream = io.BufferedOutStream(io.FileOutStream.Error).init(&file_out_stream.stream);
4949
50 var tokenizer = Tokenizer.init(in_file_name, input_file_bytes);50 var tokenizer = Tokenizer.init(in_file_name, input_file_bytes);
doc/langref.html.in+170-2
...@@ -566,7 +566,7 @@ const c_string_literal =...@@ -566,7 +566,7 @@ const c_string_literal =
566 {#header_close#}566 {#header_close#}
567 {#header_close#}567 {#header_close#}
568 {#header_open|Assignment#}568 {#header_open|Assignment#}
569 <p>Use <code>const</code> to assign a value to an identifier:</p>569 <p>Use the <code>const</code> keyword to assign a value to an identifier:</p>
570 {#code_begin|test_err|cannot assign to constant#}570 {#code_begin|test_err|cannot assign to constant#}
571const x = 1234;571const x = 1234;
572572
...@@ -582,7 +582,8 @@ test "assignment" {...@@ -582,7 +582,8 @@ test "assignment" {
582 foo();582 foo();
583}583}
584 {#code_end#}584 {#code_end#}
585 <p>If you need a variable that you can modify, use <code>var</code>:</p>585 <p><code>const</code> applies to all of the bytes that the identifier immediately addresses. {#link|Pointers#} have their own const-ness.</p>
586 <p>If you need a variable that you can modify, use the <code>var</code> keyword:</p>
586 {#code_begin|test#}587 {#code_begin|test#}
587const assert = @import("std").debug.assert;588const assert = @import("std").debug.assert;
588589
...@@ -1918,6 +1919,32 @@ test "linked list" {...@@ -1918,6 +1919,32 @@ test "linked list" {
1918 assert(list2.first.?.data == 1234);1919 assert(list2.first.?.data == 1234);
1919}1920}
1920 {#code_end#}1921 {#code_end#}
1922 {#header_open|struct Naming#}
1923 <p>Since all structs are anonymous, Zig infers the type name based on a few rules.</p>
1924 <ul>
1925 <li>If the struct is in the initialization expression of a variable, it gets named after
1926 that variable.</li>
1927 <li>If the struct is in the <code>return</code> expression, it gets named after
1928 the function it is returning from, with the parameter values serialized.</li>
1929 <li>Otherwise, the struct gets a same such as <code>(anonymous struct at file.zig:7:38)</code>.</li>
1930 </ul>
1931 {#code_begin|exe|struct_name#}
1932const std = @import("std");
1933
1934pub fn main() void {
1935 const Foo = struct {};
1936 std.debug.warn("variable: {}\n", @typeName(Foo));
1937 std.debug.warn("anonymous: {}\n", @typeName(struct {}));
1938 std.debug.warn("function: {}\n", @typeName(List(i32)));
1939}
1940
1941fn List(comptime T: type) type {
1942 return struct {
1943 x: T,
1944 };
1945}
1946 {#code_end#}
1947 {#header_close#}
1921 {#see_also|comptime|@fieldParentPtr#}1948 {#see_also|comptime|@fieldParentPtr#}
1922 {#header_close#}1949 {#header_close#}
1923 {#header_open|enum#}1950 {#header_open|enum#}
...@@ -2179,6 +2206,39 @@ test "@tagName" {...@@ -2179,6 +2206,39 @@ test "@tagName" {
2179 sorts the order of the tag and union field by the largest alignment.2206 sorts the order of the tag and union field by the largest alignment.
2180 </p>2207 </p>
2181 {#header_close#}2208 {#header_close#}
2209 {#header_open|blocks#}
2210 <p>
2211 Blocks are used to limit the scope of variable declarations:
2212 </p>
2213 {#code_begin|test_err|undeclared identifier#}
2214test "access variable after block scope" {
2215 {
2216 var x: i32 = 1;
2217 }
2218 x += 1;
2219}
2220 {#code_end#}
2221 <p>Blocks are expressions. When labeled, <code>break</code> can be used
2222 to return a value from the block:
2223 </p>
2224 {#code_begin|test#}
2225const std = @import("std");
2226const assert = std.debug.assert;
2227
2228test "labeled break from labeled block expression" {
2229 var y: i32 = 123;
2230
2231 const x = blk: {
2232 y += 1;
2233 break :blk y;
2234 };
2235 assert(x == 124);
2236 assert(y == 124);
2237}
2238 {#code_end#}
2239 <p>Here, <code>blk</code> can be any name.</p>
2240 {#see_also|Labeled while|Labeled for#}
2241 {#header_close#}
2182 {#header_open|switch#}2242 {#header_open|switch#}
2183 {#code_begin|test|switch#}2243 {#code_begin|test|switch#}
2184const assert = @import("std").debug.assert;2244const assert = @import("std").debug.assert;
...@@ -2374,6 +2434,28 @@ fn rangeHasNumber(begin: usize, end: usize, number: usize) bool {...@@ -2374,6 +2434,28 @@ fn rangeHasNumber(begin: usize, end: usize, number: usize) bool {
2374 } else false;2434 } else false;
2375}2435}
2376 {#code_end#}2436 {#code_end#}
2437 {#header_open|Labeled while#}
2438 <p>When a <code>while</code> loop is labeled, it can be referenced from a <code>break</code>
2439 or <code>continue</code> from within a nested loop:</p>
2440 {#code_begin|test#}
2441test "nested break" {
2442 outer: while (true) {
2443 while (true) {
2444 break :outer;
2445 }
2446 }
2447}
2448
2449test "nested continue" {
2450 var i: usize = 0;
2451 outer: while (i < 10) : (i += 1) {
2452 while (true) {
2453 continue :outer;
2454 }
2455 }
2456}
2457 {#code_end#}
2458 {#header_close#}
2377 {#header_open|while with Optionals#}2459 {#header_open|while with Optionals#}
2378 <p>2460 <p>
2379 Just like {#link|if#} expressions, while loops can take an optional as the2461 Just like {#link|if#} expressions, while loops can take an optional as the
...@@ -2560,6 +2642,37 @@ test "for else" {...@@ -2560,6 +2642,37 @@ test "for else" {
2560 };2642 };
2561}2643}
2562 {#code_end#}2644 {#code_end#}
2645 {#header_open|Labeled for#}
2646 <p>When a <code>for</code> loop is labeled, it can be referenced from a <code>break</code>
2647 or <code>continue</code> from within a nested loop:</p>
2648 {#code_begin|test#}
2649const std = @import("std");
2650const assert = std.debug.assert;
2651
2652test "nested break" {
2653 var count: usize = 0;
2654 outer: for ([]i32{ 1, 2, 3, 4, 5 }) |_| {
2655 for ([]i32{ 1, 2, 3, 4, 5 }) |_| {
2656 count += 1;
2657 break :outer;
2658 }
2659 }
2660 assert(count == 1);
2661}
2662
2663test "nested continue" {
2664 var count: usize = 0;
2665 outer: for ([]i32{ 1, 2, 3, 4, 5, 6, 7, 8 }) |_| {
2666 for ([]i32{ 1, 2, 3, 4, 5 }) |_| {
2667 count += 1;
2668 continue :outer;
2669 }
2670 }
2671
2672 assert(count == 8);
2673}
2674 {#code_end#}
2675 {#header_close#}
2563 {#header_open|inline for#}2676 {#header_open|inline for#}
2564 <p>2677 <p>
2565 For loops can be inlined. This causes the loop to be unrolled, which2678 For loops can be inlined. This causes the loop to be unrolled, which
...@@ -7057,6 +7170,61 @@ const c = @cImport({...@@ -7057,6 +7170,61 @@ const c = @cImport({
7057});7170});
7058 {#code_end#}7171 {#code_end#}
7059 {#see_also|@cImport|@cInclude|@cDefine|@cUndef|@import#}7172 {#see_also|@cImport|@cInclude|@cDefine|@cUndef|@import#}
7173 {#header_close#}
7174 {#header_open|Exporting a C Library#}
7175 <p>
7176 One of the primary use cases for Zig is exporting a library with the C ABI for other programming languages
7177 to call into. The <code>export</code> keyword in front of functions, variables, and types causes them to
7178 be part of the library API:
7179 </p>
7180 <p class="file">mathtest.zig</p>
7181 {#code_begin|syntax#}
7182export fn add(a: i32, b: i32) i32 {
7183 return a + b;
7184}
7185 {#code_end#}
7186 <p>To make a shared library:</p>
7187 <pre><code class="shell">$ zig build-lib mathtest.zig
7188</code></pre>
7189 <p>To make a static library:</p>
7190 <pre><code class="shell">$ zig build-lib mathtest.zig --static
7191</code></pre>
7192 <p>Here is an example with the {#link|Zig Build System#}:</p>
7193 <p class="file">test.c</p>
7194 <pre><code class="cpp">// This header is generated by zig from mathtest.zig
7195#include "mathtest.h"
7196#include &lt;assert.h&gt;
7197
7198int main(int argc, char **argv) {
7199 assert(add(42, 1337) == 1379);
7200 return 0;
7201}</code></pre>
7202 <p class="file">build.zig</p>
7203 {#code_begin|syntax#}
7204const Builder = @import("std").build.Builder;
7205
7206pub fn build(b: *Builder) void {
7207 const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
7208
7209 const exe = b.addCExecutable("test");
7210 exe.addCompileFlags([][]const u8{"-std=c99"});
7211 exe.addSourceFile("test.c");
7212 exe.linkLibrary(lib);
7213
7214 b.default_step.dependOn(&exe.step);
7215
7216 const run_cmd = b.addCommand(".", b.env_map, [][]const u8{exe.getOutputPath()});
7217 run_cmd.step.dependOn(&exe.step);
7218
7219 const test_step = b.step("test", "Test the program");
7220 test_step.dependOn(&run_cmd.step);
7221}
7222 {#code_end#}
7223 <p class="file">terminal</p>
7224 <pre><code class="shell">$ zig build
7225$ ./test
7226$ echo $?
72270</code></pre>
7060 {#header_close#}7228 {#header_close#}
7061 {#header_open|Mixing Object Files#}7229 {#header_open|Mixing Object Files#}
7062 <p>7230 <p>
example/guess_number/main.zig+1-1
...@@ -6,7 +6,7 @@ const os = std.os;...@@ -6,7 +6,7 @@ const os = std.os;
66
7pub fn main() !void {7pub fn main() !void {
8 var stdout_file = try io.getStdOut();8 var stdout_file = try io.getStdOut();
9 var stdout_file_stream = io.FileOutStream.init(&stdout_file);9 var stdout_file_stream = io.FileOutStream.init(stdout_file);
10 const stdout = &stdout_file_stream.stream;10 const stdout = &stdout_file_stream.stream;
1111
12 try stdout.print("Welcome to the Guess Number Game in Zig.\n");12 try stdout.print("Welcome to the Guess Number Game in Zig.\n");
src-self-hosted/errmsg.zig+1-1
...@@ -272,7 +272,7 @@ pub const Msg = struct {...@@ -272,7 +272,7 @@ pub const Msg = struct {
272 try stream.write("\n");272 try stream.write("\n");
273 }273 }
274274
275 pub fn printToFile(msg: *const Msg, file: *os.File, color: Color) !void {275 pub fn printToFile(msg: *const Msg, file: os.File, color: Color) !void {
276 const color_on = switch (color) {276 const color_on = switch (color) {
277 Color.Auto => file.isTty(),277 Color.Auto => file.isTty(),
278 Color.On => true,278 Color.On => true,
src-self-hosted/main.zig+6-6
...@@ -55,11 +55,11 @@ pub fn main() !void {...@@ -55,11 +55,11 @@ pub fn main() !void {
55 const allocator = std.heap.c_allocator;55 const allocator = std.heap.c_allocator;
5656
57 var stdout_file = try std.io.getStdOut();57 var stdout_file = try std.io.getStdOut();
58 var stdout_out_stream = std.io.FileOutStream.init(&stdout_file);58 var stdout_out_stream = std.io.FileOutStream.init(stdout_file);
59 stdout = &stdout_out_stream.stream;59 stdout = &stdout_out_stream.stream;
6060
61 stderr_file = try std.io.getStdErr();61 stderr_file = try std.io.getStdErr();
62 var stderr_out_stream = std.io.FileOutStream.init(&stderr_file);62 var stderr_out_stream = std.io.FileOutStream.init(stderr_file);
63 stderr = &stderr_out_stream.stream;63 stderr = &stderr_out_stream.stream;
6464
65 const args = try os.argsAlloc(allocator);65 const args = try os.argsAlloc(allocator);
...@@ -491,7 +491,7 @@ async fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void {...@@ -491,7 +491,7 @@ async fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void {
491 stderr.print("Build {} compile errors:\n", count) catch os.exit(1);491 stderr.print("Build {} compile errors:\n", count) catch os.exit(1);
492 for (msgs) |msg| {492 for (msgs) |msg| {
493 defer msg.destroy();493 defer msg.destroy();
494 msg.printToFile(&stderr_file, color) catch os.exit(1);494 msg.printToFile(stderr_file, color) catch os.exit(1);
495 }495 }
496 },496 },
497 }497 }
...@@ -619,7 +619,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {...@@ -619,7 +619,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
619 }619 }
620620
621 var stdin_file = try io.getStdIn();621 var stdin_file = try io.getStdIn();
622 var stdin = io.FileInStream.init(&stdin_file);622 var stdin = io.FileInStream.init(stdin_file);
623623
624 const source_code = try stdin.stream.readAllAlloc(allocator, max_src_size);624 const source_code = try stdin.stream.readAllAlloc(allocator, max_src_size);
625 defer allocator.free(source_code);625 defer allocator.free(source_code);
...@@ -635,7 +635,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {...@@ -635,7 +635,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
635 const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, &tree, "<stdin>");635 const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, &tree, "<stdin>");
636 defer msg.destroy();636 defer msg.destroy();
637637
638 try msg.printToFile(&stderr_file, color);638 try msg.printToFile(stderr_file, color);
639 }639 }
640 if (tree.errors.len != 0) {640 if (tree.errors.len != 0) {
641 os.exit(1);641 os.exit(1);
...@@ -772,7 +772,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8) FmtError!void {...@@ -772,7 +772,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8) FmtError!void {
772 const msg = try errmsg.Msg.createFromParseError(fmt.loop.allocator, parse_error, &tree, file_path);772 const msg = try errmsg.Msg.createFromParseError(fmt.loop.allocator, parse_error, &tree, file_path);
773 defer fmt.loop.allocator.destroy(msg);773 defer fmt.loop.allocator.destroy(msg);
774774
775 try msg.printToFile(&stderr_file, fmt.color);775 try msg.printToFile(stderr_file, fmt.color);
776 }776 }
777 if (tree.errors.len != 0) {777 if (tree.errors.len != 0) {
778 fmt.any_error = true;778 fmt.any_error = true;
src-self-hosted/test.zig+2-2
...@@ -185,7 +185,7 @@ pub const TestContext = struct {...@@ -185,7 +185,7 @@ pub const TestContext = struct {
185 try stderr.write("build incorrectly failed:\n");185 try stderr.write("build incorrectly failed:\n");
186 for (msgs) |msg| {186 for (msgs) |msg| {
187 defer msg.destroy();187 defer msg.destroy();
188 try msg.printToFile(&stderr, errmsg.Color.Auto);188 try msg.printToFile(stderr, errmsg.Color.Auto);
189 }189 }
190 },190 },
191 }191 }
...@@ -234,7 +234,7 @@ pub const TestContext = struct {...@@ -234,7 +234,7 @@ pub const TestContext = struct {
234 var stderr = try std.io.getStdErr();234 var stderr = try std.io.getStdErr();
235 for (msgs) |msg| {235 for (msgs) |msg| {
236 defer msg.destroy();236 defer msg.destroy();
237 try msg.printToFile(&stderr, errmsg.Color.Auto);237 try msg.printToFile(stderr, errmsg.Color.Auto);
238 }238 }
239 std.debug.warn("============\n");239 std.debug.warn("============\n");
240 return error.TestFailed;240 return error.TestFailed;
src/all_types.hpp+6
...@@ -43,6 +43,7 @@ struct IrAnalyze;...@@ -43,6 +43,7 @@ struct IrAnalyze;
43struct IrExecutable {43struct IrExecutable {
44 ZigList<IrBasicBlock *> basic_block_list;44 ZigList<IrBasicBlock *> basic_block_list;
45 Buf *name;45 Buf *name;
46 FnTableEntry *name_fn;
46 size_t mem_slot_count;47 size_t mem_slot_count;
47 size_t next_debug_id;48 size_t next_debug_id;
48 size_t *backward_branch_count;49 size_t *backward_branch_count;
...@@ -1805,6 +1806,11 @@ struct VariableTableEntry {...@@ -1805,6 +1806,11 @@ struct VariableTableEntry {
1805 VarLinkage linkage;1806 VarLinkage linkage;
1806 IrInstruction *decl_instruction;1807 IrInstruction *decl_instruction;
1807 uint32_t align_bytes;1808 uint32_t align_bytes;
1809
1810 // In an inline loop, multiple variables may be created,
1811 // In this case, a reference to a variable should follow
1812 // this pointer to the redefined variable.
1813 VariableTableEntry *next_var;
1808};1814};
18091815
1810struct ErrorTableEntry {1816struct ErrorTableEntry {
src/analyze.cpp+13-11
...@@ -1575,7 +1575,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c...@@ -1575,7 +1575,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
15751575
1576 switch (type_entry->id) {1576 switch (type_entry->id) {
1577 case TypeTableEntryIdInvalid:1577 case TypeTableEntryIdInvalid:
1578 return g->builtin_types.entry_invalid;1578 zig_unreachable();
1579 case TypeTableEntryIdUnreachable:1579 case TypeTableEntryIdUnreachable:
1580 case TypeTableEntryIdUndefined:1580 case TypeTableEntryIdUndefined:
1581 case TypeTableEntryIdNull:1581 case TypeTableEntryIdNull:
...@@ -1680,14 +1680,6 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c...@@ -1680,14 +1680,6 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
1680 case TypeTableEntryIdBlock:1680 case TypeTableEntryIdBlock:
1681 case TypeTableEntryIdBoundFn:1681 case TypeTableEntryIdBoundFn:
1682 case TypeTableEntryIdMetaType:1682 case TypeTableEntryIdMetaType:
1683 if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
1684 add_node_error(g, fn_proto->return_type,
1685 buf_sprintf("return type '%s' not allowed in function with calling convention '%s'",
1686 buf_ptr(&fn_type_id.return_type->name),
1687 calling_convention_name(fn_type_id.cc)));
1688 return g->builtin_types.entry_invalid;
1689 }
1690 return get_generic_fn_type(g, &fn_type_id);
1691 case TypeTableEntryIdUnreachable:1683 case TypeTableEntryIdUnreachable:
1692 case TypeTableEntryIdVoid:1684 case TypeTableEntryIdVoid:
1693 case TypeTableEntryIdBool:1685 case TypeTableEntryIdBool:
...@@ -1703,6 +1695,11 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c...@@ -1703,6 +1695,11 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
1703 case TypeTableEntryIdUnion:1695 case TypeTableEntryIdUnion:
1704 case TypeTableEntryIdFn:1696 case TypeTableEntryIdFn:
1705 case TypeTableEntryIdPromise:1697 case TypeTableEntryIdPromise:
1698 if ((err = type_ensure_zero_bits_known(g, fn_type_id.return_type)))
1699 return g->builtin_types.entry_invalid;
1700 if (type_requires_comptime(fn_type_id.return_type)) {
1701 return get_generic_fn_type(g, &fn_type_id);
1702 }
1706 break;1703 break;
1707 }1704 }
17081705
...@@ -3245,6 +3242,13 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) {...@@ -3245,6 +3242,13 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) {
3245 } else if (tld->id == TldIdFn) {3242 } else if (tld->id == TldIdFn) {
3246 assert(tld->source_node->type == NodeTypeFnProto);3243 assert(tld->source_node->type == NodeTypeFnProto);
3247 is_export = tld->source_node->data.fn_proto.is_export;3244 is_export = tld->source_node->data.fn_proto.is_export;
3245
3246 if (!is_export && !tld->source_node->data.fn_proto.is_extern &&
3247 tld->source_node->data.fn_proto.fn_def_node == nullptr)
3248 {
3249 add_node_error(g, tld->source_node, buf_sprintf("non-extern function has no body"));
3250 return;
3251 }
3248 }3252 }
3249 if (is_export) {3253 if (is_export) {
3250 g->resolve_queue.append(tld);3254 g->resolve_queue.append(tld);
...@@ -5620,8 +5624,6 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *...@@ -5620,8 +5624,6 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *
5620 if (type_entry->id == TypeTableEntryIdInt) {5624 if (type_entry->id == TypeTableEntryIdInt) {
5621 const_val->special = ConstValSpecialStatic;5625 const_val->special = ConstValSpecialStatic;
5622 eval_min_max_value_int(g, type_entry, &const_val->data.x_bigint, is_max);5626 eval_min_max_value_int(g, type_entry, &const_val->data.x_bigint, is_max);
5623 } else if (type_entry->id == TypeTableEntryIdFloat) {
5624 zig_panic("TODO analyze_min_max_value float");
5625 } else if (type_entry->id == TypeTableEntryIdBool) {5627 } else if (type_entry->id == TypeTableEntryIdBool) {
5626 const_val->special = ConstValSpecialStatic;5628 const_val->special = ConstValSpecialStatic;
5627 const_val->data.x_bool = is_max;5629 const_val->data.x_bool = is_max;
src/codegen.cpp+12-1
...@@ -2618,6 +2618,9 @@ static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable,...@@ -2618,6 +2618,9 @@ static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable,
2618 IrInstructionPtrCast *instruction)2618 IrInstructionPtrCast *instruction)
2619{2619{
2620 TypeTableEntry *wanted_type = instruction->base.value.type;2620 TypeTableEntry *wanted_type = instruction->base.value.type;
2621 if (!type_has_bits(wanted_type)) {
2622 return nullptr;
2623 }
2621 LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);2624 LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
2622 return LLVMBuildBitCast(g->builder, ptr, wanted_type->type_ref, "");2625 return LLVMBuildBitCast(g->builder, ptr, wanted_type->type_ref, "");
2623}2626}
...@@ -3036,6 +3039,12 @@ static void gen_set_stack_pointer(CodeGen *g, LLVMValueRef aligned_end_addr) {...@@ -3036,6 +3039,12 @@ static void gen_set_stack_pointer(CodeGen *g, LLVMValueRef aligned_end_addr) {
3036 LLVMBuildCall(g->builder, write_register_fn_val, params, 2, "");3039 LLVMBuildCall(g->builder, write_register_fn_val, params, 2, "");
3037}3040}
30383041
3042static void set_call_instr_sret(CodeGen *g, LLVMValueRef call_instr) {
3043 unsigned attr_kind_id = LLVMGetEnumAttributeKindForName("sret", 4);
3044 LLVMAttributeRef sret_attr = LLVMCreateEnumAttribute(LLVMGetGlobalContext(), attr_kind_id, 1);
3045 LLVMAddCallSiteAttribute(call_instr, 1, sret_attr);
3046}
3047
3039static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) {3048static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) {
3040 LLVMValueRef fn_val;3049 LLVMValueRef fn_val;
3041 TypeTableEntry *fn_type;3050 TypeTableEntry *fn_type;
...@@ -3131,6 +3140,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -3131,6 +3140,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
3131 } else if (!ret_has_bits) {3140 } else if (!ret_has_bits) {
3132 return nullptr;3141 return nullptr;
3133 } else if (first_arg_ret) {3142 } else if (first_arg_ret) {
3143 set_call_instr_sret(g, result);
3134 return instruction->tmp_ptr;3144 return instruction->tmp_ptr;
3135 } else if (handle_is_ptr(src_return_type)) {3145 } else if (handle_is_ptr(src_return_type)) {
3136 auto store_instr = LLVMBuildStore(g->builder, result, instruction->tmp_ptr);3146 auto store_instr = LLVMBuildStore(g->builder, result, instruction->tmp_ptr);
...@@ -4573,8 +4583,9 @@ static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_f...@@ -4573,8 +4583,9 @@ static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_f
4573 args.append(allocator_val);4583 args.append(allocator_val);
4574 args.append(coro_size);4584 args.append(coro_size);
4575 args.append(alignment_val);4585 args.append(alignment_val);
4576 ZigLLVMBuildCall(g->builder, alloc_fn_val, args.items, args.length,4586 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, alloc_fn_val, args.items, args.length,
4577 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");4587 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
4588 set_call_instr_sret(g, call_instruction);
4578 LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, sret_ptr, err_union_err_index, "");4589 LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, sret_ptr, err_union_err_index, "");
4579 LLVMValueRef err_val = LLVMBuildLoad(g->builder, err_val_ptr, "");4590 LLVMValueRef err_val = LLVMBuildLoad(g->builder, err_val_ptr, "");
4580 LLVMBuildStore(g->builder, err_val, err_code_ptr);4591 LLVMBuildStore(g->builder, err_val, err_code_ptr);
src/ir.cpp+173-135
...@@ -17,8 +17,7 @@...@@ -17,8 +17,7 @@
17#include "util.hpp"17#include "util.hpp"
1818
19struct IrExecContext {19struct IrExecContext {
20 ConstExprValue *mem_slot_list;20 ZigList<ConstExprValue *> mem_slot_list;
21 size_t mem_slot_count;
22};21};
2322
24struct IrBuilder {23struct IrBuilder {
...@@ -60,7 +59,7 @@ enum ConstCastResultId {...@@ -60,7 +59,7 @@ enum ConstCastResultId {
60 ConstCastResultIdType,59 ConstCastResultIdType,
61 ConstCastResultIdUnresolvedInferredErrSet,60 ConstCastResultIdUnresolvedInferredErrSet,
62 ConstCastResultIdAsyncAllocatorType,61 ConstCastResultIdAsyncAllocatorType,
63 ConstCastResultIdNullWrapPtr,62 ConstCastResultIdNullWrapPtr
64};63};
6564
66struct ConstCastOnly;65struct ConstCastOnly;
...@@ -155,18 +154,22 @@ static TypeTableEntry *adjust_slice_align(CodeGen *g, TypeTableEntry *slice_type...@@ -155,18 +154,22 @@ static TypeTableEntry *adjust_slice_align(CodeGen *g, TypeTableEntry *slice_type
155ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {154ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {
156 assert(get_codegen_ptr_type(const_val->type) != nullptr);155 assert(get_codegen_ptr_type(const_val->type) != nullptr);
157 assert(const_val->special == ConstValSpecialStatic);156 assert(const_val->special == ConstValSpecialStatic);
157 ConstExprValue *result;
158 switch (const_val->data.x_ptr.special) {158 switch (const_val->data.x_ptr.special) {
159 case ConstPtrSpecialInvalid:159 case ConstPtrSpecialInvalid:
160 zig_unreachable();160 zig_unreachable();
161 case ConstPtrSpecialRef:161 case ConstPtrSpecialRef:
162 return const_val->data.x_ptr.data.ref.pointee;162 result = const_val->data.x_ptr.data.ref.pointee;
163 break;
163 case ConstPtrSpecialBaseArray:164 case ConstPtrSpecialBaseArray:
164 expand_undef_array(g, const_val->data.x_ptr.data.base_array.array_val);165 expand_undef_array(g, const_val->data.x_ptr.data.base_array.array_val);
165 return &const_val->data.x_ptr.data.base_array.array_val->data.x_array.s_none.elements[166 result = &const_val->data.x_ptr.data.base_array.array_val->data.x_array.s_none.elements[
166 const_val->data.x_ptr.data.base_array.elem_index];167 const_val->data.x_ptr.data.base_array.elem_index];
168 break;
167 case ConstPtrSpecialBaseStruct:169 case ConstPtrSpecialBaseStruct:
168 return &const_val->data.x_ptr.data.base_struct.struct_val->data.x_struct.fields[170 result = &const_val->data.x_ptr.data.base_struct.struct_val->data.x_struct.fields[
169 const_val->data.x_ptr.data.base_struct.field_index];171 const_val->data.x_ptr.data.base_struct.field_index];
172 break;
170 case ConstPtrSpecialHardCodedAddr:173 case ConstPtrSpecialHardCodedAddr:
171 zig_unreachable();174 zig_unreachable();
172 case ConstPtrSpecialDiscard:175 case ConstPtrSpecialDiscard:
...@@ -174,7 +177,8 @@ ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {...@@ -174,7 +177,8 @@ ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {
174 case ConstPtrSpecialFunction:177 case ConstPtrSpecialFunction:
175 zig_unreachable();178 zig_unreachable();
176 }179 }
177 zig_unreachable();180 assert(result != nullptr);
181 return result;
178}182}
179183
180static bool ir_should_inline(IrExecutable *exec, Scope *scope) {184static bool ir_should_inline(IrExecutable *exec, Scope *scope) {
...@@ -3181,7 +3185,11 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -3181,7 +3185,11 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
3181 {3185 {
3182 IrInstruction *return_value;3186 IrInstruction *return_value;
3183 if (expr_node) {3187 if (expr_node) {
3188 // Temporarily set this so that if we return a type it gets the name of the function
3189 FnTableEntry *prev_name_fn = irb->exec->name_fn;
3190 irb->exec->name_fn = exec_fn_entry(irb->exec);
3184 return_value = ir_gen_node(irb, expr_node, scope);3191 return_value = ir_gen_node(irb, expr_node, scope);
3192 irb->exec->name_fn = prev_name_fn;
3185 if (return_value == irb->codegen->invalid_instruction)3193 if (return_value == irb->codegen->invalid_instruction)
3186 return irb->codegen->invalid_instruction;3194 return irb->codegen->invalid_instruction;
3187 } else {3195 } else {
...@@ -3275,7 +3283,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -3275,7 +3283,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
3275}3283}
32763284
3277static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope,3285static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope,
3278 Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime)3286 Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime,
3287 bool skip_name_check)
3279{3288{
3280 VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);3289 VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);
3281 variable_entry->parent_scope = parent_scope;3290 variable_entry->parent_scope = parent_scope;
...@@ -3288,29 +3297,30 @@ static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Sco...@@ -3288,29 +3297,30 @@ static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Sco
3288 if (name) {3297 if (name) {
3289 buf_init_from_buf(&variable_entry->name, name);3298 buf_init_from_buf(&variable_entry->name, name);
32903299
3291 VariableTableEntry *existing_var = find_variable(codegen, parent_scope, name);3300 if (!skip_name_check) {
3292 if (existing_var && !existing_var->shadowable) {3301 VariableTableEntry *existing_var = find_variable(codegen, parent_scope, name);
3293 ErrorMsg *msg = add_node_error(codegen, node,3302 if (existing_var && !existing_var->shadowable) {
3294 buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));3303 ErrorMsg *msg = add_node_error(codegen, node,
3295 add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));3304 buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
3296 variable_entry->value->type = codegen->builtin_types.entry_invalid;3305 add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
3297 } else {
3298 TypeTableEntry *type = get_primitive_type(codegen, name);
3299 if (type != nullptr) {
3300 add_node_error(codegen, node,
3301 buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name)));
3302 variable_entry->value->type = codegen->builtin_types.entry_invalid;3306 variable_entry->value->type = codegen->builtin_types.entry_invalid;
3303 } else {3307 } else {
3304 Tld *tld = find_decl(codegen, parent_scope, name);3308 TypeTableEntry *type = get_primitive_type(codegen, name);
3305 if (tld != nullptr) {3309 if (type != nullptr) {
3306 ErrorMsg *msg = add_node_error(codegen, node,3310 add_node_error(codegen, node,
3307 buf_sprintf("redefinition of '%s'", buf_ptr(name)));3311 buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name)));
3308 add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here"));
3309 variable_entry->value->type = codegen->builtin_types.entry_invalid;3312 variable_entry->value->type = codegen->builtin_types.entry_invalid;
3313 } else {
3314 Tld *tld = find_decl(codegen, parent_scope, name);
3315 if (tld != nullptr) {
3316 ErrorMsg *msg = add_node_error(codegen, node,
3317 buf_sprintf("redefinition of '%s'", buf_ptr(name)));
3318 add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here"));
3319 variable_entry->value->type = codegen->builtin_types.entry_invalid;
3320 }
3310 }3321 }
3311 }3322 }
3312 }3323 }
3313
3314 } else {3324 } else {
3315 assert(is_shadowable);3325 assert(is_shadowable);
3316 // TODO make this name not actually be in scope. user should be able to make a variable called "_anon"3326 // TODO make this name not actually be in scope. user should be able to make a variable called "_anon"
...@@ -3333,14 +3343,9 @@ static VariableTableEntry *ir_create_var(IrBuilder *irb, AstNode *node, Scope *s...@@ -3333,14 +3343,9 @@ static VariableTableEntry *ir_create_var(IrBuilder *irb, AstNode *node, Scope *s
3333 bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime)3343 bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime)
3334{3344{
3335 bool is_underscored = name ? buf_eql_str(name, "_") : false;3345 bool is_underscored = name ? buf_eql_str(name, "_") : false;
3336 VariableTableEntry *var = create_local_var( irb->codegen3346 VariableTableEntry *var = create_local_var(irb->codegen, node, scope,
3337 , node3347 (is_underscored ? nullptr : name), src_is_const, gen_is_const,
3338 , scope3348 (is_underscored ? true : is_shadowable), is_comptime, false);
3339 , (is_underscored ? nullptr : name)
3340 , src_is_const
3341 , gen_is_const
3342 , (is_underscored ? true : is_shadowable)
3343 , is_comptime );
3344 if (is_comptime != nullptr || gen_is_const) {3349 if (is_comptime != nullptr || gen_is_const) {
3345 var->mem_slot_index = exec_next_mem_slot(irb->exec);3350 var->mem_slot_index = exec_next_mem_slot(irb->exec);
3346 var->owner_exec = irb->exec;3351 var->owner_exec = irb->exec;
...@@ -6479,20 +6484,17 @@ static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *o...@@ -6479,20 +6484,17 @@ static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *o
6479static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char *kind_name, AstNode *source_node) {6484static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char *kind_name, AstNode *source_node) {
6480 if (exec->name) {6485 if (exec->name) {
6481 return exec->name;6486 return exec->name;
6487 } else if (exec->name_fn != nullptr) {
6488 Buf *name = buf_alloc();
6489 buf_append_buf(name, &exec->name_fn->symbol_name);
6490 buf_appendf(name, "(");
6491 render_instance_name_recursive(codegen, name, &exec->name_fn->fndef_scope->base, exec->begin_scope);
6492 buf_appendf(name, ")");
6493 return name;
6482 } else {6494 } else {
6483 FnTableEntry *fn_entry = exec_fn_entry(exec);6495 //Note: C-imports do not have valid location information
6484 if (fn_entry) {6496 return buf_sprintf("(anonymous %s at %s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ")", kind_name,
6485 Buf *name = buf_alloc();6497 (source_node->owner->path != nullptr) ? buf_ptr(source_node->owner->path) : "(null)", source_node->line + 1, source_node->column + 1);
6486 buf_append_buf(name, &fn_entry->symbol_name);
6487 buf_appendf(name, "(");
6488 render_instance_name_recursive(codegen, name, &fn_entry->fndef_scope->base, exec->begin_scope);
6489 buf_appendf(name, ")");
6490 return name;
6491 } else {
6492 //Note: C-imports do not have valid location information
6493 return buf_sprintf("(anonymous %s at %s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ")", kind_name,
6494 (source_node->owner->path != nullptr) ? buf_ptr(source_node->owner->path) : "(null)", source_node->line + 1, source_node->column + 1);
6495 }
6496 }6498 }
6497}6499}
64986500
...@@ -6690,7 +6692,10 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo...@@ -6690,7 +6692,10 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
6690 return irb->codegen->invalid_instruction;6692 return irb->codegen->invalid_instruction;
6691 }6693 }
6692 } else {6694 } else {
6693 return_type = nullptr;6695 add_node_error(irb->codegen, node,
6696 buf_sprintf("TODO implement inferred return types https://github.com/ziglang/zig/issues/447"));
6697 return irb->codegen->invalid_instruction;
6698 //return_type = nullptr;
6694 }6699 }
66956700
6696 IrInstruction *async_allocator_type_value = nullptr;6701 IrInstruction *async_allocator_type_value = nullptr;
...@@ -8466,9 +8471,9 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry...@@ -8466,9 +8471,9 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
8466 if (wanted_type == actual_type)8471 if (wanted_type == actual_type)
8467 return result;8472 return result;
84688473
8469 // * and [*] can do a const-cast-only to ?* and ?[*], respectively8474 // *T and [*]T may const-cast-only to ?*U and ?[*]U, respectively
8470 // but not if there is a mutable parent pointer8475 // but not if we want a mutable pointer
8471 // and not if the pointer is zero bits8476 // and not if the actual pointer has zero bits
8472 if (!wanted_is_mutable && wanted_type->id == TypeTableEntryIdOptional &&8477 if (!wanted_is_mutable && wanted_type->id == TypeTableEntryIdOptional &&
8473 wanted_type->data.maybe.child_type->id == TypeTableEntryIdPointer &&8478 wanted_type->data.maybe.child_type->id == TypeTableEntryIdPointer &&
8474 actual_type->id == TypeTableEntryIdPointer && type_has_bits(actual_type))8479 actual_type->id == TypeTableEntryIdPointer && type_has_bits(actual_type))
...@@ -8483,6 +8488,18 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry...@@ -8483,6 +8488,18 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
8483 return result;8488 return result;
8484 }8489 }
84858490
8491 // *T and [*]T can always cast to *c_void
8492 if (wanted_type->id == TypeTableEntryIdPointer &&
8493 wanted_type->data.pointer.ptr_len == PtrLenSingle &&
8494 wanted_type->data.pointer.child_type == g->builtin_types.entry_c_void &&
8495 actual_type->id == TypeTableEntryIdPointer &&
8496 (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) &&
8497 (!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile))
8498 {
8499 assert(actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment);
8500 return result;
8501 }
8502
8486 // pointer const8503 // pointer const
8487 if (wanted_type->id == TypeTableEntryIdPointer && actual_type->id == TypeTableEntryIdPointer) {8504 if (wanted_type->id == TypeTableEntryIdPointer && actual_type->id == TypeTableEntryIdPointer) {
8488 ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,8505 ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
...@@ -12478,6 +12495,24 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc...@@ -12478,6 +12495,24 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
12478 }12495 }
12479 }12496 }
1248012497
12498 if (var->value->type != nullptr && !is_comptime_var) {
12499 // This is at least the second time we've seen this variable declaration during analysis.
12500 // This means that this is actually a different variable due to, e.g. an inline while loop.
12501 // We make a new variable so that it can hold a different type, and so the debug info can
12502 // be distinct.
12503 VariableTableEntry *new_var = create_local_var(ira->codegen, var->decl_node, var->child_scope,
12504 &var->name, var->src_is_const, var->gen_is_const, var->shadowable, var->is_comptime, true);
12505 new_var->owner_exec = var->owner_exec;
12506 if (var->mem_slot_index != SIZE_MAX) {
12507 ConstExprValue *vals = create_const_vals(1);
12508 new_var->mem_slot_index = ira->exec_context.mem_slot_list.length;
12509 ira->exec_context.mem_slot_list.append(vals);
12510 }
12511
12512 var->next_var = new_var;
12513 var = new_var;
12514 }
12515
12481 var->value->type = result_type;12516 var->value->type = result_type;
12482 assert(var->value->type);12517 assert(var->value->type);
1248312518
...@@ -12496,10 +12531,9 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc...@@ -12496,10 +12531,9 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
1249612531
12497 if (casted_init_value->value.special != ConstValSpecialRuntime) {12532 if (casted_init_value->value.special != ConstValSpecialRuntime) {
12498 if (var->mem_slot_index != SIZE_MAX) {12533 if (var->mem_slot_index != SIZE_MAX) {
12499 assert(var->mem_slot_index < ira->exec_context.mem_slot_count);12534 assert(var->mem_slot_index < ira->exec_context.mem_slot_list.length);
12500 ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];12535 ConstExprValue *mem_slot = ira->exec_context.mem_slot_list.at(var->mem_slot_index);
12501 copy_const_val(mem_slot, &casted_init_value->value,12536 copy_const_val(mem_slot, &casted_init_value->value, !is_comptime_var || var->gen_is_const);
12502 !is_comptime_var || var->gen_is_const);
1250312537
12504 if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) {12538 if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) {
12505 ir_build_const_from(ira, &decl_var_instruction->base);12539 ir_build_const_from(ira, &decl_var_instruction->base);
...@@ -12960,6 +12994,10 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,...@@ -12960,6 +12994,10 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
12960 VariableTableEntry *var)12994 VariableTableEntry *var)
12961{12995{
12962 Error err;12996 Error err;
12997 while (var->next_var != nullptr) {
12998 var = var->next_var;
12999 }
13000
12963 if (var->mem_slot_index != SIZE_MAX && var->owner_exec->analysis == nullptr) {13001 if (var->mem_slot_index != SIZE_MAX && var->owner_exec->analysis == nullptr) {
12964 assert(ira->codegen->errors.length != 0);13002 assert(ira->codegen->errors.length != 0);
12965 return ira->codegen->invalid_instruction;13003 return ira->codegen->invalid_instruction;
...@@ -12979,8 +13017,8 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,...@@ -12979,8 +13017,8 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
12979 assert(var->owner_exec != nullptr);13017 assert(var->owner_exec != nullptr);
12980 assert(var->owner_exec->analysis != nullptr);13018 assert(var->owner_exec->analysis != nullptr);
12981 IrExecContext *exec_context = &var->owner_exec->analysis->exec_context;13019 IrExecContext *exec_context = &var->owner_exec->analysis->exec_context;
12982 assert(var->mem_slot_index < exec_context->mem_slot_count);13020 assert(var->mem_slot_index < exec_context->mem_slot_list.length);
12983 mem_slot = &exec_context->mem_slot_list[var->mem_slot_index];13021 mem_slot = exec_context->mem_slot_list.at(var->mem_slot_index);
12984 }13022 }
12985 }13023 }
1298613024
...@@ -14439,8 +14477,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_...@@ -14439,8 +14477,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
14439 ConstExprValue *payload_val = union_val->data.x_union.payload;14477 ConstExprValue *payload_val = union_val->data.x_union.payload;
1444014478
14441 TypeTableEntry *field_type = field->type_entry;14479 TypeTableEntry *field_type = field->type_entry;
14442 if (field_type->id == TypeTableEntryIdVoid)14480 if (field_type->id == TypeTableEntryIdVoid) {
14443 {
14444 assert(payload_val == nullptr);14481 assert(payload_val == nullptr);
14445 payload_val = create_const_vals(1);14482 payload_val = create_const_vals(1);
14446 payload_val->special = ConstValSpecialStatic;14483 payload_val->special = ConstValSpecialStatic;
...@@ -16445,12 +16482,6 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_...@@ -16445,12 +16482,6 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_
16445 eval_min_max_value(ira->codegen, target_type, out_val, is_max);16482 eval_min_max_value(ira->codegen, target_type, out_val, is_max);
16446 return ira->codegen->builtin_types.entry_num_lit_int;16483 return ira->codegen->builtin_types.entry_num_lit_int;
16447 }16484 }
16448 case TypeTableEntryIdFloat:
16449 {
16450 ConstExprValue *out_val = ir_build_const_from(ira, source_instruction);
16451 eval_min_max_value(ira->codegen, target_type, out_val, is_max);
16452 return ira->codegen->builtin_types.entry_num_lit_float;
16453 }
16454 case TypeTableEntryIdBool:16485 case TypeTableEntryIdBool:
16455 case TypeTableEntryIdVoid:16486 case TypeTableEntryIdVoid:
16456 {16487 {
...@@ -16459,7 +16490,7 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_...@@ -16459,7 +16490,7 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_
16459 return target_type;16490 return target_type;
16460 }16491 }
16461 case TypeTableEntryIdEnum:16492 case TypeTableEntryIdEnum:
16462 zig_panic("TODO min/max value for enum type");16493 case TypeTableEntryIdFloat:
16463 case TypeTableEntryIdMetaType:16494 case TypeTableEntryIdMetaType:
16464 case TypeTableEntryIdUnreachable:16495 case TypeTableEntryIdUnreachable:
16465 case TypeTableEntryIdPointer:16496 case TypeTableEntryIdPointer:
...@@ -16792,12 +16823,11 @@ static TypeTableEntry *ir_type_info_get_type(IrAnalyze *ira, const char *type_na...@@ -16792,12 +16823,11 @@ static TypeTableEntry *ir_type_info_get_type(IrAnalyze *ira, const char *type_na
16792 return var->value->data.x_type;16823 return var->value->data.x_type;
16793}16824}
1679416825
16795static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, ScopeDecls *decls_scope)16826static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, ScopeDecls *decls_scope) {
16796{
16797 Error err;16827 Error err;
16798 TypeTableEntry *type_info_definition_type = ir_type_info_get_type(ira, "Definition", nullptr);16828 TypeTableEntry *type_info_definition_type = ir_type_info_get_type(ira, "Definition", nullptr);
16799 if ((err = ensure_complete_type(ira->codegen, type_info_definition_type)))16829 if ((err = ensure_complete_type(ira->codegen, type_info_definition_type)))
16800 return false;16830 return err;
1680116831
16802 ensure_field_index(type_info_definition_type, "name", 0);16832 ensure_field_index(type_info_definition_type, "name", 0);
16803 ensure_field_index(type_info_definition_type, "is_pub", 1);16833 ensure_field_index(type_info_definition_type, "is_pub", 1);
...@@ -16805,38 +16835,33 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop...@@ -16805,38 +16835,33 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop
1680516835
16806 TypeTableEntry *type_info_definition_data_type = ir_type_info_get_type(ira, "Data", type_info_definition_type);16836 TypeTableEntry *type_info_definition_data_type = ir_type_info_get_type(ira, "Data", type_info_definition_type);
16807 if ((err = ensure_complete_type(ira->codegen, type_info_definition_data_type)))16837 if ((err = ensure_complete_type(ira->codegen, type_info_definition_data_type)))
16808 return false;16838 return err;
1680916839
16810 TypeTableEntry *type_info_fn_def_type = ir_type_info_get_type(ira, "FnDef", type_info_definition_data_type);16840 TypeTableEntry *type_info_fn_def_type = ir_type_info_get_type(ira, "FnDef", type_info_definition_data_type);
16811 if ((err = ensure_complete_type(ira->codegen, type_info_fn_def_type)))16841 if ((err = ensure_complete_type(ira->codegen, type_info_fn_def_type)))
16812 return false;16842 return err;
1681316843
16814 TypeTableEntry *type_info_fn_def_inline_type = ir_type_info_get_type(ira, "Inline", type_info_fn_def_type);16844 TypeTableEntry *type_info_fn_def_inline_type = ir_type_info_get_type(ira, "Inline", type_info_fn_def_type);
16815 if ((err = ensure_complete_type(ira->codegen, type_info_fn_def_inline_type)))16845 if ((err = ensure_complete_type(ira->codegen, type_info_fn_def_inline_type)))
16816 return false;16846 return err;
1681716847
16818 // Loop through our definitions once to figure out how many definitions we will generate info for.16848 // Loop through our definitions once to figure out how many definitions we will generate info for.
16819 auto decl_it = decls_scope->decl_table.entry_iterator();16849 auto decl_it = decls_scope->decl_table.entry_iterator();
16820 decltype(decls_scope->decl_table)::Entry *curr_entry = nullptr;16850 decltype(decls_scope->decl_table)::Entry *curr_entry = nullptr;
16821 int definition_count = 0;16851 int definition_count = 0;
1682216852
16823 while ((curr_entry = decl_it.next()) != nullptr)16853 while ((curr_entry = decl_it.next()) != nullptr) {
16824 {
16825 // If the definition is unresolved, force it to be resolved again.16854 // If the definition is unresolved, force it to be resolved again.
16826 if (curr_entry->value->resolution == TldResolutionUnresolved)16855 if (curr_entry->value->resolution == TldResolutionUnresolved) {
16827 {
16828 resolve_top_level_decl(ira->codegen, curr_entry->value, false, curr_entry->value->source_node);16856 resolve_top_level_decl(ira->codegen, curr_entry->value, false, curr_entry->value->source_node);
16829 if (curr_entry->value->resolution != TldResolutionOk)16857 if (curr_entry->value->resolution != TldResolutionOk) {
16830 {16858 return ErrorSemanticAnalyzeFail;
16831 return false;
16832 }16859 }
16833 }16860 }
1683416861
16835 // Skip comptime blocks and test functions.16862 // Skip comptime blocks and test functions.
16836 if (curr_entry->value->id != TldIdCompTime)16863 if (curr_entry->value->id != TldIdCompTime) {
16837 {16864 if (curr_entry->value->id == TldIdFn) {
16838 if (curr_entry->value->id == TldIdFn)
16839 {
16840 FnTableEntry *fn_entry = ((TldFn *)curr_entry->value)->fn_entry;16865 FnTableEntry *fn_entry = ((TldFn *)curr_entry->value)->fn_entry;
16841 if (fn_entry->is_test)16866 if (fn_entry->is_test)
16842 continue;16867 continue;
...@@ -16858,13 +16883,11 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop...@@ -16858,13 +16883,11 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop
16858 decl_it = decls_scope->decl_table.entry_iterator();16883 decl_it = decls_scope->decl_table.entry_iterator();
16859 curr_entry = nullptr; 16884 curr_entry = nullptr;
16860 int definition_index = 0;16885 int definition_index = 0;
16861 while ((curr_entry = decl_it.next()) != nullptr)16886 while ((curr_entry = decl_it.next()) != nullptr) {
16862 {
16863 // Skip comptime blocks and test functions.16887 // Skip comptime blocks and test functions.
16864 if (curr_entry->value->id == TldIdCompTime)16888 if (curr_entry->value->id == TldIdCompTime) {
16865 continue;16889 continue;
16866 else if (curr_entry->value->id == TldIdFn)16890 } else if (curr_entry->value->id == TldIdFn) {
16867 {
16868 FnTableEntry *fn_entry = ((TldFn *)curr_entry->value)->fn_entry;16891 FnTableEntry *fn_entry = ((TldFn *)curr_entry->value)->fn_entry;
16869 if (fn_entry->is_test)16892 if (fn_entry->is_test)
16870 continue;16893 continue;
...@@ -16887,13 +16910,12 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop...@@ -16887,13 +16910,12 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop
16887 inner_fields[2].data.x_union.parent.data.p_struct.struct_val = definition_val;16910 inner_fields[2].data.x_union.parent.data.p_struct.struct_val = definition_val;
16888 inner_fields[2].data.x_union.parent.data.p_struct.field_index = 1;16911 inner_fields[2].data.x_union.parent.data.p_struct.field_index = 1;
1688916912
16890 switch (curr_entry->value->id)16913 switch (curr_entry->value->id) {
16891 {
16892 case TldIdVar:16914 case TldIdVar:
16893 {16915 {
16894 VariableTableEntry *var = ((TldVar *)curr_entry->value)->var;16916 VariableTableEntry *var = ((TldVar *)curr_entry->value)->var;
16895 if ((err = ensure_complete_type(ira->codegen, var->value->type)))16917 if ((err = ensure_complete_type(ira->codegen, var->value->type)))
16896 return false;16918 return ErrorSemanticAnalyzeFail;
1689716919
16898 if (var->value->type->id == TypeTableEntryIdMetaType)16920 if (var->value->type->id == TypeTableEntryIdMetaType)
16899 {16921 {
...@@ -17024,7 +17046,7 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop...@@ -17024,7 +17046,7 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop
17024 {17046 {
17025 TypeTableEntry *type_entry = ((TldContainer *)curr_entry->value)->type_entry;17047 TypeTableEntry *type_entry = ((TldContainer *)curr_entry->value)->type_entry;
17026 if ((err = ensure_complete_type(ira->codegen, type_entry)))17048 if ((err = ensure_complete_type(ira->codegen, type_entry)))
17027 return false;17049 return ErrorSemanticAnalyzeFail;
1702817050
17029 // This is a type.17051 // This is a type.
17030 bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 0);17052 bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 0);
...@@ -17046,7 +17068,7 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop...@@ -17046,7 +17068,7 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop
17046 }17068 }
1704717069
17048 assert(definition_index == definition_count);17070 assert(definition_index == definition_count);
17049 return true;17071 return ErrorNone;
17050}17072}
1705117073
17052static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, TypeTableEntry *ptr_type_entry) {17074static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, TypeTableEntry *ptr_type_entry) {
...@@ -17104,30 +17126,31 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, TypeTableEntry...@@ -17104,30 +17126,31 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, TypeTableEntry
17104 return result;17126 return result;
17105};17127};
1710617128
17107static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *type_entry) {17129static void make_enum_field_val(IrAnalyze *ira, ConstExprValue *enum_field_val, TypeEnumField *enum_field,
17108 Error err;17130 TypeTableEntry *type_info_enum_field_type)
17109 assert(type_entry != nullptr);17131{
17110 assert(!type_is_invalid(type_entry));17132 enum_field_val->special = ConstValSpecialStatic;
17133 enum_field_val->type = type_info_enum_field_type;
1711117134
17112 if ((err = ensure_complete_type(ira->codegen, type_entry)))17135 ConstExprValue *inner_fields = create_const_vals(2);
17113 return nullptr;17136 inner_fields[1].special = ConstValSpecialStatic;
17137 inner_fields[1].type = ira->codegen->builtin_types.entry_usize;
1711417138
17115 const auto make_enum_field_val = [ira](ConstExprValue *enum_field_val, TypeEnumField *enum_field,17139 ConstExprValue *name = create_const_str_lit(ira->codegen, enum_field->name);
17116 TypeTableEntry *type_info_enum_field_type) {17140 init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(enum_field->name), true);
17117 enum_field_val->special = ConstValSpecialStatic;
17118 enum_field_val->type = type_info_enum_field_type;
1711917141
17120 ConstExprValue *inner_fields = create_const_vals(2);17142 bigint_init_bigint(&inner_fields[1].data.x_bigint, &enum_field->value);
17121 inner_fields[1].special = ConstValSpecialStatic;
17122 inner_fields[1].type = ira->codegen->builtin_types.entry_usize;
1712317143
17124 ConstExprValue *name = create_const_str_lit(ira->codegen, enum_field->name);17144 enum_field_val->data.x_struct.fields = inner_fields;
17125 init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(enum_field->name), true);17145}
1712617146
17127 bigint_init_bigint(&inner_fields[1].data.x_bigint, &enum_field->value);17147static Error ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *type_entry, ConstExprValue **out) {
17148 Error err;
17149 assert(type_entry != nullptr);
17150 assert(!type_is_invalid(type_entry));
1712817151
17129 enum_field_val->data.x_struct.fields = inner_fields;17152 if ((err = ensure_complete_type(ira->codegen, type_entry)))
17130 };17153 return err;
1713117154
17132 if (type_entry == ira->codegen->builtin_types.entry_global_error_set) {17155 if (type_entry == ira->codegen->builtin_types.entry_global_error_set) {
17133 zig_panic("TODO implement @typeInfo for global error set");17156 zig_panic("TODO implement @typeInfo for global error set");
...@@ -17150,13 +17173,16 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t...@@ -17150,13 +17173,16 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
17150 case TypeTableEntryIdBlock:17173 case TypeTableEntryIdBlock:
17151 case TypeTableEntryIdArgTuple:17174 case TypeTableEntryIdArgTuple:
17152 case TypeTableEntryIdOpaque:17175 case TypeTableEntryIdOpaque:
17153 return nullptr;17176 *out = nullptr;
17177 return ErrorNone;
17154 default:17178 default:
17155 {17179 {
17156 // Lookup an available value in our cache.17180 // Lookup an available value in our cache.
17157 auto entry = ira->codegen->type_info_cache.maybe_get(type_entry);17181 auto entry = ira->codegen->type_info_cache.maybe_get(type_entry);
17158 if (entry != nullptr)17182 if (entry != nullptr) {
17159 return entry->value;17183 *out = entry->value;
17184 return ErrorNone;
17185 }
1716017186
17161 // Fallthrough if we don't find one.17187 // Fallthrough if we don't find one.
17162 }17188 }
...@@ -17307,15 +17333,15 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t...@@ -17307,15 +17333,15 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
17307 {17333 {
17308 TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum_field_index];17334 TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum_field_index];
17309 ConstExprValue *enum_field_val = &enum_field_array->data.x_array.s_none.elements[enum_field_index];17335 ConstExprValue *enum_field_val = &enum_field_array->data.x_array.s_none.elements[enum_field_index];
17310 make_enum_field_val(enum_field_val, enum_field, type_info_enum_field_type);17336 make_enum_field_val(ira, enum_field_val, enum_field, type_info_enum_field_type);
17311 enum_field_val->data.x_struct.parent.id = ConstParentIdArray;17337 enum_field_val->data.x_struct.parent.id = ConstParentIdArray;
17312 enum_field_val->data.x_struct.parent.data.p_array.array_val = enum_field_array;17338 enum_field_val->data.x_struct.parent.data.p_array.array_val = enum_field_array;
17313 enum_field_val->data.x_struct.parent.data.p_array.elem_index = enum_field_index;17339 enum_field_val->data.x_struct.parent.data.p_array.elem_index = enum_field_index;
17314 }17340 }
17315 // defs: []TypeInfo.Definition17341 // defs: []TypeInfo.Definition
17316 ensure_field_index(result->type, "defs", 3);17342 ensure_field_index(result->type, "defs", 3);
17317 if (!ir_make_type_info_defs(ira, &fields[3], type_entry->data.enumeration.decls_scope))17343 if ((err = ir_make_type_info_defs(ira, &fields[3], type_entry->data.enumeration.decls_scope)))
17318 return nullptr;17344 return err;
1731917345
17320 break;17346 break;
17321 }17347 }
...@@ -17341,8 +17367,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t...@@ -17341,8 +17367,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
17341 error_array->data.x_array.s_none.elements = create_const_vals(error_count);17367 error_array->data.x_array.s_none.elements = create_const_vals(error_count);
1734217368
17343 init_const_slice(ira->codegen, &fields[0], error_array, 0, error_count, false);17369 init_const_slice(ira->codegen, &fields[0], error_array, 0, error_count, false);
17344 for (uint32_t error_index = 0; error_index < error_count; error_index++)17370 for (uint32_t error_index = 0; error_index < error_count; error_index++) {
17345 {
17346 ErrorTableEntry *error = type_entry->data.error_set.errors[error_index];17371 ErrorTableEntry *error = type_entry->data.error_set.errors[error_index];
17347 ConstExprValue *error_val = &error_array->data.x_array.s_none.elements[error_index];17372 ConstExprValue *error_val = &error_array->data.x_array.s_none.elements[error_index];
1734817373
...@@ -17420,9 +17445,9 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t...@@ -17420,9 +17445,9 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
17420 tag_type->type = ira->codegen->builtin_types.entry_type;17445 tag_type->type = ira->codegen->builtin_types.entry_type;
17421 tag_type->data.x_type = type_entry->data.unionation.tag_type;17446 tag_type->data.x_type = type_entry->data.unionation.tag_type;
17422 fields[1].data.x_optional = tag_type;17447 fields[1].data.x_optional = tag_type;
17423 }17448 } else {
17424 else
17425 fields[1].data.x_optional = nullptr;17449 fields[1].data.x_optional = nullptr;
17450 }
17426 // fields: []TypeInfo.UnionField17451 // fields: []TypeInfo.UnionField
17427 ensure_field_index(result->type, "fields", 2);17452 ensure_field_index(result->type, "fields", 2);
1742817453
...@@ -17455,7 +17480,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t...@@ -17455,7 +17480,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
17455 inner_fields[1].data.x_optional = nullptr;17480 inner_fields[1].data.x_optional = nullptr;
17456 } else {17481 } else {
17457 inner_fields[1].data.x_optional = create_const_vals(1);17482 inner_fields[1].data.x_optional = create_const_vals(1);
17458 make_enum_field_val(inner_fields[1].data.x_optional, union_field->enum_field, type_info_enum_field_type);17483 make_enum_field_val(ira, inner_fields[1].data.x_optional, union_field->enum_field, type_info_enum_field_type);
17459 }17484 }
1746017485
17461 inner_fields[2].special = ConstValSpecialStatic;17486 inner_fields[2].special = ConstValSpecialStatic;
...@@ -17472,8 +17497,8 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t...@@ -17472,8 +17497,8 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
17472 }17497 }
17473 // defs: []TypeInfo.Definition17498 // defs: []TypeInfo.Definition
17474 ensure_field_index(result->type, "defs", 3);17499 ensure_field_index(result->type, "defs", 3);
17475 if (!ir_make_type_info_defs(ira, &fields[3], type_entry->data.unionation.decls_scope))17500 if ((err = ir_make_type_info_defs(ira, &fields[3], type_entry->data.unionation.decls_scope)))
17476 return nullptr;17501 return err;
1747717502
17478 break;17503 break;
17479 }17504 }
...@@ -17546,8 +17571,8 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t...@@ -17546,8 +17571,8 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
17546 }17571 }
17547 // defs: []TypeInfo.Definition17572 // defs: []TypeInfo.Definition
17548 ensure_field_index(result->type, "defs", 2);17573 ensure_field_index(result->type, "defs", 2);
17549 if (!ir_make_type_info_defs(ira, &fields[2], type_entry->data.structure.decls_scope))17574 if ((err = ir_make_type_info_defs(ira, &fields[2], type_entry->data.structure.decls_scope)))
17550 return nullptr;17575 return err;
1755117576
17552 break;17577 break;
17553 }17578 }
...@@ -17660,7 +17685,8 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t...@@ -17660,7 +17685,8 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
17660 {17685 {
17661 TypeTableEntry *fn_type = type_entry->data.bound_fn.fn_type;17686 TypeTableEntry *fn_type = type_entry->data.bound_fn.fn_type;
17662 assert(fn_type->id == TypeTableEntryIdFn);17687 assert(fn_type->id == TypeTableEntryIdFn);
17663 result = ir_make_type_info_value(ira, fn_type);17688 if ((err = ir_make_type_info_value(ira, fn_type, &result)))
17689 return err;
1766417690
17665 break;17691 break;
17666 }17692 }
...@@ -17668,12 +17694,14 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t...@@ -17668,12 +17694,14 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
1766817694
17669 assert(result != nullptr);17695 assert(result != nullptr);
17670 ira->codegen->type_info_cache.put(type_entry, result);17696 ira->codegen->type_info_cache.put(type_entry, result);
17671 return result;17697 *out = result;
17698 return ErrorNone;
17672}17699}
1767317700
17674static TypeTableEntry *ir_analyze_instruction_type_info(IrAnalyze *ira,17701static TypeTableEntry *ir_analyze_instruction_type_info(IrAnalyze *ira,
17675 IrInstructionTypeInfo *instruction)17702 IrInstructionTypeInfo *instruction)
17676{17703{
17704 Error err;
17677 IrInstruction *type_value = instruction->type_value->other;17705 IrInstruction *type_value = instruction->type_value->other;
17678 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);17706 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
17679 if (type_is_invalid(type_entry))17707 if (type_is_invalid(type_entry))
...@@ -17681,15 +17709,16 @@ static TypeTableEntry *ir_analyze_instruction_type_info(IrAnalyze *ira,...@@ -17681,15 +17709,16 @@ static TypeTableEntry *ir_analyze_instruction_type_info(IrAnalyze *ira,
1768117709
17682 TypeTableEntry *result_type = ir_type_info_get_type(ira, nullptr, nullptr);17710 TypeTableEntry *result_type = ir_type_info_get_type(ira, nullptr, nullptr);
1768317711
17712 ConstExprValue *payload;
17713 if ((err = ir_make_type_info_value(ira, type_entry, &payload)))
17714 return ira->codegen->builtin_types.entry_invalid;
17715
17684 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);17716 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
17685 out_val->type = result_type;17717 out_val->type = result_type;
17686 bigint_init_unsigned(&out_val->data.x_union.tag, type_id_index(type_entry));17718 bigint_init_unsigned(&out_val->data.x_union.tag, type_id_index(type_entry));
17687
17688 ConstExprValue *payload = ir_make_type_info_value(ira, type_entry);
17689 out_val->data.x_union.payload = payload;17719 out_val->data.x_union.payload = payload;
1769017720
17691 if (payload != nullptr)17721 if (payload != nullptr) {
17692 {
17693 assert(payload->type->id == TypeTableEntryIdStruct);17722 assert(payload->type->id == TypeTableEntryIdStruct);
17694 payload->data.x_struct.parent.id = ConstParentIdUnion;17723 payload->data.x_struct.parent.id = ConstParentIdUnion;
17695 payload->data.x_struct.parent.data.p_union.union_val = out_val;17724 payload->data.x_struct.parent.data.p_union.union_val = out_val;
...@@ -19731,6 +19760,8 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3...@@ -19731,6 +19760,8 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3
19731}19760}
1973219761
19733static TypeTableEntry *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) {19762static TypeTableEntry *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) {
19763 Error err;
19764
19734 IrInstruction *dest_type_value = instruction->dest_type->other;19765 IrInstruction *dest_type_value = instruction->dest_type->other;
19735 TypeTableEntry *dest_type = ir_resolve_type(ira, dest_type_value);19766 TypeTableEntry *dest_type = ir_resolve_type(ira, dest_type_value);
19736 if (type_is_invalid(dest_type))19767 if (type_is_invalid(dest_type))
...@@ -19784,9 +19815,13 @@ static TypeTableEntry *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruc...@@ -19784,9 +19815,13 @@ static TypeTableEntry *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruc
19784 instruction->base.source_node, nullptr, ptr);19815 instruction->base.source_node, nullptr, ptr);
19785 casted_ptr->value.type = dest_type;19816 casted_ptr->value.type = dest_type;
1978619817
19787 // keep the bigger alignment, it can only help19818 // Keep the bigger alignment, it can only help-
19819 // unless the target is zero bits.
19820 if ((err = type_ensure_zero_bits_known(ira->codegen, dest_type)))
19821 return ira->codegen->builtin_types.entry_invalid;
19822
19788 IrInstruction *result;19823 IrInstruction *result;
19789 if (src_align_bytes > dest_align_bytes) {19824 if (src_align_bytes > dest_align_bytes && type_has_bits(dest_type)) {
19790 result = ir_align_cast(ira, casted_ptr, src_align_bytes, false);19825 result = ir_align_cast(ira, casted_ptr, src_align_bytes, false);
19791 if (type_is_invalid(result->value.type))19826 if (type_is_invalid(result->value.type))
19792 return ira->codegen->builtin_types.entry_invalid;19827 return ira->codegen->builtin_types.entry_invalid;
...@@ -21192,8 +21227,11 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl...@@ -21192,8 +21227,11 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl
21192 ira->new_irb.codegen = codegen;21227 ira->new_irb.codegen = codegen;
21193 ira->new_irb.exec = new_exec;21228 ira->new_irb.exec = new_exec;
2119421229
21195 ira->exec_context.mem_slot_count = ira->old_irb.exec->mem_slot_count;21230 ConstExprValue *vals = create_const_vals(ira->old_irb.exec->mem_slot_count);
21196 ira->exec_context.mem_slot_list = create_const_vals(ira->exec_context.mem_slot_count);21231 ira->exec_context.mem_slot_list.resize(ira->old_irb.exec->mem_slot_count);
21232 for (size_t i = 0; i < ira->exec_context.mem_slot_list.length; i += 1) {
21233 ira->exec_context.mem_slot_list.items[i] = &vals[i];
21234 }
2119721235
21198 IrBasicBlock *old_entry_bb = ira->old_irb.exec->basic_block_list.at(0);21236 IrBasicBlock *old_entry_bb = ira->old_irb.exec->basic_block_list.at(0);
21199 IrBasicBlock *new_entry_bb = ir_get_new_bb(ira, old_entry_bb, nullptr);21237 IrBasicBlock *new_entry_bb = ir_get_new_bb(ira, old_entry_bb, nullptr);
src/translate_c.cpp+10-11
...@@ -3075,12 +3075,19 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt,...@@ -3075,12 +3075,19 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt,
3075 trans_unary_operator(c, result_used, scope, (const UnaryOperator *)stmt));3075 trans_unary_operator(c, result_used, scope, (const UnaryOperator *)stmt));
3076 case Stmt::DeclStmtClass:3076 case Stmt::DeclStmtClass:
3077 return trans_local_declaration(c, scope, (const DeclStmt *)stmt, out_node, out_child_scope);3077 return trans_local_declaration(c, scope, (const DeclStmt *)stmt, out_node, out_child_scope);
3078 case Stmt::DoStmtClass:
3078 case Stmt::WhileStmtClass: {3079 case Stmt::WhileStmtClass: {
3079 AstNode *while_node = trans_while_loop(c, scope, (const WhileStmt *)stmt);3080 AstNode *while_node = sc == Stmt::DoStmtClass
3081 ? trans_do_loop(c, scope, (const DoStmt *)stmt)
3082 : trans_while_loop(c, scope, (const WhileStmt *)stmt);
3083
3084 if (while_node == nullptr)
3085 return ErrorUnexpected;
3086
3080 assert(while_node->type == NodeTypeWhileExpr);3087 assert(while_node->type == NodeTypeWhileExpr);
3081 if (while_node->data.while_expr.body == nullptr) {3088 if (while_node->data.while_expr.body == nullptr)
3082 while_node->data.while_expr.body = trans_create_node(c, NodeTypeBlock);3089 while_node->data.while_expr.body = trans_create_node(c, NodeTypeBlock);
3083 }3090
3084 return wrap_stmt(out_node, out_child_scope, scope, while_node);3091 return wrap_stmt(out_node, out_child_scope, scope, while_node);
3085 }3092 }
3086 case Stmt::IfStmtClass:3093 case Stmt::IfStmtClass:
...@@ -3105,14 +3112,6 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt,...@@ -3105,14 +3112,6 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt,
3105 case Stmt::UnaryExprOrTypeTraitExprClass:3112 case Stmt::UnaryExprOrTypeTraitExprClass:
3106 return wrap_stmt(out_node, out_child_scope, scope,3113 return wrap_stmt(out_node, out_child_scope, scope,
3107 trans_unary_expr_or_type_trait_expr(c, scope, (const UnaryExprOrTypeTraitExpr *)stmt));3114 trans_unary_expr_or_type_trait_expr(c, scope, (const UnaryExprOrTypeTraitExpr *)stmt));
3108 case Stmt::DoStmtClass: {
3109 AstNode *while_node = trans_do_loop(c, scope, (const DoStmt *)stmt);
3110 assert(while_node->type == NodeTypeWhileExpr);
3111 if (while_node->data.while_expr.body == nullptr) {
3112 while_node->data.while_expr.body = trans_create_node(c, NodeTypeBlock);
3113 }
3114 return wrap_stmt(out_node, out_child_scope, scope, while_node);
3115 }
3116 case Stmt::ForStmtClass: {3115 case Stmt::ForStmtClass: {
3117 AstNode *node = trans_for_loop(c, scope, (const ForStmt *)stmt);3116 AstNode *node = trans_for_loop(c, scope, (const ForStmt *)stmt);
3118 return wrap_stmt(out_node, out_child_scope, scope, node);3117 return wrap_stmt(out_node, out_child_scope, scope, node);
src/windows_sdk.cpp+7-2
...@@ -204,7 +204,11 @@ static ZigFindWindowsSdkError find_10_version(ZigWindowsSDKPrivate *priv) {...@@ -204,7 +204,11 @@ static ZigFindWindowsSdkError find_10_version(ZigWindowsSDKPrivate *priv) {
204 // https://developer.microsoft.com/en-us/windows/downloads/sdk-archive204 // https://developer.microsoft.com/en-us/windows/downloads/sdk-archive
205 c2 = 26624;205 c2 = 26624;
206 }206 }
207 if ((c0 > v0) || (c1 > v1) || (c2 > v2) || (c3 > v3)) {207
208 if ( (c0 > v0)
209 || (c0 == v0 && c1 > v1)
210 || (c0 == v0 && c1 == v1 && c2 > v2)
211 || (c0 == v0 && c1 == v1 && c2 == v2 && c3 > v3) ) {
208 v0 = c0, v1 = c1, v2 = c2, v3 = c3;212 v0 = c0, v1 = c1, v2 = c2, v3 = c3;
209 free((void*)priv->base.version10_ptr);213 free((void*)priv->base.version10_ptr);
210 priv->base.version10_ptr = strdup(ffd.cFileName);214 priv->base.version10_ptr = strdup(ffd.cFileName);
...@@ -244,7 +248,8 @@ static ZigFindWindowsSdkError find_81_version(ZigWindowsSDKPrivate *priv) {...@@ -244,7 +248,8 @@ static ZigFindWindowsSdkError find_81_version(ZigWindowsSDKPrivate *priv) {
244 if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {248 if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
245 int c0 = 0, c1 = 0;249 int c0 = 0, c1 = 0;
246 sscanf(ffd.cFileName, "winv%d.%d", &c0, &c1);250 sscanf(ffd.cFileName, "winv%d.%d", &c0, &c1);
247 if ((c0 > v0) || (c1 > v1)) {251
252 if ( (c0 > v0) || (c0 == v0 && c1 > v1) ) {
248 v0 = c0, v1 = c1;253 v0 = c0, v1 = c1;
249 free((void*)priv->base.version81_ptr);254 free((void*)priv->base.version81_ptr);
250 priv->base.version81_ptr = strdup(ffd.cFileName);255 priv->base.version81_ptr = strdup(ffd.cFileName);
std/coff.zig created+230
...@@ -0,0 +1,230 @@
1const builtin = @import("builtin");
2const std = @import("index.zig");
3const io = std.io;
4const mem = std.mem;
5const os = std.os;
6
7const ArrayList = std.ArrayList;
8
9// CoffHeader.machine values
10// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680313(v=vs.85).aspx
11const IMAGE_FILE_MACHINE_I386 = 0x014c;
12const IMAGE_FILE_MACHINE_IA64 = 0x0200;
13const IMAGE_FILE_MACHINE_AMD64 = 0x8664;
14
15// OptionalHeader.magic values
16// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680339(v=vs.85).aspx
17const IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;
18const IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;
19
20const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
21const DEBUG_DIRECTORY = 6;
22
23pub const CoffError = error {
24 InvalidPEMagic,
25 InvalidPEHeader,
26 InvalidMachine,
27 MissingCoffSection,
28};
29
30pub const Coff = struct {
31 in_file: os.File,
32 allocator: *mem.Allocator,
33
34 coff_header: CoffHeader,
35 pe_header: OptionalHeader,
36 sections: ArrayList(Section),
37
38 guid: [16]u8,
39 age: u32,
40
41 pub fn loadHeader(self: *Coff) !void {
42 const pe_pointer_offset = 0x3C;
43
44 var file_stream = io.FileInStream.init(self.in_file);
45 const in = &file_stream.stream;
46
47 var magic: [2]u8 = undefined;
48 try in.readNoEof(magic[0..]);
49 if (!mem.eql(u8, magic, "MZ"))
50 return error.InvalidPEMagic;
51
52 // Seek to PE File Header (coff header)
53 try self.in_file.seekTo(pe_pointer_offset);
54 const pe_magic_offset = try in.readIntLe(u32);
55 try self.in_file.seekTo(pe_magic_offset);
56
57 var pe_header_magic: [4]u8 = undefined;
58 try in.readNoEof(pe_header_magic[0..]);
59 if (!mem.eql(u8, pe_header_magic, []u8{'P', 'E', 0, 0}))
60 return error.InvalidPEHeader;
61
62 self.coff_header = CoffHeader {
63 .machine = try in.readIntLe(u16),
64 .number_of_sections = try in.readIntLe(u16),
65 .timedate_stamp = try in.readIntLe(u32),
66 .pointer_to_symbol_table = try in.readIntLe(u32),
67 .number_of_symbols = try in.readIntLe(u32),
68 .size_of_optional_header = try in.readIntLe(u16),
69 .characteristics = try in.readIntLe(u16),
70 };
71
72 switch (self.coff_header.machine) {
73 IMAGE_FILE_MACHINE_I386,
74 IMAGE_FILE_MACHINE_AMD64,
75 IMAGE_FILE_MACHINE_IA64
76 => {},
77 else => return error.InvalidMachine,
78 }
79
80 try self.loadOptionalHeader(&file_stream);
81 }
82
83 fn loadOptionalHeader(self: *Coff, file_stream: *io.FileInStream) !void {
84 const in = &file_stream.stream;
85 self.pe_header.magic = try in.readIntLe(u16);
86 // For now we're only interested in finding the reference to the .pdb,
87 // so we'll skip most of this header, which size is different in 32
88 // 64 bits by the way.
89 var skip_size: u16 = undefined;
90 if (self.pe_header.magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
91 skip_size = 2 * @sizeOf(u8) + 8 * @sizeOf(u16) + 18 * @sizeOf(u32);
92 }
93 else if (self.pe_header.magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
94 skip_size = 2 * @sizeOf(u8) + 8 * @sizeOf(u16) + 12 * @sizeOf(u32) + 5 * @sizeOf(u64);
95 }
96 else
97 return error.InvalidPEMagic;
98
99 try self.in_file.seekForward(skip_size);
100
101 const number_of_rva_and_sizes = try in.readIntLe(u32);
102 if (number_of_rva_and_sizes != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
103 return error.InvalidPEHeader;
104
105 for (self.pe_header.data_directory) |*data_dir| {
106 data_dir.* = OptionalHeader.DataDirectory {
107 .virtual_address = try in.readIntLe(u32),
108 .size = try in.readIntLe(u32),
109 };
110 }
111 }
112
113 pub fn getPdbPath(self: *Coff, buffer: []u8) !usize {
114 try self.loadSections();
115 const header = (self.getSection(".rdata") orelse return error.MissingCoffSection).header;
116
117 // The linker puts a chunk that contains the .pdb path right after the
118 // debug_directory.
119 const debug_dir = &self.pe_header.data_directory[DEBUG_DIRECTORY];
120 const file_offset = debug_dir.virtual_address - header.virtual_address + header.pointer_to_raw_data;
121 try self.in_file.seekTo(file_offset + debug_dir.size);
122
123 var file_stream = io.FileInStream.init(self.in_file);
124 const in = &file_stream.stream;
125
126 var cv_signature: [4]u8 = undefined; // CodeView signature
127 try in.readNoEof(cv_signature[0..]);
128 // 'RSDS' indicates PDB70 format, used by lld.
129 if (!mem.eql(u8, cv_signature, "RSDS"))
130 return error.InvalidPEMagic;
131 try in.readNoEof(self.guid[0..]);
132 self.age = try in.readIntLe(u32);
133
134 // Finally read the null-terminated string.
135 var byte = try in.readByte();
136 var i: usize = 0;
137 while (byte != 0 and i < buffer.len) : (i += 1) {
138 buffer[i] = byte;
139 byte = try in.readByte();
140 }
141
142 if (byte != 0 and i == buffer.len)
143 return error.NameTooLong;
144
145 return i;
146 }
147
148 pub fn loadSections(self: *Coff) !void {
149 if (self.sections.len != 0)
150 return;
151
152 self.sections = ArrayList(Section).init(self.allocator);
153
154 var file_stream = io.FileInStream.init(self.in_file);
155 const in = &file_stream.stream;
156
157 var name: [8]u8 = undefined;
158
159 var i: u16 = 0;
160 while (i < self.coff_header.number_of_sections) : (i += 1) {
161 try in.readNoEof(name[0..]);
162 try self.sections.append(Section {
163 .header = SectionHeader {
164 .name = name,
165 .misc = SectionHeader.Misc { .physical_address = try in.readIntLe(u32) },
166 .virtual_address = try in.readIntLe(u32),
167 .size_of_raw_data = try in.readIntLe(u32),
168 .pointer_to_raw_data = try in.readIntLe(u32),
169 .pointer_to_relocations = try in.readIntLe(u32),
170 .pointer_to_line_numbers = try in.readIntLe(u32),
171 .number_of_relocations = try in.readIntLe(u16),
172 .number_of_line_numbers = try in.readIntLe(u16),
173 .characteristics = try in.readIntLe(u32),
174 },
175 });
176 }
177 }
178
179 pub fn getSection(self: *Coff, comptime name: []const u8) ?*Section {
180 for (self.sections.toSlice()) |*sec| {
181 if (mem.eql(u8, sec.header.name[0..name.len], name)) {
182 return sec;
183 }
184 }
185 return null;
186 }
187
188};
189
190const CoffHeader = struct {
191 machine: u16,
192 number_of_sections: u16,
193 timedate_stamp: u32,
194 pointer_to_symbol_table: u32,
195 number_of_symbols: u32,
196 size_of_optional_header: u16,
197 characteristics: u16
198};
199
200const OptionalHeader = struct {
201 const DataDirectory = struct {
202 virtual_address: u32,
203 size: u32
204 };
205
206 magic: u16,
207 data_directory: [IMAGE_NUMBEROF_DIRECTORY_ENTRIES]DataDirectory,
208};
209
210pub const Section = struct {
211 header: SectionHeader,
212};
213
214const SectionHeader = struct {
215 const Misc = union {
216 physical_address: u32,
217 virtual_size: u32
218 };
219
220 name: [8]u8,
221 misc: Misc,
222 virtual_address: u32,
223 size_of_raw_data: u32,
224 pointer_to_raw_data: u32,
225 pointer_to_relocations: u32,
226 pointer_to_line_numbers: u32,
227 number_of_relocations: u16,
228 number_of_line_numbers: u16,
229 characteristics: u32,
230};
std/crypto/blake2.zig+8-8
...@@ -34,8 +34,8 @@ pub const Blake2s256 = Blake2s(256);...@@ -34,8 +34,8 @@ pub const Blake2s256 = Blake2s(256);
34fn Blake2s(comptime out_len: usize) type {34fn Blake2s(comptime out_len: usize) type {
35 return struct {35 return struct {
36 const Self = this;36 const Self = this;
37 const block_size = 64;37 const block_length = 64;
38 const digest_size = out_len / 8;38 const digest_length = out_len / 8;
3939
40 const iv = [8]u32{40 const iv = [8]u32{
41 0x6A09E667,41 0x6A09E667,
...@@ -250,8 +250,8 @@ test "blake2s256 streaming" {...@@ -250,8 +250,8 @@ test "blake2s256 streaming" {
250}250}
251251
252test "blake2s256 aligned final" {252test "blake2s256 aligned final" {
253 var block = []u8{0} ** Blake2s256.block_size;253 var block = []u8{0} ** Blake2s256.block_length;
254 var out: [Blake2s256.digest_size]u8 = undefined;254 var out: [Blake2s256.digest_length]u8 = undefined;
255255
256 var h = Blake2s256.init();256 var h = Blake2s256.init();
257 h.update(block);257 h.update(block);
...@@ -267,8 +267,8 @@ pub const Blake2b512 = Blake2b(512);...@@ -267,8 +267,8 @@ pub const Blake2b512 = Blake2b(512);
267fn Blake2b(comptime out_len: usize) type {267fn Blake2b(comptime out_len: usize) type {
268 return struct {268 return struct {
269 const Self = this;269 const Self = this;
270 const block_size = 128;270 const block_length = 128;
271 const digest_size = out_len / 8;271 const digest_length = out_len / 8;
272272
273 const iv = [8]u64{273 const iv = [8]u64{
274 0x6a09e667f3bcc908,274 0x6a09e667f3bcc908,
...@@ -483,8 +483,8 @@ test "blake2b512 streaming" {...@@ -483,8 +483,8 @@ test "blake2b512 streaming" {
483}483}
484484
485test "blake2b512 aligned final" {485test "blake2b512 aligned final" {
486 var block = []u8{0} ** Blake2b512.block_size;486 var block = []u8{0} ** Blake2b512.block_length;
487 var out: [Blake2b512.digest_size]u8 = undefined;487 var out: [Blake2b512.digest_length]u8 = undefined;
488488
489 var h = Blake2b512.init();489 var h = Blake2b512.init();
490 h.update(block);490 h.update(block);
std/crypto/chacha20.zig created+432
...@@ -0,0 +1,432 @@
1// Based on public domain Supercop by Daniel J. Bernstein
2
3const std = @import("../index.zig");
4const mem = std.mem;
5const endian = std.endian;
6const assert = std.debug.assert;
7const builtin = @import("builtin");
8
9const QuarterRound = struct {
10 a: usize,
11 b: usize,
12 c: usize,
13 d: usize,
14};
15
16fn Rp(a: usize, b: usize, c: usize, d: usize) QuarterRound {
17 return QuarterRound{
18 .a = a,
19 .b = b,
20 .c = c,
21 .d = d,
22 };
23}
24
25// The chacha family of ciphers are based on the salsa family.
26fn salsa20_wordtobyte(out: []u8, input: [16]u32) void {
27 assert(out.len >= 64);
28
29 var x: [16]u32 = undefined;
30
31 for (x) |_, i|
32 x[i] = input[i];
33
34 const rounds = comptime []QuarterRound{
35 Rp(0, 4, 8, 12),
36 Rp(1, 5, 9, 13),
37 Rp(2, 6, 10, 14),
38 Rp(3, 7, 11, 15),
39 Rp(0, 5, 10, 15),
40 Rp(1, 6, 11, 12),
41 Rp(2, 7, 8, 13),
42 Rp(3, 4, 9, 14),
43 };
44
45 comptime var j: usize = 0;
46 inline while (j < 20) : (j += 2) {
47 // two-round cycles
48 inline for (rounds) |r| {
49 x[r.a] +%= x[r.b];
50 x[r.d] = std.math.rotl(u32, x[r.d] ^ x[r.a], u32(16));
51 x[r.c] +%= x[r.d];
52 x[r.b] = std.math.rotl(u32, x[r.b] ^ x[r.c], u32(12));
53 x[r.a] +%= x[r.b];
54 x[r.d] = std.math.rotl(u32, x[r.d] ^ x[r.a], u32(8));
55 x[r.c] +%= x[r.d];
56 x[r.b] = std.math.rotl(u32, x[r.b] ^ x[r.c], u32(7));
57 }
58 }
59
60 for (x) |_, i| {
61 mem.writeInt(out[4 * i .. 4 * i + 4], x[i] +% input[i], builtin.Endian.Little);
62 }
63}
64
65fn chaCha20_internal(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) void {
66 var ctx: [16]u32 = undefined;
67 var remaining: usize = if (in.len > out.len) in.len else out.len;
68 var cursor: usize = 0;
69
70 const c = "expand 32-byte k";
71 const constant_le = []u32{
72 mem.readIntLE(u32, c[0..4]),
73 mem.readIntLE(u32, c[4..8]),
74 mem.readIntLE(u32, c[8..12]),
75 mem.readIntLE(u32, c[12..16]),
76 };
77
78 mem.copy(u32, ctx[0..], constant_le[0..4]);
79 mem.copy(u32, ctx[4..12], key[0..8]);
80 mem.copy(u32, ctx[12..16], counter[0..4]);
81
82 while (true) {
83 var buf: [64]u8 = undefined;
84 salsa20_wordtobyte(buf[0..], ctx);
85
86 if (remaining < 64) {
87 var i: usize = 0;
88 while (i < remaining) : (i += 1)
89 out[cursor + i] = in[cursor + i] ^ buf[i];
90 return;
91 }
92
93 var i: usize = 0;
94 while (i < 64) : (i += 1)
95 out[cursor + i] = in[cursor + i] ^ buf[i];
96
97 cursor += 64;
98 remaining -= 64;
99
100 ctx[12] += 1;
101 }
102}
103
104/// ChaCha20 avoids the possibility of timing attacks, as there are no branches
105/// on secret key data.
106///
107/// in and out should be the same length.
108/// counter should generally be 0 or 1
109///
110/// ChaCha20 is self-reversing. To decrypt just run the cipher with the same
111/// counter, nonce, and key.
112pub fn chaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [12]u8) void {
113 assert(in.len >= out.len);
114 assert((in.len >> 6) + counter <= @maxValue(u32));
115
116 var k: [8]u32 = undefined;
117 var c: [4]u32 = undefined;
118
119 k[0] = mem.readIntLE(u32, key[0..4]);
120 k[1] = mem.readIntLE(u32, key[4..8]);
121 k[2] = mem.readIntLE(u32, key[8..12]);
122 k[3] = mem.readIntLE(u32, key[12..16]);
123 k[4] = mem.readIntLE(u32, key[16..20]);
124 k[5] = mem.readIntLE(u32, key[20..24]);
125 k[6] = mem.readIntLE(u32, key[24..28]);
126 k[7] = mem.readIntLE(u32, key[28..32]);
127
128 c[0] = counter;
129 c[1] = mem.readIntLE(u32, nonce[0..4]);
130 c[2] = mem.readIntLE(u32, nonce[4..8]);
131 c[3] = mem.readIntLE(u32, nonce[8..12]);
132 chaCha20_internal(out, in, k, c);
133}
134
135/// This is the original ChaCha20 before RFC 7539, which recommends using the
136/// orgininal version on applications such as disk or file encryption that might
137/// exceed the 256 GiB limit of the 96-bit nonce version.
138pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32]u8, nonce: [8]u8) void {
139 assert(in.len >= out.len);
140 assert(counter +% (in.len >> 6) >= counter);
141
142 var cursor: u64 = 0;
143 var k: [8]u32 = undefined;
144 var c: [4]u32 = undefined;
145
146 k[0] = mem.readIntLE(u32, key[0..4]);
147 k[1] = mem.readIntLE(u32, key[4..8]);
148 k[2] = mem.readIntLE(u32, key[8..12]);
149 k[3] = mem.readIntLE(u32, key[12..16]);
150 k[4] = mem.readIntLE(u32, key[16..20]);
151 k[5] = mem.readIntLE(u32, key[20..24]);
152 k[6] = mem.readIntLE(u32, key[24..28]);
153 k[7] = mem.readIntLE(u32, key[28..32]);
154
155 c[0] = @truncate(u32, counter);
156 c[1] = @truncate(u32, counter >> 32);
157 c[2] = mem.readIntLE(u32, nonce[0..4]);
158 c[3] = mem.readIntLE(u32, nonce[4..8]);
159
160 const block_size = (1 << 6);
161 const big_block = (block_size << 32);
162
163 // first partial big block
164 if (((@intCast(u64, @maxValue(u32) - @truncate(u32, counter)) + 1) << 6) < in.len) {
165 chaCha20_internal(out[cursor..big_block], in[cursor..big_block], k, c);
166 cursor = big_block - cursor;
167 c[1] += 1;
168 if (comptime @sizeOf(usize) > 4) {
169 // A big block is giant: 256 GiB, but we can avoid this limitation
170 var remaining_blocks: u32 = @intCast(u32, (in.len / big_block));
171 var i: u32 = 0;
172 while (remaining_blocks > 0) : (remaining_blocks -= 1) {
173 chaCha20_internal(out[cursor .. cursor + big_block], in[cursor .. cursor + big_block], k, c);
174 c[1] += 1; // upper 32-bit of counter, generic chaCha20_internal() doesn't know about this.
175 cursor += big_block;
176 }
177 }
178 }
179
180 chaCha20_internal(out[cursor..], in[cursor..], k, c);
181}
182
183// https://tools.ietf.org/html/rfc7539#section-2.4.2
184test "crypto.chacha20 test vector sunscreen" {
185 const expected_result = []u8{
186 0x6e, 0x2e, 0x35, 0x9a, 0x25, 0x68, 0xf9, 0x80,
187 0x41, 0xba, 0x07, 0x28, 0xdd, 0x0d, 0x69, 0x81,
188 0xe9, 0x7e, 0x7a, 0xec, 0x1d, 0x43, 0x60, 0xc2,
189 0x0a, 0x27, 0xaf, 0xcc, 0xfd, 0x9f, 0xae, 0x0b,
190 0xf9, 0x1b, 0x65, 0xc5, 0x52, 0x47, 0x33, 0xab,
191 0x8f, 0x59, 0x3d, 0xab, 0xcd, 0x62, 0xb3, 0x57,
192 0x16, 0x39, 0xd6, 0x24, 0xe6, 0x51, 0x52, 0xab,
193 0x8f, 0x53, 0x0c, 0x35, 0x9f, 0x08, 0x61, 0xd8,
194 0x07, 0xca, 0x0d, 0xbf, 0x50, 0x0d, 0x6a, 0x61,
195 0x56, 0xa3, 0x8e, 0x08, 0x8a, 0x22, 0xb6, 0x5e,
196 0x52, 0xbc, 0x51, 0x4d, 0x16, 0xcc, 0xf8, 0x06,
197 0x81, 0x8c, 0xe9, 0x1a, 0xb7, 0x79, 0x37, 0x36,
198 0x5a, 0xf9, 0x0b, 0xbf, 0x74, 0xa3, 0x5b, 0xe6,
199 0xb4, 0x0b, 0x8e, 0xed, 0xf2, 0x78, 0x5e, 0x42,
200 0x87, 0x4d,
201 };
202 const input = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.";
203 var result: [114]u8 = undefined;
204 const key = []u8{
205 0, 1, 2, 3, 4, 5, 6, 7,
206 8, 9, 10, 11, 12, 13, 14, 15,
207 16, 17, 18, 19, 20, 21, 22, 23,
208 24, 25, 26, 27, 28, 29, 30, 31,
209 };
210 const nonce = []u8{
211 0, 0, 0, 0,
212 0, 0, 0, 0x4a,
213 0, 0, 0, 0,
214 };
215
216 chaCha20IETF(result[0..], input[0..], 1, key, nonce);
217 assert(mem.eql(u8, expected_result, result));
218
219 // Chacha20 is self-reversing.
220 var plaintext: [114]u8 = undefined;
221 chaCha20IETF(plaintext[0..], result[0..], 1, key, nonce);
222 assert(mem.compare(u8, input, plaintext) == mem.Compare.Equal);
223}
224
225// https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-7
226test "crypto.chacha20 test vector 1" {
227 const expected_result = []u8{
228 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90,
229 0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28,
230 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a,
231 0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7,
232 0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d,
233 0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37,
234 0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c,
235 0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86,
236 };
237 const input = []u8{
238 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
239 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
240 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
241 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
242 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
243 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
244 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
245 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
246 };
247 var result: [64]u8 = undefined;
248 const key = []u8{
249 0, 0, 0, 0, 0, 0, 0, 0,
250 0, 0, 0, 0, 0, 0, 0, 0,
251 0, 0, 0, 0, 0, 0, 0, 0,
252 0, 0, 0, 0, 0, 0, 0, 0,
253 };
254 const nonce = []u8{ 0, 0, 0, 0, 0, 0, 0, 0 };
255
256 chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce);
257 assert(mem.eql(u8, expected_result, result));
258}
259
260test "crypto.chacha20 test vector 2" {
261 const expected_result = []u8{
262 0x45, 0x40, 0xf0, 0x5a, 0x9f, 0x1f, 0xb2, 0x96,
263 0xd7, 0x73, 0x6e, 0x7b, 0x20, 0x8e, 0x3c, 0x96,
264 0xeb, 0x4f, 0xe1, 0x83, 0x46, 0x88, 0xd2, 0x60,
265 0x4f, 0x45, 0x09, 0x52, 0xed, 0x43, 0x2d, 0x41,
266 0xbb, 0xe2, 0xa0, 0xb6, 0xea, 0x75, 0x66, 0xd2,
267 0xa5, 0xd1, 0xe7, 0xe2, 0x0d, 0x42, 0xaf, 0x2c,
268 0x53, 0xd7, 0x92, 0xb1, 0xc4, 0x3f, 0xea, 0x81,
269 0x7e, 0x9a, 0xd2, 0x75, 0xae, 0x54, 0x69, 0x63,
270 };
271 const input = []u8{
272 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
273 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
274 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
275 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
276 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
277 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
278 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
279 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
280 };
281 var result: [64]u8 = undefined;
282 const key = []u8{
283 0, 0, 0, 0, 0, 0, 0, 0,
284 0, 0, 0, 0, 0, 0, 0, 0,
285 0, 0, 0, 0, 0, 0, 0, 0,
286 0, 0, 0, 0, 0, 0, 0, 1,
287 };
288 const nonce = []u8{ 0, 0, 0, 0, 0, 0, 0, 0 };
289
290 chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce);
291 assert(mem.eql(u8, expected_result, result));
292}
293
294test "crypto.chacha20 test vector 3" {
295 const expected_result = []u8{
296 0xde, 0x9c, 0xba, 0x7b, 0xf3, 0xd6, 0x9e, 0xf5,
297 0xe7, 0x86, 0xdc, 0x63, 0x97, 0x3f, 0x65, 0x3a,
298 0x0b, 0x49, 0xe0, 0x15, 0xad, 0xbf, 0xf7, 0x13,
299 0x4f, 0xcb, 0x7d, 0xf1, 0x37, 0x82, 0x10, 0x31,
300 0xe8, 0x5a, 0x05, 0x02, 0x78, 0xa7, 0x08, 0x45,
301 0x27, 0x21, 0x4f, 0x73, 0xef, 0xc7, 0xfa, 0x5b,
302 0x52, 0x77, 0x06, 0x2e, 0xb7, 0xa0, 0x43, 0x3e,
303 0x44, 0x5f, 0x41, 0xe3,
304 };
305 const input = []u8{
306 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
307 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
308 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
310 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
313 0x00, 0x00, 0x00, 0x00,
314 };
315 var result: [60]u8 = undefined;
316 const key = []u8{
317 0, 0, 0, 0, 0, 0, 0, 0,
318 0, 0, 0, 0, 0, 0, 0, 0,
319 0, 0, 0, 0, 0, 0, 0, 0,
320 0, 0, 0, 0, 0, 0, 0, 0,
321 };
322 const nonce = []u8{ 0, 0, 0, 0, 0, 0, 0, 1 };
323
324 chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce);
325 assert(mem.eql(u8, expected_result, result));
326}
327
328test "crypto.chacha20 test vector 4" {
329 const expected_result = []u8{
330 0xef, 0x3f, 0xdf, 0xd6, 0xc6, 0x15, 0x78, 0xfb,
331 0xf5, 0xcf, 0x35, 0xbd, 0x3d, 0xd3, 0x3b, 0x80,
332 0x09, 0x63, 0x16, 0x34, 0xd2, 0x1e, 0x42, 0xac,
333 0x33, 0x96, 0x0b, 0xd1, 0x38, 0xe5, 0x0d, 0x32,
334 0x11, 0x1e, 0x4c, 0xaf, 0x23, 0x7e, 0xe5, 0x3c,
335 0xa8, 0xad, 0x64, 0x26, 0x19, 0x4a, 0x88, 0x54,
336 0x5d, 0xdc, 0x49, 0x7a, 0x0b, 0x46, 0x6e, 0x7d,
337 0x6b, 0xbd, 0xb0, 0x04, 0x1b, 0x2f, 0x58, 0x6b,
338 };
339 const input = []u8{
340 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
341 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
342 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
343 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
344 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
345 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
346 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
347 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
348 };
349 var result: [64]u8 = undefined;
350 const key = []u8{
351 0, 0, 0, 0, 0, 0, 0, 0,
352 0, 0, 0, 0, 0, 0, 0, 0,
353 0, 0, 0, 0, 0, 0, 0, 0,
354 0, 0, 0, 0, 0, 0, 0, 0,
355 };
356 const nonce = []u8{ 1, 0, 0, 0, 0, 0, 0, 0 };
357
358 chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce);
359 assert(mem.eql(u8, expected_result, result));
360}
361
362test "crypto.chacha20 test vector 5" {
363 const expected_result = []u8{
364 0xf7, 0x98, 0xa1, 0x89, 0xf1, 0x95, 0xe6, 0x69,
365 0x82, 0x10, 0x5f, 0xfb, 0x64, 0x0b, 0xb7, 0x75,
366 0x7f, 0x57, 0x9d, 0xa3, 0x16, 0x02, 0xfc, 0x93,
367 0xec, 0x01, 0xac, 0x56, 0xf8, 0x5a, 0xc3, 0xc1,
368 0x34, 0xa4, 0x54, 0x7b, 0x73, 0x3b, 0x46, 0x41,
369 0x30, 0x42, 0xc9, 0x44, 0x00, 0x49, 0x17, 0x69,
370 0x05, 0xd3, 0xbe, 0x59, 0xea, 0x1c, 0x53, 0xf1,
371 0x59, 0x16, 0x15, 0x5c, 0x2b, 0xe8, 0x24, 0x1a,
372
373 0x38, 0x00, 0x8b, 0x9a, 0x26, 0xbc, 0x35, 0x94,
374 0x1e, 0x24, 0x44, 0x17, 0x7c, 0x8a, 0xde, 0x66,
375 0x89, 0xde, 0x95, 0x26, 0x49, 0x86, 0xd9, 0x58,
376 0x89, 0xfb, 0x60, 0xe8, 0x46, 0x29, 0xc9, 0xbd,
377 0x9a, 0x5a, 0xcb, 0x1c, 0xc1, 0x18, 0xbe, 0x56,
378 0x3e, 0xb9, 0xb3, 0xa4, 0xa4, 0x72, 0xf8, 0x2e,
379 0x09, 0xa7, 0xe7, 0x78, 0x49, 0x2b, 0x56, 0x2e,
380 0xf7, 0x13, 0x0e, 0x88, 0xdf, 0xe0, 0x31, 0xc7,
381
382 0x9d, 0xb9, 0xd4, 0xf7, 0xc7, 0xa8, 0x99, 0x15,
383 0x1b, 0x9a, 0x47, 0x50, 0x32, 0xb6, 0x3f, 0xc3,
384 0x85, 0x24, 0x5f, 0xe0, 0x54, 0xe3, 0xdd, 0x5a,
385 0x97, 0xa5, 0xf5, 0x76, 0xfe, 0x06, 0x40, 0x25,
386 0xd3, 0xce, 0x04, 0x2c, 0x56, 0x6a, 0xb2, 0xc5,
387 0x07, 0xb1, 0x38, 0xdb, 0x85, 0x3e, 0x3d, 0x69,
388 0x59, 0x66, 0x09, 0x96, 0x54, 0x6c, 0xc9, 0xc4,
389 0xa6, 0xea, 0xfd, 0xc7, 0x77, 0xc0, 0x40, 0xd7,
390
391 0x0e, 0xaf, 0x46, 0xf7, 0x6d, 0xad, 0x39, 0x79,
392 0xe5, 0xc5, 0x36, 0x0c, 0x33, 0x17, 0x16, 0x6a,
393 0x1c, 0x89, 0x4c, 0x94, 0xa3, 0x71, 0x87, 0x6a,
394 0x94, 0xdf, 0x76, 0x28, 0xfe, 0x4e, 0xaa, 0xf2,
395 0xcc, 0xb2, 0x7d, 0x5a, 0xaa, 0xe0, 0xad, 0x7a,
396 0xd0, 0xf9, 0xd4, 0xb6, 0xad, 0x3b, 0x54, 0x09,
397 0x87, 0x46, 0xd4, 0x52, 0x4d, 0x38, 0x40, 0x7a,
398 0x6d, 0xeb, 0x3a, 0xb7, 0x8f, 0xab, 0x78, 0xc9,
399 };
400 const input = []u8{
401 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
402 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
403 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
404 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
405 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
406 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
407 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
408 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
409
410 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
411 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
412 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
413 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
414 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
415 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
416 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
417 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
418 };
419 var result: [256]u8 = undefined;
420 const key = []u8{
421 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
422 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
423 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
424 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
425 };
426 const nonce = []u8{
427 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
428 };
429
430 chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce);
431 assert(mem.eql(u8, expected_result, result));
432}
std/crypto/hmac.zig+54-37
...@@ -7,46 +7,63 @@ pub const HmacMd5 = Hmac(crypto.Md5);...@@ -7,46 +7,63 @@ pub const HmacMd5 = Hmac(crypto.Md5);
7pub const HmacSha1 = Hmac(crypto.Sha1);7pub const HmacSha1 = Hmac(crypto.Sha1);
8pub const HmacSha256 = Hmac(crypto.Sha256);8pub const HmacSha256 = Hmac(crypto.Sha256);
99
10pub fn Hmac(comptime H: type) type {10pub fn Hmac(comptime Hash: type) type {
11 return struct {11 return struct {
12 const digest_size = H.digest_size;12 const Self = this;
13 pub const mac_length = Hash.digest_length;
14 pub const minimum_key_length = 0;
1315
14 pub fn hash(output: []u8, key: []const u8, message: []const u8) void {16 o_key_pad: [Hash.block_length]u8,
15 debug.assert(output.len >= H.digest_size);17 i_key_pad: [Hash.block_length]u8,
16 debug.assert(H.digest_size <= H.block_size); // HMAC makes this assumption18 scratch: [Hash.block_length]u8,
17 var scratch: [H.block_size]u8 = undefined;19 hash: Hash,
20
21 // HMAC(k, m) = H(o_key_pad | H(i_key_pad | msg)) where | is concatenation
22 pub fn create(out: []u8, msg: []const u8, key: []const u8) void {
23 var ctx = Self.init(key);
24 ctx.update(msg);
25 ctx.final(out[0..]);
26 }
27
28 pub fn init(key: []const u8) Self {
29 var ctx: Self = undefined;
1830
19 // Normalize key length to block size of hash31 // Normalize key length to block size of hash
20 if (key.len > H.block_size) {32 if (key.len > Hash.block_length) {
21 H.hash(key, scratch[0..H.digest_size]);33 Hash.hash(key, ctx.scratch[0..mac_length]);
22 mem.set(u8, scratch[H.digest_size..H.block_size], 0);34 mem.set(u8, ctx.scratch[mac_length..Hash.block_length], 0);
23 } else if (key.len < H.block_size) {35 } else if (key.len < Hash.block_length) {
24 mem.copy(u8, scratch[0..key.len], key);36 mem.copy(u8, ctx.scratch[0..key.len], key);
25 mem.set(u8, scratch[key.len..H.block_size], 0);37 mem.set(u8, ctx.scratch[key.len..Hash.block_length], 0);
26 } else {38 } else {
27 mem.copy(u8, scratch[0..], key);39 mem.copy(u8, ctx.scratch[0..], key);
28 }40 }
2941
30 var o_key_pad: [H.block_size]u8 = undefined;42 for (ctx.o_key_pad) |*b, i| {
31 for (o_key_pad) |*b, i| {43 b.* = ctx.scratch[i] ^ 0x5c;
32 b.* = scratch[i] ^ 0x5c;
33 }44 }
3445
35 var i_key_pad: [H.block_size]u8 = undefined;46 for (ctx.i_key_pad) |*b, i| {
36 for (i_key_pad) |*b, i| {47 b.* = ctx.scratch[i] ^ 0x36;
37 b.* = scratch[i] ^ 0x36;
38 }48 }
3949
40 // HMAC(k, m) = H(o_key_pad | H(i_key_pad | message)) where | is concatenation50 ctx.hash = Hash.init();
41 var hmac = H.init();51 ctx.hash.update(ctx.i_key_pad[0..]);
42 hmac.update(i_key_pad[0..]);52 return ctx;
43 hmac.update(message);53 }
44 hmac.final(scratch[0..H.digest_size]);54
55 pub fn update(ctx: *Self, msg: []const u8) void {
56 ctx.hash.update(msg);
57 }
58
59 pub fn final(ctx: *Self, out: []u8) void {
60 debug.assert(Hash.block_length >= out.len and out.len >= mac_length);
4561
46 hmac.reset();62 ctx.hash.final(ctx.scratch[0..mac_length]);
47 hmac.update(o_key_pad[0..]);63 ctx.hash.reset();
48 hmac.update(scratch[0..H.digest_size]);64 ctx.hash.update(ctx.o_key_pad[0..]);
49 hmac.final(output[0..H.digest_size]);65 ctx.hash.update(ctx.scratch[0..mac_length]);
66 ctx.hash.final(out[0..mac_length]);
50 }67 }
51 };68 };
52}69}
...@@ -54,28 +71,28 @@ pub fn Hmac(comptime H: type) type {...@@ -54,28 +71,28 @@ pub fn Hmac(comptime H: type) type {
54const htest = @import("test.zig");71const htest = @import("test.zig");
5572
56test "hmac md5" {73test "hmac md5" {
57 var out: [crypto.Md5.digest_size]u8 = undefined;74 var out: [HmacMd5.mac_length]u8 = undefined;
58 HmacMd5.hash(out[0..], "", "");75 HmacMd5.create(out[0..], "", "");
59 htest.assertEqual("74e6f7298a9c2d168935f58c001bad88", out[0..]);76 htest.assertEqual("74e6f7298a9c2d168935f58c001bad88", out[0..]);
6077
61 HmacMd5.hash(out[0..], "key", "The quick brown fox jumps over the lazy dog");78 HmacMd5.create(out[0..], "The quick brown fox jumps over the lazy dog", "key");
62 htest.assertEqual("80070713463e7749b90c2dc24911e275", out[0..]);79 htest.assertEqual("80070713463e7749b90c2dc24911e275", out[0..]);
63}80}
6481
65test "hmac sha1" {82test "hmac sha1" {
66 var out: [crypto.Sha1.digest_size]u8 = undefined;83 var out: [HmacSha1.mac_length]u8 = undefined;
67 HmacSha1.hash(out[0..], "", "");84 HmacSha1.create(out[0..], "", "");
68 htest.assertEqual("fbdb1d1b18aa6c08324b7d64b71fb76370690e1d", out[0..]);85 htest.assertEqual("fbdb1d1b18aa6c08324b7d64b71fb76370690e1d", out[0..]);
6986
70 HmacSha1.hash(out[0..], "key", "The quick brown fox jumps over the lazy dog");87 HmacSha1.create(out[0..], "The quick brown fox jumps over the lazy dog", "key");
71 htest.assertEqual("de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9", out[0..]);88 htest.assertEqual("de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9", out[0..]);
72}89}
7390
74test "hmac sha256" {91test "hmac sha256" {
75 var out: [crypto.Sha256.digest_size]u8 = undefined;92 var out: [HmacSha256.mac_length]u8 = undefined;
76 HmacSha256.hash(out[0..], "", "");93 HmacSha256.create(out[0..], "", "");
77 htest.assertEqual("b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad", out[0..]);94 htest.assertEqual("b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad", out[0..]);
7895
79 HmacSha256.hash(out[0..], "key", "The quick brown fox jumps over the lazy dog");96 HmacSha256.create(out[0..], "The quick brown fox jumps over the lazy dog", "key");
80 htest.assertEqual("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8", out[0..]);97 htest.assertEqual("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8", out[0..]);
81}98}
std/crypto/index.zig+14-4
...@@ -21,14 +21,24 @@ pub const Blake2b512 = blake2.Blake2b512;...@@ -21,14 +21,24 @@ pub const Blake2b512 = blake2.Blake2b512;
2121
22const hmac = @import("hmac.zig");22const hmac = @import("hmac.zig");
23pub const HmacMd5 = hmac.HmacMd5;23pub const HmacMd5 = hmac.HmacMd5;
24pub const HmacSha1 = hmac.Sha1;24pub const HmacSha1 = hmac.HmacSha1;
25pub const HmacSha256 = hmac.Sha256;25pub const HmacSha256 = hmac.HmacSha256;
26
27const import_chaCha20 = @import("chacha20.zig");
28pub const chaCha20IETF = import_chaCha20.chaCha20IETF;
29pub const chaCha20With64BitNonce = import_chaCha20.chaCha20With64BitNonce;
30
31pub const Poly1305 = @import("poly1305.zig").Poly1305;
32pub const X25519 = @import("x25519.zig").X25519;
2633
27test "crypto" {34test "crypto" {
35 _ = @import("blake2.zig");
36 _ = @import("chacha20.zig");
37 _ = @import("hmac.zig");
28 _ = @import("md5.zig");38 _ = @import("md5.zig");
39 _ = @import("poly1305.zig");
29 _ = @import("sha1.zig");40 _ = @import("sha1.zig");
30 _ = @import("sha2.zig");41 _ = @import("sha2.zig");
31 _ = @import("sha3.zig");42 _ = @import("sha3.zig");
32 _ = @import("blake2.zig");43 _ = @import("x25519.zig");
33 _ = @import("hmac.zig");
34}44}
std/crypto/md5.zig+4-4
...@@ -29,8 +29,8 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, k: usize, s: u32, t: u32) RoundPar...@@ -29,8 +29,8 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, k: usize, s: u32, t: u32) RoundPar
2929
30pub const Md5 = struct {30pub const Md5 = struct {
31 const Self = this;31 const Self = this;
32 const block_size = 64;32 const block_length = 64;
33 const digest_size = 16;33 const digest_length = 16;
3434
35 s: [4]u32,35 s: [4]u32,
36 // Streaming Cache36 // Streaming Cache
...@@ -271,8 +271,8 @@ test "md5 streaming" {...@@ -271,8 +271,8 @@ test "md5 streaming" {
271}271}
272272
273test "md5 aligned final" {273test "md5 aligned final" {
274 var block = []u8{0} ** Md5.block_size;274 var block = []u8{0} ** Md5.block_length;
275 var out: [Md5.digest_size]u8 = undefined;275 var out: [Md5.digest_length]u8 = undefined;
276276
277 var h = Md5.init();277 var h = Md5.init();
278 h.update(block);278 h.update(block);
std/crypto/poly1305.zig created+233
...@@ -0,0 +1,233 @@
1// Translated from monocypher which is licensed under CC-0/BSD-3.
2//
3// https://monocypher.org/
4
5const std = @import("../index.zig");
6const builtin = @import("builtin");
7
8const Endian = builtin.Endian;
9const readInt = std.mem.readInt;
10const writeInt = std.mem.writeInt;
11
12pub const Poly1305 = struct {
13 const Self = this;
14
15 pub const mac_length = 16;
16 pub const minimum_key_length = 32;
17
18 // constant multiplier (from the secret key)
19 r: [4]u32,
20 // accumulated hash
21 h: [5]u32,
22 // chunk of the message
23 c: [5]u32,
24 // random number added at the end (from the secret key)
25 pad: [4]u32,
26 // How many bytes are there in the chunk.
27 c_idx: usize,
28
29 fn secureZero(self: *Self) void {
30 std.mem.secureZero(u8, @ptrCast([*]u8, self)[0..@sizeOf(Poly1305)]);
31 }
32
33 pub fn create(out: []u8, msg: []const u8, key: []const u8) void {
34 std.debug.assert(out.len >= mac_length);
35 std.debug.assert(key.len >= minimum_key_length);
36
37 var ctx = Poly1305.init(key);
38 ctx.update(msg);
39 ctx.final(out);
40 }
41
42 // Initialize the MAC context.
43 // - key.len is sufficient size.
44 pub fn init(key: []const u8) Self {
45 var ctx: Poly1305 = undefined;
46
47 // Initial hash is zero
48 {
49 var i: usize = 0;
50 while (i < 5) : (i += 1) {
51 ctx.h[i] = 0;
52 }
53 }
54 // add 2^130 to every input block
55 ctx.c[4] = 1;
56 polyClearC(&ctx);
57
58 // load r and pad (r has some of its bits cleared)
59 {
60 var i: usize = 0;
61 while (i < 1) : (i += 1) {
62 ctx.r[0] = readInt(key[0..4], u32, Endian.Little) & 0x0fffffff;
63 }
64 }
65 {
66 var i: usize = 1;
67 while (i < 4) : (i += 1) {
68 ctx.r[i] = readInt(key[i * 4 .. i * 4 + 4], u32, Endian.Little) & 0x0ffffffc;
69 }
70 }
71 {
72 var i: usize = 0;
73 while (i < 4) : (i += 1) {
74 ctx.pad[i] = readInt(key[i * 4 + 16 .. i * 4 + 16 + 4], u32, Endian.Little);
75 }
76 }
77
78 return ctx;
79 }
80
81 // h = (h + c) * r
82 // preconditions:
83 // ctx->h <= 4_ffffffff_ffffffff_ffffffff_ffffffff
84 // ctx->c <= 1_ffffffff_ffffffff_ffffffff_ffffffff
85 // ctx->r <= 0ffffffc_0ffffffc_0ffffffc_0fffffff
86 // Postcondition:
87 // ctx->h <= 4_ffffffff_ffffffff_ffffffff_ffffffff
88 fn polyBlock(ctx: *Self) void {
89 // s = h + c, without carry propagation
90 const s0 = u64(ctx.h[0]) + ctx.c[0]; // s0 <= 1_fffffffe
91 const s1 = u64(ctx.h[1]) + ctx.c[1]; // s1 <= 1_fffffffe
92 const s2 = u64(ctx.h[2]) + ctx.c[2]; // s2 <= 1_fffffffe
93 const s3 = u64(ctx.h[3]) + ctx.c[3]; // s3 <= 1_fffffffe
94 const s4 = u64(ctx.h[4]) + ctx.c[4]; // s4 <= 5
95
96 // Local all the things!
97 const r0 = ctx.r[0]; // r0 <= 0fffffff
98 const r1 = ctx.r[1]; // r1 <= 0ffffffc
99 const r2 = ctx.r[2]; // r2 <= 0ffffffc
100 const r3 = ctx.r[3]; // r3 <= 0ffffffc
101 const rr0 = (r0 >> 2) * 5; // rr0 <= 13fffffb // lose 2 bits...
102 const rr1 = (r1 >> 2) + r1; // rr1 <= 13fffffb // rr1 == (r1 >> 2) * 5
103 const rr2 = (r2 >> 2) + r2; // rr2 <= 13fffffb // rr1 == (r2 >> 2) * 5
104 const rr3 = (r3 >> 2) + r3; // rr3 <= 13fffffb // rr1 == (r3 >> 2) * 5
105
106 // (h + c) * r, without carry propagation
107 const x0 = s0 * r0 + s1 * rr3 + s2 * rr2 + s3 * rr1 + s4 * rr0; //<=97ffffe007fffff8
108 const x1 = s0 * r1 + s1 * r0 + s2 * rr3 + s3 * rr2 + s4 * rr1; //<=8fffffe20ffffff6
109 const x2 = s0 * r2 + s1 * r1 + s2 * r0 + s3 * rr3 + s4 * rr2; //<=87ffffe417fffff4
110 const x3 = s0 * r3 + s1 * r2 + s2 * r1 + s3 * r0 + s4 * rr3; //<=7fffffe61ffffff2
111 const x4 = s4 * (r0 & 3); // ...recover 2 bits //<= f
112
113 // partial reduction modulo 2^130 - 5
114 const _u5 = @truncate(u32, x4 + (x3 >> 32)); // u5 <= 7ffffff5
115 const _u0 = (_u5 >> 2) * 5 + (x0 & 0xffffffff);
116 const _u1 = (_u0 >> 32) + (x1 & 0xffffffff) + (x0 >> 32);
117 const _u2 = (_u1 >> 32) + (x2 & 0xffffffff) + (x1 >> 32);
118 const _u3 = (_u2 >> 32) + (x3 & 0xffffffff) + (x2 >> 32);
119 const _u4 = (_u3 >> 32) + (_u5 & 3);
120
121 // Update the hash
122 ctx.h[0] = @truncate(u32, _u0); // u0 <= 1_9ffffff0
123 ctx.h[1] = @truncate(u32, _u1); // u1 <= 1_97ffffe0
124 ctx.h[2] = @truncate(u32, _u2); // u2 <= 1_8fffffe2
125 ctx.h[3] = @truncate(u32, _u3); // u3 <= 1_87ffffe4
126 ctx.h[4] = @truncate(u32, _u4); // u4 <= 4
127 }
128
129 // (re-)initializes the input counter and input buffer
130 fn polyClearC(ctx: *Self) void {
131 ctx.c[0] = 0;
132 ctx.c[1] = 0;
133 ctx.c[2] = 0;
134 ctx.c[3] = 0;
135 ctx.c_idx = 0;
136 }
137
138 fn polyTakeInput(ctx: *Self, input: u8) void {
139 const word = ctx.c_idx >> 2;
140 const byte = ctx.c_idx & 3;
141 ctx.c[word] |= std.math.shl(u32, input, byte * 8);
142 ctx.c_idx += 1;
143 }
144
145 fn polyUpdate(ctx: *Self, msg: []const u8) void {
146 for (msg) |b| {
147 polyTakeInput(ctx, b);
148 if (ctx.c_idx == 16) {
149 polyBlock(ctx);
150 polyClearC(ctx);
151 }
152 }
153 }
154
155 fn alignTo(x: usize, block_size: usize) usize {
156 return ((~x) +% 1) & (block_size - 1);
157 }
158
159 // Feed data into the MAC context.
160 pub fn update(ctx: *Self, msg: []const u8) void {
161 // Align ourselves with block boundaries
162 const alignm = std.math.min(alignTo(ctx.c_idx, 16), msg.len);
163 polyUpdate(ctx, msg[0..alignm]);
164
165 var nmsg = msg[alignm..];
166
167 // Process the msg block by block
168 const nb_blocks = nmsg.len >> 4;
169 var i: usize = 0;
170 while (i < nb_blocks) : (i += 1) {
171 ctx.c[0] = readInt(nmsg[0..4], u32, Endian.Little);
172 ctx.c[1] = readInt(nmsg[4..8], u32, Endian.Little);
173 ctx.c[2] = readInt(nmsg[8..12], u32, Endian.Little);
174 ctx.c[3] = readInt(nmsg[12..16], u32, Endian.Little);
175 polyBlock(ctx);
176 nmsg = nmsg[16..];
177 }
178 if (nb_blocks > 0) {
179 polyClearC(ctx);
180 }
181
182 // remaining bytes
183 polyUpdate(ctx, nmsg[0..]);
184 }
185
186 // Finalize the MAC and output into buffer provided by caller.
187 pub fn final(ctx: *Self, out: []u8) void {
188 // Process the last block (if any)
189 if (ctx.c_idx != 0) {
190 // move the final 1 according to remaining input length
191 // (We may add less than 2^130 to the last input block)
192 ctx.c[4] = 0;
193 polyTakeInput(ctx, 1);
194 // one last hash update
195 polyBlock(ctx);
196 }
197
198 // check if we should subtract 2^130-5 by performing the
199 // corresponding carry propagation.
200 const _u0 = u64(5) + ctx.h[0]; // <= 1_00000004
201 const _u1 = (_u0 >> 32) + ctx.h[1]; // <= 1_00000000
202 const _u2 = (_u1 >> 32) + ctx.h[2]; // <= 1_00000000
203 const _u3 = (_u2 >> 32) + ctx.h[3]; // <= 1_00000000
204 const _u4 = (_u3 >> 32) + ctx.h[4]; // <= 5
205 // u4 indicates how many times we should subtract 2^130-5 (0 or 1)
206
207 // h + pad, minus 2^130-5 if u4 exceeds 3
208 const uu0 = (_u4 >> 2) * 5 + ctx.h[0] + ctx.pad[0]; // <= 2_00000003
209 const uu1 = (uu0 >> 32) + ctx.h[1] + ctx.pad[1]; // <= 2_00000000
210 const uu2 = (uu1 >> 32) + ctx.h[2] + ctx.pad[2]; // <= 2_00000000
211 const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000
212
213 writeInt(out[0..], @truncate(u32, uu0), Endian.Little);
214 writeInt(out[4..], @truncate(u32, uu1), Endian.Little);
215 writeInt(out[8..], @truncate(u32, uu2), Endian.Little);
216 writeInt(out[12..], @truncate(u32, uu3), Endian.Little);
217
218 ctx.secureZero();
219 }
220};
221
222test "poly1305 rfc7439 vector1" {
223 const expected_mac = "\xa8\x06\x1d\xc1\x30\x51\x36\xc6\xc2\x2b\x8b\xaf\x0c\x01\x27\xa9";
224
225 const msg = "Cryptographic Forum Research Group";
226 const key = "\x85\xd6\xbe\x78\x57\x55\x6d\x33\x7f\x44\x52\xfe\x42\xd5\x06\xa8" ++
227 "\x01\x03\x80\x8a\xfb\x0d\xb2\xfd\x4a\xbf\xf6\xaf\x41\x49\xf5\x1b";
228
229 var mac: [16]u8 = undefined;
230 Poly1305.create(mac[0..], msg, key);
231
232 std.debug.assert(std.mem.eql(u8, mac, expected_mac));
233}
std/crypto/sha1.zig+4-4
...@@ -26,8 +26,8 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) RoundParam {...@@ -26,8 +26,8 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) RoundParam {
2626
27pub const Sha1 = struct {27pub const Sha1 = struct {
28 const Self = this;28 const Self = this;
29 const block_size = 64;29 const block_length = 64;
30 const digest_size = 20;30 const digest_length = 20;
3131
32 s: [5]u32,32 s: [5]u32,
33 // Streaming Cache33 // Streaming Cache
...@@ -292,8 +292,8 @@ test "sha1 streaming" {...@@ -292,8 +292,8 @@ test "sha1 streaming" {
292}292}
293293
294test "sha1 aligned final" {294test "sha1 aligned final" {
295 var block = []u8{0} ** Sha1.block_size;295 var block = []u8{0} ** Sha1.block_length;
296 var out: [Sha1.digest_size]u8 = undefined;296 var out: [Sha1.digest_length]u8 = undefined;
297297
298 var h = Sha1.init();298 var h = Sha1.init();
299 h.update(block);299 h.update(block);
std/crypto/sha2.zig+8-8
...@@ -78,8 +78,8 @@ pub const Sha256 = Sha2_32(Sha256Params);...@@ -78,8 +78,8 @@ pub const Sha256 = Sha2_32(Sha256Params);
78fn Sha2_32(comptime params: Sha2Params32) type {78fn Sha2_32(comptime params: Sha2Params32) type {
79 return struct {79 return struct {
80 const Self = this;80 const Self = this;
81 const block_size = 64;81 const block_length = 64;
82 const digest_size = params.out_len / 8;82 const digest_length = params.out_len / 8;
8383
84 s: [8]u32,84 s: [8]u32,
85 // Streaming Cache85 // Streaming Cache
...@@ -338,8 +338,8 @@ test "sha256 streaming" {...@@ -338,8 +338,8 @@ test "sha256 streaming" {
338}338}
339339
340test "sha256 aligned final" {340test "sha256 aligned final" {
341 var block = []u8{0} ** Sha256.block_size;341 var block = []u8{0} ** Sha256.block_length;
342 var out: [Sha256.digest_size]u8 = undefined;342 var out: [Sha256.digest_length]u8 = undefined;
343343
344 var h = Sha256.init();344 var h = Sha256.init();
345 h.update(block);345 h.update(block);
...@@ -419,8 +419,8 @@ pub const Sha512 = Sha2_64(Sha512Params);...@@ -419,8 +419,8 @@ pub const Sha512 = Sha2_64(Sha512Params);
419fn Sha2_64(comptime params: Sha2Params64) type {419fn Sha2_64(comptime params: Sha2Params64) type {
420 return struct {420 return struct {
421 const Self = this;421 const Self = this;
422 const block_size = 128;422 const block_length = 128;
423 const digest_size = params.out_len / 8;423 const digest_length = params.out_len / 8;
424424
425 s: [8]u64,425 s: [8]u64,
426 // Streaming Cache426 // Streaming Cache
...@@ -715,8 +715,8 @@ test "sha512 streaming" {...@@ -715,8 +715,8 @@ test "sha512 streaming" {
715}715}
716716
717test "sha512 aligned final" {717test "sha512 aligned final" {
718 var block = []u8{0} ** Sha512.block_size;718 var block = []u8{0} ** Sha512.block_length;
719 var out: [Sha512.digest_size]u8 = undefined;719 var out: [Sha512.digest_length]u8 = undefined;
720720
721 var h = Sha512.init();721 var h = Sha512.init();
722 h.update(block);722 h.update(block);
std/crypto/sha3.zig+15-88
...@@ -13,8 +13,8 @@ pub const Sha3_512 = Keccak(512, 0x06);...@@ -13,8 +13,8 @@ pub const Sha3_512 = Keccak(512, 0x06);
13fn Keccak(comptime bits: usize, comptime delim: u8) type {13fn Keccak(comptime bits: usize, comptime delim: u8) type {
14 return struct {14 return struct {
15 const Self = this;15 const Self = this;
16 const block_size = 200;16 const block_length = 200;
17 const digest_size = bits / 8;17 const digest_length = bits / 8;
1818
19 s: [200]u8,19 s: [200]u8,
20 offset: usize,20 offset: usize,
...@@ -87,97 +87,24 @@ fn Keccak(comptime bits: usize, comptime delim: u8) type {...@@ -87,97 +87,24 @@ fn Keccak(comptime bits: usize, comptime delim: u8) type {
87}87}
8888
89const RC = []const u64{89const RC = []const u64{
90 0x0000000000000001,90 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000,
91 0x0000000000008082,91 0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009,
92 0x800000000000808a,92 0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
93 0x8000000080008000,93 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003,
94 0x000000000000808b,94 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a,
95 0x0000000080000001,95 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008,
96 0x8000000080008081,
97 0x8000000000008009,
98 0x000000000000008a,
99 0x0000000000000088,
100 0x0000000080008009,
101 0x000000008000000a,
102 0x000000008000808b,
103 0x800000000000008b,
104 0x8000000000008089,
105 0x8000000000008003,
106 0x8000000000008002,
107 0x8000000000000080,
108 0x000000000000800a,
109 0x800000008000000a,
110 0x8000000080008081,
111 0x8000000000008080,
112 0x0000000080000001,
113 0x8000000080008008,
114};96};
11597
116const ROTC = []const usize{98const ROTC = []const usize{
117 1,99 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44,
118 3,
119 6,
120 10,
121 15,
122 21,
123 28,
124 36,
125 45,
126 55,
127 2,
128 14,
129 27,
130 41,
131 56,
132 8,
133 25,
134 43,
135 62,
136 18,
137 39,
138 61,
139 20,
140 44,
141};100};
142101
143const PIL = []const usize{102const PIL = []const usize{
144 10,103 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
145 7,
146 11,
147 17,
148 18,
149 3,
150 5,
151 16,
152 8,
153 21,
154 24,
155 4,
156 15,
157 23,
158 19,
159 13,
160 12,
161 2,
162 20,
163 14,
164 22,
165 9,
166 6,
167 1,
168};104};
169105
170const M5 = []const usize{106const M5 = []const usize{
171 0,107 0, 1, 2, 3, 4, 0, 1, 2, 3, 4,
172 1,
173 2,
174 3,
175 4,
176 0,
177 1,
178 2,
179 3,
180 4,
181};108};
182109
183fn keccak_f(comptime F: usize, d: []u8) void {110fn keccak_f(comptime F: usize, d: []u8) void {
...@@ -297,8 +224,8 @@ test "sha3-256 streaming" {...@@ -297,8 +224,8 @@ test "sha3-256 streaming" {
297}224}
298225
299test "sha3-256 aligned final" {226test "sha3-256 aligned final" {
300 var block = []u8{0} ** Sha3_256.block_size;227 var block = []u8{0} ** Sha3_256.block_length;
301 var out: [Sha3_256.digest_size]u8 = undefined;228 var out: [Sha3_256.digest_length]u8 = undefined;
302229
303 var h = Sha3_256.init();230 var h = Sha3_256.init();
304 h.update(block);231 h.update(block);
...@@ -368,8 +295,8 @@ test "sha3-512 streaming" {...@@ -368,8 +295,8 @@ test "sha3-512 streaming" {
368}295}
369296
370test "sha3-512 aligned final" {297test "sha3-512 aligned final" {
371 var block = []u8{0} ** Sha3_512.block_size;298 var block = []u8{0} ** Sha3_512.block_length;
372 var out: [Sha3_512.digest_size]u8 = undefined;299 var out: [Sha3_512.digest_length]u8 = undefined;
373300
374 var h = Sha3_512.init();301 var h = Sha3_512.init();
375 h.update(block);302 h.update(block);
std/crypto/throughput_test.zig+176-21
...@@ -1,38 +1,193 @@...@@ -1,38 +1,193 @@
1// Modify the HashFunction variable to the one wanted to test.1const builtin = @import("builtin");
2//
3// ```
4// zig build-exe --release-fast throughput_test.zig
5// ./throughput_test
6// ```
7
8const std = @import("std");2const std = @import("std");
9const time = std.os.time;3const time = std.os.time;
10const Timer = time.Timer;4const Timer = time.Timer;
11const HashFunction = @import("md5.zig").Md5;5const crypto = @import("index.zig");
126
13const MiB = 1024 * 1024;7const KiB = 1024;
14const BytesToHash = 1024 * MiB;8const MiB = 1024 * KiB;
159
16pub fn main() !void {10var prng = std.rand.DefaultPrng.init(0);
17 var stdout_file = try std.io.getStdOut();
18 var stdout_out_stream = std.io.FileOutStream.init(&stdout_file);
19 const stdout = &stdout_out_stream.stream;
2011
21 var block: [HashFunction.block_size]u8 = undefined;12const Crypto = struct {
22 std.mem.set(u8, block[0..], 0);13 ty: type,
14 name: []const u8,
15};
2316
24 var h = HashFunction.init();17const hashes = []Crypto{
25 var offset: usize = 0;18 Crypto{ .ty = crypto.Md5, .name = "md5" },
19 Crypto{ .ty = crypto.Sha1, .name = "sha1" },
20 Crypto{ .ty = crypto.Sha256, .name = "sha256" },
21 Crypto{ .ty = crypto.Sha512, .name = "sha512" },
22 Crypto{ .ty = crypto.Sha3_256, .name = "sha3-256" },
23 Crypto{ .ty = crypto.Sha3_512, .name = "sha3-512" },
24 Crypto{ .ty = crypto.Blake2s256, .name = "blake2s" },
25 Crypto{ .ty = crypto.Blake2b512, .name = "blake2b" },
26};
27
28pub fn benchmarkHash(comptime Hash: var, comptime bytes: comptime_int) !u64 {
29 var h = Hash.init();
30
31 var block: [Hash.digest_length]u8 = undefined;
32 prng.random.bytes(block[0..]);
2633
34 var offset: usize = 0;
27 var timer = try Timer.start();35 var timer = try Timer.start();
28 const start = timer.lap();36 const start = timer.lap();
29 while (offset < BytesToHash) : (offset += block.len) {37 while (offset < bytes) : (offset += block.len) {
30 h.update(block[0..]);38 h.update(block[0..]);
31 }39 }
32 const end = timer.read();40 const end = timer.read();
3341
34 const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;42 const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
35 const throughput = @floatToInt(u64, BytesToHash / elapsed_s);43 const throughput = @floatToInt(u64, bytes / elapsed_s);
44
45 return throughput;
46}
47
48const macs = []Crypto{
49 Crypto{ .ty = crypto.Poly1305, .name = "poly1305" },
50 Crypto{ .ty = crypto.HmacMd5, .name = "hmac-md5" },
51 Crypto{ .ty = crypto.HmacSha1, .name = "hmac-sha1" },
52 Crypto{ .ty = crypto.HmacSha256, .name = "hmac-sha256" },
53};
54
55pub fn benchmarkMac(comptime Mac: var, comptime bytes: comptime_int) !u64 {
56 std.debug.assert(32 >= Mac.mac_length and 32 >= Mac.minimum_key_length);
57
58 var in: [1 * MiB]u8 = undefined;
59 prng.random.bytes(in[0..]);
60
61 var key: [32]u8 = undefined;
62 prng.random.bytes(key[0..]);
63
64 var offset: usize = 0;
65 var timer = try Timer.start();
66 const start = timer.lap();
67 while (offset < bytes) : (offset += in.len) {
68 Mac.create(key[0..], in[0..], key);
69 }
70 const end = timer.read();
71
72 const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
73 const throughput = @floatToInt(u64, bytes / elapsed_s);
74
75 return throughput;
76}
77
78const exchanges = []Crypto{Crypto{ .ty = crypto.X25519, .name = "x25519" }};
79
80pub fn benchmarkKeyExchange(comptime DhKeyExchange: var, comptime exchange_count: comptime_int) !u64 {
81 std.debug.assert(DhKeyExchange.minimum_key_length >= DhKeyExchange.secret_length);
82
83 var in: [DhKeyExchange.minimum_key_length]u8 = undefined;
84 prng.random.bytes(in[0..]);
85
86 var out: [DhKeyExchange.minimum_key_length]u8 = undefined;
87 prng.random.bytes(out[0..]);
88
89 var offset: usize = 0;
90 var timer = try Timer.start();
91 const start = timer.lap();
92 {
93 var i: usize = 0;
94 while (i < exchange_count) : (i += 1) {
95 _ = DhKeyExchange.create(out[0..], out, in);
96 }
97 }
98 const end = timer.read();
99
100 const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
101 const throughput = @floatToInt(u64, exchange_count / elapsed_s);
102
103 return throughput;
104}
36105
37 try stdout.print("{}: {} MiB/s\n", @typeName(HashFunction), throughput / (1 * MiB));106fn usage() void {
107 std.debug.warn(
108 \\throughput_test [options]
109 \\
110 \\Options:
111 \\ --filter [test-name]
112 \\ --seed [int]
113 \\ --help
114 \\
115 );
116}
117
118fn mode(comptime x: comptime_int) comptime_int {
119 return if (builtin.mode == builtin.Mode.Debug) x / 64 else x;
120}
121
122// TODO(#1358): Replace with builtin formatted padding when available.
123fn printPad(stdout: var, s: []const u8) !void {
124 var i: usize = 0;
125 while (i < 12 - s.len) : (i += 1) {
126 try stdout.print(" ");
127 }
128 try stdout.print("{}", s);
129}
130
131pub fn main() !void {
132 var stdout_file = try std.io.getStdOut();
133 var stdout_out_stream = std.io.FileOutStream.init(&stdout_file);
134 const stdout = &stdout_out_stream.stream;
135
136 var buffer: [1024]u8 = undefined;
137 var fixed = std.heap.FixedBufferAllocator.init(buffer[0..]);
138 const args = try std.os.argsAlloc(&fixed.allocator);
139
140 var filter: ?[]u8 = "";
141
142 var i: usize = 1;
143 while (i < args.len) : (i += 1) {
144 if (std.mem.eql(u8, args[i], "--seed")) {
145 i += 1;
146 if (i == args.len) {
147 usage();
148 std.os.exit(1);
149 }
150
151 const seed = try std.fmt.parseUnsigned(u32, args[i], 10);
152 prng.seed(seed);
153 } else if (std.mem.eql(u8, args[i], "--filter")) {
154 i += 1;
155 if (i == args.len) {
156 usage();
157 std.os.exit(1);
158 }
159
160 filter = args[i];
161 } else if (std.mem.eql(u8, args[i], "--help")) {
162 usage();
163 return;
164 } else {
165 usage();
166 std.os.exit(1);
167 }
168 }
169
170 inline for (hashes) |H| {
171 if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) {
172 const throughput = try benchmarkHash(H.ty, mode(32 * MiB));
173 try printPad(stdout, H.name);
174 try stdout.print(": {} MiB/s\n", throughput / (1 * MiB));
175 }
176 }
177
178 inline for (macs) |M| {
179 if (filter == null or std.mem.indexOf(u8, M.name, filter.?) != null) {
180 const throughput = try benchmarkMac(M.ty, mode(128 * MiB));
181 try printPad(stdout, M.name);
182 try stdout.print(": {} MiB/s\n", throughput / (1 * MiB));
183 }
184 }
185
186 inline for (exchanges) |E| {
187 if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
188 const throughput = try benchmarkKeyExchange(E.ty, mode(1000));
189 try printPad(stdout, E.name);
190 try stdout.print(": {} exchanges/s\n", throughput);
191 }
192 }
38}193}
std/crypto/x25519.zig created+664
...@@ -0,0 +1,664 @@
1// Translated from monocypher which is licensed under CC-0/BSD-3.
2//
3// https://monocypher.org/
4
5const std = @import("../index.zig");
6const builtin = @import("builtin");
7
8const Endian = builtin.Endian;
9const readInt = std.mem.readInt;
10const writeInt = std.mem.writeInt;
11
12// Based on Supercop's ref10 implementation.
13pub const X25519 = struct {
14 pub const secret_length = 32;
15 pub const minimum_key_length = 32;
16
17 fn trimScalar(s: []u8) void {
18 s[0] &= 248;
19 s[31] &= 127;
20 s[31] |= 64;
21 }
22
23 fn scalarBit(s: []const u8, i: usize) i32 {
24 return (s[i >> 3] >> @intCast(u3, i & 7)) & 1;
25 }
26
27 pub fn create(out: []u8, private_key: []const u8, public_key: []const u8) bool {
28 std.debug.assert(out.len >= secret_length);
29 std.debug.assert(private_key.len >= minimum_key_length);
30 std.debug.assert(public_key.len >= minimum_key_length);
31
32 var storage: [7]Fe = undefined;
33 var x1 = &storage[0];
34 var x2 = &storage[1];
35 var z2 = &storage[2];
36 var x3 = &storage[3];
37 var z3 = &storage[4];
38 var t0 = &storage[5];
39 var t1 = &storage[6];
40
41 // computes the scalar product
42 Fe.fromBytes(x1, public_key);
43
44 // restrict the possible scalar values
45 var e: [32]u8 = undefined;
46 for (e[0..]) |_, i| {
47 e[i] = private_key[i];
48 }
49 trimScalar(e[0..]);
50
51 // computes the actual scalar product (the result is in x2 and z2)
52
53 // Montgomery ladder
54 // In projective coordinates, to avoid divisons: x = X / Z
55 // We don't care about the y coordinate, it's only 1 bit of information
56 Fe.init1(x2);
57 Fe.init0(z2); // "zero" point
58 Fe.copy(x3, x1);
59 Fe.init1(z3);
60
61 var swap: i32 = 0;
62 var pos: isize = 254;
63 while (pos >= 0) : (pos -= 1) {
64 // constant time conditional swap before ladder step
65 const b = scalarBit(e, @intCast(usize, pos));
66 swap ^= b; // xor trick avoids swapping at the end of the loop
67 Fe.cswap(x2, x3, swap);
68 Fe.cswap(z2, z3, swap);
69 swap = b; // anticipates one last swap after the loop
70
71 // Montgomery ladder step: replaces (P2, P3) by (P2*2, P2+P3)
72 // with differential addition
73 Fe.sub(t0, x3, z3);
74 Fe.sub(t1, x2, z2);
75 Fe.add(x2, x2, z2);
76 Fe.add(z2, x3, z3);
77 Fe.mul(z3, t0, x2);
78 Fe.mul(z2, z2, t1);
79 Fe.sq(t0, t1);
80 Fe.sq(t1, x2);
81 Fe.add(x3, z3, z2);
82 Fe.sub(z2, z3, z2);
83 Fe.mul(x2, t1, t0);
84 Fe.sub(t1, t1, t0);
85 Fe.sq(z2, z2);
86 Fe.mulSmall(z3, t1, 121666);
87 Fe.sq(x3, x3);
88 Fe.add(t0, t0, z3);
89 Fe.mul(z3, x1, z2);
90 Fe.mul(z2, t1, t0);
91 }
92
93 // last swap is necessary to compensate for the xor trick
94 // Note: after this swap, P3 == P2 + P1.
95 Fe.cswap(x2, x3, swap);
96 Fe.cswap(z2, z3, swap);
97
98 // normalises the coordinates: x == X / Z
99 Fe.invert(z2, z2);
100 Fe.mul(x2, x2, z2);
101 Fe.toBytes(out, x2);
102
103 x1.secureZero();
104 x2.secureZero();
105 x3.secureZero();
106 t0.secureZero();
107 t1.secureZero();
108 z2.secureZero();
109 z3.secureZero();
110 std.mem.secureZero(u8, e[0..]);
111
112 // Returns false if the output is all zero
113 // (happens with some malicious public keys)
114 return !zerocmp(u8, out);
115 }
116
117 pub fn createPublicKey(public_key: []const u8, private_key: []const u8) bool {
118 var base_point = []u8{9} ++ []u8{0} ** 31;
119 return create(public_key, private_key, base_point);
120 }
121};
122
123// Constant time compare to zero.
124fn zerocmp(comptime T: type, a: []const T) bool {
125 var s: T = 0;
126 for (a) |b| {
127 s |= b;
128 }
129 return s == 0;
130}
131
132////////////////////////////////////
133/// Arithmetic modulo 2^255 - 19 ///
134////////////////////////////////////
135// Taken from Supercop's ref10 implementation.
136// A bit bigger than TweetNaCl, over 4 times faster.
137
138// field element
139const Fe = struct {
140 b: [10]i32,
141
142 fn secureZero(self: *Fe) void {
143 std.mem.secureZero(u8, @ptrCast([*]u8, self)[0..@sizeOf(Fe)]);
144 }
145
146 fn init0(h: *Fe) void {
147 for (h.b) |*e| {
148 e.* = 0;
149 }
150 }
151
152 fn init1(h: *Fe) void {
153 for (h.b[1..]) |*e| {
154 e.* = 0;
155 }
156 h.b[0] = 1;
157 }
158
159 fn copy(h: *Fe, f: *const Fe) void {
160 for (h.b) |_, i| {
161 h.b[i] = f.b[i];
162 }
163 }
164
165 fn neg(h: *Fe, f: *const Fe) void {
166 for (h.b) |_, i| {
167 h.b[i] = -f.b[i];
168 }
169 }
170
171 fn add(h: *Fe, f: *const Fe, g: *const Fe) void {
172 for (h.b) |_, i| {
173 h.b[i] = f.b[i] + g.b[i];
174 }
175 }
176
177 fn sub(h: *Fe, f: *const Fe, g: *const Fe) void {
178 for (h.b) |_, i| {
179 h.b[i] = f.b[i] - g.b[i];
180 }
181 }
182
183 fn cswap(f: *Fe, g: *Fe, b: i32) void {
184 for (f.b) |_, i| {
185 const x = (f.b[i] ^ g.b[i]) & -b;
186 f.b[i] ^= x;
187 g.b[i] ^= x;
188 }
189 }
190
191 fn ccopy(f: *Fe, g: *const Fe, b: i32) void {
192 for (f.b) |_, i| {
193 const x = (f.b[i] ^ g.b[i]) & -b;
194 f.b[i] ^= x;
195 }
196 }
197
198 inline fn carryRound(c: []i64, t: []i64, comptime i: comptime_int, comptime shift: comptime_int, comptime mult: comptime_int) void {
199 const j = (i + 1) % 10;
200
201 c[i] = (t[i] + (i64(1) << shift)) >> (shift + 1);
202 t[j] += c[i] * mult;
203 t[i] -= c[i] * (i64(1) << (shift + 1));
204 }
205
206 fn carry1(h: *Fe, t: []i64) void {
207 var c: [10]i64 = undefined;
208
209 var sc = c[0..];
210 var st = t[0..];
211
212 carryRound(sc, st, 9, 24, 19);
213 carryRound(sc, st, 1, 24, 1);
214 carryRound(sc, st, 3, 24, 1);
215 carryRound(sc, st, 5, 24, 1);
216 carryRound(sc, st, 7, 24, 1);
217 carryRound(sc, st, 0, 25, 1);
218 carryRound(sc, st, 2, 25, 1);
219 carryRound(sc, st, 4, 25, 1);
220 carryRound(sc, st, 6, 25, 1);
221 carryRound(sc, st, 8, 25, 1);
222
223 for (h.b) |_, i| {
224 h.b[i] = @intCast(i32, t[i]);
225 }
226 }
227
228 fn carry2(h: *Fe, t: []i64) void {
229 var c: [10]i64 = undefined;
230
231 var sc = c[0..];
232 var st = t[0..];
233
234 carryRound(sc, st, 0, 25, 1);
235 carryRound(sc, st, 4, 25, 1);
236 carryRound(sc, st, 1, 24, 1);
237 carryRound(sc, st, 5, 24, 1);
238 carryRound(sc, st, 2, 25, 1);
239 carryRound(sc, st, 6, 25, 1);
240 carryRound(sc, st, 3, 24, 1);
241 carryRound(sc, st, 7, 24, 1);
242 carryRound(sc, st, 4, 25, 1);
243 carryRound(sc, st, 8, 25, 1);
244 carryRound(sc, st, 9, 24, 19);
245 carryRound(sc, st, 0, 25, 1);
246
247 for (h.b) |_, i| {
248 h.b[i] = @intCast(i32, t[i]);
249 }
250 }
251
252 fn fromBytes(h: *Fe, s: []const u8) void {
253 std.debug.assert(s.len >= 32);
254
255 var t: [10]i64 = undefined;
256
257 t[0] = readInt(s[0..4], u32, Endian.Little);
258 t[1] = readInt(s[4..7], u32, Endian.Little) << 6;
259 t[2] = readInt(s[7..10], u32, Endian.Little) << 5;
260 t[3] = readInt(s[10..13], u32, Endian.Little) << 3;
261 t[4] = readInt(s[13..16], u32, Endian.Little) << 2;
262 t[5] = readInt(s[16..20], u32, Endian.Little);
263 t[6] = readInt(s[20..23], u32, Endian.Little) << 7;
264 t[7] = readInt(s[23..26], u32, Endian.Little) << 5;
265 t[8] = readInt(s[26..29], u32, Endian.Little) << 4;
266 t[9] = (readInt(s[29..32], u32, Endian.Little) & 0x7fffff) << 2;
267
268 carry1(h, t[0..]);
269 }
270
271 fn mulSmall(h: *Fe, f: *const Fe, comptime g: comptime_int) void {
272 var t: [10]i64 = undefined;
273
274 for (t[0..]) |_, i| {
275 t[i] = i64(f.b[i]) * g;
276 }
277
278 carry1(h, t[0..]);
279 }
280
281 fn mul(h: *Fe, f1: *const Fe, g1: *const Fe) void {
282 const f = f1.b;
283 const g = g1.b;
284
285 var F: [10]i32 = undefined;
286 var G: [10]i32 = undefined;
287
288 F[1] = f[1] * 2;
289 F[3] = f[3] * 2;
290 F[5] = f[5] * 2;
291 F[7] = f[7] * 2;
292 F[9] = f[9] * 2;
293
294 G[1] = g[1] * 19;
295 G[2] = g[2] * 19;
296 G[3] = g[3] * 19;
297 G[4] = g[4] * 19;
298 G[5] = g[5] * 19;
299 G[6] = g[6] * 19;
300 G[7] = g[7] * 19;
301 G[8] = g[8] * 19;
302 G[9] = g[9] * 19;
303
304 // t's become h
305 var t: [10]i64 = undefined;
306
307 t[0] = f[0] * i64(g[0]) + F[1] * i64(G[9]) + f[2] * i64(G[8]) + F[3] * i64(G[7]) + f[4] * i64(G[6]) + F[5] * i64(G[5]) + f[6] * i64(G[4]) + F[7] * i64(G[3]) + f[8] * i64(G[2]) + F[9] * i64(G[1]);
308 t[1] = f[0] * i64(g[1]) + f[1] * i64(g[0]) + f[2] * i64(G[9]) + f[3] * i64(G[8]) + f[4] * i64(G[7]) + f[5] * i64(G[6]) + f[6] * i64(G[5]) + f[7] * i64(G[4]) + f[8] * i64(G[3]) + f[9] * i64(G[2]);
309 t[2] = f[0] * i64(g[2]) + F[1] * i64(g[1]) + f[2] * i64(g[0]) + F[3] * i64(G[9]) + f[4] * i64(G[8]) + F[5] * i64(G[7]) + f[6] * i64(G[6]) + F[7] * i64(G[5]) + f[8] * i64(G[4]) + F[9] * i64(G[3]);
310 t[3] = f[0] * i64(g[3]) + f[1] * i64(g[2]) + f[2] * i64(g[1]) + f[3] * i64(g[0]) + f[4] * i64(G[9]) + f[5] * i64(G[8]) + f[6] * i64(G[7]) + f[7] * i64(G[6]) + f[8] * i64(G[5]) + f[9] * i64(G[4]);
311 t[4] = f[0] * i64(g[4]) + F[1] * i64(g[3]) + f[2] * i64(g[2]) + F[3] * i64(g[1]) + f[4] * i64(g[0]) + F[5] * i64(G[9]) + f[6] * i64(G[8]) + F[7] * i64(G[7]) + f[8] * i64(G[6]) + F[9] * i64(G[5]);
312 t[5] = f[0] * i64(g[5]) + f[1] * i64(g[4]) + f[2] * i64(g[3]) + f[3] * i64(g[2]) + f[4] * i64(g[1]) + f[5] * i64(g[0]) + f[6] * i64(G[9]) + f[7] * i64(G[8]) + f[8] * i64(G[7]) + f[9] * i64(G[6]);
313 t[6] = f[0] * i64(g[6]) + F[1] * i64(g[5]) + f[2] * i64(g[4]) + F[3] * i64(g[3]) + f[4] * i64(g[2]) + F[5] * i64(g[1]) + f[6] * i64(g[0]) + F[7] * i64(G[9]) + f[8] * i64(G[8]) + F[9] * i64(G[7]);
314 t[7] = f[0] * i64(g[7]) + f[1] * i64(g[6]) + f[2] * i64(g[5]) + f[3] * i64(g[4]) + f[4] * i64(g[3]) + f[5] * i64(g[2]) + f[6] * i64(g[1]) + f[7] * i64(g[0]) + f[8] * i64(G[9]) + f[9] * i64(G[8]);
315 t[8] = f[0] * i64(g[8]) + F[1] * i64(g[7]) + f[2] * i64(g[6]) + F[3] * i64(g[5]) + f[4] * i64(g[4]) + F[5] * i64(g[3]) + f[6] * i64(g[2]) + F[7] * i64(g[1]) + f[8] * i64(g[0]) + F[9] * i64(G[9]);
316 t[9] = f[0] * i64(g[9]) + f[1] * i64(g[8]) + f[2] * i64(g[7]) + f[3] * i64(g[6]) + f[4] * i64(g[5]) + f[5] * i64(g[4]) + f[6] * i64(g[3]) + f[7] * i64(g[2]) + f[8] * i64(g[1]) + f[9] * i64(g[0]);
317
318 carry2(h, t[0..]);
319 }
320
321 // we could use Fe.mul() for this, but this is significantly faster
322 fn sq(h: *Fe, fz: *const Fe) void {
323 const f0 = fz.b[0];
324 const f1 = fz.b[1];
325 const f2 = fz.b[2];
326 const f3 = fz.b[3];
327 const f4 = fz.b[4];
328 const f5 = fz.b[5];
329 const f6 = fz.b[6];
330 const f7 = fz.b[7];
331 const f8 = fz.b[8];
332 const f9 = fz.b[9];
333
334 const f0_2 = f0 * 2;
335 const f1_2 = f1 * 2;
336 const f2_2 = f2 * 2;
337 const f3_2 = f3 * 2;
338 const f4_2 = f4 * 2;
339 const f5_2 = f5 * 2;
340 const f6_2 = f6 * 2;
341 const f7_2 = f7 * 2;
342 const f5_38 = f5 * 38;
343 const f6_19 = f6 * 19;
344 const f7_38 = f7 * 38;
345 const f8_19 = f8 * 19;
346 const f9_38 = f9 * 38;
347
348 var t: [10]i64 = undefined;
349
350 t[0] = f0 * i64(f0) + f1_2 * i64(f9_38) + f2_2 * i64(f8_19) + f3_2 * i64(f7_38) + f4_2 * i64(f6_19) + f5 * i64(f5_38);
351 t[1] = f0_2 * i64(f1) + f2 * i64(f9_38) + f3_2 * i64(f8_19) + f4 * i64(f7_38) + f5_2 * i64(f6_19);
352 t[2] = f0_2 * i64(f2) + f1_2 * i64(f1) + f3_2 * i64(f9_38) + f4_2 * i64(f8_19) + f5_2 * i64(f7_38) + f6 * i64(f6_19);
353 t[3] = f0_2 * i64(f3) + f1_2 * i64(f2) + f4 * i64(f9_38) + f5_2 * i64(f8_19) + f6 * i64(f7_38);
354 t[4] = f0_2 * i64(f4) + f1_2 * i64(f3_2) + f2 * i64(f2) + f5_2 * i64(f9_38) + f6_2 * i64(f8_19) + f7 * i64(f7_38);
355 t[5] = f0_2 * i64(f5) + f1_2 * i64(f4) + f2_2 * i64(f3) + f6 * i64(f9_38) + f7_2 * i64(f8_19);
356 t[6] = f0_2 * i64(f6) + f1_2 * i64(f5_2) + f2_2 * i64(f4) + f3_2 * i64(f3) + f7_2 * i64(f9_38) + f8 * i64(f8_19);
357 t[7] = f0_2 * i64(f7) + f1_2 * i64(f6) + f2_2 * i64(f5) + f3_2 * i64(f4) + f8 * i64(f9_38);
358 t[8] = f0_2 * i64(f8) + f1_2 * i64(f7_2) + f2_2 * i64(f6) + f3_2 * i64(f5_2) + f4 * i64(f4) + f9 * i64(f9_38);
359 t[9] = f0_2 * i64(f9) + f1_2 * i64(f8) + f2_2 * i64(f7) + f3_2 * i64(f6) + f4 * i64(f5_2);
360
361 carry2(h, t[0..]);
362 }
363
364 fn sq2(h: *Fe, f: *const Fe) void {
365 Fe.sq(h, f);
366 Fe.mul_small(h, h, 2);
367 }
368
369 // This could be simplified, but it would be slower
370 fn invert(out: *Fe, z: *const Fe) void {
371 var i: usize = undefined;
372
373 var t: [4]Fe = undefined;
374 var t0 = &t[0];
375 var t1 = &t[1];
376 var t2 = &t[2];
377 var t3 = &t[3];
378
379 Fe.sq(t0, z);
380 Fe.sq(t1, t0);
381 Fe.sq(t1, t1);
382 Fe.mul(t1, z, t1);
383 Fe.mul(t0, t0, t1);
384
385 Fe.sq(t2, t0);
386 Fe.mul(t1, t1, t2);
387
388 Fe.sq(t2, t1);
389 i = 1;
390 while (i < 5) : (i += 1) Fe.sq(t2, t2);
391 Fe.mul(t1, t2, t1);
392
393 Fe.sq(t2, t1);
394 i = 1;
395 while (i < 10) : (i += 1) Fe.sq(t2, t2);
396 Fe.mul(t2, t2, t1);
397
398 Fe.sq(t3, t2);
399 i = 1;
400 while (i < 20) : (i += 1) Fe.sq(t3, t3);
401 Fe.mul(t2, t3, t2);
402
403 Fe.sq(t2, t2);
404 i = 1;
405 while (i < 10) : (i += 1) Fe.sq(t2, t2);
406 Fe.mul(t1, t2, t1);
407
408 Fe.sq(t2, t1);
409 i = 1;
410 while (i < 50) : (i += 1) Fe.sq(t2, t2);
411 Fe.mul(t2, t2, t1);
412
413 Fe.sq(t3, t2);
414 i = 1;
415 while (i < 100) : (i += 1) Fe.sq(t3, t3);
416 Fe.mul(t2, t3, t2);
417
418 Fe.sq(t2, t2);
419 i = 1;
420 while (i < 50) : (i += 1) Fe.sq(t2, t2);
421 Fe.mul(t1, t2, t1);
422
423 Fe.sq(t1, t1);
424 i = 1;
425 while (i < 5) : (i += 1) Fe.sq(t1, t1);
426 Fe.mul(out, t1, t0);
427
428 t0.secureZero();
429 t1.secureZero();
430 t2.secureZero();
431 t3.secureZero();
432 }
433
434 // This could be simplified, but it would be slower
435 fn pow22523(out: *Fe, z: *const Fe) void {
436 var i: usize = undefined;
437
438 var t: [3]Fe = undefined;
439 var t0 = &t[0];
440 var t1 = &t[1];
441 var t2 = &t[2];
442
443 Fe.sq(t0, z);
444 Fe.sq(t1, t0);
445 Fe.sq(t1, t1);
446 Fe.mul(t1, z, t1);
447 Fe.mul(t0, t0, t1);
448
449 Fe.sq(t0, t0);
450 Fe.mul(t0, t1, t0);
451
452 Fe.sq(t1, t0);
453 i = 1;
454 while (i < 5) : (i += 1) Fe.sq(t1, t1);
455 Fe.mul(t0, t1, t0);
456
457 Fe.sq(t1, t0);
458 i = 1;
459 while (i < 10) : (i += 1) Fe.sq(t1, t1);
460 Fe.mul(t1, t1, t0);
461
462 Fe.sq(t2, t1);
463 i = 1;
464 while (i < 20) : (i += 1) Fe.sq(t2, t2);
465 Fe.mul(t1, t2, t1);
466
467 Fe.sq(t1, t1);
468 i = 1;
469 while (i < 10) : (i += 1) Fe.sq(t1, t1);
470 Fe.mul(t0, t1, t0);
471
472 Fe.sq(t1, t0);
473 i = 1;
474 while (i < 50) : (i += 1) Fe.sq(t1, t1);
475 Fe.mul(t1, t1, t0);
476
477 Fe.sq(t2, t1);
478 i = 1;
479 while (i < 100) : (i += 1) Fe.sq(t2, t2);
480 Fe.mul(t1, t2, t1);
481
482 Fe.sq(t1, t1);
483 i = 1;
484 while (i < 50) : (i += 1) Fe.sq(t1, t1);
485 Fe.mul(t0, t1, t0);
486
487 Fe.sq(t0, t0);
488 i = 1;
489 while (i < 2) : (i += 1) Fe.sq(t0, t0);
490 Fe.mul(out, t0, z);
491
492 t0.secureZero();
493 t1.secureZero();
494 t2.secureZero();
495 }
496
497 inline fn toBytesRound(c: []i64, t: []i64, comptime i: comptime_int, comptime shift: comptime_int) void {
498 c[i] = t[i] >> shift;
499 if (i + 1 < 10) {
500 t[i + 1] += c[i];
501 }
502 t[i] -= c[i] * (i32(1) << shift);
503 }
504
505 fn toBytes(s: []u8, h: *const Fe) void {
506 std.debug.assert(s.len >= 32);
507
508 var t: [10]i64 = undefined;
509 for (h.b[0..]) |_, i| {
510 t[i] = h.b[i];
511 }
512
513 var q = (19 * t[9] + ((i32(1) << 24))) >> 25;
514 {
515 var i: usize = 0;
516 while (i < 5) : (i += 1) {
517 q += t[2 * i];
518 q >>= 26;
519 q += t[2 * i + 1];
520 q >>= 25;
521 }
522 }
523 t[0] += 19 * q;
524
525 var c: [10]i64 = undefined;
526
527 var st = t[0..];
528 var sc = c[0..];
529
530 toBytesRound(sc, st, 0, 26);
531 toBytesRound(sc, st, 1, 25);
532 toBytesRound(sc, st, 2, 26);
533 toBytesRound(sc, st, 3, 25);
534 toBytesRound(sc, st, 4, 26);
535 toBytesRound(sc, st, 5, 25);
536 toBytesRound(sc, st, 6, 26);
537 toBytesRound(sc, st, 7, 25);
538 toBytesRound(sc, st, 8, 26);
539 toBytesRound(sc, st, 9, 25);
540
541 var ut: [10]u32 = undefined;
542 for (ut[0..]) |_, i| {
543 ut[i] = @bitCast(u32, @intCast(i32, t[i]));
544 }
545
546 writeInt(s[0..], (ut[0] >> 0) | (ut[1] << 26), Endian.Little);
547 writeInt(s[4..], (ut[1] >> 6) | (ut[2] << 19), Endian.Little);
548 writeInt(s[8..], (ut[2] >> 13) | (ut[3] << 13), Endian.Little);
549 writeInt(s[12..], (ut[3] >> 19) | (ut[4] << 6), Endian.Little);
550 writeInt(s[16..], (ut[5] >> 0) | (ut[6] << 25), Endian.Little);
551 writeInt(s[20..], (ut[6] >> 7) | (ut[7] << 19), Endian.Little);
552 writeInt(s[24..], (ut[7] >> 13) | (ut[8] << 12), Endian.Little);
553 writeInt(s[28..], (ut[8] >> 20) | (ut[9] << 6), Endian.Little);
554
555 std.mem.secureZero(i64, t[0..]);
556 }
557
558 // Parity check. Returns 0 if even, 1 if odd
559 fn isNegative(f: *const Fe) bool {
560 var s: [32]u8 = undefined;
561 Fe.toBytes(s[0..], f);
562 const isneg = s[0] & 1;
563 s.secureZero();
564 return isneg;
565 }
566
567 fn isNonZero(f: *const Fe) bool {
568 var s: [32]u8 = undefined;
569 Fe.toBytes(s[0..], f);
570 const isnonzero = zerocmp(u8, s[0..]);
571 s.secureZero();
572 return isneg;
573 }
574};
575
576test "x25519 rfc7748 vector1" {
577 const secret_key = "\xa5\x46\xe3\x6b\xf0\x52\x7c\x9d\x3b\x16\x15\x4b\x82\x46\x5e\xdd\x62\x14\x4c\x0a\xc1\xfc\x5a\x18\x50\x6a\x22\x44\xba\x44\x9a\xc4";
578 const public_key = "\xe6\xdb\x68\x67\x58\x30\x30\xdb\x35\x94\xc1\xa4\x24\xb1\x5f\x7c\x72\x66\x24\xec\x26\xb3\x35\x3b\x10\xa9\x03\xa6\xd0\xab\x1c\x4c";
579
580 const expected_output = "\xc3\xda\x55\x37\x9d\xe9\xc6\x90\x8e\x94\xea\x4d\xf2\x8d\x08\x4f\x32\xec\xcf\x03\x49\x1c\x71\xf7\x54\xb4\x07\x55\x77\xa2\x85\x52";
581
582 var output: [32]u8 = undefined;
583
584 std.debug.assert(X25519.create(output[0..], secret_key, public_key));
585 std.debug.assert(std.mem.eql(u8, output, expected_output));
586}
587
588test "x25519 rfc7748 vector2" {
589 const secret_key = "\x4b\x66\xe9\xd4\xd1\xb4\x67\x3c\x5a\xd2\x26\x91\x95\x7d\x6a\xf5\xc1\x1b\x64\x21\xe0\xea\x01\xd4\x2c\xa4\x16\x9e\x79\x18\xba\x0d";
590 const public_key = "\xe5\x21\x0f\x12\x78\x68\x11\xd3\xf4\xb7\x95\x9d\x05\x38\xae\x2c\x31\xdb\xe7\x10\x6f\xc0\x3c\x3e\xfc\x4c\xd5\x49\xc7\x15\xa4\x93";
591
592 const expected_output = "\x95\xcb\xde\x94\x76\xe8\x90\x7d\x7a\xad\xe4\x5c\xb4\xb8\x73\xf8\x8b\x59\x5a\x68\x79\x9f\xa1\x52\xe6\xf8\xf7\x64\x7a\xac\x79\x57";
593
594 var output: [32]u8 = undefined;
595
596 std.debug.assert(X25519.create(output[0..], secret_key, public_key));
597 std.debug.assert(std.mem.eql(u8, output, expected_output));
598}
599
600test "x25519 rfc7748 one iteration" {
601 const initial_value = "\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
602 const expected_output = "\x42\x2c\x8e\x7a\x62\x27\xd7\xbc\xa1\x35\x0b\x3e\x2b\xb7\x27\x9f\x78\x97\xb8\x7b\xb6\x85\x4b\x78\x3c\x60\xe8\x03\x11\xae\x30\x79";
603
604 var k: [32]u8 = initial_value;
605 var u: [32]u8 = initial_value;
606
607 var i: usize = 0;
608 while (i < 1) : (i += 1) {
609 var output: [32]u8 = undefined;
610 std.debug.assert(X25519.create(output[0..], k, u));
611
612 std.mem.copy(u8, u[0..], k[0..]);
613 std.mem.copy(u8, k[0..], output[0..]);
614 }
615
616 std.debug.assert(std.mem.eql(u8, k[0..], expected_output));
617}
618
619test "x25519 rfc7748 1,000 iterations" {
620 // These iteration tests are slow so we always skip them. Results have been verified.
621 if (true) {
622 return error.SkipZigTest;
623 }
624
625 const initial_value = "\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
626 const expected_output = "\x68\x4c\xf5\x9b\xa8\x33\x09\x55\x28\x00\xef\x56\x6f\x2f\x4d\x3c\x1c\x38\x87\xc4\x93\x60\xe3\x87\x5f\x2e\xb9\x4d\x99\x53\x2c\x51";
627
628 var k: [32]u8 = initial_value;
629 var u: [32]u8 = initial_value;
630
631 var i: usize = 0;
632 while (i < 1000) : (i += 1) {
633 var output: [32]u8 = undefined;
634 std.debug.assert(X25519.create(output[0..], k, u));
635
636 std.mem.copy(u8, u[0..], k[0..]);
637 std.mem.copy(u8, k[0..], output[0..]);
638 }
639
640 std.debug.assert(std.mem.eql(u8, k[0..], expected_output));
641}
642
643test "x25519 rfc7748 1,000,000 iterations" {
644 if (true) {
645 return error.SkipZigTest;
646 }
647
648 const initial_value = "\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
649 const expected_output = "\x7c\x39\x11\xe0\xab\x25\x86\xfd\x86\x44\x97\x29\x7e\x57\x5e\x6f\x3b\xc6\x01\xc0\x88\x3c\x30\xdf\x5f\x4d\xd2\xd2\x4f\x66\x54\x24";
650
651 var k: [32]u8 = initial_value;
652 var u: [32]u8 = initial_value;
653
654 var i: usize = 0;
655 while (i < 1000000) : (i += 1) {
656 var output: [32]u8 = undefined;
657 std.debug.assert(X25519.create(output[0..], k, u));
658
659 std.mem.copy(u8, u[0..], k[0..]);
660 std.mem.copy(u8, k[0..], output[0..]);
661 }
662
663 std.debug.assert(std.mem.eql(u8, k[0..], expected_output));
664}
std/debug/index.zig+494-20
...@@ -4,8 +4,11 @@ const mem = std.mem;...@@ -4,8 +4,11 @@ const mem = std.mem;
4const io = std.io;4const io = std.io;
5const os = std.os;5const os = std.os;
6const elf = std.elf;6const elf = std.elf;
7const macho = std.macho;
8const DW = std.dwarf;7const DW = std.dwarf;
8const macho = std.macho;
9const coff = std.coff;
10const pdb = std.pdb;
11const windows = os.windows;
9const ArrayList = std.ArrayList;12const ArrayList = std.ArrayList;
10const builtin = @import("builtin");13const builtin = @import("builtin");
1114
...@@ -17,6 +20,17 @@ pub const runtime_safety = switch (builtin.mode) {...@@ -17,6 +20,17 @@ pub const runtime_safety = switch (builtin.mode) {
17 builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => false,20 builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => false,
18};21};
1922
23const Module = struct {
24 mod_info: pdb.ModInfo,
25 module_name: []u8,
26 obj_file_name: []u8,
27
28 populated: bool,
29 symbols: []u8,
30 subsect_info: []u8,
31 checksum_offset: ?usize,
32};
33
20/// Tries to write to stderr, unbuffered, and ignores any error returned.34/// Tries to write to stderr, unbuffered, and ignores any error returned.
21/// Does not append a newline.35/// Does not append a newline.
22var stderr_file: os.File = undefined;36var stderr_file: os.File = undefined;
...@@ -37,7 +51,7 @@ pub fn getStderrStream() !*io.OutStream(io.FileOutStream.Error) {...@@ -37,7 +51,7 @@ pub fn getStderrStream() !*io.OutStream(io.FileOutStream.Error) {
37 return st;51 return st;
38 } else {52 } else {
39 stderr_file = try io.getStdErr();53 stderr_file = try io.getStdErr();
40 stderr_file_out_stream = io.FileOutStream.init(&stderr_file);54 stderr_file_out_stream = io.FileOutStream.init(stderr_file);
41 const st = &stderr_file_out_stream.stream;55 const st = &stderr_file_out_stream.stream;
42 stderr_stream = st;56 stderr_stream = st;
43 return st;57 return st;
...@@ -70,7 +84,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {...@@ -70,7 +84,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
70 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;84 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
71 return;85 return;
72 };86 };
73 writeCurrentStackTrace(stderr, getDebugInfoAllocator(), debug_info, wantTtyColor(), start_addr) catch |err| {87 writeCurrentStackTrace(stderr, debug_info, wantTtyColor(), start_addr) catch |err| {
74 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;88 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
75 return;89 return;
76 };90 };
...@@ -191,7 +205,11 @@ pub inline fn getReturnAddress(frame_count: usize) usize {...@@ -191,7 +205,11 @@ pub inline fn getReturnAddress(frame_count: usize) usize {
191 return @intToPtr(*const usize, fp + @sizeOf(usize)).*;205 return @intToPtr(*const usize, fp + @sizeOf(usize)).*;
192}206}
193207
194pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void {208pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void {
209 switch (builtin.os) {
210 builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr),
211 else => {},
212 }
195 const AddressState = union(enum) {213 const AddressState = union(enum) {
196 NotLookingForStartAddress,214 NotLookingForStartAddress,
197 LookingForStartAddress: usize,215 LookingForStartAddress: usize,
...@@ -224,18 +242,296 @@ pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_...@@ -224,18 +242,296 @@ pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_
224 }242 }
225}243}
226244
245pub fn writeCurrentStackTraceWindows(out_stream: var, debug_info: *DebugInfo,
246 tty_color: bool, start_addr: ?usize) !void
247{
248 var addr_buf: [1024]usize = undefined;
249 const casted_len = @intCast(u32, addr_buf.len); // TODO shouldn't need this cast
250 const n = windows.RtlCaptureStackBackTrace(0, casted_len, @ptrCast(**c_void, &addr_buf), null);
251 const addrs = addr_buf[0..n];
252 var start_i: usize = if (start_addr) |saddr| blk: {
253 for (addrs) |addr, i| {
254 if (addr == saddr) break :blk i;
255 }
256 return;
257 } else 0;
258 for (addrs[start_i..]) |addr| {
259 try printSourceAtAddress(debug_info, out_stream, addr, tty_color);
260 }
261}
262
227pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {263pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
228 switch (builtin.os) {264 switch (builtin.os) {
229 builtin.Os.macosx => return printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color),265 builtin.Os.macosx => return printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color),
230 builtin.Os.linux => return printSourceAtAddressLinux(debug_info, out_stream, address, tty_color),266 builtin.Os.linux => return printSourceAtAddressLinux(debug_info, out_stream, address, tty_color),
231 builtin.Os.windows => {267 builtin.Os.windows => return printSourceAtAddressWindows(debug_info, out_stream, address, tty_color),
232 // TODO https://github.com/ziglang/zig/issues/721
233 return error.UnsupportedOperatingSystem;
234 },
235 else => return error.UnsupportedOperatingSystem,268 else => return error.UnsupportedOperatingSystem,
236 }269 }
237}270}
238271
272fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_address: usize, tty_color: bool) !void {
273 const allocator = getDebugInfoAllocator();
274 const base_address = os.getBaseAddress();
275 const relative_address = relocated_address - base_address;
276
277 var coff_section: *coff.Section = undefined;
278 const mod_index = for (di.sect_contribs) |sect_contrib| {
279 if (sect_contrib.Section >= di.coff.sections.len) continue;
280 coff_section = &di.coff.sections.toSlice()[sect_contrib.Section];
281
282 const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset;
283 const vaddr_end = vaddr_start + sect_contrib.Size;
284 if (relative_address >= vaddr_start and relative_address < vaddr_end) {
285 break sect_contrib.ModuleIndex;
286 }
287 } else {
288 // we have no information to add to the address
289 if (tty_color) {
290 try out_stream.print("???:?:?: ");
291 setTtyColor(TtyColor.Dim);
292 try out_stream.print("0x{x} in ??? (???)", relocated_address);
293 setTtyColor(TtyColor.Reset);
294 try out_stream.print("\n\n\n");
295 } else {
296 try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", relocated_address);
297 }
298 return;
299 };
300
301 const mod = &di.modules[mod_index];
302 try populateModule(di, mod);
303 const obj_basename = os.path.basename(mod.obj_file_name);
304
305 var symbol_i: usize = 0;
306 const symbol_name = while (symbol_i != mod.symbols.len) {
307 const prefix = @ptrCast(*pdb.RecordPrefix, &mod.symbols[symbol_i]);
308 if (prefix.RecordLen < 2)
309 return error.InvalidDebugInfo;
310 switch (prefix.RecordKind) {
311 pdb.SymbolKind.S_LPROC32 => {
312 const proc_sym = @ptrCast(*pdb.ProcSym, &mod.symbols[symbol_i + @sizeOf(pdb.RecordPrefix)]);
313 const vaddr_start = coff_section.header.virtual_address + proc_sym.CodeOffset;
314 const vaddr_end = vaddr_start + proc_sym.CodeSize;
315 if (relative_address >= vaddr_start and relative_address < vaddr_end) {
316 break mem.toSliceConst(u8, @ptrCast([*]u8, proc_sym) + @sizeOf(pdb.ProcSym));
317 }
318 },
319 else => {},
320 }
321 symbol_i += prefix.RecordLen + @sizeOf(u16);
322 if (symbol_i > mod.symbols.len)
323 return error.InvalidDebugInfo;
324 } else "???";
325
326 const subsect_info = mod.subsect_info;
327
328 var sect_offset: usize = 0;
329 var skip_len: usize = undefined;
330 const opt_line_info = subsections: {
331 const checksum_offset = mod.checksum_offset orelse break :subsections null;
332 while (sect_offset != subsect_info.len) : (sect_offset += skip_len) {
333 const subsect_hdr = @ptrCast(*pdb.DebugSubsectionHeader, &subsect_info[sect_offset]);
334 skip_len = subsect_hdr.Length;
335 sect_offset += @sizeOf(pdb.DebugSubsectionHeader);
336
337 switch (subsect_hdr.Kind) {
338 pdb.DebugSubsectionKind.Lines => {
339 var line_index: usize = sect_offset;
340
341 const line_hdr = @ptrCast(*pdb.LineFragmentHeader, &subsect_info[line_index]);
342 if (line_hdr.RelocSegment == 0) return error.MissingDebugInfo;
343 line_index += @sizeOf(pdb.LineFragmentHeader);
344
345 const block_hdr = @ptrCast(*pdb.LineBlockFragmentHeader, &subsect_info[line_index]);
346 line_index += @sizeOf(pdb.LineBlockFragmentHeader);
347
348 const has_column = line_hdr.Flags.LF_HaveColumns;
349
350 const frag_vaddr_start = coff_section.header.virtual_address + line_hdr.RelocOffset;
351 const frag_vaddr_end = frag_vaddr_start + line_hdr.CodeSize;
352 if (relative_address >= frag_vaddr_start and relative_address < frag_vaddr_end) {
353 var line_i: usize = 0;
354 const start_line_index = line_index;
355 while (line_i < block_hdr.NumLines) : (line_i += 1) {
356 const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[line_index]);
357 line_index += @sizeOf(pdb.LineNumberEntry);
358 const flags = @ptrCast(*pdb.LineNumberEntry.Flags, &line_num_entry.Flags);
359 const vaddr_start = frag_vaddr_start + line_num_entry.Offset;
360 const vaddr_end = if (flags.End == 0) frag_vaddr_end else vaddr_start + flags.End;
361 if (relative_address >= vaddr_start and relative_address < vaddr_end) {
362 const subsect_index = checksum_offset + block_hdr.NameIndex;
363 const chksum_hdr = @ptrCast(*pdb.FileChecksumEntryHeader, &mod.subsect_info[subsect_index]);
364 const strtab_offset = @sizeOf(pdb.PDBStringTableHeader) + chksum_hdr.FileNameOffset;
365 try di.pdb.string_table.seekTo(strtab_offset);
366 const source_file_name = try di.pdb.string_table.readNullTermString(allocator);
367 const line = flags.Start;
368 const column = if (has_column) blk: {
369 line_index = start_line_index + @sizeOf(pdb.LineNumberEntry) * block_hdr.NumLines;
370 line_index += @sizeOf(pdb.ColumnNumberEntry) * line_i;
371 const col_num_entry = @ptrCast(*pdb.ColumnNumberEntry, &subsect_info[line_index]);
372 break :blk col_num_entry.StartColumn;
373 } else 0;
374 break :subsections LineInfo{
375 .allocator = allocator,
376 .file_name = source_file_name,
377 .line = line,
378 .column = column,
379 };
380 }
381 }
382 break :subsections null;
383 }
384 },
385 else => {},
386 }
387
388 if (sect_offset > subsect_info.len)
389 return error.InvalidDebugInfo;
390 } else {
391 break :subsections null;
392 }
393 };
394
395 if (tty_color) {
396 setTtyColor(TtyColor.White);
397 if (opt_line_info) |li| {
398 try out_stream.print("{}:{}:{}", li.file_name, li.line, li.column);
399 } else {
400 try out_stream.print("???:?:?");
401 }
402 setTtyColor(TtyColor.Reset);
403 try out_stream.print(": ");
404 setTtyColor(TtyColor.Dim);
405 try out_stream.print("0x{x} in {} ({})", relocated_address, symbol_name, obj_basename);
406 setTtyColor(TtyColor.Reset);
407
408 if (opt_line_info) |line_info| {
409 try out_stream.print("\n");
410 if (printLineFromFile(out_stream, line_info)) {
411 if (line_info.column == 0) {
412 try out_stream.write("\n");
413 } else {
414 {
415 var col_i: usize = 1;
416 while (col_i < line_info.column) : (col_i += 1) {
417 try out_stream.writeByte(' ');
418 }
419 }
420 setTtyColor(TtyColor.Green);
421 try out_stream.write("^");
422 setTtyColor(TtyColor.Reset);
423 try out_stream.write("\n");
424 }
425 } else |err| switch (err) {
426 error.EndOfFile => {},
427 else => return err,
428 }
429 } else {
430 try out_stream.print("\n\n\n");
431 }
432 } else {
433 if (opt_line_info) |li| {
434 try out_stream.print("{}:{}:{}: 0x{x} in {} ({})\n\n\n", li.file_name, li.line, li.column, relocated_address, symbol_name, obj_basename);
435 } else {
436 try out_stream.print("???:?:?: 0x{x} in {} ({})\n\n\n", relocated_address, symbol_name, obj_basename);
437 }
438 }
439}
440
441const TtyColor = enum{
442 Red,
443 Green,
444 Cyan,
445 White,
446 Dim,
447 Bold,
448 Reset,
449};
450
451/// TODO this is a special case hack right now. clean it up and maybe make it part of std.fmt
452fn setTtyColor(tty_color: TtyColor) void {
453 const S = struct {
454 var attrs: windows.WORD = undefined;
455 var init_attrs = false;
456 };
457 if (!S.init_attrs) {
458 S.init_attrs = true;
459 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
460 // TODO handle error
461 _ = windows.GetConsoleScreenBufferInfo(stderr_file.handle, &info);
462 S.attrs = info.wAttributes;
463 }
464
465 // TODO handle errors
466 switch (tty_color) {
467 TtyColor.Red => {
468 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED|windows.FOREGROUND_INTENSITY);
469 },
470 TtyColor.Green => {
471 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN|windows.FOREGROUND_INTENSITY);
472 },
473 TtyColor.Cyan => {
474 _ = windows.SetConsoleTextAttribute(stderr_file.handle,
475 windows.FOREGROUND_GREEN|windows.FOREGROUND_BLUE|windows.FOREGROUND_INTENSITY);
476 },
477 TtyColor.White, TtyColor.Bold => {
478 _ = windows.SetConsoleTextAttribute(stderr_file.handle,
479 windows.FOREGROUND_RED|windows.FOREGROUND_GREEN|windows.FOREGROUND_BLUE|windows.FOREGROUND_INTENSITY);
480 },
481 TtyColor.Dim => {
482 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_INTENSITY);
483 },
484 TtyColor.Reset => {
485 _ = windows.SetConsoleTextAttribute(stderr_file.handle, S.attrs);
486 },
487 }
488}
489
490fn populateModule(di: *DebugInfo, mod: *Module) !void {
491 if (mod.populated)
492 return;
493 const allocator = getDebugInfoAllocator();
494
495 if (mod.mod_info.C11ByteSize != 0)
496 return error.InvalidDebugInfo;
497
498 if (mod.mod_info.C13ByteSize == 0)
499 return error.MissingDebugInfo;
500
501 const modi = di.pdb.getStreamById(mod.mod_info.ModuleSymStream) orelse return error.MissingDebugInfo;
502
503 const signature = try modi.stream.readIntLe(u32);
504 if (signature != 4)
505 return error.InvalidDebugInfo;
506
507 mod.symbols = try allocator.alloc(u8, mod.mod_info.SymByteSize - 4);
508 try modi.stream.readNoEof(mod.symbols);
509
510 mod.subsect_info = try allocator.alloc(u8, mod.mod_info.C13ByteSize);
511 try modi.stream.readNoEof(mod.subsect_info);
512
513 var sect_offset: usize = 0;
514 var skip_len: usize = undefined;
515 while (sect_offset != mod.subsect_info.len) : (sect_offset += skip_len) {
516 const subsect_hdr = @ptrCast(*pdb.DebugSubsectionHeader, &mod.subsect_info[sect_offset]);
517 skip_len = subsect_hdr.Length;
518 sect_offset += @sizeOf(pdb.DebugSubsectionHeader);
519
520 switch (subsect_hdr.Kind) {
521 pdb.DebugSubsectionKind.FileChecksums => {
522 mod.checksum_offset = sect_offset;
523 break;
524 },
525 else => {},
526 }
527
528 if (sect_offset > mod.subsect_info.len)
529 return error.InvalidDebugInfo;
530 }
531
532 mod.populated = true;
533}
534
239fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const MachoSymbol {535fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const MachoSymbol {
240 var min: usize = 0;536 var min: usize = 0;
241 var max: usize = symbols.len - 1; // Exclude sentinel.537 var max: usize = symbols.len - 1; // Exclude sentinel.
...@@ -372,14 +668,185 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo {...@@ -372,14 +668,185 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo {
372 switch (builtin.os) {668 switch (builtin.os) {
373 builtin.Os.linux => return openSelfDebugInfoLinux(allocator),669 builtin.Os.linux => return openSelfDebugInfoLinux(allocator),
374 builtin.Os.macosx, builtin.Os.ios => return openSelfDebugInfoMacOs(allocator),670 builtin.Os.macosx, builtin.Os.ios => return openSelfDebugInfoMacOs(allocator),
375 builtin.Os.windows => {671 builtin.Os.windows => return openSelfDebugInfoWindows(allocator),
376 // TODO: https://github.com/ziglang/zig/issues/721
377 return error.UnsupportedOperatingSystem;
378 },
379 else => return error.UnsupportedOperatingSystem,672 else => return error.UnsupportedOperatingSystem,
380 }673 }
381}674}
382675
676fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
677 const self_file = try os.openSelfExe();
678 defer self_file.close();
679
680 const coff_obj = try allocator.createOne(coff.Coff);
681 coff_obj.* = coff.Coff{
682 .in_file = self_file,
683 .allocator = allocator,
684 .coff_header = undefined,
685 .pe_header = undefined,
686 .sections = undefined,
687 .guid = undefined,
688 .age = undefined,
689 };
690
691 var di = DebugInfo{
692 .coff = coff_obj,
693 .pdb = undefined,
694 .sect_contribs = undefined,
695 .modules = undefined,
696 };
697
698 try di.coff.loadHeader();
699
700 var path_buf: [windows.MAX_PATH]u8 = undefined;
701 const len = try di.coff.getPdbPath(path_buf[0..]);
702 const raw_path = path_buf[0..len];
703
704 const path = try os.path.resolve(allocator, raw_path);
705
706 try di.pdb.openFile(di.coff, path);
707
708 var pdb_stream = di.pdb.getStream(pdb.StreamType.Pdb) orelse return error.InvalidDebugInfo;
709 const version = try pdb_stream.stream.readIntLe(u32);
710 const signature = try pdb_stream.stream.readIntLe(u32);
711 const age = try pdb_stream.stream.readIntLe(u32);
712 var guid: [16]u8 = undefined;
713 try pdb_stream.stream.readNoEof(guid[0..]);
714 if (!mem.eql(u8, di.coff.guid, guid) or di.coff.age != age)
715 return error.InvalidDebugInfo;
716 // We validated the executable and pdb match.
717
718 const string_table_index = str_tab_index: {
719 const name_bytes_len = try pdb_stream.stream.readIntLe(u32);
720 const name_bytes = try allocator.alloc(u8, name_bytes_len);
721 try pdb_stream.stream.readNoEof(name_bytes);
722
723 const HashTableHeader = packed struct {
724 Size: u32,
725 Capacity: u32,
726
727 fn maxLoad(cap: u32) u32 {
728 return cap * 2 / 3 + 1;
729 }
730 };
731 var hash_tbl_hdr: HashTableHeader = undefined;
732 try pdb_stream.stream.readStruct(HashTableHeader, &hash_tbl_hdr);
733 if (hash_tbl_hdr.Capacity == 0)
734 return error.InvalidDebugInfo;
735
736 if (hash_tbl_hdr.Size > HashTableHeader.maxLoad(hash_tbl_hdr.Capacity))
737 return error.InvalidDebugInfo;
738
739 const present = try readSparseBitVector(&pdb_stream.stream, allocator);
740 if (present.len != hash_tbl_hdr.Size)
741 return error.InvalidDebugInfo;
742 const deleted = try readSparseBitVector(&pdb_stream.stream, allocator);
743
744 const Bucket = struct {
745 first: u32,
746 second: u32,
747 };
748 const bucket_list = try allocator.alloc(Bucket, present.len);
749 for (present) |_| {
750 const name_offset = try pdb_stream.stream.readIntLe(u32);
751 const name_index = try pdb_stream.stream.readIntLe(u32);
752 const name = mem.toSlice(u8, name_bytes.ptr + name_offset);
753 if (mem.eql(u8, name, "/names")) {
754 break :str_tab_index name_index;
755 }
756 }
757 return error.MissingDebugInfo;
758 };
759
760 di.pdb.string_table = di.pdb.getStreamById(string_table_index) orelse return error.InvalidDebugInfo;
761 di.pdb.dbi = di.pdb.getStream(pdb.StreamType.Dbi) orelse return error.MissingDebugInfo;
762
763 const dbi = di.pdb.dbi;
764
765 // Dbi Header
766 var dbi_stream_header: pdb.DbiStreamHeader = undefined;
767 try dbi.stream.readStruct(pdb.DbiStreamHeader, &dbi_stream_header);
768 const mod_info_size = dbi_stream_header.ModInfoSize;
769 const section_contrib_size = dbi_stream_header.SectionContributionSize;
770
771 var modules = ArrayList(Module).init(allocator);
772
773 // Module Info Substream
774 var mod_info_offset: usize = 0;
775 while (mod_info_offset != mod_info_size) {
776 var mod_info: pdb.ModInfo = undefined;
777 try dbi.stream.readStruct(pdb.ModInfo, &mod_info);
778 var this_record_len: usize = @sizeOf(pdb.ModInfo);
779
780 const module_name = try dbi.readNullTermString(allocator);
781 this_record_len += module_name.len + 1;
782
783 const obj_file_name = try dbi.readNullTermString(allocator);
784 this_record_len += obj_file_name.len + 1;
785
786 const march_forward_bytes = this_record_len % 4;
787 if (march_forward_bytes != 0) {
788 try dbi.seekForward(march_forward_bytes);
789 this_record_len += march_forward_bytes;
790 }
791
792 try modules.append(Module{
793 .mod_info = mod_info,
794 .module_name = module_name,
795 .obj_file_name = obj_file_name,
796
797 .populated = false,
798 .symbols = undefined,
799 .subsect_info = undefined,
800 .checksum_offset = null,
801 });
802
803 mod_info_offset += this_record_len;
804 if (mod_info_offset > mod_info_size)
805 return error.InvalidDebugInfo;
806 }
807
808 di.modules = modules.toOwnedSlice();
809
810 // Section Contribution Substream
811 var sect_contribs = ArrayList(pdb.SectionContribEntry).init(allocator);
812 var sect_cont_offset: usize = 0;
813 if (section_contrib_size != 0) {
814 const ver = @intToEnum(pdb.SectionContrSubstreamVersion, try dbi.stream.readIntLe(u32));
815 if (ver != pdb.SectionContrSubstreamVersion.Ver60)
816 return error.InvalidDebugInfo;
817 sect_cont_offset += @sizeOf(u32);
818 }
819 while (sect_cont_offset != section_contrib_size) {
820 const entry = try sect_contribs.addOne();
821 try dbi.stream.readStruct(pdb.SectionContribEntry, entry);
822 sect_cont_offset += @sizeOf(pdb.SectionContribEntry);
823
824 if (sect_cont_offset > section_contrib_size)
825 return error.InvalidDebugInfo;
826 }
827
828 di.sect_contribs = sect_contribs.toOwnedSlice();
829
830 return di;
831}
832
833fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize {
834 const num_words = try stream.readIntLe(u32);
835 var word_i: usize = 0;
836 var list = ArrayList(usize).init(allocator);
837 while (word_i != num_words) : (word_i += 1) {
838 const word = try stream.readIntLe(u32);
839 var bit_i: u5 = 0;
840 while (true) : (bit_i += 1) {
841 if (word & (u32(1) << bit_i) != 0) {
842 try list.append(word_i * 32 + bit_i);
843 }
844 if (bit_i == @maxValue(u5)) break;
845 }
846 }
847 return list.toOwnedSlice();
848}
849
383fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {850fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {
384 var di = DebugInfo{851 var di = DebugInfo{
385 .self_exe_file = undefined,852 .self_exe_file = undefined,
...@@ -395,7 +862,7 @@ fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {...@@ -395,7 +862,7 @@ fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {
395 di.self_exe_file = try os.openSelfExe();862 di.self_exe_file = try os.openSelfExe();
396 errdefer di.self_exe_file.close();863 errdefer di.self_exe_file.close();
397864
398 try di.elf.openFile(allocator, &di.self_exe_file);865 try di.elf.openFile(allocator, di.self_exe_file);
399 errdefer di.elf.close();866 errdefer di.elf.close();
400867
401 di.debug_info = (try di.elf.findSection(".debug_info")) orelse return error.MissingDebugInfo;868 di.debug_info = (try di.elf.findSection(".debug_info")) orelse return error.MissingDebugInfo;
...@@ -578,7 +1045,13 @@ pub const DebugInfo = switch (builtin.os) {...@@ -578,7 +1045,13 @@ pub const DebugInfo = switch (builtin.os) {
578 return self.ofiles.allocator;1045 return self.ofiles.allocator;
579 }1046 }
580 },1047 },
581 else => struct {1048 builtin.Os.windows => struct {
1049 pdb: pdb.Pdb,
1050 coff: *coff.Coff,
1051 sect_contribs: []pdb.SectionContribEntry,
1052 modules: []Module,
1053 },
1054 builtin.Os.linux => struct {
582 self_exe_file: os.File,1055 self_exe_file: os.File,
583 elf: elf.Elf,1056 elf: elf.Elf,
584 debug_info: *elf.SectionHeader,1057 debug_info: *elf.SectionHeader,
...@@ -594,7 +1067,7 @@ pub const DebugInfo = switch (builtin.os) {...@@ -594,7 +1067,7 @@ pub const DebugInfo = switch (builtin.os) {
594 }1067 }
5951068
596 pub fn readString(self: *DebugInfo) ![]u8 {1069 pub fn readString(self: *DebugInfo) ![]u8 {
597 var in_file_stream = io.FileInStream.init(&self.self_exe_file);1070 var in_file_stream = io.FileInStream.init(self.self_exe_file);
598 const in_stream = &in_file_stream.stream;1071 const in_stream = &in_file_stream.stream;
599 return readStringRaw(self.allocator(), in_stream);1072 return readStringRaw(self.allocator(), in_stream);
600 }1073 }
...@@ -604,6 +1077,7 @@ pub const DebugInfo = switch (builtin.os) {...@@ -604,6 +1077,7 @@ pub const DebugInfo = switch (builtin.os) {
604 self.elf.close();1077 self.elf.close();
605 }1078 }
606 },1079 },
1080 else => @compileError("Unsupported OS"),
607};1081};
6081082
609const PcRange = struct {1083const PcRange = struct {
...@@ -929,7 +1403,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64...@@ -929,7 +1403,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
929}1403}
9301404
931fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable {1405fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable {
932 const in_file = &st.self_exe_file;1406 const in_file = st.self_exe_file;
933 var in_file_stream = io.FileInStream.init(in_file);1407 var in_file_stream = io.FileInStream.init(in_file);
934 const in_stream = &in_file_stream.stream;1408 const in_stream = &in_file_stream.stream;
935 var result = AbbrevTable.init(st.allocator());1409 var result = AbbrevTable.init(st.allocator());
...@@ -980,7 +1454,7 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con...@@ -980,7 +1454,7 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con
980}1454}
9811455
982fn parseDie(st: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {1456fn parseDie(st: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {
983 const in_file = &st.self_exe_file;1457 const in_file = st.self_exe_file;
984 var in_file_stream = io.FileInStream.init(in_file);1458 var in_file_stream = io.FileInStream.init(in_file);
985 const in_stream = &in_file_stream.stream;1459 const in_stream = &in_file_stream.stream;
986 const abbrev_code = try readULeb128(in_stream);1460 const abbrev_code = try readULeb128(in_stream);
...@@ -1202,7 +1676,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u...@@ -1202,7 +1676,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
1202fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, target_address: usize) !LineInfo {1676fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, target_address: usize) !LineInfo {
1203 const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir);1677 const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir);
12041678
1205 const in_file = &di.self_exe_file;1679 const in_file = di.self_exe_file;
1206 const debug_line_end = di.debug_line.offset + di.debug_line.size;1680 const debug_line_end = di.debug_line.offset + di.debug_line.size;
1207 var this_offset = di.debug_line.offset;1681 var this_offset = di.debug_line.offset;
1208 var this_index: usize = 0;1682 var this_index: usize = 0;
...@@ -1382,7 +1856,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void {...@@ -1382,7 +1856,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void {
1382 var this_unit_offset = st.debug_info.offset;1856 var this_unit_offset = st.debug_info.offset;
1383 var cu_index: usize = 0;1857 var cu_index: usize = 0;
13841858
1385 var in_file_stream = io.FileInStream.init(&st.self_exe_file);1859 var in_file_stream = io.FileInStream.init(st.self_exe_file);
1386 const in_stream = &in_file_stream.stream;1860 const in_stream = &in_file_stream.stream;
13871861
1388 while (this_unit_offset < debug_info_end) {1862 while (this_unit_offset < debug_info_end) {
...@@ -1448,7 +1922,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void {...@@ -1448,7 +1922,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void {
1448}1922}
14491923
1450fn findCompileUnit(st: *DebugInfo, target_address: u64) !*const CompileUnit {1924fn findCompileUnit(st: *DebugInfo, target_address: u64) !*const CompileUnit {
1451 var in_file_stream = io.FileInStream.init(&st.self_exe_file);1925 var in_file_stream = io.FileInStream.init(st.self_exe_file);
1452 const in_stream = &in_file_stream.stream;1926 const in_stream = &in_file_stream.stream;
1453 for (st.compile_unit_list.toSlice()) |*compile_unit| {1927 for (st.compile_unit_list.toSlice()) |*compile_unit| {
1454 if (compile_unit.pc_range) |range| {1928 if (compile_unit.pc_range) |range| {
std/elf.zig+2-2
...@@ -353,7 +353,7 @@ pub const SectionHeader = struct {...@@ -353,7 +353,7 @@ pub const SectionHeader = struct {
353};353};
354354
355pub const Elf = struct {355pub const Elf = struct {
356 in_file: *os.File,356 in_file: os.File,
357 auto_close_stream: bool,357 auto_close_stream: bool,
358 is_64: bool,358 is_64: bool,
359 endian: builtin.Endian,359 endian: builtin.Endian,
...@@ -376,7 +376,7 @@ pub const Elf = struct {...@@ -376,7 +376,7 @@ pub const Elf = struct {
376 }376 }
377377
378 /// Call close when done.378 /// Call close when done.
379 pub fn openFile(elf: *Elf, allocator: *mem.Allocator, file: *os.File) !void {379 pub fn openFile(elf: *Elf, allocator: *mem.Allocator, file: os.File) !void {
380 elf.allocator = allocator;380 elf.allocator = allocator;
381 elf.in_file = file;381 elf.in_file = file;
382 elf.auto_close_stream = false;382 elf.auto_close_stream = false;
std/event/lock.zig+1-1
...@@ -7,7 +7,7 @@ const AtomicOrder = builtin.AtomicOrder;...@@ -7,7 +7,7 @@ const AtomicOrder = builtin.AtomicOrder;
7const Loop = std.event.Loop;7const Loop = std.event.Loop;
88
9/// Thread-safe async/await lock.9/// Thread-safe async/await lock.
10/// Does not make any syscalls - coroutines which are waiting for the lock are suspended, and10/// coroutines which are waiting for the lock are suspended, and
11/// are resumed when the lock is released, in order.11/// are resumed when the lock is released, in order.
12/// Allows only one actor to hold the lock.12/// Allows only one actor to hold the lock.
13pub const Lock = struct {13pub const Lock = struct {
std/event/locked.zig+1-1
...@@ -3,7 +3,7 @@ const Lock = std.event.Lock;...@@ -3,7 +3,7 @@ const Lock = std.event.Lock;
3const Loop = std.event.Loop;3const Loop = std.event.Loop;
44
5/// Thread-safe async/await lock that protects one piece of data.5/// Thread-safe async/await lock that protects one piece of data.
6/// Does not make any syscalls - coroutines which are waiting for the lock are suspended, and6/// coroutines which are waiting for the lock are suspended, and
7/// are resumed when the lock is released, in order.7/// are resumed when the lock is released, in order.
8pub fn Locked(comptime T: type) type {8pub fn Locked(comptime T: type) type {
9 return struct {9 return struct {
std/event/rwlock.zig+1-1
...@@ -7,7 +7,7 @@ const AtomicOrder = builtin.AtomicOrder;...@@ -7,7 +7,7 @@ const AtomicOrder = builtin.AtomicOrder;
7const Loop = std.event.Loop;7const Loop = std.event.Loop;
88
9/// Thread-safe async/await lock.9/// Thread-safe async/await lock.
10/// Does not make any syscalls - coroutines which are waiting for the lock are suspended, and10/// coroutines which are waiting for the lock are suspended, and
11/// are resumed when the lock is released, in order.11/// are resumed when the lock is released, in order.
12/// Many readers can hold the lock at the same time; however locking for writing is exclusive.12/// Many readers can hold the lock at the same time; however locking for writing is exclusive.
13/// When a read lock is held, it will not be released until the reader queue is empty.13/// When a read lock is held, it will not be released until the reader queue is empty.
std/event/rwlocked.zig+1-1
...@@ -3,7 +3,7 @@ const RwLock = std.event.RwLock;...@@ -3,7 +3,7 @@ const RwLock = std.event.RwLock;
3const Loop = std.event.Loop;3const Loop = std.event.Loop;
44
5/// Thread-safe async/await RW lock that protects one piece of data.5/// Thread-safe async/await RW lock that protects one piece of data.
6/// Does not make any syscalls - coroutines which are waiting for the lock are suspended, and6/// coroutines which are waiting for the lock are suspended, and
7/// are resumed when the lock is released, in order.7/// are resumed when the lock is released, in order.
8pub fn RwLocked(comptime T: type) type {8pub fn RwLocked(comptime T: type) type {
9 return struct {9 return struct {
std/event/tcp.zig+4-4
...@@ -89,7 +89,7 @@ pub const Server = struct {...@@ -89,7 +89,7 @@ pub const Server = struct {
89 error.ProcessFdQuotaExceeded => {89 error.ProcessFdQuotaExceeded => {
90 errdefer std.os.emfile_promise_queue.remove(&self.waiting_for_emfile_node);90 errdefer std.os.emfile_promise_queue.remove(&self.waiting_for_emfile_node);
91 suspend {91 suspend {
92 self.waiting_for_emfile_node = PromiseNode.init( @handle() );92 self.waiting_for_emfile_node = PromiseNode.init(@handle());
93 std.os.emfile_promise_queue.append(&self.waiting_for_emfile_node);93 std.os.emfile_promise_queue.append(&self.waiting_for_emfile_node);
94 }94 }
95 continue;95 continue;
...@@ -145,11 +145,11 @@ test "listen on a port, send bytes, receive bytes" {...@@ -145,11 +145,11 @@ test "listen on a port, send bytes, receive bytes" {
145 cancel @handle();145 cancel @handle();
146 }146 }
147 }147 }
148 async fn errorableHandler(self: *Self, _addr: *const std.net.Address, _socket: *const std.os.File) !void {148 async fn errorableHandler(self: *Self, _addr: *const std.net.Address, _socket: std.os.File) !void {
149 const addr = _addr.*; // TODO https://github.com/ziglang/zig/issues/733149 const addr = _addr.*; // TODO https://github.com/ziglang/zig/issues/733
150 var socket = _socket.*; // TODO https://github.com/ziglang/zig/issues/733150 var socket = _socket; // TODO https://github.com/ziglang/zig/issues/733
151151
152 var adapter = std.io.FileOutStream.init(&socket);152 var adapter = std.io.FileOutStream.init(socket);
153 var stream = &adapter.stream;153 var stream = &adapter.stream;
154 try stream.print("hello from server\n");154 try stream.print("hello from server\n");
155 }155 }
std/fmt/index.zig+126-17
...@@ -163,26 +163,47 @@ pub fn formatType(...@@ -163,26 +163,47 @@ pub fn formatType(
163 }163 }
164 break :cf false;164 break :cf false;
165 };165 };
166
167 if (has_cust_fmt) return value.format(fmt, context, Errors, output);166 if (has_cust_fmt) return value.format(fmt, context, Errors, output);
167
168 try output(context, @typeName(T));168 try output(context, @typeName(T));
169 if (comptime @typeId(T) == builtin.TypeId.Enum) {169 switch (comptime @typeId(T)) {
170 try output(context, ".");170 builtin.TypeId.Enum => {
171 try formatType(@tagName(value), "", context, Errors, output);171 try output(context, ".");
172 return;172 try formatType(@tagName(value), "", context, Errors, output);
173 }173 return;
174 comptime var field_i = 0;174 },
175 inline while (field_i < @memberCount(T)) : (field_i += 1) {175 builtin.TypeId.Struct => {
176 if (field_i == 0) {176 comptime var field_i = 0;
177 try output(context, "{ .");177 inline while (field_i < @memberCount(T)) : (field_i += 1) {
178 } else {178 if (field_i == 0) {
179 try output(context, ", .");179 try output(context, "{ .");
180 }180 } else {
181 try output(context, @memberName(T, field_i));181 try output(context, ", .");
182 try output(context, " = ");182 }
183 try formatType(@field(value, @memberName(T, field_i)), "", context, Errors, output);183 try output(context, @memberName(T, field_i));
184 try output(context, " = ");
185 try formatType(@field(value, @memberName(T, field_i)), "", context, Errors, output);
186 }
187 try output(context, " }");
188 },
189 builtin.TypeId.Union => {
190 const info = @typeInfo(T).Union;
191 if (info.tag_type) |UnionTagType| {
192 try output(context, "{ .");
193 try output(context, @tagName(UnionTagType(value)));
194 try output(context, " = ");
195 inline for (info.fields) |u_field| {
196 if (@enumToInt(UnionTagType(value)) == u_field.enum_field.?.value) {
197 try formatType(@field(value, u_field.name), "", context, Errors, output);
198 }
199 }
200 try output(context, " }");
201 } else {
202 try format(context, Errors, output, "@{x}", @ptrToInt(&value));
203 }
204 },
205 else => unreachable,
184 }206 }
185 try output(context, " }");
186 return;207 return;
187 },208 },
188 builtin.TypeId.Pointer => |ptr_info| switch (ptr_info.size) {209 builtin.TypeId.Pointer => |ptr_info| switch (ptr_info.size) {
...@@ -329,6 +350,11 @@ pub fn formatText(...@@ -329,6 +350,11 @@ pub fn formatText(
329 comptime var width = 0;350 comptime var width = 0;
330 if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);351 if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
331 return formatBuf(bytes, width, context, Errors, output);352 return formatBuf(bytes, width, context, Errors, output);
353 } else if ((fmt[0] == 'x') or (fmt[0] == 'X')) {
354 for (bytes) |c| {
355 try formatInt(c, 16, fmt[0] == 'X', 2, context, Errors, output);
356 }
357 return;
332 } else @compileError("Unknown format character: " ++ []u8{fmt[0]});358 } else @compileError("Unknown format character: " ++ []u8{fmt[0]});
333 }359 }
334 return output(context, bytes);360 return output(context, bytes);
...@@ -1194,6 +1220,70 @@ test "fmt.format" {...@@ -1194,6 +1220,70 @@ test "fmt.format" {
1194 try testFmt("point: (10.200,2.220)\n", "point: {}\n", value);1220 try testFmt("point: (10.200,2.220)\n", "point: {}\n", value);
1195 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", value);1221 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", value);
1196 }1222 }
1223 //struct format
1224 {
1225 const S = struct {
1226 a: u32,
1227 b: error,
1228 };
1229
1230 const inst = S{
1231 .a = 456,
1232 .b = error.Unused,
1233 };
1234
1235 try testFmt("S{ .a = 456, .b = error.Unused }", "{}", inst);
1236 }
1237 //union format
1238 {
1239 const TU = union(enum) {
1240 float: f32,
1241 int: u32,
1242 };
1243
1244 const UU = union {
1245 float: f32,
1246 int: u32,
1247 };
1248
1249 const EU = extern union {
1250 float: f32,
1251 int: u32,
1252 };
1253
1254 const tu_inst = TU{ .int = 123 };
1255 const uu_inst = UU{ .int = 456 };
1256 const eu_inst = EU{ .float = 321.123 };
1257
1258 try testFmt("TU{ .int = 123 }", "{}", tu_inst);
1259
1260 var buf: [100]u8 = undefined;
1261 const uu_result = try bufPrint(buf[0..], "{}", uu_inst);
1262 debug.assert(mem.eql(u8, uu_result[0..3], "UU@"));
1263
1264 const eu_result = try bufPrint(buf[0..], "{}", eu_inst);
1265 debug.assert(mem.eql(u8, uu_result[0..3], "EU@"));
1266 }
1267 //enum format
1268 {
1269 const E = enum {
1270 One,
1271 Two,
1272 Three,
1273 };
1274
1275 const inst = E.Two;
1276
1277 try testFmt("E.Two", "{}", inst);
1278 }
1279 //print bytes as hex
1280 {
1281 const some_bytes = "\xCA\xFE\xBA\xBE";
1282 try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", some_bytes);
1283 try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", some_bytes);
1284 const bytes_with_zeros = "\x00\x0E\xBA\xBE";
1285 try testFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", bytes_with_zeros);
1286 }
1197}1287}
11981288
1199fn testFmt(expected: []const u8, comptime template: []const u8, args: ...) !void {1289fn testFmt(expected: []const u8, comptime template: []const u8, args: ...) !void {
...@@ -1241,3 +1331,22 @@ pub fn isWhiteSpace(byte: u8) bool {...@@ -1241,3 +1331,22 @@ pub fn isWhiteSpace(byte: u8) bool {
1241 else => false,1331 else => false,
1242 };1332 };
1243}1333}
1334
1335pub fn hexToBytes(out: []u8, input: []const u8) !void {
1336 if (out.len * 2 < input.len)
1337 return error.InvalidLength;
1338
1339 var in_i: usize = 0;
1340 while (in_i != input.len) : (in_i += 2) {
1341 const hi = try charToDigit(input[in_i], 16);
1342 const lo = try charToDigit(input[in_i + 1], 16);
1343 out[in_i / 2] = (hi << 4) | lo;
1344 }
1345}
1346
1347test "fmt.hexToBytes" {
1348 const test_hex_str = "909A312BB12ED1F819B3521AC4C1E896F2160507FFC1C8381E3B07BB16BD1706";
1349 var pb: [32]u8 = undefined;
1350 try hexToBytes(pb[0..], test_hex_str);
1351 try testFmt(test_hex_str, "{X}", pb);
1352}
std/index.zig+4
...@@ -15,6 +15,7 @@ pub const atomic = @import("atomic/index.zig");...@@ -15,6 +15,7 @@ pub const atomic = @import("atomic/index.zig");
15pub const base64 = @import("base64.zig");15pub const base64 = @import("base64.zig");
16pub const build = @import("build.zig");16pub const build = @import("build.zig");
17pub const c = @import("c/index.zig");17pub const c = @import("c/index.zig");
18pub const coff = @import("coff.zig");
18pub const crypto = @import("crypto/index.zig");19pub const crypto = @import("crypto/index.zig");
19pub const cstr = @import("cstr.zig");20pub const cstr = @import("cstr.zig");
20pub const debug = @import("debug/index.zig");21pub const debug = @import("debug/index.zig");
...@@ -33,6 +34,7 @@ pub const math = @import("math/index.zig");...@@ -33,6 +34,7 @@ pub const math = @import("math/index.zig");
33pub const mem = @import("mem.zig");34pub const mem = @import("mem.zig");
34pub const net = @import("net.zig");35pub const net = @import("net.zig");
35pub const os = @import("os/index.zig");36pub const os = @import("os/index.zig");
37pub const pdb = @import("pdb.zig");
36pub const rand = @import("rand/index.zig");38pub const rand = @import("rand/index.zig");
37pub const rb = @import("rb.zig");39pub const rb = @import("rb.zig");
38pub const sort = @import("sort.zig");40pub const sort = @import("sort.zig");
...@@ -56,6 +58,7 @@ test "std" {...@@ -56,6 +58,7 @@ test "std" {
56 _ = @import("base64.zig");58 _ = @import("base64.zig");
57 _ = @import("build.zig");59 _ = @import("build.zig");
58 _ = @import("c/index.zig");60 _ = @import("c/index.zig");
61 _ = @import("coff.zig");
59 _ = @import("crypto/index.zig");62 _ = @import("crypto/index.zig");
60 _ = @import("cstr.zig");63 _ = @import("cstr.zig");
61 _ = @import("debug/index.zig");64 _ = @import("debug/index.zig");
...@@ -74,6 +77,7 @@ test "std" {...@@ -74,6 +77,7 @@ test "std" {
74 _ = @import("heap.zig");77 _ = @import("heap.zig");
75 _ = @import("os/index.zig");78 _ = @import("os/index.zig");
76 _ = @import("rand/index.zig");79 _ = @import("rand/index.zig");
80 _ = @import("pdb.zig");
77 _ = @import("sort.zig");81 _ = @import("sort.zig");
78 _ = @import("unicode.zig");82 _ = @import("unicode.zig");
79 _ = @import("zig/index.zig");83 _ = @import("zig/index.zig");
std/io.zig+8-8
...@@ -34,13 +34,13 @@ pub fn getStdIn() GetStdIoErrs!File {...@@ -34,13 +34,13 @@ pub fn getStdIn() GetStdIoErrs!File {
3434
35/// Implementation of InStream trait for File35/// Implementation of InStream trait for File
36pub const FileInStream = struct {36pub const FileInStream = struct {
37 file: *File,37 file: File,
38 stream: Stream,38 stream: Stream,
3939
40 pub const Error = @typeOf(File.read).ReturnType.ErrorSet;40 pub const Error = @typeOf(File.read).ReturnType.ErrorSet;
41 pub const Stream = InStream(Error);41 pub const Stream = InStream(Error);
4242
43 pub fn init(file: *File) FileInStream {43 pub fn init(file: File) FileInStream {
44 return FileInStream{44 return FileInStream{
45 .file = file,45 .file = file,
46 .stream = Stream{ .readFn = readFn },46 .stream = Stream{ .readFn = readFn },
...@@ -55,13 +55,13 @@ pub const FileInStream = struct {...@@ -55,13 +55,13 @@ pub const FileInStream = struct {
5555
56/// Implementation of OutStream trait for File56/// Implementation of OutStream trait for File
57pub const FileOutStream = struct {57pub const FileOutStream = struct {
58 file: *File,58 file: File,
59 stream: Stream,59 stream: Stream,
6060
61 pub const Error = File.WriteError;61 pub const Error = File.WriteError;
62 pub const Stream = OutStream(Error);62 pub const Stream = OutStream(Error);
6363
64 pub fn init(file: *File) FileOutStream {64 pub fn init(file: File) FileOutStream {
65 return FileOutStream{65 return FileOutStream{
66 .file = file,66 .file = file,
67 .stream = Stream{ .writeFn = writeFn },67 .stream = Stream{ .writeFn = writeFn },
...@@ -210,7 +210,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -210,7 +210,7 @@ pub fn InStream(comptime ReadError: type) type {
210210
211 pub fn readStruct(self: *Self, comptime T: type, ptr: *T) !void {211 pub fn readStruct(self: *Self, comptime T: type, ptr: *T) !void {
212 // Only extern and packed structs have defined in-memory layout.212 // Only extern and packed structs have defined in-memory layout.
213 assert(@typeInfo(T).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto);213 comptime assert(@typeInfo(T).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto);
214 return self.readNoEof(@sliceToBytes((*[1]T)(ptr)[0..]));214 return self.readNoEof(@sliceToBytes((*[1]T)(ptr)[0..]));
215 }215 }
216 };216 };
...@@ -280,7 +280,7 @@ pub fn readFileAllocAligned(allocator: *mem.Allocator, path: []const u8, comptim...@@ -280,7 +280,7 @@ pub fn readFileAllocAligned(allocator: *mem.Allocator, path: []const u8, comptim
280 const buf = try allocator.alignedAlloc(u8, A, size);280 const buf = try allocator.alignedAlloc(u8, A, size);
281 errdefer allocator.free(buf);281 errdefer allocator.free(buf);
282282
283 var adapter = FileInStream.init(&file);283 var adapter = FileInStream.init(file);
284 try adapter.stream.readNoEof(buf[0..size]);284 try adapter.stream.readNoEof(buf[0..size]);
285 return buf;285 return buf;
286}286}
...@@ -592,7 +592,7 @@ pub const BufferedAtomicFile = struct {...@@ -592,7 +592,7 @@ pub const BufferedAtomicFile = struct {
592 self.atomic_file = try os.AtomicFile.init(allocator, dest_path, os.File.default_mode);592 self.atomic_file = try os.AtomicFile.init(allocator, dest_path, os.File.default_mode);
593 errdefer self.atomic_file.deinit();593 errdefer self.atomic_file.deinit();
594594
595 self.file_stream = FileOutStream.init(&self.atomic_file.file);595 self.file_stream = FileOutStream.init(self.atomic_file.file);
596 self.buffered_stream = BufferedOutStream(FileOutStream.Error).init(&self.file_stream.stream);596 self.buffered_stream = BufferedOutStream(FileOutStream.Error).init(&self.file_stream.stream);
597 return self;597 return self;
598 }598 }
...@@ -622,7 +622,7 @@ test "import io tests" {...@@ -622,7 +622,7 @@ test "import io tests" {
622622
623pub fn readLine(buf: []u8) !usize {623pub fn readLine(buf: []u8) !usize {
624 var stdin = getStdIn() catch return error.StdInUnavailable;624 var stdin = getStdIn() catch return error.StdInUnavailable;
625 var adapter = FileInStream.init(&stdin);625 var adapter = FileInStream.init(stdin);
626 var stream = &adapter.stream;626 var stream = &adapter.stream;
627 var index: usize = 0;627 var index: usize = 0;
628 while (true) {628 while (true) {
std/io_test.zig+2-2
...@@ -19,7 +19,7 @@ test "write a file, read it, then delete it" {...@@ -19,7 +19,7 @@ test "write a file, read it, then delete it" {
19 var file = try os.File.openWrite(tmp_file_name);19 var file = try os.File.openWrite(tmp_file_name);
20 defer file.close();20 defer file.close();
2121
22 var file_out_stream = io.FileOutStream.init(&file);22 var file_out_stream = io.FileOutStream.init(file);
23 var buf_stream = io.BufferedOutStream(io.FileOutStream.Error).init(&file_out_stream.stream);23 var buf_stream = io.BufferedOutStream(io.FileOutStream.Error).init(&file_out_stream.stream);
24 const st = &buf_stream.stream;24 const st = &buf_stream.stream;
25 try st.print("begin");25 try st.print("begin");
...@@ -35,7 +35,7 @@ test "write a file, read it, then delete it" {...@@ -35,7 +35,7 @@ test "write a file, read it, then delete it" {
35 const expected_file_size = "begin".len + data.len + "end".len;35 const expected_file_size = "begin".len + data.len + "end".len;
36 assert(file_size == expected_file_size);36 assert(file_size == expected_file_size);
3737
38 var file_in_stream = io.FileInStream.init(&file);38 var file_in_stream = io.FileInStream.init(file);
39 var buf_stream = io.BufferedInStream(io.FileInStream.Error).init(&file_in_stream.stream);39 var buf_stream = io.BufferedInStream(io.FileInStream.Error).init(&file_in_stream.stream);
40 const st = &buf_stream.stream;40 const st = &buf_stream.stream;
41 const contents = try st.readAllAlloc(allocator, 2 * 1024);41 const contents = try st.readAllAlloc(allocator, 2 * 1024);
std/macho.zig+552-206
...@@ -1,4 +1,3 @@...@@ -1,4 +1,3 @@
1
2pub const mach_header = extern struct {1pub const mach_header = extern struct {
3 magic: u32,2 magic: u32,
4 cputype: cpu_type_t,3 cputype: cpu_type_t,
...@@ -25,26 +24,43 @@ pub const load_command = extern struct {...@@ -25,26 +24,43 @@ pub const load_command = extern struct {
25 cmdsize: u32,24 cmdsize: u32,
26};25};
2726
28
29/// The symtab_command contains the offsets and sizes of the link-edit 4.3BSD27/// The symtab_command contains the offsets and sizes of the link-edit 4.3BSD
30/// "stab" style symbol table information as described in the header files28/// "stab" style symbol table information as described in the header files
31/// <nlist.h> and <stab.h>.29/// <nlist.h> and <stab.h>.
32pub const symtab_command = extern struct {30pub const symtab_command = extern struct {
33 cmd: u32, /// LC_SYMTAB31 /// LC_SYMTAB
34 cmdsize: u32, /// sizeof(struct symtab_command)32 cmd: u32,
35 symoff: u32, /// symbol table offset33
36 nsyms: u32, /// number of symbol table entries34 /// sizeof(struct symtab_command)
37 stroff: u32, /// string table offset35 cmdsize: u32,
38 strsize: u32, /// string table size in bytes36
37 /// symbol table offset
38 symoff: u32,
39
40 /// number of symbol table entries
41 nsyms: u32,
42
43 /// string table offset
44 stroff: u32,
45
46 /// string table size in bytes
47 strsize: u32,
39};48};
4049
41/// The linkedit_data_command contains the offsets and sizes of a blob50/// The linkedit_data_command contains the offsets and sizes of a blob
42/// of data in the __LINKEDIT segment. 51/// of data in the __LINKEDIT segment.
43const linkedit_data_command = extern struct {52const linkedit_data_command = extern struct {
44 cmd: u32,/// LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, LC_DYLIB_CODE_SIGN_DRS or LC_LINKER_OPTIMIZATION_HINT.53 /// LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, LC_DYLIB_CODE_SIGN_DRS or LC_LINKER_OPTIMIZATION_HINT.
45 cmdsize: u32, /// sizeof(struct linkedit_data_command)54 cmd: u32,
46 dataoff: u32 , /// file offset of data in __LINKEDIT segment55
47 datasize: u32 , /// file size of data in __LINKEDIT segment 56 /// sizeof(struct linkedit_data_command)
57 cmdsize: u32,
58
59 /// file offset of data in __LINKEDIT segment
60 dataoff: u32,
61
62 /// file size of data in __LINKEDIT segment
63 datasize: u32,
48};64};
4965
50/// The segment load command indicates that a part of this file is to be66/// The segment load command indicates that a part of this file is to be
...@@ -58,16 +74,35 @@ const linkedit_data_command = extern struct {...@@ -58,16 +74,35 @@ const linkedit_data_command = extern struct {
58/// section structures directly follow the segment command and their size is74/// section structures directly follow the segment command and their size is
59/// reflected in cmdsize.75/// reflected in cmdsize.
60pub const segment_command = extern struct {76pub const segment_command = extern struct {
61 cmd: u32,/// LC_SEGMENT77 /// LC_SEGMENT
62 cmdsize: u32,/// includes sizeof section structs78 cmd: u32,
63 segname: [16]u8,/// segment name79
64 vmaddr: u32,/// memory address of this segment80 /// includes sizeof section structs
65 vmsize: u32,/// memory size of this segment81 cmdsize: u32,
66 fileoff: u32,/// file offset of this segment82
67 filesize: u32,/// amount to map from the file83 /// segment name
68 maxprot: vm_prot_t,/// maximum VM protection84 segname: [16]u8,
69 initprot: vm_prot_t,/// initial VM protection85
70 nsects: u32,/// number of sections in segment86 /// memory address of this segment
87 vmaddr: u32,
88
89 /// memory size of this segment
90 vmsize: u32,
91
92 /// file offset of this segment
93 fileoff: u32,
94
95 /// amount to map from the file
96 filesize: u32,
97
98 /// maximum VM protection
99 maxprot: vm_prot_t,
100
101 /// initial VM protection
102 initprot: vm_prot_t,
103
104 /// number of sections in segment
105 nsects: u32,
71 flags: u32,106 flags: u32,
72};107};
73108
...@@ -76,17 +111,36 @@ pub const segment_command = extern struct {...@@ -76,17 +111,36 @@ pub const segment_command = extern struct {
76/// sections then section_64 structures directly follow the 64-bit segment111/// sections then section_64 structures directly follow the 64-bit segment
77/// command and their size is reflected in cmdsize.112/// command and their size is reflected in cmdsize.
78pub const segment_command_64 = extern struct {113pub const segment_command_64 = extern struct {
79 cmd: u32, /// LC_SEGMENT_64114 /// LC_SEGMENT_64
80 cmdsize: u32, /// includes sizeof section_64 structs115 cmd: u32,
81 segname: [16]u8, /// segment name116
82 vmaddr: u64, /// memory address of this segment117 /// includes sizeof section_64 structs
83 vmsize: u64, /// memory size of this segment118 cmdsize: u32,
84 fileoff: u64, /// file offset of this segment119
85 filesize: u64, /// amount to map from the file120 /// segment name
86 maxprot: vm_prot_t, /// maximum VM protection121 segname: [16]u8,
87 initprot: vm_prot_t, /// initial VM protection122
88 nsects: u32, /// number of sections in segment123 /// memory address of this segment
89 flags: u32, 124 vmaddr: u64,
125
126 /// memory size of this segment
127 vmsize: u64,
128
129 /// file offset of this segment
130 fileoff: u64,
131
132 /// amount to map from the file
133 filesize: u64,
134
135 /// maximum VM protection
136 maxprot: vm_prot_t,
137
138 /// initial VM protection
139 initprot: vm_prot_t,
140
141 /// number of sections in segment
142 nsects: u32,
143 flags: u32,
90};144};
91145
92/// A segment is made up of zero or more sections. Non-MH_OBJECT files have146/// A segment is made up of zero or more sections. Non-MH_OBJECT files have
...@@ -115,32 +169,76 @@ pub const segment_command_64 = extern struct {...@@ -115,32 +169,76 @@ pub const segment_command_64 = extern struct {
115/// fields of the section structure for mach object files is described in the169/// fields of the section structure for mach object files is described in the
116/// header file <reloc.h>.170/// header file <reloc.h>.
117pub const @"section" = extern struct {171pub const @"section" = extern struct {
118 sectname: [16]u8, /// name of this section172 /// name of this section
119 segname: [16]u8, /// segment this section goes in173 sectname: [16]u8,
120 addr: u32, /// memory address of this section174
121 size: u32, /// size in bytes of this section175 /// segment this section goes in
122 offset: u32, /// file offset of this section176 segname: [16]u8,
123 @"align": u32, /// section alignment (power of 2)177
124 reloff: u32, /// file offset of relocation entries178 /// memory address of this section
125 nreloc: u32, /// number of relocation entries179 addr: u32,
126 flags: u32, /// flags (section type and attributes180
127 reserved1: u32, /// reserved (for offset or index)181 /// size in bytes of this section
128 reserved2: u32, /// reserved (for count or sizeof)182 size: u32,
183
184 /// file offset of this section
185 offset: u32,
186
187 /// section alignment (power of 2)
188 @"align": u32,
189
190 /// file offset of relocation entries
191 reloff: u32,
192
193 /// number of relocation entries
194 nreloc: u32,
195
196 /// flags (section type and attributes
197 flags: u32,
198
199 /// reserved (for offset or index)
200 reserved1: u32,
201
202 /// reserved (for count or sizeof)
203 reserved2: u32,
129};204};
130205
131pub const section_64 = extern struct {206pub const section_64 = extern struct {
132 sectname: [16]u8, /// name of this section207 /// name of this section
133 segname: [16]u8, /// segment this section goes in208 sectname: [16]u8,
134 addr: u64, /// memory address of this section209
135 size: u64, /// size in bytes of this section210 /// segment this section goes in
136 offset: u32, /// file offset of this section211 segname: [16]u8,
137 @"align": u32, /// section alignment (power of 2)212
138 reloff: u32, /// file offset of relocation entries213 /// memory address of this section
139 nreloc: u32, /// number of relocation entries214 addr: u64,
140 flags: u32, /// flags (section type and attributes215
141 reserved1: u32, /// reserved (for offset or index)216 /// size in bytes of this section
142 reserved2: u32, /// reserved (for count or sizeof)217 size: u64,
143 reserved3: u32, /// reserved218
219 /// file offset of this section
220 offset: u32,
221
222 /// section alignment (power of 2)
223 @"align": u32,
224
225 /// file offset of relocation entries
226 reloff: u32,
227
228 /// number of relocation entries
229 nreloc: u32,
230
231 /// flags (section type and attributes
232 flags: u32,
233
234 /// reserved (for offset or index)
235 reserved1: u32,
236
237 /// reserved (for count or sizeof)
238 reserved2: u32,
239
240 /// reserved
241 reserved3: u32,
144};242};
145243
146pub const nlist = extern struct {244pub const nlist = extern struct {
...@@ -168,116 +266,287 @@ pub const nlist_64 = extern struct {...@@ -168,116 +266,287 @@ pub const nlist_64 = extern struct {
168/// simply be ignored.266/// simply be ignored.
169pub const LC_REQ_DYLD = 0x80000000;267pub const LC_REQ_DYLD = 0x80000000;
170268
171pub const LC_SEGMENT = 0x1; /// segment of this file to be mapped269/// segment of this file to be mapped
172pub const LC_SYMTAB = 0x2; /// link-edit stab symbol table info270pub const LC_SEGMENT = 0x1;
173pub const LC_SYMSEG = 0x3; /// link-edit gdb symbol table info (obsolete)271
174pub const LC_THREAD = 0x4; /// thread272/// link-edit stab symbol table info
175pub const LC_UNIXTHREAD = 0x5; /// unix thread (includes a stack)273pub const LC_SYMTAB = 0x2;
176pub const LC_LOADFVMLIB = 0x6; /// load a specified fixed VM shared library274
177pub const LC_IDFVMLIB = 0x7; /// fixed VM shared library identification275/// link-edit gdb symbol table info (obsolete)
178pub const LC_IDENT = 0x8; /// object identification info (obsolete)276pub const LC_SYMSEG = 0x3;
179pub const LC_FVMFILE = 0x9; /// fixed VM file inclusion (internal use)277
180pub const LC_PREPAGE = 0xa; /// prepage command (internal use)278/// thread
181pub const LC_DYSYMTAB = 0xb; /// dynamic link-edit symbol table info279pub const LC_THREAD = 0x4;
182pub const LC_LOAD_DYLIB = 0xc; /// load a dynamically linked shared library280
183pub const LC_ID_DYLIB = 0xd; /// dynamically linked shared lib ident281/// unix thread (includes a stack)
184pub const LC_LOAD_DYLINKER = 0xe; /// load a dynamic linker282pub const LC_UNIXTHREAD = 0x5;
185pub const LC_ID_DYLINKER = 0xf; /// dynamic linker identification283
186pub const LC_PREBOUND_DYLIB = 0x10; /// modules prebound for a dynamically284/// load a specified fixed VM shared library
187pub const LC_ROUTINES = 0x11; /// image routines285pub const LC_LOADFVMLIB = 0x6;
188pub const LC_SUB_FRAMEWORK = 0x12; /// sub framework286
189pub const LC_SUB_UMBRELLA = 0x13; /// sub umbrella287/// fixed VM shared library identification
190pub const LC_SUB_CLIENT = 0x14; /// sub client288pub const LC_IDFVMLIB = 0x7;
191pub const LC_SUB_LIBRARY = 0x15; /// sub library289
192pub const LC_TWOLEVEL_HINTS = 0x16; /// two-level namespace lookup hints290/// object identification info (obsolete)
193pub const LC_PREBIND_CKSUM = 0x17; /// prebind checksum291pub const LC_IDENT = 0x8;
292
293/// fixed VM file inclusion (internal use)
294pub const LC_FVMFILE = 0x9;
295
296/// prepage command (internal use)
297pub const LC_PREPAGE = 0xa;
298
299/// dynamic link-edit symbol table info
300pub const LC_DYSYMTAB = 0xb;
301
302/// load a dynamically linked shared library
303pub const LC_LOAD_DYLIB = 0xc;
304
305/// dynamically linked shared lib ident
306pub const LC_ID_DYLIB = 0xd;
307
308/// load a dynamic linker
309pub const LC_LOAD_DYLINKER = 0xe;
310
311/// dynamic linker identification
312pub const LC_ID_DYLINKER = 0xf;
313
314/// modules prebound for a dynamically
315pub const LC_PREBOUND_DYLIB = 0x10;
316
317/// image routines
318pub const LC_ROUTINES = 0x11;
319
320/// sub framework
321pub const LC_SUB_FRAMEWORK = 0x12;
322
323/// sub umbrella
324pub const LC_SUB_UMBRELLA = 0x13;
325
326/// sub client
327pub const LC_SUB_CLIENT = 0x14;
328
329/// sub library
330pub const LC_SUB_LIBRARY = 0x15;
331
332/// two-level namespace lookup hints
333pub const LC_TWOLEVEL_HINTS = 0x16;
334
335/// prebind checksum
336pub const LC_PREBIND_CKSUM = 0x17;
194337
195/// load a dynamically linked shared library that is allowed to be missing338/// load a dynamically linked shared library that is allowed to be missing
196/// (all symbols are weak imported).339/// (all symbols are weak imported).
197pub const LC_LOAD_WEAK_DYLIB = (0x18 | LC_REQ_DYLD);340pub const LC_LOAD_WEAK_DYLIB = (0x18 | LC_REQ_DYLD);
198341
199pub const LC_SEGMENT_64 = 0x19; /// 64-bit segment of this file to be mapped342/// 64-bit segment of this file to be mapped
200pub const LC_ROUTINES_64 = 0x1a; /// 64-bit image routines343pub const LC_SEGMENT_64 = 0x19;
201pub const LC_UUID = 0x1b; /// the uuid344
202pub const LC_RPATH = (0x1c | LC_REQ_DYLD); /// runpath additions345/// 64-bit image routines
203pub const LC_CODE_SIGNATURE = 0x1d; /// local of code signature346pub const LC_ROUTINES_64 = 0x1a;
204pub const LC_SEGMENT_SPLIT_INFO = 0x1e; /// local of info to split segments347
205pub const LC_REEXPORT_DYLIB = (0x1f | LC_REQ_DYLD); /// load and re-export dylib348/// the uuid
206pub const LC_LAZY_LOAD_DYLIB = 0x20; /// delay load of dylib until first use349pub const LC_UUID = 0x1b;
207pub const LC_ENCRYPTION_INFO = 0x21; /// encrypted segment information350
208pub const LC_DYLD_INFO = 0x22; /// compressed dyld information351/// runpath additions
209pub const LC_DYLD_INFO_ONLY = (0x22|LC_REQ_DYLD); /// compressed dyld information only352pub const LC_RPATH = (0x1c | LC_REQ_DYLD);
210pub const LC_LOAD_UPWARD_DYLIB = (0x23 | LC_REQ_DYLD); /// load upward dylib353
211pub const LC_VERSION_MIN_MACOSX = 0x24; /// build for MacOSX min OS version354/// local of code signature
212pub const LC_VERSION_MIN_IPHONEOS = 0x25; /// build for iPhoneOS min OS version355pub const LC_CODE_SIGNATURE = 0x1d;
213pub const LC_FUNCTION_STARTS = 0x26; /// compressed table of function start addresses356
214pub const LC_DYLD_ENVIRONMENT = 0x27; /// string for dyld to treat like environment variable357/// local of info to split segments
215pub const LC_MAIN = (0x28|LC_REQ_DYLD); /// replacement for LC_UNIXTHREAD358pub const LC_SEGMENT_SPLIT_INFO = 0x1e;
216pub const LC_DATA_IN_CODE = 0x29; /// table of non-instructions in __text359
217pub const LC_SOURCE_VERSION = 0x2A; /// source version used to build binary360/// load and re-export dylib
218pub const LC_DYLIB_CODE_SIGN_DRS = 0x2B; /// Code signing DRs copied from linked dylibs361pub const LC_REEXPORT_DYLIB = (0x1f | LC_REQ_DYLD);
219pub const LC_ENCRYPTION_INFO_64 = 0x2C; /// 64-bit encrypted segment information362
220pub const LC_LINKER_OPTION = 0x2D; /// linker options in MH_OBJECT files363/// delay load of dylib until first use
221pub const LC_LINKER_OPTIMIZATION_HINT = 0x2E; /// optimization hints in MH_OBJECT files364pub const LC_LAZY_LOAD_DYLIB = 0x20;
222pub const LC_VERSION_MIN_TVOS = 0x2F; /// build for AppleTV min OS version365
223pub const LC_VERSION_MIN_WATCHOS = 0x30; /// build for Watch min OS version366/// encrypted segment information
224pub const LC_NOTE = 0x31; /// arbitrary data included within a Mach-O file367pub const LC_ENCRYPTION_INFO = 0x21;
225pub const LC_BUILD_VERSION = 0x32; /// build for platform min OS version368
226369/// compressed dyld information
227pub const MH_MAGIC = 0xfeedface; /// the mach magic number370pub const LC_DYLD_INFO = 0x22;
228pub const MH_CIGAM = 0xcefaedfe; /// NXSwapInt(MH_MAGIC)371
229372/// compressed dyld information only
230pub const MH_MAGIC_64 = 0xfeedfacf; /// the 64-bit mach magic number373pub const LC_DYLD_INFO_ONLY = (0x22 | LC_REQ_DYLD);
231pub const MH_CIGAM_64 = 0xcffaedfe; /// NXSwapInt(MH_MAGIC_64)374
232375/// load upward dylib
233pub const MH_OBJECT = 0x1; /// relocatable object file376pub const LC_LOAD_UPWARD_DYLIB = (0x23 | LC_REQ_DYLD);
234pub const MH_EXECUTE = 0x2; /// demand paged executable file377
235pub const MH_FVMLIB = 0x3; /// fixed VM shared library file378/// build for MacOSX min OS version
236pub const MH_CORE = 0x4; /// core file379pub const LC_VERSION_MIN_MACOSX = 0x24;
237pub const MH_PRELOAD = 0x5; /// preloaded executable file380
238pub const MH_DYLIB = 0x6; /// dynamically bound shared library381/// build for iPhoneOS min OS version
239pub const MH_DYLINKER = 0x7; /// dynamic link editor382pub const LC_VERSION_MIN_IPHONEOS = 0x25;
240pub const MH_BUNDLE = 0x8; /// dynamically bound bundle file383
241pub const MH_DYLIB_STUB = 0x9; /// shared library stub for static linking only, no section contents384/// compressed table of function start addresses
242pub const MH_DSYM = 0xa; /// companion file with only debug sections385pub const LC_FUNCTION_STARTS = 0x26;
243pub const MH_KEXT_BUNDLE = 0xb; /// x86_64 kexts386
387/// string for dyld to treat like environment variable
388pub const LC_DYLD_ENVIRONMENT = 0x27;
389
390/// replacement for LC_UNIXTHREAD
391pub const LC_MAIN = (0x28 | LC_REQ_DYLD);
392
393/// table of non-instructions in __text
394pub const LC_DATA_IN_CODE = 0x29;
395
396/// source version used to build binary
397pub const LC_SOURCE_VERSION = 0x2A;
398
399/// Code signing DRs copied from linked dylibs
400pub const LC_DYLIB_CODE_SIGN_DRS = 0x2B;
401
402/// 64-bit encrypted segment information
403pub const LC_ENCRYPTION_INFO_64 = 0x2C;
404
405/// linker options in MH_OBJECT files
406pub const LC_LINKER_OPTION = 0x2D;
407
408/// optimization hints in MH_OBJECT files
409pub const LC_LINKER_OPTIMIZATION_HINT = 0x2E;
410
411/// build for AppleTV min OS version
412pub const LC_VERSION_MIN_TVOS = 0x2F;
413
414/// build for Watch min OS version
415pub const LC_VERSION_MIN_WATCHOS = 0x30;
416
417/// arbitrary data included within a Mach-O file
418pub const LC_NOTE = 0x31;
419
420/// build for platform min OS version
421pub const LC_BUILD_VERSION = 0x32;
422
423/// the mach magic number
424pub const MH_MAGIC = 0xfeedface;
425
426/// NXSwapInt(MH_MAGIC)
427pub const MH_CIGAM = 0xcefaedfe;
428
429/// the 64-bit mach magic number
430pub const MH_MAGIC_64 = 0xfeedfacf;
431
432/// NXSwapInt(MH_MAGIC_64)
433pub const MH_CIGAM_64 = 0xcffaedfe;
434
435/// relocatable object file
436pub const MH_OBJECT = 0x1;
437
438/// demand paged executable file
439pub const MH_EXECUTE = 0x2;
440
441/// fixed VM shared library file
442pub const MH_FVMLIB = 0x3;
443
444/// core file
445pub const MH_CORE = 0x4;
446
447/// preloaded executable file
448pub const MH_PRELOAD = 0x5;
449
450/// dynamically bound shared library
451pub const MH_DYLIB = 0x6;
452
453/// dynamic link editor
454pub const MH_DYLINKER = 0x7;
455
456/// dynamically bound bundle file
457pub const MH_BUNDLE = 0x8;
458
459/// shared library stub for static linking only, no section contents
460pub const MH_DYLIB_STUB = 0x9;
461
462/// companion file with only debug sections
463pub const MH_DSYM = 0xa;
464
465/// x86_64 kexts
466pub const MH_KEXT_BUNDLE = 0xb;
244467
245// Constants for the flags field of the mach_header468// Constants for the flags field of the mach_header
246469
247pub const MH_NOUNDEFS = 0x1; /// the object file has no undefined references470/// the object file has no undefined references
248pub const MH_INCRLINK = 0x2; /// the object file is the output of an incremental link against a base file and can't be link edited again471pub const MH_NOUNDEFS = 0x1;
249pub const MH_DYLDLINK = 0x4; /// the object file is input for the dynamic linker and can't be staticly link edited again472
250pub const MH_BINDATLOAD = 0x8; /// the object file's undefined references are bound by the dynamic linker when loaded.473/// the object file is the output of an incremental link against a base file and can't be link edited again
251pub const MH_PREBOUND = 0x10; /// the file has its dynamic undefined references prebound.474pub const MH_INCRLINK = 0x2;
252pub const MH_SPLIT_SEGS = 0x20; /// the file has its read-only and read-write segments split475
253pub const MH_LAZY_INIT = 0x40; /// the shared library init routine is to be run lazily via catching memory faults to its writeable segments (obsolete)476/// the object file is input for the dynamic linker and can't be staticly link edited again
254pub const MH_TWOLEVEL = 0x80; /// the image is using two-level name space bindings477pub const MH_DYLDLINK = 0x4;
255pub const MH_FORCE_FLAT = 0x100; /// the executable is forcing all images to use flat name space bindings478
256pub const MH_NOMULTIDEFS = 0x200; /// this umbrella guarantees no multiple defintions of symbols in its sub-images so the two-level namespace hints can always be used.479/// the object file's undefined references are bound by the dynamic linker when loaded.
257pub const MH_NOFIXPREBINDING = 0x400; /// do not have dyld notify the prebinding agent about this executable480pub const MH_BINDATLOAD = 0x8;
258pub const MH_PREBINDABLE = 0x800; /// the binary is not prebound but can have its prebinding redone. only used when MH_PREBOUND is not set.481
259pub const MH_ALLMODSBOUND = 0x1000; /// indicates that this binary binds to all two-level namespace modules of its dependent libraries. only used when MH_PREBINDABLE and MH_TWOLEVEL are both set. 482/// the file has its dynamic undefined references prebound.
260pub const MH_SUBSECTIONS_VIA_SYMBOLS = 0x2000;/// safe to divide up the sections into sub-sections via symbols for dead code stripping483pub const MH_PREBOUND = 0x10;
261pub const MH_CANONICAL = 0x4000; /// the binary has been canonicalized via the unprebind operation484
262pub const MH_WEAK_DEFINES = 0x8000; /// the final linked image contains external weak symbols485/// the file has its read-only and read-write segments split
263pub const MH_BINDS_TO_WEAK = 0x10000; /// the final linked image uses weak symbols486pub const MH_SPLIT_SEGS = 0x20;
264487
265pub const MH_ALLOW_STACK_EXECUTION = 0x20000;/// When this bit is set, all stacks in the task will be given stack execution privilege. Only used in MH_EXECUTE filetypes.488/// the shared library init routine is to be run lazily via catching memory faults to its writeable segments (obsolete)
266pub const MH_ROOT_SAFE = 0x40000; /// When this bit is set, the binary declares it is safe for use in processes with uid zero489pub const MH_LAZY_INIT = 0x40;
267 490
268pub const MH_SETUID_SAFE = 0x80000; /// When this bit is set, the binary declares it is safe for use in processes when issetugid() is true491/// the image is using two-level name space bindings
269492pub const MH_TWOLEVEL = 0x80;
270pub const MH_NO_REEXPORTED_DYLIBS = 0x100000; /// When this bit is set on a dylib, the static linker does not need to examine dependent dylibs to see if any are re-exported493
271pub const MH_PIE = 0x200000; /// When this bit is set, the OS will load the main executable at a random address. Only used in MH_EXECUTE filetypes.494/// the executable is forcing all images to use flat name space bindings
272pub const MH_DEAD_STRIPPABLE_DYLIB = 0x400000; /// Only for use on dylibs. When linking against a dylib that has this bit set, the static linker will automatically not create a LC_LOAD_DYLIB load command to the dylib if no symbols are being referenced from the dylib.495pub const MH_FORCE_FLAT = 0x100;
273pub const MH_HAS_TLV_DESCRIPTORS = 0x800000; /// Contains a section of type S_THREAD_LOCAL_VARIABLES496
274497/// this umbrella guarantees no multiple defintions of symbols in its sub-images so the two-level namespace hints can always be used.
275pub const MH_NO_HEAP_EXECUTION = 0x1000000; /// When this bit is set, the OS will run the main executable with a non-executable heap even on platforms (e.g. i386) that don't require it. Only used in MH_EXECUTE filetypes.498pub const MH_NOMULTIDEFS = 0x200;
276499
277pub const MH_APP_EXTENSION_SAFE = 0x02000000; /// The code was linked for use in an application extension.500/// do not have dyld notify the prebinding agent about this executable
278501pub const MH_NOFIXPREBINDING = 0x400;
279pub const MH_NLIST_OUTOFSYNC_WITH_DYLDINFO = 0x04000000; /// The external symbols listed in the nlist symbol table do not include all the symbols listed in the dyld info.502
503/// the binary is not prebound but can have its prebinding redone. only used when MH_PREBOUND is not set.
504pub const MH_PREBINDABLE = 0x800;
505
506/// indicates that this binary binds to all two-level namespace modules of its dependent libraries. only used when MH_PREBINDABLE and MH_TWOLEVEL are both set.
507pub const MH_ALLMODSBOUND = 0x1000;
508
509/// safe to divide up the sections into sub-sections via symbols for dead code stripping
510pub const MH_SUBSECTIONS_VIA_SYMBOLS = 0x2000;
511
512/// the binary has been canonicalized via the unprebind operation
513pub const MH_CANONICAL = 0x4000;
514
515/// the final linked image contains external weak symbols
516pub const MH_WEAK_DEFINES = 0x8000;
517
518/// the final linked image uses weak symbols
519pub const MH_BINDS_TO_WEAK = 0x10000;
520
521/// When this bit is set, all stacks in the task will be given stack execution privilege. Only used in MH_EXECUTE filetypes.
522pub const MH_ALLOW_STACK_EXECUTION = 0x20000;
523
524/// When this bit is set, the binary declares it is safe for use in processes with uid zero
525pub const MH_ROOT_SAFE = 0x40000;
526
527/// When this bit is set, the binary declares it is safe for use in processes when issetugid() is true
528pub const MH_SETUID_SAFE = 0x80000;
529
530/// When this bit is set on a dylib, the static linker does not need to examine dependent dylibs to see if any are re-exported
531pub const MH_NO_REEXPORTED_DYLIBS = 0x100000;
280532
533/// When this bit is set, the OS will load the main executable at a random address. Only used in MH_EXECUTE filetypes.
534pub const MH_PIE = 0x200000;
535
536/// Only for use on dylibs. When linking against a dylib that has this bit set, the static linker will automatically not create a LC_LOAD_DYLIB load command to the dylib if no symbols are being referenced from the dylib.
537pub const MH_DEAD_STRIPPABLE_DYLIB = 0x400000;
538
539/// Contains a section of type S_THREAD_LOCAL_VARIABLES
540pub const MH_HAS_TLV_DESCRIPTORS = 0x800000;
541
542/// When this bit is set, the OS will run the main executable with a non-executable heap even on platforms (e.g. i386) that don't require it. Only used in MH_EXECUTE filetypes.
543pub const MH_NO_HEAP_EXECUTION = 0x1000000;
544
545/// The code was linked for use in an application extension.
546pub const MH_APP_EXTENSION_SAFE = 0x02000000;
547
548/// The external symbols listed in the nlist symbol table do not include all the symbols listed in the dyld info.
549pub const MH_NLIST_OUTOFSYNC_WITH_DYLDINFO = 0x04000000;
281550
282/// The flags field of a section structure is separated into two parts a section551/// The flags field of a section structure is separated into two parts a section
283/// type and section attributes. The section types are mutually exclusive (it552/// type and section attributes. The section types are mutually exclusive (it
...@@ -285,52 +554,129 @@ pub const MH_NLIST_OUTOFSYNC_WITH_DYLDINFO = 0x04000000; /// The external symbol...@@ -285,52 +554,129 @@ pub const MH_NLIST_OUTOFSYNC_WITH_DYLDINFO = 0x04000000; /// The external symbol
285/// than one attribute).554/// than one attribute).
286/// 256 section types555/// 256 section types
287pub const SECTION_TYPE = 0x000000ff;556pub const SECTION_TYPE = 0x000000ff;
288pub const SECTION_ATTRIBUTES = 0xffffff00; /// 24 section attributes557
289558/// 24 section attributes
290pub const S_REGULAR = 0x0; /// regular section559pub const SECTION_ATTRIBUTES = 0xffffff00;
291pub const S_ZEROFILL = 0x1; /// zero fill on demand section560
292pub const S_CSTRING_LITERALS = 0x2; /// section with only literal C string561/// regular section
293pub const S_4BYTE_LITERALS = 0x3; /// section with only 4 byte literals562pub const S_REGULAR = 0x0;
294pub const S_8BYTE_LITERALS = 0x4; /// section with only 8 byte literals563
295pub const S_LITERAL_POINTERS = 0x5; /// section with only pointers to564/// zero fill on demand section
296565pub const S_ZEROFILL = 0x1;
297566
298pub const N_STAB = 0xe0; /// if any of these bits set, a symbolic debugging entry567/// section with only literal C string
299pub const N_PEXT = 0x10; /// private external symbol bit568pub const S_CSTRING_LITERALS = 0x2;
300pub const N_TYPE = 0x0e; /// mask for the type bits569
301pub const N_EXT = 0x01; /// external symbol bit, set for external symbols570/// section with only 4 byte literals
302571pub const S_4BYTE_LITERALS = 0x3;
303572
304pub const N_GSYM = 0x20; /// global symbol: name,,NO_SECT,type,0573/// section with only 8 byte literals
305pub const N_FNAME = 0x22; /// procedure name (f77 kludge): name,,NO_SECT,0,0574pub const S_8BYTE_LITERALS = 0x4;
306pub const N_FUN = 0x24; /// procedure: name,,n_sect,linenumber,address575
307pub const N_STSYM = 0x26; /// static symbol: name,,n_sect,type,address576/// section with only pointers to
308pub const N_LCSYM = 0x28; /// .lcomm symbol: name,,n_sect,type,address577pub const S_LITERAL_POINTERS = 0x5;
309pub const N_BNSYM = 0x2e; /// begin nsect sym: 0,,n_sect,0,address578
310pub const N_AST = 0x32; /// AST file path: name,,NO_SECT,0,0579/// if any of these bits set, a symbolic debugging entry
311pub const N_OPT = 0x3c; /// emitted with gcc2_compiled and in gcc source580pub const N_STAB = 0xe0;
312pub const N_RSYM = 0x40; /// register sym: name,,NO_SECT,type,register581
313pub const N_SLINE = 0x44; /// src line: 0,,n_sect,linenumber,address582/// private external symbol bit
314pub const N_ENSYM = 0x4e; /// end nsect sym: 0,,n_sect,0,address583pub const N_PEXT = 0x10;
315pub const N_SSYM = 0x60; /// structure elt: name,,NO_SECT,type,struct_offset584
316pub const N_SO = 0x64; /// source file name: name,,n_sect,0,address585/// mask for the type bits
317pub const N_OSO = 0x66; /// object file name: name,,0,0,st_mtime586pub const N_TYPE = 0x0e;
318pub const N_LSYM = 0x80; /// local sym: name,,NO_SECT,type,offset587
319pub const N_BINCL = 0x82; /// include file beginning: name,,NO_SECT,0,sum588/// external symbol bit, set for external symbols
320pub const N_SOL = 0x84; /// #included file name: name,,n_sect,0,address589pub const N_EXT = 0x01;
321pub const N_PARAMS = 0x86; /// compiler parameters: name,,NO_SECT,0,0590
322pub const N_VERSION = 0x88; /// compiler version: name,,NO_SECT,0,0591/// global symbol: name,,NO_SECT,type,0
323pub const N_OLEVEL = 0x8A; /// compiler -O level: name,,NO_SECT,0,0592pub const N_GSYM = 0x20;
324pub const N_PSYM = 0xa0; /// parameter: name,,NO_SECT,type,offset593
325pub const N_EINCL = 0xa2; /// include file end: name,,NO_SECT,0,0594/// procedure name (f77 kludge): name,,NO_SECT,0,0
326pub const N_ENTRY = 0xa4; /// alternate entry: name,,n_sect,linenumber,address595pub const N_FNAME = 0x22;
327pub const N_LBRAC = 0xc0; /// left bracket: 0,,NO_SECT,nesting level,address596
328pub const N_EXCL = 0xc2; /// deleted include file: name,,NO_SECT,0,sum597/// procedure: name,,n_sect,linenumber,address
329pub const N_RBRAC = 0xe0; /// right bracket: 0,,NO_SECT,nesting level,address598pub const N_FUN = 0x24;
330pub const N_BCOMM = 0xe2; /// begin common: name,,NO_SECT,0,0599
331pub const N_ECOMM = 0xe4; /// end common: name,,n_sect,0,0600/// static symbol: name,,n_sect,type,address
332pub const N_ECOML = 0xe8; /// end common (local name): 0,,n_sect,0,address601pub const N_STSYM = 0x26;
333pub const N_LENG = 0xfe; /// second stab entry with length information602
603/// .lcomm symbol: name,,n_sect,type,address
604pub const N_LCSYM = 0x28;
605
606/// begin nsect sym: 0,,n_sect,0,address
607pub const N_BNSYM = 0x2e;
608
609/// AST file path: name,,NO_SECT,0,0
610pub const N_AST = 0x32;
611
612/// emitted with gcc2_compiled and in gcc source
613pub const N_OPT = 0x3c;
614
615/// register sym: name,,NO_SECT,type,register
616pub const N_RSYM = 0x40;
617
618/// src line: 0,,n_sect,linenumber,address
619pub const N_SLINE = 0x44;
620
621/// end nsect sym: 0,,n_sect,0,address
622pub const N_ENSYM = 0x4e;
623
624/// structure elt: name,,NO_SECT,type,struct_offset
625pub const N_SSYM = 0x60;
626
627/// source file name: name,,n_sect,0,address
628pub const N_SO = 0x64;
629
630/// object file name: name,,0,0,st_mtime
631pub const N_OSO = 0x66;
632
633/// local sym: name,,NO_SECT,type,offset
634pub const N_LSYM = 0x80;
635
636/// include file beginning: name,,NO_SECT,0,sum
637pub const N_BINCL = 0x82;
638
639/// #included file name: name,,n_sect,0,address
640pub const N_SOL = 0x84;
641
642/// compiler parameters: name,,NO_SECT,0,0
643pub const N_PARAMS = 0x86;
644
645/// compiler version: name,,NO_SECT,0,0
646pub const N_VERSION = 0x88;
647
648/// compiler -O level: name,,NO_SECT,0,0
649pub const N_OLEVEL = 0x8A;
650
651/// parameter: name,,NO_SECT,type,offset
652pub const N_PSYM = 0xa0;
653
654/// include file end: name,,NO_SECT,0,0
655pub const N_EINCL = 0xa2;
656
657/// alternate entry: name,,n_sect,linenumber,address
658pub const N_ENTRY = 0xa4;
659
660/// left bracket: 0,,NO_SECT,nesting level,address
661pub const N_LBRAC = 0xc0;
662
663/// deleted include file: name,,NO_SECT,0,sum
664pub const N_EXCL = 0xc2;
665
666/// right bracket: 0,,NO_SECT,nesting level,address
667pub const N_RBRAC = 0xe0;
668
669/// begin common: name,,NO_SECT,0,0
670pub const N_BCOMM = 0xe2;
671
672/// end common: name,,n_sect,0,0
673pub const N_ECOMM = 0xe4;
674
675/// end common (local name): 0,,n_sect,0,address
676pub const N_ECOML = 0xe8;
677
678/// second stab entry with length information
679pub const N_LENG = 0xfe;
334680
335/// If a segment contains any sections marked with S_ATTR_DEBUG then all681/// If a segment contains any sections marked with S_ATTR_DEBUG then all
336/// sections in that segment must have this attribute. No section other than682/// sections in that segment must have this attribute. No section other than
...@@ -339,10 +685,10 @@ pub const N_LENG = 0xfe; /// second stab entry with length information...@@ -339,10 +685,10 @@ pub const N_LENG = 0xfe; /// second stab entry with length information
339/// a section type S_REGULAR. The static linker will not copy section contents685/// a section type S_REGULAR. The static linker will not copy section contents
340/// from sections with this attribute into its output file. These sections686/// from sections with this attribute into its output file. These sections
341/// generally contain DWARF debugging info.687/// generally contain DWARF debugging info.
342pub const S_ATTR_DEBUG = 0x02000000; /// a debug section688/// a debug section
689pub const S_ATTR_DEBUG = 0x02000000;
343690
344pub const cpu_type_t = integer_t;691pub const cpu_type_t = integer_t;
345pub const cpu_subtype_t = integer_t;692pub const cpu_subtype_t = integer_t;
346pub const integer_t = c_int;693pub const integer_t = c_int;
347pub const vm_prot_t = c_int;694pub const vm_prot_t = c_int;
348
std/os/child_process.zig+48-14
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("../index.zig");1const std = @import("../index.zig");
2const cstr = std.cstr;2const cstr = std.cstr;
3const unicode = std.unicode;
3const io = std.io;4const io = std.io;
4const os = std.os;5const os = std.os;
5const posix = os.posix;6const posix = os.posix;
...@@ -12,6 +13,7 @@ const Buffer = std.Buffer;...@@ -12,6 +13,7 @@ const Buffer = std.Buffer;
12const builtin = @import("builtin");13const builtin = @import("builtin");
13const Os = builtin.Os;14const Os = builtin.Os;
14const LinkedList = std.LinkedList;15const LinkedList = std.LinkedList;
16const windows_util = @import("windows/util.zig");
1517
16const is_windows = builtin.os == Os.windows;18const is_windows = builtin.os == Os.windows;
1719
...@@ -209,8 +211,8 @@ pub const ChildProcess = struct {...@@ -209,8 +211,8 @@ pub const ChildProcess = struct {
209 defer Buffer.deinit(&stdout);211 defer Buffer.deinit(&stdout);
210 defer Buffer.deinit(&stderr);212 defer Buffer.deinit(&stderr);
211213
212 var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);214 var stdout_file_in_stream = io.FileInStream.init(child.stdout.?);
213 var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);215 var stderr_file_in_stream = io.FileInStream.init(child.stderr.?);
214216
215 try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size);217 try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size);
216 try stderr_file_in_stream.stream.readAllBuffer(&stderr, max_output_size);218 try stderr_file_in_stream.stream.readAllBuffer(&stderr, max_output_size);
...@@ -520,8 +522,8 @@ pub const ChildProcess = struct {...@@ -520,8 +522,8 @@ pub const ChildProcess = struct {
520 const cmd_line = try windowsCreateCommandLine(self.allocator, self.argv);522 const cmd_line = try windowsCreateCommandLine(self.allocator, self.argv);
521 defer self.allocator.free(cmd_line);523 defer self.allocator.free(cmd_line);
522524
523 var siStartInfo = windows.STARTUPINFOA{525 var siStartInfo = windows.STARTUPINFOW{
524 .cb = @sizeOf(windows.STARTUPINFOA),526 .cb = @sizeOf(windows.STARTUPINFOW),
525 .hStdError = g_hChildStd_ERR_Wr,527 .hStdError = g_hChildStd_ERR_Wr,
526 .hStdOutput = g_hChildStd_OUT_Wr,528 .hStdOutput = g_hChildStd_OUT_Wr,
527 .hStdInput = g_hChildStd_IN_Rd,529 .hStdInput = g_hChildStd_IN_Rd,
...@@ -545,7 +547,9 @@ pub const ChildProcess = struct {...@@ -545,7 +547,9 @@ pub const ChildProcess = struct {
545547
546 const cwd_slice = if (self.cwd) |cwd| try cstr.addNullByte(self.allocator, cwd) else null;548 const cwd_slice = if (self.cwd) |cwd| try cstr.addNullByte(self.allocator, cwd) else null;
547 defer if (cwd_slice) |cwd| self.allocator.free(cwd);549 defer if (cwd_slice) |cwd| self.allocator.free(cwd);
548 const cwd_ptr = if (cwd_slice) |cwd| cwd.ptr else null;550 const cwd_w = if (cwd_slice) |cwd| try unicode.utf8ToUtf16LeWithNull(self.allocator, cwd) else null;
551 defer if (cwd_w) |cwd| self.allocator.free(cwd);
552 const cwd_w_ptr = if (cwd_w) |cwd| cwd.ptr else null;
549553
550 const maybe_envp_buf = if (self.env_map) |env_map| try os.createWindowsEnvBlock(self.allocator, env_map) else null;554 const maybe_envp_buf = if (self.env_map) |env_map| try os.createWindowsEnvBlock(self.allocator, env_map) else null;
551 defer if (maybe_envp_buf) |envp_buf| self.allocator.free(envp_buf);555 defer if (maybe_envp_buf) |envp_buf| self.allocator.free(envp_buf);
...@@ -564,7 +568,13 @@ pub const ChildProcess = struct {...@@ -564,7 +568,13 @@ pub const ChildProcess = struct {
564 };568 };
565 defer self.allocator.free(app_name);569 defer self.allocator.free(app_name);
566570
567 windowsCreateProcess(app_name.ptr, cmd_line.ptr, envp_ptr, cwd_ptr, &siStartInfo, &piProcInfo) catch |no_path_err| {571 const app_name_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, app_name);
572 defer self.allocator.free(app_name_w);
573
574 const cmd_line_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, cmd_line);
575 defer self.allocator.free(cmd_line_w);
576
577 windowsCreateProcess(app_name_w.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo) catch |no_path_err| {
568 if (no_path_err != error.FileNotFound) return no_path_err;578 if (no_path_err != error.FileNotFound) return no_path_err;
569579
570 const PATH = try os.getEnvVarOwned(self.allocator, "PATH");580 const PATH = try os.getEnvVarOwned(self.allocator, "PATH");
...@@ -575,7 +585,10 @@ pub const ChildProcess = struct {...@@ -575,7 +585,10 @@ pub const ChildProcess = struct {
575 const joined_path = try os.path.join(self.allocator, search_path, app_name);585 const joined_path = try os.path.join(self.allocator, search_path, app_name);
576 defer self.allocator.free(joined_path);586 defer self.allocator.free(joined_path);
577587
578 if (windowsCreateProcess(joined_path.ptr, cmd_line.ptr, envp_ptr, cwd_ptr, &siStartInfo, &piProcInfo)) |_| {588 const joined_path_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, app_name);
589 defer self.allocator.free(joined_path_w);
590
591 if (windowsCreateProcess(joined_path_w.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo)) |_| {
579 break;592 break;
580 } else |err| if (err == error.FileNotFound) {593 } else |err| if (err == error.FileNotFound) {
581 continue;594 continue;
...@@ -626,15 +639,36 @@ pub const ChildProcess = struct {...@@ -626,15 +639,36 @@ pub const ChildProcess = struct {
626 }639 }
627};640};
628641
629fn windowsCreateProcess(app_name: [*]u8, cmd_line: [*]u8, envp_ptr: ?[*]u8, cwd_ptr: ?[*]u8, lpStartupInfo: *windows.STARTUPINFOA, lpProcessInformation: *windows.PROCESS_INFORMATION) !void {642fn windowsCreateProcess(app_name: [*]u16, cmd_line: [*]u16, envp_ptr: ?[*]u16, cwd_ptr: ?[*]u16, lpStartupInfo: *windows.STARTUPINFOW, lpProcessInformation: *windows.PROCESS_INFORMATION) !void {
630 if (windows.CreateProcessA(app_name, cmd_line, null, null, windows.TRUE, 0, @ptrCast(?*c_void, envp_ptr), cwd_ptr, lpStartupInfo, lpProcessInformation) == 0) {643 // TODO the docs for environment pointer say:
644 // > A pointer to the environment block for the new process. If this parameter
645 // > is NULL, the new process uses the environment of the calling process.
646 // > ...
647 // > An environment block can contain either Unicode or ANSI characters. If
648 // > the environment block pointed to by lpEnvironment contains Unicode
649 // > characters, be sure that dwCreationFlags includes CREATE_UNICODE_ENVIRONMENT.
650 // > If this parameter is NULL and the environment block of the parent process
651 // > contains Unicode characters, you must also ensure that dwCreationFlags
652 // > includes CREATE_UNICODE_ENVIRONMENT.
653 // This seems to imply that we have to somehow know whether our process parent passed
654 // CREATE_UNICODE_ENVIRONMENT if we want to pass NULL for the environment parameter.
655 // Since we do not know this information that would imply that we must not pass NULL
656 // for the parameter.
657 // However this would imply that programs compiled with -DUNICODE could not pass
658 // environment variables to programs that were not, which seems unlikely.
659 // More investigation is needed.
660 if (windows.CreateProcessW(
661 app_name, cmd_line, null, null, windows.TRUE, windows.CREATE_UNICODE_ENVIRONMENT,
662 @ptrCast(?*c_void, envp_ptr), cwd_ptr, lpStartupInfo, lpProcessInformation,
663 ) == 0) {
631 const err = windows.GetLastError();664 const err = windows.GetLastError();
632 return switch (err) {665 switch (err) {
633 windows.ERROR.FILE_NOT_FOUND, windows.ERROR.PATH_NOT_FOUND => error.FileNotFound,666 windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
667 windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
634 windows.ERROR.INVALID_PARAMETER => unreachable,668 windows.ERROR.INVALID_PARAMETER => unreachable,
635 windows.ERROR.INVALID_NAME => error.InvalidName,669 windows.ERROR.INVALID_NAME => return error.InvalidName,
636 else => os.unexpectedErrorWindows(err),670 else => return os.unexpectedErrorWindows(err),
637 };671 }
638 }672 }
639}673}
640674
std/os/file.zig+49-34
...@@ -48,18 +48,23 @@ pub const File = struct {...@@ -48,18 +48,23 @@ pub const File = struct {
48 return openReadC(&path_c);48 return openReadC(&path_c);
49 }49 }
50 if (is_windows) {50 if (is_windows) {
51 const handle = try os.windowsOpen(51 const path_w = try windows_util.sliceToPrefixedFileW(path);
52 path,52 return openReadW(&path_w);
53 windows.GENERIC_READ,
54 windows.FILE_SHARE_READ,
55 windows.OPEN_EXISTING,
56 windows.FILE_ATTRIBUTE_NORMAL,
57 );
58 return openHandle(handle);
59 }53 }
60 @compileError("Unsupported OS");54 @compileError("Unsupported OS");
61 }55 }
6256
57 pub fn openReadW(path_w: [*]const u16) OpenError!File {
58 const handle = try os.windowsOpenW(
59 path_w,
60 windows.GENERIC_READ,
61 windows.FILE_SHARE_READ,
62 windows.OPEN_EXISTING,
63 windows.FILE_ATTRIBUTE_NORMAL,
64 );
65 return openHandle(handle);
66 }
67
63 /// Calls `openWriteMode` with os.File.default_mode for the mode.68 /// Calls `openWriteMode` with os.File.default_mode for the mode.
64 pub fn openWrite(path: []const u8) OpenError!File {69 pub fn openWrite(path: []const u8) OpenError!File {
65 return openWriteMode(path, os.File.default_mode);70 return openWriteMode(path, os.File.default_mode);
...@@ -74,19 +79,24 @@ pub const File = struct {...@@ -74,19 +79,24 @@ pub const File = struct {
74 const fd = try os.posixOpen(path, flags, file_mode);79 const fd = try os.posixOpen(path, flags, file_mode);
75 return openHandle(fd);80 return openHandle(fd);
76 } else if (is_windows) {81 } else if (is_windows) {
77 const handle = try os.windowsOpen(82 const path_w = try windows_util.sliceToPrefixedFileW(path);
78 path,83 return openWriteModeW(&path_w, file_mode);
79 windows.GENERIC_WRITE,
80 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
81 windows.CREATE_ALWAYS,
82 windows.FILE_ATTRIBUTE_NORMAL,
83 );
84 return openHandle(handle);
85 } else {84 } else {
86 @compileError("TODO implement openWriteMode for this OS");85 @compileError("TODO implement openWriteMode for this OS");
87 }86 }
88 }87 }
8988
89 pub fn openWriteModeW(path_w: [*]const u16, file_mode: Mode) OpenError!File {
90 const handle = try os.windowsOpenW(
91 path_w,
92 windows.GENERIC_WRITE,
93 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
94 windows.CREATE_ALWAYS,
95 windows.FILE_ATTRIBUTE_NORMAL,
96 );
97 return openHandle(handle);
98 }
99
90 /// If the path does not exist it will be created.100 /// If the path does not exist it will be created.
91 /// If a file already exists in the destination this returns OpenError.PathAlreadyExists101 /// If a file already exists in the destination this returns OpenError.PathAlreadyExists
92 /// Call close to clean up.102 /// Call close to clean up.
...@@ -96,19 +106,24 @@ pub const File = struct {...@@ -96,19 +106,24 @@ pub const File = struct {
96 const fd = try os.posixOpen(path, flags, file_mode);106 const fd = try os.posixOpen(path, flags, file_mode);
97 return openHandle(fd);107 return openHandle(fd);
98 } else if (is_windows) {108 } else if (is_windows) {
99 const handle = try os.windowsOpen(109 const path_w = try windows_util.sliceToPrefixedFileW(path);
100 path,110 return openWriteNoClobberW(&path_w, file_mode);
101 windows.GENERIC_WRITE,
102 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
103 windows.CREATE_NEW,
104 windows.FILE_ATTRIBUTE_NORMAL,
105 );
106 return openHandle(handle);
107 } else {111 } else {
108 @compileError("TODO implement openWriteMode for this OS");112 @compileError("TODO implement openWriteMode for this OS");
109 }113 }
110 }114 }
111115
116 pub fn openWriteNoClobberW(path_w: [*]const u16, file_mode: Mode) OpenError!File {
117 const handle = try os.windowsOpenW(
118 path_w,
119 windows.GENERIC_WRITE,
120 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
121 windows.CREATE_NEW,
122 windows.FILE_ATTRIBUTE_NORMAL,
123 );
124 return openHandle(handle);
125 }
126
112 pub fn openHandle(handle: os.FileHandle) File {127 pub fn openHandle(handle: os.FileHandle) File {
113 return File{ .handle = handle };128 return File{ .handle = handle };
114 }129 }
...@@ -190,17 +205,16 @@ pub const File = struct {...@@ -190,17 +205,16 @@ pub const File = struct {
190205
191 /// Upon success, the stream is in an uninitialized state. To continue using it,206 /// Upon success, the stream is in an uninitialized state. To continue using it,
192 /// you must use the open() function.207 /// you must use the open() function.
193 pub fn close(self: *File) void {208 pub fn close(self: File) void {
194 os.close(self.handle);209 os.close(self.handle);
195 self.handle = undefined;
196 }210 }
197211
198 /// Calls `os.isTty` on `self.handle`.212 /// Calls `os.isTty` on `self.handle`.
199 pub fn isTty(self: *File) bool {213 pub fn isTty(self: File) bool {
200 return os.isTty(self.handle);214 return os.isTty(self.handle);
201 }215 }
202216
203 pub fn seekForward(self: *File, amount: isize) !void {217 pub fn seekForward(self: File, amount: isize) !void {
204 switch (builtin.os) {218 switch (builtin.os) {
205 Os.linux, Os.macosx, Os.ios => {219 Os.linux, Os.macosx, Os.ios => {
206 const result = posix.lseek(self.handle, amount, posix.SEEK_CUR);220 const result = posix.lseek(self.handle, amount, posix.SEEK_CUR);
...@@ -231,7 +245,7 @@ pub const File = struct {...@@ -231,7 +245,7 @@ pub const File = struct {
231 }245 }
232 }246 }
233247
234 pub fn seekTo(self: *File, pos: usize) !void {248 pub fn seekTo(self: File, pos: usize) !void {
235 switch (builtin.os) {249 switch (builtin.os) {
236 Os.linux, Os.macosx, Os.ios => {250 Os.linux, Os.macosx, Os.ios => {
237 const ipos = try math.cast(isize, pos);251 const ipos = try math.cast(isize, pos);
...@@ -256,6 +270,7 @@ pub const File = struct {...@@ -256,6 +270,7 @@ pub const File = struct {
256 const err = windows.GetLastError();270 const err = windows.GetLastError();
257 return switch (err) {271 return switch (err) {
258 windows.ERROR.INVALID_PARAMETER => unreachable,272 windows.ERROR.INVALID_PARAMETER => unreachable,
273 windows.ERROR.INVALID_HANDLE => unreachable,
259 else => os.unexpectedErrorWindows(err),274 else => os.unexpectedErrorWindows(err),
260 };275 };
261 }276 }
...@@ -264,7 +279,7 @@ pub const File = struct {...@@ -264,7 +279,7 @@ pub const File = struct {
264 }279 }
265 }280 }
266281
267 pub fn getPos(self: *File) !usize {282 pub fn getPos(self: File) !usize {
268 switch (builtin.os) {283 switch (builtin.os) {
269 Os.linux, Os.macosx, Os.ios => {284 Os.linux, Os.macosx, Os.ios => {
270 const result = posix.lseek(self.handle, 0, posix.SEEK_CUR);285 const result = posix.lseek(self.handle, 0, posix.SEEK_CUR);
...@@ -300,7 +315,7 @@ pub const File = struct {...@@ -300,7 +315,7 @@ pub const File = struct {
300 }315 }
301 }316 }
302317
303 pub fn getEndPos(self: *File) !usize {318 pub fn getEndPos(self: File) !usize {
304 if (is_posix) {319 if (is_posix) {
305 const stat = try os.posixFStat(self.handle);320 const stat = try os.posixFStat(self.handle);
306 return @intCast(usize, stat.size);321 return @intCast(usize, stat.size);
...@@ -325,7 +340,7 @@ pub const File = struct {...@@ -325,7 +340,7 @@ pub const File = struct {
325 Unexpected,340 Unexpected,
326 };341 };
327342
328 pub fn mode(self: *File) ModeError!Mode {343 pub fn mode(self: File) ModeError!Mode {
329 if (is_posix) {344 if (is_posix) {
330 var stat: posix.Stat = undefined;345 var stat: posix.Stat = undefined;
331 const err = posix.getErrno(posix.fstat(self.handle, &stat));346 const err = posix.getErrno(posix.fstat(self.handle, &stat));
...@@ -359,7 +374,7 @@ pub const File = struct {...@@ -359,7 +374,7 @@ pub const File = struct {
359 Unexpected,374 Unexpected,
360 };375 };
361376
362 pub fn read(self: *File, buffer: []u8) ReadError!usize {377 pub fn read(self: File, buffer: []u8) ReadError!usize {
363 if (is_posix) {378 if (is_posix) {
364 var index: usize = 0;379 var index: usize = 0;
365 while (index < buffer.len) {380 while (index < buffer.len) {
...@@ -407,7 +422,7 @@ pub const File = struct {...@@ -407,7 +422,7 @@ pub const File = struct {
407422
408 pub const WriteError = os.WindowsWriteError || os.PosixWriteError;423 pub const WriteError = os.WindowsWriteError || os.PosixWriteError;
409424
410 pub fn write(self: *File, bytes: []const u8) WriteError!void {425 pub fn write(self: File, bytes: []const u8) WriteError!void {
411 if (is_posix) {426 if (is_posix) {
412 try os.posixWrite(self.handle, bytes);427 try os.posixWrite(self.handle, bytes);
413 } else if (is_windows) {428 } else if (is_windows) {
std/os/index.zig+136-99
...@@ -57,6 +57,7 @@ pub const windowsWaitSingle = windows_util.windowsWaitSingle;...@@ -57,6 +57,7 @@ pub const windowsWaitSingle = windows_util.windowsWaitSingle;
57pub const windowsWrite = windows_util.windowsWrite;57pub const windowsWrite = windows_util.windowsWrite;
58pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty;58pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty;
59pub const windowsOpen = windows_util.windowsOpen;59pub const windowsOpen = windows_util.windowsOpen;
60pub const windowsOpenW = windows_util.windowsOpenW;
60pub const windowsLoadDll = windows_util.windowsLoadDll;61pub const windowsLoadDll = windows_util.windowsLoadDll;
61pub const windowsUnloadDll = windows_util.windowsUnloadDll;62pub const windowsUnloadDll = windows_util.windowsUnloadDll;
62pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;63pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
...@@ -660,6 +661,7 @@ pub fn getBaseAddress() usize {...@@ -660,6 +661,7 @@ pub fn getBaseAddress() usize {
660 return phdr - @sizeOf(ElfHeader);661 return phdr - @sizeOf(ElfHeader);
661 },662 },
662 builtin.Os.macosx => return @ptrToInt(&std.c._mh_execute_header),663 builtin.Os.macosx => return @ptrToInt(&std.c._mh_execute_header),
664 builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)),
663 else => @compileError("Unsupported OS"),665 else => @compileError("Unsupported OS"),
664 }666 }
665}667}
...@@ -817,37 +819,40 @@ test "os.getCwd" {...@@ -817,37 +819,40 @@ test "os.getCwd" {
817819
818pub const SymLinkError = PosixSymLinkError || WindowsSymLinkError;820pub const SymLinkError = PosixSymLinkError || WindowsSymLinkError;
819821
820pub fn symLink(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) SymLinkError!void {822/// TODO add a symLinkC variant
823pub fn symLink(existing_path: []const u8, new_path: []const u8) SymLinkError!void {
821 if (is_windows) {824 if (is_windows) {
822 return symLinkWindows(allocator, existing_path, new_path);825 return symLinkWindows(existing_path, new_path);
823 } else {826 } else {
824 return symLinkPosix(allocator, existing_path, new_path);827 return symLinkPosix(existing_path, new_path);
825 }828 }
826}829}
827830
828pub const WindowsSymLinkError = error{831pub const WindowsSymLinkError = error{
829 OutOfMemory,832 NameTooLong,
833 InvalidUtf8,
834 BadPathName,
830835
831 /// See https://github.com/ziglang/zig/issues/1396836 /// See https://github.com/ziglang/zig/issues/1396
832 Unexpected,837 Unexpected,
833};838};
834839
835pub fn symLinkWindows(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) WindowsSymLinkError!void {840pub fn symLinkW(existing_path_w: [*]const u16, new_path_w: [*]const u16) WindowsSymLinkError!void {
836 const existing_with_null = try cstr.addNullByte(allocator, existing_path);841 if (windows.CreateSymbolicLinkW(existing_path_w, new_path_w, 0) == 0) {
837 defer allocator.free(existing_with_null);
838 const new_with_null = try cstr.addNullByte(allocator, new_path);
839 defer allocator.free(new_with_null);
840
841 if (windows.CreateSymbolicLinkA(existing_with_null.ptr, new_with_null.ptr, 0) == 0) {
842 const err = windows.GetLastError();842 const err = windows.GetLastError();
843 return switch (err) {843 switch (err) {
844 else => unexpectedErrorWindows(err),844 else => return unexpectedErrorWindows(err),
845 };845 }
846 }846 }
847}847}
848848
849pub fn symLinkWindows(existing_path: []const u8, new_path: []const u8) WindowsSymLinkError!void {
850 const existing_path_w = try windows_util.sliceToPrefixedFileW(existing_path);
851 const new_path_w = try windows_util.sliceToPrefixedFileW(new_path);
852 return symLinkW(&existing_path_w, &new_path_w);
853}
854
849pub const PosixSymLinkError = error{855pub const PosixSymLinkError = error{
850 OutOfMemory,
851 AccessDenied,856 AccessDenied,
852 DiskQuota,857 DiskQuota,
853 PathAlreadyExists,858 PathAlreadyExists,
...@@ -864,43 +869,40 @@ pub const PosixSymLinkError = error{...@@ -864,43 +869,40 @@ pub const PosixSymLinkError = error{
864 Unexpected,869 Unexpected,
865};870};
866871
867pub fn symLinkPosix(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) PosixSymLinkError!void {872pub fn symLinkPosixC(existing_path: [*]const u8, new_path: [*]const u8) PosixSymLinkError!void {
868 const full_buf = try allocator.alloc(u8, existing_path.len + new_path.len + 2);873 const err = posix.getErrno(posix.symlink(existing_path, new_path));
869 defer allocator.free(full_buf);874 switch (err) {
870875 0 => return,
871 const existing_buf = full_buf;876 posix.EFAULT => unreachable,
872 mem.copy(u8, existing_buf, existing_path);877 posix.EINVAL => unreachable,
873 existing_buf[existing_path.len] = 0;878 posix.EACCES => return error.AccessDenied,
874879 posix.EPERM => return error.AccessDenied,
875 const new_buf = full_buf[existing_path.len + 1 ..];880 posix.EDQUOT => return error.DiskQuota,
876 mem.copy(u8, new_buf, new_path);881 posix.EEXIST => return error.PathAlreadyExists,
877 new_buf[new_path.len] = 0;882 posix.EIO => return error.FileSystem,
878883 posix.ELOOP => return error.SymLinkLoop,
879 const err = posix.getErrno(posix.symlink(existing_buf.ptr, new_buf.ptr));884 posix.ENAMETOOLONG => return error.NameTooLong,
880 if (err > 0) {885 posix.ENOENT => return error.FileNotFound,
881 return switch (err) {886 posix.ENOTDIR => return error.NotDir,
882 posix.EFAULT, posix.EINVAL => unreachable,887 posix.ENOMEM => return error.SystemResources,
883 posix.EACCES, posix.EPERM => error.AccessDenied,888 posix.ENOSPC => return error.NoSpaceLeft,
884 posix.EDQUOT => error.DiskQuota,889 posix.EROFS => return error.ReadOnlyFileSystem,
885 posix.EEXIST => error.PathAlreadyExists,890 else => return unexpectedErrorPosix(err),
886 posix.EIO => error.FileSystem,
887 posix.ELOOP => error.SymLinkLoop,
888 posix.ENAMETOOLONG => error.NameTooLong,
889 posix.ENOENT => error.FileNotFound,
890 posix.ENOTDIR => error.NotDir,
891 posix.ENOMEM => error.SystemResources,
892 posix.ENOSPC => error.NoSpaceLeft,
893 posix.EROFS => error.ReadOnlyFileSystem,
894 else => unexpectedErrorPosix(err),
895 };
896 }891 }
897}892}
898893
894pub fn symLinkPosix(existing_path: []const u8, new_path: []const u8) PosixSymLinkError!void {
895 const existing_path_c = try toPosixPath(existing_path);
896 const new_path_c = try toPosixPath(new_path);
897 return symLinkPosixC(&existing_path_c, &new_path_c);
898}
899
899// here we replace the standard +/ with -_ so that it can be used in a file name900// here we replace the standard +/ with -_ so that it can be used in a file name
900const b64_fs_encoder = base64.Base64Encoder.init("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", base64.standard_pad_char);901const b64_fs_encoder = base64.Base64Encoder.init("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", base64.standard_pad_char);
901902
903/// TODO remove the allocator requirement from this API
902pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) !void {904pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) !void {
903 if (symLink(allocator, existing_path, new_path)) {905 if (symLink(existing_path, new_path)) {
904 return;906 return;
905 } else |err| switch (err) {907 } else |err| switch (err) {
906 error.PathAlreadyExists => {},908 error.PathAlreadyExists => {},
...@@ -918,7 +920,7 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path:...@@ -918,7 +920,7 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path:
918 try getRandomBytes(rand_buf[0..]);920 try getRandomBytes(rand_buf[0..]);
919 b64_fs_encoder.encode(tmp_path[dirname.len + 1 ..], rand_buf);921 b64_fs_encoder.encode(tmp_path[dirname.len + 1 ..], rand_buf);
920922
921 if (symLink(allocator, existing_path, tmp_path)) {923 if (symLink(existing_path, tmp_path)) {
922 return rename(tmp_path, new_path);924 return rename(tmp_path, new_path);
923 } else |err| switch (err) {925 } else |err| switch (err) {
924 error.PathAlreadyExists => continue,926 error.PathAlreadyExists => continue,
...@@ -1250,49 +1252,65 @@ pub const DeleteDirError = error{...@@ -1250,49 +1252,65 @@ pub const DeleteDirError = error{
1250 NotDir,1252 NotDir,
1251 DirNotEmpty,1253 DirNotEmpty,
1252 ReadOnlyFileSystem,1254 ReadOnlyFileSystem,
1253 OutOfMemory,1255 InvalidUtf8,
1256 BadPathName,
12541257
1255 /// See https://github.com/ziglang/zig/issues/13961258 /// See https://github.com/ziglang/zig/issues/1396
1256 Unexpected,1259 Unexpected,
1257};1260};
12581261
1259/// Returns ::error.DirNotEmpty if the directory is not empty.1262pub fn deleteDirC(dir_path: [*]const u8) DeleteDirError!void {
1260/// To delete a directory recursively, see ::deleteTree1263 switch (builtin.os) {
1261pub fn deleteDir(allocator: *Allocator, dir_path: []const u8) DeleteDirError!void {1264 Os.windows => {
1262 const path_buf = try allocator.alloc(u8, dir_path.len + 1);1265 const dir_path_w = try windows_util.cStrToPrefixedFileW(dir_path);
1263 defer allocator.free(path_buf);1266 return deleteDirW(&dir_path_w);
1267 },
1268 Os.linux, Os.macosx, Os.ios => {
1269 const err = posix.getErrno(posix.rmdir(dir_path));
1270 switch (err) {
1271 0 => return,
1272 posix.EACCES => return error.AccessDenied,
1273 posix.EPERM => return error.AccessDenied,
1274 posix.EBUSY => return error.FileBusy,
1275 posix.EFAULT => unreachable,
1276 posix.EINVAL => unreachable,
1277 posix.ELOOP => return error.SymLinkLoop,
1278 posix.ENAMETOOLONG => return error.NameTooLong,
1279 posix.ENOENT => return error.FileNotFound,
1280 posix.ENOMEM => return error.SystemResources,
1281 posix.ENOTDIR => return error.NotDir,
1282 posix.EEXIST => return error.DirNotEmpty,
1283 posix.ENOTEMPTY => return error.DirNotEmpty,
1284 posix.EROFS => return error.ReadOnlyFileSystem,
1285 else => return unexpectedErrorPosix(err),
1286 }
1287 },
1288 else => @compileError("unimplemented"),
1289 }
1290}
12641291
1265 mem.copy(u8, path_buf, dir_path);1292pub fn deleteDirW(dir_path_w: [*]const u16) DeleteDirError!void {
1266 path_buf[dir_path.len] = 0;1293 if (windows.RemoveDirectoryW(dir_path_w) == 0) {
1294 const err = windows.GetLastError();
1295 switch (err) {
1296 windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
1297 windows.ERROR.DIR_NOT_EMPTY => return error.DirNotEmpty,
1298 else => return unexpectedErrorWindows(err),
1299 }
1300 }
1301}
12671302
1303/// Returns ::error.DirNotEmpty if the directory is not empty.
1304/// To delete a directory recursively, see ::deleteTree
1305pub fn deleteDir(dir_path: []const u8) DeleteDirError!void {
1268 switch (builtin.os) {1306 switch (builtin.os) {
1269 Os.windows => {1307 Os.windows => {
1270 if (windows.RemoveDirectoryA(path_buf.ptr) == 0) {1308 const dir_path_w = try windows_util.sliceToPrefixedFileW(dir_path);
1271 const err = windows.GetLastError();1309 return deleteDirW(&dir_path_w);
1272 return switch (err) {
1273 windows.ERROR.PATH_NOT_FOUND => error.FileNotFound,
1274 windows.ERROR.DIR_NOT_EMPTY => error.DirNotEmpty,
1275 else => unexpectedErrorWindows(err),
1276 };
1277 }
1278 },1310 },
1279 Os.linux, Os.macosx, Os.ios => {1311 Os.linux, Os.macosx, Os.ios => {
1280 const err = posix.getErrno(posix.rmdir(path_buf.ptr));1312 const dir_path_c = try toPosixPath(dir_path);
1281 if (err > 0) {1313 return deleteDirC(&dir_path_c);
1282 return switch (err) {
1283 posix.EACCES, posix.EPERM => error.AccessDenied,
1284 posix.EBUSY => error.FileBusy,
1285 posix.EFAULT, posix.EINVAL => unreachable,
1286 posix.ELOOP => error.SymLinkLoop,
1287 posix.ENAMETOOLONG => error.NameTooLong,
1288 posix.ENOENT => error.FileNotFound,
1289 posix.ENOMEM => error.SystemResources,
1290 posix.ENOTDIR => error.NotDir,
1291 posix.EEXIST, posix.ENOTEMPTY => error.DirNotEmpty,
1292 posix.EROFS => error.ReadOnlyFileSystem,
1293 else => unexpectedErrorPosix(err),
1294 };
1295 }
1296 },1314 },
1297 else => @compileError("unimplemented"),1315 else => @compileError("unimplemented"),
1298 }1316 }
...@@ -1344,6 +1362,7 @@ pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError!...@@ -1344,6 +1362,7 @@ pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError!
1344 error.IsDir => {},1362 error.IsDir => {},
1345 error.AccessDenied => got_access_denied = true,1363 error.AccessDenied => got_access_denied = true,
13461364
1365 error.InvalidUtf8,
1347 error.SymLinkLoop,1366 error.SymLinkLoop,
1348 error.NameTooLong,1367 error.NameTooLong,
1349 error.SystemResources,1368 error.SystemResources,
...@@ -1351,7 +1370,6 @@ pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError!...@@ -1351,7 +1370,6 @@ pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError!
1351 error.NotDir,1370 error.NotDir,
1352 error.FileSystem,1371 error.FileSystem,
1353 error.FileBusy,1372 error.FileBusy,
1354 error.InvalidUtf8,
1355 error.BadPathName,1373 error.BadPathName,
1356 error.Unexpected,1374 error.Unexpected,
1357 => return err,1375 => return err,
...@@ -1379,6 +1397,8 @@ pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError!...@@ -1379,6 +1397,8 @@ pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError!
1379 error.NoSpaceLeft,1397 error.NoSpaceLeft,
1380 error.PathAlreadyExists,1398 error.PathAlreadyExists,
1381 error.Unexpected,1399 error.Unexpected,
1400 error.InvalidUtf8,
1401 error.BadPathName,
1382 => return err,1402 => return err,
1383 };1403 };
1384 defer dir.close();1404 defer dir.close();
...@@ -1396,7 +1416,7 @@ pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError!...@@ -1396,7 +1416,7 @@ pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError!
1396 try deleteTree(allocator, full_entry_path);1416 try deleteTree(allocator, full_entry_path);
1397 }1417 }
1398 }1418 }
1399 return deleteDir(allocator, full_path);1419 return deleteDir(full_path);
1400 }1420 }
1401}1421}
14021422
...@@ -1420,8 +1440,9 @@ pub const Dir = struct {...@@ -1420,8 +1440,9 @@ pub const Dir = struct {
1420 },1440 },
1421 Os.windows => struct {1441 Os.windows => struct {
1422 handle: windows.HANDLE,1442 handle: windows.HANDLE,
1423 find_file_data: windows.WIN32_FIND_DATAA,1443 find_file_data: windows.WIN32_FIND_DATAW,
1424 first: bool,1444 first: bool,
1445 name_data: [256]u8,
1425 },1446 },
1426 else => @compileError("unimplemented"),1447 else => @compileError("unimplemented"),
1427 };1448 };
...@@ -1458,6 +1479,8 @@ pub const Dir = struct {...@@ -1458,6 +1479,8 @@ pub const Dir = struct {
1458 NoSpaceLeft,1479 NoSpaceLeft,
1459 PathAlreadyExists,1480 PathAlreadyExists,
1460 OutOfMemory,1481 OutOfMemory,
1482 InvalidUtf8,
1483 BadPathName,
14611484
1462 /// See https://github.com/ziglang/zig/issues/13961485 /// See https://github.com/ziglang/zig/issues/1396
1463 Unexpected,1486 Unexpected,
...@@ -1469,12 +1492,13 @@ pub const Dir = struct {...@@ -1469,12 +1492,13 @@ pub const Dir = struct {
1469 .allocator = allocator,1492 .allocator = allocator,
1470 .handle = switch (builtin.os) {1493 .handle = switch (builtin.os) {
1471 Os.windows => blk: {1494 Os.windows => blk: {
1472 var find_file_data: windows.WIN32_FIND_DATAA = undefined;1495 var find_file_data: windows.WIN32_FIND_DATAW = undefined;
1473 const handle = try windows_util.windowsFindFirstFile(allocator, dir_path, &find_file_data);1496 const handle = try windows_util.windowsFindFirstFile(dir_path, &find_file_data);
1474 break :blk Handle{1497 break :blk Handle{
1475 .handle = handle,1498 .handle = handle,
1476 .find_file_data = find_file_data, // TODO guaranteed copy elision1499 .find_file_data = find_file_data, // TODO guaranteed copy elision
1477 .first = true,1500 .first = true,
1501 .name_data = undefined,
1478 };1502 };
1479 },1503 },
1480 Os.macosx, Os.ios => Handle{1504 Os.macosx, Os.ios => Handle{
...@@ -1589,9 +1613,12 @@ pub const Dir = struct {...@@ -1589,9 +1613,12 @@ pub const Dir = struct {
1589 if (!try windows_util.windowsFindNextFile(self.handle.handle, &self.handle.find_file_data))1613 if (!try windows_util.windowsFindNextFile(self.handle.handle, &self.handle.find_file_data))
1590 return null;1614 return null;
1591 }1615 }
1592 const name = std.cstr.toSlice(self.handle.find_file_data.cFileName[0..].ptr);1616 const name_utf16le = mem.toSlice(u16, self.handle.find_file_data.cFileName[0..].ptr);
1593 if (mem.eql(u8, name, ".") or mem.eql(u8, name, ".."))1617 if (mem.eql(u16, name_utf16le, []u16{'.'}) or mem.eql(u16, name_utf16le, []u16{'.', '.'}))
1594 continue;1618 continue;
1619 // Trust that Windows gives us valid UTF-16LE
1620 const name_utf8_len = std.unicode.utf16leToUtf8(self.handle.name_data[0..], name_utf16le) catch unreachable;
1621 const name_utf8 = self.handle.name_data[0..name_utf8_len];
1595 const kind = blk: {1622 const kind = blk: {
1596 const attrs = self.handle.find_file_data.dwFileAttributes;1623 const attrs = self.handle.find_file_data.dwFileAttributes;
1597 if (attrs & windows.FILE_ATTRIBUTE_DIRECTORY != 0) break :blk Entry.Kind.Directory;1624 if (attrs & windows.FILE_ATTRIBUTE_DIRECTORY != 0) break :blk Entry.Kind.Directory;
...@@ -1600,7 +1627,7 @@ pub const Dir = struct {...@@ -1600,7 +1627,7 @@ pub const Dir = struct {
1600 break :blk Entry.Kind.Unknown;1627 break :blk Entry.Kind.Unknown;
1601 };1628 };
1602 return Entry{1629 return Entry{
1603 .name = name,1630 .name = name_utf8,
1604 .kind = kind,1631 .kind = kind,
1605 };1632 };
1606 }1633 }
...@@ -2087,8 +2114,9 @@ pub fn unexpectedErrorPosix(errno: usize) UnexpectedError {...@@ -2087,8 +2114,9 @@ pub fn unexpectedErrorPosix(errno: usize) UnexpectedError {
2087/// Call this when you made a windows DLL call or something that does SetLastError2114/// Call this when you made a windows DLL call or something that does SetLastError
2088/// and you get an unexpected error.2115/// and you get an unexpected error.
2089pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {2116pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {
2090 if (true) {2117 if (unexpected_error_tracing) {
2091 debug.warn("unexpected GetLastError(): {}\n", err);2118 debug.warn("unexpected GetLastError(): {}\n", err);
2119 @breakpoint();
2092 debug.dumpCurrentStackTrace(null);2120 debug.dumpCurrentStackTrace(null);
2093 }2121 }
2094 return error.Unexpected;2122 return error.Unexpected;
...@@ -2103,17 +2131,35 @@ pub fn openSelfExe() !os.File {...@@ -2103,17 +2131,35 @@ pub fn openSelfExe() !os.File {
2103 buf[self_exe_path.len] = 0;2131 buf[self_exe_path.len] = 0;
2104 return os.File.openReadC(self_exe_path.ptr);2132 return os.File.openReadC(self_exe_path.ptr);
2105 },2133 },
2134 Os.windows => {
2135 var buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
2136 const wide_slice = try selfExePathW(&buf);
2137 return os.File.openReadW(wide_slice.ptr);
2138 },
2106 else => @compileError("Unsupported OS"),2139 else => @compileError("Unsupported OS"),
2107 }2140 }
2108}2141}
21092142
2110test "openSelfExe" {2143test "openSelfExe" {
2111 switch (builtin.os) {2144 switch (builtin.os) {
2112 Os.linux, Os.macosx, Os.ios => (try openSelfExe()).close(),2145 Os.linux, Os.macosx, Os.ios, Os.windows => (try openSelfExe()).close(),
2113 else => return error.SkipZigTest, // Unsupported OS2146 else => return error.SkipZigTest, // Unsupported OS.
2114 }2147 }
2115}2148}
21162149
2150pub fn selfExePathW(out_buffer: *[windows_util.PATH_MAX_WIDE]u16) ![]u16 {
2151 const casted_len = @intCast(windows.DWORD, out_buffer.len); // TODO shouldn't need this cast
2152 const rc = windows.GetModuleFileNameW(null, out_buffer, casted_len);
2153 assert(rc <= out_buffer.len);
2154 if (rc == 0) {
2155 const err = windows.GetLastError();
2156 switch (err) {
2157 else => return unexpectedErrorWindows(err),
2158 }
2159 }
2160 return out_buffer[0..rc];
2161}
2162
2117/// Get the path to the current executable.2163/// Get the path to the current executable.
2118/// If you only need the directory, use selfExeDirPath.2164/// If you only need the directory, use selfExeDirPath.
2119/// If you only want an open file handle, use openSelfExe.2165/// If you only want an open file handle, use openSelfExe.
...@@ -2129,16 +2175,7 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 {...@@ -2129,16 +2175,7 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
2129 Os.linux => return readLink(out_buffer, "/proc/self/exe"),2175 Os.linux => return readLink(out_buffer, "/proc/self/exe"),
2130 Os.windows => {2176 Os.windows => {
2131 var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;2177 var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
2132 const casted_len = @intCast(windows.DWORD, utf16le_buf.len); // TODO shouldn't need this cast2178 const utf16le_slice = try selfExePathW(&utf16le_buf);
2133 const rc = windows.GetModuleFileNameW(null, &utf16le_buf, casted_len);
2134 assert(rc <= utf16le_buf.len);
2135 if (rc == 0) {
2136 const err = windows.GetLastError();
2137 switch (err) {
2138 else => return unexpectedErrorWindows(err),
2139 }
2140 }
2141 const utf16le_slice = utf16le_buf[0..rc];
2142 // Trust that Windows gives us valid UTF-16LE.2179 // Trust that Windows gives us valid UTF-16LE.
2143 const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;2180 const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
2144 return out_buffer[0..end_index];2181 return out_buffer[0..end_index];
std/os/windows/advapi32.zig+16-5
...@@ -23,11 +23,22 @@ pub extern "advapi32" stdcallcc fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlag...@@ -23,11 +23,22 @@ pub extern "advapi32" stdcallcc fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlag
2323
24pub extern "advapi32" stdcallcc fn CryptGenRandom(hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: [*]BYTE) BOOL;24pub extern "advapi32" stdcallcc fn CryptGenRandom(hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: [*]BYTE) BOOL;
2525
26pub extern "advapi32" stdcallcc fn RegOpenKeyExW(hKey: HKEY, lpSubKey: LPCWSTR, ulOptions: DWORD, samDesired: REGSAM,26pub extern "advapi32" stdcallcc fn RegOpenKeyExW(
27 phkResult: &HKEY,) LSTATUS;27 hKey: HKEY,
2828 lpSubKey: LPCWSTR,
29pub extern "advapi32" stdcallcc fn RegQueryValueExW(hKey: HKEY, lpValueName: LPCWSTR, lpReserved: LPDWORD,29 ulOptions: DWORD,
30 lpType: LPDWORD, lpData: LPBYTE, lpcbData: LPDWORD,) LSTATUS;30 samDesired: REGSAM,
31 phkResult: &HKEY,
32) LSTATUS;
33
34pub extern "advapi32" stdcallcc fn RegQueryValueExW(
35 hKey: HKEY,
36 lpValueName: LPCWSTR,
37 lpReserved: LPDWORD,
38 lpType: LPDWORD,
39 lpData: LPBYTE,
40 lpcbData: LPDWORD,
41) LSTATUS;
3142
32// RtlGenRandom is known as SystemFunction036 under advapi3243// RtlGenRandom is known as SystemFunction036 under advapi32
33// http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx */44// http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx */
std/os/windows/index.zig+29-15
...@@ -3,10 +3,9 @@ const assert = std.debug.assert;...@@ -3,10 +3,9 @@ const assert = std.debug.assert;
33
4pub use @import("advapi32.zig");4pub use @import("advapi32.zig");
5pub use @import("kernel32.zig");5pub use @import("kernel32.zig");
6pub use @import("ntdll.zig");
6pub use @import("ole32.zig");7pub use @import("ole32.zig");
7pub use @import("shell32.zig");8pub use @import("shell32.zig");
8pub use @import("shlwapi.zig");
9pub use @import("user32.zig");
109
11test "import" {10test "import" {
12 _ = @import("util.zig");11 _ = @import("util.zig");
...@@ -14,6 +13,7 @@ test "import" {...@@ -14,6 +13,7 @@ test "import" {
1413
15pub const ERROR = @import("error.zig");14pub const ERROR = @import("error.zig");
1615
16pub const SHORT = c_short;
17pub const BOOL = c_int;17pub const BOOL = c_int;
18pub const BOOLEAN = BYTE;18pub const BOOLEAN = BYTE;
19pub const BYTE = u8;19pub const BYTE = u8;
...@@ -172,11 +172,11 @@ pub const PROCESS_INFORMATION = extern struct {...@@ -172,11 +172,11 @@ pub const PROCESS_INFORMATION = extern struct {
172 dwThreadId: DWORD,172 dwThreadId: DWORD,
173};173};
174174
175pub const STARTUPINFOA = extern struct {175pub const STARTUPINFOW = extern struct {
176 cb: DWORD,176 cb: DWORD,
177 lpReserved: ?LPSTR,177 lpReserved: ?LPWSTR,
178 lpDesktop: ?LPSTR,178 lpDesktop: ?LPWSTR,
179 lpTitle: ?LPSTR,179 lpTitle: ?LPWSTR,
180 dwX: DWORD,180 dwX: DWORD,
181 dwY: DWORD,181 dwY: DWORD,
182 dwXSize: DWORD,182 dwXSize: DWORD,
...@@ -236,7 +236,7 @@ pub const HEAP_NO_SERIALIZE = 0x00000001;...@@ -236,7 +236,7 @@ pub const HEAP_NO_SERIALIZE = 0x00000001;
236pub const PTHREAD_START_ROUTINE = extern fn (LPVOID) DWORD;236pub const PTHREAD_START_ROUTINE = extern fn (LPVOID) DWORD;
237pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE;237pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE;
238238
239pub const WIN32_FIND_DATAA = extern struct {239pub const WIN32_FIND_DATAW = extern struct {
240 dwFileAttributes: DWORD,240 dwFileAttributes: DWORD,
241 ftCreationTime: FILETIME,241 ftCreationTime: FILETIME,
242 ftLastAccessTime: FILETIME,242 ftLastAccessTime: FILETIME,
...@@ -245,8 +245,8 @@ pub const WIN32_FIND_DATAA = extern struct {...@@ -245,8 +245,8 @@ pub const WIN32_FIND_DATAA = extern struct {
245 nFileSizeLow: DWORD,245 nFileSizeLow: DWORD,
246 dwReserved0: DWORD,246 dwReserved0: DWORD,
247 dwReserved1: DWORD,247 dwReserved1: DWORD,
248 cFileName: [260]CHAR,248 cFileName: [260]u16,
249 cAlternateFileName: [14]CHAR,249 cAlternateFileName: [14]u16,
250};250};
251251
252pub const FILETIME = extern struct {252pub const FILETIME = extern struct {
...@@ -288,27 +288,27 @@ pub const GUID = extern struct {...@@ -288,27 +288,27 @@ pub const GUID = extern struct {
288 assert(str[index] == '{');288 assert(str[index] == '{');
289 index += 1;289 index += 1;
290290
291 guid.Data1 = std.fmt.parseUnsigned(c_ulong, str[index..index + 8], 16) catch unreachable;291 guid.Data1 = std.fmt.parseUnsigned(c_ulong, str[index .. index + 8], 16) catch unreachable;
292 index += 8;292 index += 8;
293293
294 assert(str[index] == '-');294 assert(str[index] == '-');
295 index += 1;295 index += 1;
296296
297 guid.Data2 = std.fmt.parseUnsigned(c_ushort, str[index..index + 4], 16) catch unreachable;297 guid.Data2 = std.fmt.parseUnsigned(c_ushort, str[index .. index + 4], 16) catch unreachable;
298 index += 4;298 index += 4;
299299
300 assert(str[index] == '-');300 assert(str[index] == '-');
301 index += 1;301 index += 1;
302302
303 guid.Data3 = std.fmt.parseUnsigned(c_ushort, str[index..index + 4], 16) catch unreachable;303 guid.Data3 = std.fmt.parseUnsigned(c_ushort, str[index .. index + 4], 16) catch unreachable;
304 index += 4;304 index += 4;
305305
306 assert(str[index] == '-');306 assert(str[index] == '-');
307 index += 1;307 index += 1;
308308
309 guid.Data4[0] = std.fmt.parseUnsigned(u8, str[index..index + 2], 16) catch unreachable;309 guid.Data4[0] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
310 index += 2;310 index += 2;
311 guid.Data4[1] = std.fmt.parseUnsigned(u8, str[index..index + 2], 16) catch unreachable;311 guid.Data4[1] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
312 index += 2;312 index += 2;
313313
314 assert(str[index] == '-');314 assert(str[index] == '-');
...@@ -316,7 +316,7 @@ pub const GUID = extern struct {...@@ -316,7 +316,7 @@ pub const GUID = extern struct {
316316
317 var i: usize = 2;317 var i: usize = 2;
318 while (i < guid.Data4.len) : (i += 1) {318 while (i < guid.Data4.len) : (i += 1) {
319 guid.Data4[i] = std.fmt.parseUnsigned(u8, str[index..index + 2], 16) catch unreachable;319 guid.Data4[i] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
320 index += 2;320 index += 2;
321 }321 }
322322
...@@ -363,3 +363,17 @@ pub const FILE_FLAG_RANDOM_ACCESS = 0x10000000;...@@ -363,3 +363,17 @@ pub const FILE_FLAG_RANDOM_ACCESS = 0x10000000;
363pub const FILE_FLAG_SESSION_AWARE = 0x00800000;363pub const FILE_FLAG_SESSION_AWARE = 0x00800000;
364pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;364pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;
365pub const FILE_FLAG_WRITE_THROUGH = 0x80000000;365pub const FILE_FLAG_WRITE_THROUGH = 0x80000000;
366
367pub const SMALL_RECT = extern struct {
368 Left: SHORT,
369 Top: SHORT,
370 Right: SHORT,
371 Bottom: SHORT,
372};
373
374pub const COORD = extern struct {
375 X: SHORT,
376 Y: SHORT,
377};
378
379pub const CREATE_UNICODE_ENVIRONMENT = 1024;
std/os/windows/kernel32.zig+30-43
...@@ -4,19 +4,8 @@ pub extern "kernel32" stdcallcc fn CancelIoEx(hFile: HANDLE, lpOverlapped: LPOVE...@@ -4,19 +4,8 @@ pub extern "kernel32" stdcallcc fn CancelIoEx(hFile: HANDLE, lpOverlapped: LPOVE
44
5pub extern "kernel32" stdcallcc fn CloseHandle(hObject: HANDLE) BOOL;5pub extern "kernel32" stdcallcc fn CloseHandle(hObject: HANDLE) BOOL;
66
7pub extern "kernel32" stdcallcc fn CreateDirectoryA(lpPathName: [*]const u8, lpSecurityAttributes: ?*SECURITY_ATTRIBUTES) BOOL;
8pub extern "kernel32" stdcallcc fn CreateDirectoryW(lpPathName: [*]const u16, lpSecurityAttributes: ?*SECURITY_ATTRIBUTES) BOOL;7pub extern "kernel32" stdcallcc fn CreateDirectoryW(lpPathName: [*]const u16, lpSecurityAttributes: ?*SECURITY_ATTRIBUTES) BOOL;
98
10pub extern "kernel32" stdcallcc fn CreateFileA(
11 lpFileName: [*]const u8, // TODO null terminated pointer type
12 dwDesiredAccess: DWORD,
13 dwShareMode: DWORD,
14 lpSecurityAttributes: ?LPSECURITY_ATTRIBUTES,
15 dwCreationDisposition: DWORD,
16 dwFlagsAndAttributes: DWORD,
17 hTemplateFile: ?HANDLE,
18) HANDLE;
19
20pub extern "kernel32" stdcallcc fn CreateFileW(9pub extern "kernel32" stdcallcc fn CreateFileW(
21 lpFileName: [*]const u16, // TODO null terminated pointer type10 lpFileName: [*]const u16, // TODO null terminated pointer type
22 dwDesiredAccess: DWORD,11 dwDesiredAccess: DWORD,
...@@ -34,37 +23,32 @@ pub extern "kernel32" stdcallcc fn CreatePipe(...@@ -34,37 +23,32 @@ pub extern "kernel32" stdcallcc fn CreatePipe(
34 nSize: DWORD,23 nSize: DWORD,
35) BOOL;24) BOOL;
3625
37pub extern "kernel32" stdcallcc fn CreateProcessA(26pub extern "kernel32" stdcallcc fn CreateProcessW(
38 lpApplicationName: ?LPCSTR,27 lpApplicationName: ?LPWSTR,
39 lpCommandLine: LPSTR,28 lpCommandLine: LPWSTR,
40 lpProcessAttributes: ?*SECURITY_ATTRIBUTES,29 lpProcessAttributes: ?*SECURITY_ATTRIBUTES,
41 lpThreadAttributes: ?*SECURITY_ATTRIBUTES,30 lpThreadAttributes: ?*SECURITY_ATTRIBUTES,
42 bInheritHandles: BOOL,31 bInheritHandles: BOOL,
43 dwCreationFlags: DWORD,32 dwCreationFlags: DWORD,
44 lpEnvironment: ?*c_void,33 lpEnvironment: ?*c_void,
45 lpCurrentDirectory: ?LPCSTR,34 lpCurrentDirectory: ?LPWSTR,
46 lpStartupInfo: *STARTUPINFOA,35 lpStartupInfo: *STARTUPINFOW,
47 lpProcessInformation: *PROCESS_INFORMATION,36 lpProcessInformation: *PROCESS_INFORMATION,
48) BOOL;37) BOOL;
4938
50pub extern "kernel32" stdcallcc fn CreateSymbolicLinkA(39pub extern "kernel32" stdcallcc fn CreateSymbolicLinkW(lpSymlinkFileName: [*]const u16, lpTargetFileName: [*]const u16, dwFlags: DWORD) BOOLEAN;
51 lpSymlinkFileName: LPCSTR,
52 lpTargetFileName: LPCSTR,
53 dwFlags: DWORD,
54) BOOLEAN;
5540
56pub extern "kernel32" stdcallcc fn CreateIoCompletionPort(FileHandle: HANDLE, ExistingCompletionPort: ?HANDLE, CompletionKey: ULONG_PTR, NumberOfConcurrentThreads: DWORD) ?HANDLE;41pub extern "kernel32" stdcallcc fn CreateIoCompletionPort(FileHandle: HANDLE, ExistingCompletionPort: ?HANDLE, CompletionKey: ULONG_PTR, NumberOfConcurrentThreads: DWORD) ?HANDLE;
5742
58pub extern "kernel32" stdcallcc fn CreateThread(lpThreadAttributes: ?LPSECURITY_ATTRIBUTES, dwStackSize: SIZE_T, lpStartAddress: LPTHREAD_START_ROUTINE, lpParameter: ?LPVOID, dwCreationFlags: DWORD, lpThreadId: ?LPDWORD) ?HANDLE;43pub extern "kernel32" stdcallcc fn CreateThread(lpThreadAttributes: ?LPSECURITY_ATTRIBUTES, dwStackSize: SIZE_T, lpStartAddress: LPTHREAD_START_ROUTINE, lpParameter: ?LPVOID, dwCreationFlags: DWORD, lpThreadId: ?LPDWORD) ?HANDLE;
5944
60pub extern "kernel32" stdcallcc fn DeleteFileA(lpFileName: [*]const u8) BOOL;
61pub extern "kernel32" stdcallcc fn DeleteFileW(lpFileName: [*]const u16) BOOL;45pub extern "kernel32" stdcallcc fn DeleteFileW(lpFileName: [*]const u16) BOOL;
6246
63pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) noreturn;47pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) noreturn;
6448
65pub extern "kernel32" stdcallcc fn FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: *WIN32_FIND_DATAA) HANDLE;49pub extern "kernel32" stdcallcc fn FindFirstFileW(lpFileName: [*]const u16, lpFindFileData: *WIN32_FIND_DATAW) HANDLE;
66pub extern "kernel32" stdcallcc fn FindClose(hFindFile: HANDLE) BOOL;50pub extern "kernel32" stdcallcc fn FindClose(hFindFile: HANDLE) BOOL;
67pub extern "kernel32" stdcallcc fn FindNextFileA(hFindFile: HANDLE, lpFindFileData: *WIN32_FIND_DATAA) BOOL;51pub extern "kernel32" stdcallcc fn FindNextFileW(hFindFile: HANDLE, lpFindFileData: *WIN32_FIND_DATAW) BOOL;
6852
69pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: [*]u8) BOOL;53pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: [*]u8) BOOL;
7054
...@@ -72,7 +56,8 @@ pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR;...@@ -72,7 +56,8 @@ pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR;
7256
73pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: *DWORD) BOOL;57pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: *DWORD) BOOL;
7458
75pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: DWORD, lpBuffer: ?[*]CHAR) DWORD;59pub extern "kernel32" stdcallcc fn GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: *CONSOLE_SCREEN_BUFFER_INFO) BOOL;
60
76pub extern "kernel32" stdcallcc fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: ?[*]WCHAR) DWORD;61pub extern "kernel32" stdcallcc fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: ?[*]WCHAR) DWORD;
7762
78pub extern "kernel32" stdcallcc fn GetCurrentThread() HANDLE;63pub extern "kernel32" stdcallcc fn GetCurrentThread() HANDLE;
...@@ -86,12 +71,12 @@ pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCo...@@ -86,12 +71,12 @@ pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCo
8671
87pub extern "kernel32" stdcallcc fn GetFileSizeEx(hFile: HANDLE, lpFileSize: *LARGE_INTEGER) BOOL;72pub extern "kernel32" stdcallcc fn GetFileSizeEx(hFile: HANDLE, lpFileSize: *LARGE_INTEGER) BOOL;
8873
89pub extern "kernel32" stdcallcc fn GetFileAttributesA(lpFileName: [*]const CHAR) DWORD;
90pub extern "kernel32" stdcallcc fn GetFileAttributesW(lpFileName: [*]const WCHAR) DWORD;74pub extern "kernel32" stdcallcc fn GetFileAttributesW(lpFileName: [*]const WCHAR) DWORD;
9175
92pub extern "kernel32" stdcallcc fn GetModuleFileNameA(hModule: ?HMODULE, lpFilename: [*]u8, nSize: DWORD) DWORD;
93pub extern "kernel32" stdcallcc fn GetModuleFileNameW(hModule: ?HMODULE, lpFilename: [*]u16, nSize: DWORD) DWORD;76pub extern "kernel32" stdcallcc fn GetModuleFileNameW(hModule: ?HMODULE, lpFilename: [*]u16, nSize: DWORD) DWORD;
9477
78pub extern "kernel32" stdcallcc fn GetModuleHandleW(lpModuleName: ?[*]const WCHAR) HMODULE;
79
95pub extern "kernel32" stdcallcc fn GetLastError() DWORD;80pub extern "kernel32" stdcallcc fn GetLastError() DWORD;
9681
97pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx(82pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx(
...@@ -101,13 +86,6 @@ pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx(...@@ -101,13 +86,6 @@ pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx(
101 in_dwBufferSize: DWORD,86 in_dwBufferSize: DWORD,
102) BOOL;87) BOOL;
10388
104pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA(
105 hFile: HANDLE,
106 lpszFilePath: LPSTR,
107 cchFilePath: DWORD,
108 dwFlags: DWORD,
109) DWORD;
110
111pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleW(89pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleW(
112 hFile: HANDLE,90 hFile: HANDLE,
113 lpszFilePath: [*]u16,91 lpszFilePath: [*]u16,
...@@ -138,12 +116,6 @@ pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem...@@ -138,12 +116,6 @@ pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem
138116
139pub extern "kernel32" stdcallcc fn HeapValidate(hHeap: HANDLE, dwFlags: DWORD, lpMem: ?*const c_void) BOOL;117pub extern "kernel32" stdcallcc fn HeapValidate(hHeap: HANDLE, dwFlags: DWORD, lpMem: ?*const c_void) BOOL;
140118
141pub extern "kernel32" stdcallcc fn MoveFileExA(
142 lpExistingFileName: [*]const u8,
143 lpNewFileName: [*]const u8,
144 dwFlags: DWORD,
145) BOOL;
146
147pub extern "kernel32" stdcallcc fn MoveFileExW(119pub extern "kernel32" stdcallcc fn MoveFileExW(
148 lpExistingFileName: [*]const u16,120 lpExistingFileName: [*]const u16,
149 lpNewFileName: [*]const u16,121 lpNewFileName: [*]const u16,
...@@ -175,7 +147,9 @@ pub extern "kernel32" stdcallcc fn ReadFile(...@@ -175,7 +147,9 @@ pub extern "kernel32" stdcallcc fn ReadFile(
175 in_out_lpOverlapped: ?*OVERLAPPED,147 in_out_lpOverlapped: ?*OVERLAPPED,
176) BOOL;148) BOOL;
177149
178pub extern "kernel32" stdcallcc fn RemoveDirectoryA(lpPathName: LPCSTR) BOOL;150pub extern "kernel32" stdcallcc fn RemoveDirectoryW(lpPathName: [*]const u16) BOOL;
151
152pub extern "kernel32" stdcallcc fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) BOOL;
179153
180pub extern "kernel32" stdcallcc fn SetFilePointerEx(154pub extern "kernel32" stdcallcc fn SetFilePointerEx(
181 in_fFile: HANDLE,155 in_fFile: HANDLE,
...@@ -202,8 +176,7 @@ pub extern "kernel32" stdcallcc fn WriteFile(...@@ -202,8 +176,7 @@ pub extern "kernel32" stdcallcc fn WriteFile(
202176
203pub extern "kernel32" stdcallcc fn WriteFileEx(hFile: HANDLE, lpBuffer: [*]const u8, nNumberOfBytesToWrite: DWORD, lpOverlapped: LPOVERLAPPED, lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE) BOOL;177pub extern "kernel32" stdcallcc fn WriteFileEx(hFile: HANDLE, lpBuffer: [*]const u8, nNumberOfBytesToWrite: DWORD, lpOverlapped: LPOVERLAPPED, lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE) BOOL;
204178
205//TODO: call unicode versions instead of relying on ANSI code page179pub extern "kernel32" stdcallcc fn LoadLibraryW(lpLibFileName: [*]const u16) ?HMODULE;
206pub extern "kernel32" stdcallcc fn LoadLibraryA(lpLibFileName: LPCSTR) ?HMODULE;
207180
208pub extern "kernel32" stdcallcc fn FreeLibrary(hModule: HMODULE) BOOL;181pub extern "kernel32" stdcallcc fn FreeLibrary(hModule: HMODULE) BOOL;
209182
...@@ -232,3 +205,17 @@ pub const FILE_NOTIFY_CHANGE_LAST_WRITE = 16;...@@ -232,3 +205,17 @@ pub const FILE_NOTIFY_CHANGE_LAST_WRITE = 16;
232pub const FILE_NOTIFY_CHANGE_DIR_NAME = 2;205pub const FILE_NOTIFY_CHANGE_DIR_NAME = 2;
233pub const FILE_NOTIFY_CHANGE_FILE_NAME = 1;206pub const FILE_NOTIFY_CHANGE_FILE_NAME = 1;
234pub const FILE_NOTIFY_CHANGE_ATTRIBUTES = 4;207pub const FILE_NOTIFY_CHANGE_ATTRIBUTES = 4;
208
209
210pub const CONSOLE_SCREEN_BUFFER_INFO = extern struct {
211 dwSize: COORD,
212 dwCursorPosition: COORD,
213 wAttributes: WORD,
214 srWindow: SMALL_RECT,
215 dwMaximumWindowSize: COORD,
216};
217
218pub const FOREGROUND_BLUE = 1;
219pub const FOREGROUND_GREEN = 2;
220pub const FOREGROUND_RED = 4;
221pub const FOREGROUND_INTENSITY = 8;
std/os/windows/ntdll.zig created+3
...@@ -0,0 +1,3 @@
1use @import("index.zig");
2
3pub extern "NtDll" stdcallcc fn RtlCaptureStackBackTrace(FramesToSkip: DWORD, FramesToCapture: DWORD, BackTrace: **c_void, BackTraceHash: ?*DWORD) WORD;
std/os/windows/ole32.zig-1
...@@ -5,7 +5,6 @@ pub extern "ole32.dll" stdcallcc fn CoUninitialize() void;...@@ -5,7 +5,6 @@ pub extern "ole32.dll" stdcallcc fn CoUninitialize() void;
5pub extern "ole32.dll" stdcallcc fn CoGetCurrentProcess() DWORD;5pub extern "ole32.dll" stdcallcc fn CoGetCurrentProcess() DWORD;
6pub extern "ole32.dll" stdcallcc fn CoInitializeEx(pvReserved: LPVOID, dwCoInit: DWORD) HRESULT;6pub extern "ole32.dll" stdcallcc fn CoInitializeEx(pvReserved: LPVOID, dwCoInit: DWORD) HRESULT;
77
8
9pub const COINIT_APARTMENTTHREADED = COINIT.COINIT_APARTMENTTHREADED;8pub const COINIT_APARTMENTTHREADED = COINIT.COINIT_APARTMENTTHREADED;
10pub const COINIT_MULTITHREADED = COINIT.COINIT_MULTITHREADED;9pub const COINIT_MULTITHREADED = COINIT.COINIT_MULTITHREADED;
11pub const COINIT_DISABLE_OLE1DDE = COINIT.COINIT_DISABLE_OLE1DDE;10pub const COINIT_DISABLE_OLE1DDE = COINIT.COINIT_DISABLE_OLE1DDE;
std/os/windows/shlwapi.zig deleted-4
...@@ -1,4 +0,0 @@
1use @import("index.zig");
2
3pub extern "shlwapi" stdcallcc fn PathFileExistsA(pszPath: ?LPCTSTR) BOOL;
4
std/os/windows/user32.zig deleted-4
...@@ -1,4 +0,0 @@
1use @import("index.zig");
2
3pub extern "user32" stdcallcc fn MessageBoxA(hWnd: ?HANDLE, lpText: ?LPCTSTR, lpCaption: ?LPCTSTR, uType: UINT) c_int;
4
std/os/windows/util.zig+60-43
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const std = @import("../../index.zig");1const std = @import("../../index.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const os = std.os;3const os = std.os;
4const unicode = std.unicode;
4const windows = std.os.windows;5const windows = std.os.windows;
5const assert = std.debug.assert;6const assert = std.debug.assert;
6const mem = std.mem;7const mem = std.mem;
...@@ -118,16 +119,14 @@ pub const OpenError = error{...@@ -118,16 +119,14 @@ pub const OpenError = error{
118 Unexpected,119 Unexpected,
119};120};
120121
121pub fn windowsOpen(122pub fn windowsOpenW(
122 file_path: []const u8,123 file_path_w: [*]const u16,
123 desired_access: windows.DWORD,124 desired_access: windows.DWORD,
124 share_mode: windows.DWORD,125 share_mode: windows.DWORD,
125 creation_disposition: windows.DWORD,126 creation_disposition: windows.DWORD,
126 flags_and_attrs: windows.DWORD,127 flags_and_attrs: windows.DWORD,
127) OpenError!windows.HANDLE {128) OpenError!windows.HANDLE {
128 const file_path_w = try sliceToPrefixedFileW(file_path);129 const result = windows.CreateFileW(file_path_w, desired_access, share_mode, null, creation_disposition, flags_and_attrs, null);
129
130 const result = windows.CreateFileW(&file_path_w, desired_access, share_mode, null, creation_disposition, flags_and_attrs, null);
131130
132 if (result == windows.INVALID_HANDLE_VALUE) {131 if (result == windows.INVALID_HANDLE_VALUE) {
133 const err = windows.GetLastError();132 const err = windows.GetLastError();
...@@ -146,42 +145,63 @@ pub fn windowsOpen(...@@ -146,42 +145,63 @@ pub fn windowsOpen(
146 return result;145 return result;
147}146}
148147
148pub fn windowsOpen(
149 file_path: []const u8,
150 desired_access: windows.DWORD,
151 share_mode: windows.DWORD,
152 creation_disposition: windows.DWORD,
153 flags_and_attrs: windows.DWORD,
154) OpenError!windows.HANDLE {
155 const file_path_w = try sliceToPrefixedFileW(file_path);
156 return windowsOpenW(&file_path_w, desired_access, share_mode, creation_disposition, flags_and_attrs);
157}
158
149/// Caller must free result.159/// Caller must free result.
150pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap) ![]u8 {160pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap) ![]u16 {
151 // count bytes needed161 // count bytes needed
152 const bytes_needed = x: {162 const max_chars_needed = x: {
153 var bytes_needed: usize = 1; // 1 for the final null byte163 var max_chars_needed: usize = 1; // 1 for the final null byte
154 var it = env_map.iterator();164 var it = env_map.iterator();
155 while (it.next()) |pair| {165 while (it.next()) |pair| {
156 // +1 for '='166 // +1 for '='
157 // +1 for null byte167 // +1 for null byte
158 bytes_needed += pair.key.len + pair.value.len + 2;168 max_chars_needed += pair.key.len + pair.value.len + 2;
159 }169 }
160 break :x bytes_needed;170 break :x max_chars_needed;
161 };171 };
162 const result = try allocator.alloc(u8, bytes_needed);172 const result = try allocator.alloc(u16, max_chars_needed);
163 errdefer allocator.free(result);173 errdefer allocator.free(result);
164174
165 var it = env_map.iterator();175 var it = env_map.iterator();
166 var i: usize = 0;176 var i: usize = 0;
167 while (it.next()) |pair| {177 while (it.next()) |pair| {
168 mem.copy(u8, result[i..], pair.key);178 i += try unicode.utf8ToUtf16Le(result[i..], pair.key);
169 i += pair.key.len;
170 result[i] = '=';179 result[i] = '=';
171 i += 1;180 i += 1;
172 mem.copy(u8, result[i..], pair.value);181 i += try unicode.utf8ToUtf16Le(result[i..], pair.value);
173 i += pair.value.len;
174 result[i] = 0;182 result[i] = 0;
175 i += 1;183 i += 1;
176 }184 }
177 result[i] = 0;185 result[i] = 0;
178 return result;186 i += 1;
187 return allocator.shrink(u16, result, i);
179}188}
180189
181pub fn windowsLoadDll(allocator: *mem.Allocator, dll_path: []const u8) !windows.HMODULE {190pub fn windowsLoadDllW(dll_path_w: [*]const u16) !windows.HMODULE {
182 const padded_buff = try cstr.addNullByte(allocator, dll_path);191 return windows.LoadLibraryW(dll_path_w) orelse {
183 defer allocator.free(padded_buff);192 const err = windows.GetLastError();
184 return windows.LoadLibraryA(padded_buff.ptr) orelse error.DllNotFound;193 switch (err) {
194 windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
195 windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
196 windows.ERROR.MOD_NOT_FOUND => return error.FileNotFound,
197 else => return os.unexpectedErrorWindows(err),
198 }
199 };
200}
201
202pub fn windowsLoadDll(dll_path: []const u8) !windows.HMODULE {
203 const dll_path_w = try sliceToPrefixedFileW(dll_path);
204 return windowsLoadDllW(&dll_path_w);
185}205}
186206
187pub fn windowsUnloadDll(hModule: windows.HMODULE) void {207pub fn windowsUnloadDll(hModule: windows.HMODULE) void {
...@@ -191,27 +211,19 @@ pub fn windowsUnloadDll(hModule: windows.HMODULE) void {...@@ -191,27 +211,19 @@ pub fn windowsUnloadDll(hModule: windows.HMODULE) void {
191test "InvalidDll" {211test "InvalidDll" {
192 if (builtin.os != builtin.Os.windows) return error.SkipZigTest;212 if (builtin.os != builtin.Os.windows) return error.SkipZigTest;
193213
194 const DllName = "asdf.dll";214 const handle = os.windowsLoadDll("asdf.dll") catch |err| {
195 const allocator = std.debug.global_allocator;215 assert(err == error.FileNotFound);
196 const handle = os.windowsLoadDll(allocator, DllName) catch |err| {
197 assert(err == error.DllNotFound);
198 return;216 return;
199 };217 };
218 @panic("Expected error from function");
200}219}
201220
202pub fn windowsFindFirstFile(221pub fn windowsFindFirstFile(
203 allocator: *mem.Allocator,
204 dir_path: []const u8,222 dir_path: []const u8,
205 find_file_data: *windows.WIN32_FIND_DATAA,223 find_file_data: *windows.WIN32_FIND_DATAW,
206) !windows.HANDLE {224) !windows.HANDLE {
207 const wild_and_null = []u8{ '\\', '*', 0 };225 const dir_path_w = try sliceToPrefixedSuffixedFileW(dir_path, []u16{'\\', '*', 0});
208 const path_with_wild_and_null = try allocator.alloc(u8, dir_path.len + wild_and_null.len);226 const handle = windows.FindFirstFileW(&dir_path_w, find_file_data);
209 defer allocator.free(path_with_wild_and_null);
210
211 mem.copy(u8, path_with_wild_and_null, dir_path);
212 mem.copy(u8, path_with_wild_and_null[dir_path.len..], wild_and_null);
213
214 const handle = windows.FindFirstFileA(path_with_wild_and_null.ptr, find_file_data);
215227
216 if (handle == windows.INVALID_HANDLE_VALUE) {228 if (handle == windows.INVALID_HANDLE_VALUE) {
217 const err = windows.GetLastError();229 const err = windows.GetLastError();
...@@ -226,8 +238,8 @@ pub fn windowsFindFirstFile(...@@ -226,8 +238,8 @@ pub fn windowsFindFirstFile(
226}238}
227239
228/// Returns `true` if there was another file, `false` otherwise.240/// Returns `true` if there was another file, `false` otherwise.
229pub fn windowsFindNextFile(handle: windows.HANDLE, find_file_data: *windows.WIN32_FIND_DATAA) !bool {241pub fn windowsFindNextFile(handle: windows.HANDLE, find_file_data: *windows.WIN32_FIND_DATAW) !bool {
230 if (windows.FindNextFileA(handle, find_file_data) == 0) {242 if (windows.FindNextFileW(handle, find_file_data) == 0) {
231 const err = windows.GetLastError();243 const err = windows.GetLastError();
232 return switch (err) {244 return switch (err) {
233 windows.ERROR.NO_MORE_FILES => false,245 windows.ERROR.NO_MORE_FILES => false,
...@@ -288,8 +300,12 @@ pub fn cStrToPrefixedFileW(s: [*]const u8) ![PATH_MAX_WIDE + 1]u16 {...@@ -288,8 +300,12 @@ pub fn cStrToPrefixedFileW(s: [*]const u8) ![PATH_MAX_WIDE + 1]u16 {
288}300}
289301
290pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE + 1]u16 {302pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE + 1]u16 {
303 return sliceToPrefixedSuffixedFileW(s, []u16{0});
304}
305
306pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) ![PATH_MAX_WIDE + suffix.len]u16 {
291 // TODO well defined copy elision307 // TODO well defined copy elision
292 var result: [PATH_MAX_WIDE + 1]u16 = undefined;308 var result: [PATH_MAX_WIDE + suffix.len]u16 = undefined;
293309
294 // > File I/O functions in the Windows API convert "/" to "\" as part of310 // > File I/O functions in the Windows API convert "/" to "\" as part of
295 // > converting the name to an NT-style name, except when using the "\\?\"311 // > converting the name to an NT-style name, except when using the "\\?\"
...@@ -297,11 +313,12 @@ pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE + 1]u16 {...@@ -297,11 +313,12 @@ pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE + 1]u16 {
297 // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation313 // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
298 // Because we want the larger maximum path length for absolute paths, we314 // Because we want the larger maximum path length for absolute paths, we
299 // disallow forward slashes in zig std lib file functions on Windows.315 // disallow forward slashes in zig std lib file functions on Windows.
300 for (s) |byte|316 for (s) |byte| {
301 switch (byte) {317 switch (byte) {
302 '/', '*', '?', '"', '<', '>', '|' => return error.BadPathName,318 '/', '*', '?', '"', '<', '>', '|' => return error.BadPathName,
303 else => {},319 else => {},
304 };320 }
321 }
305 const start_index = if (mem.startsWith(u8, s, "\\\\") or !os.path.isAbsolute(s)) 0 else blk: {322 const start_index = if (mem.startsWith(u8, s, "\\\\") or !os.path.isAbsolute(s)) 0 else blk: {
306 const prefix = []u16{ '\\', '\\', '?', '\\' };323 const prefix = []u16{ '\\', '\\', '?', '\\' };
307 mem.copy(u16, result[0..], prefix);324 mem.copy(u16, result[0..], prefix);
...@@ -309,7 +326,7 @@ pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE + 1]u16 {...@@ -309,7 +326,7 @@ pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE + 1]u16 {
309 };326 };
310 const end_index = start_index + try std.unicode.utf8ToUtf16Le(result[start_index..], s);327 const end_index = start_index + try std.unicode.utf8ToUtf16Le(result[start_index..], s);
311 assert(end_index <= result.len);328 assert(end_index <= result.len);
312 if (end_index == result.len) return error.NameTooLong;329 if (end_index + suffix.len > result.len) return error.NameTooLong;
313 result[end_index] = 0;330 mem.copy(u16, result[end_index..], suffix);
314 return result;331 return result;
315}332}
std/os/zen.zig+24-25
...@@ -6,32 +6,32 @@ const assert = std.debug.assert;...@@ -6,32 +6,32 @@ const assert = std.debug.assert;
6//////////////////////////6//////////////////////////
77
8pub const Message = struct {8pub const Message = struct {
9sender: MailboxId,9 sender: MailboxId,
10 receiver: MailboxId,10 receiver: MailboxId,
11 code: usize,11 code: usize,
12 args: [5]usize,12 args: [5]usize,
13 payload: ?[]const u8,13 payload: ?[]const u8,
1414
15 pub fn from(mailbox_id: *const MailboxId) Message {15 pub fn from(mailbox_id: *const MailboxId) Message {
16 return Message {16 return Message{
17 .sender = MailboxId.Undefined,17 .sender = MailboxId.Undefined,
18 .receiver = mailbox_id.*,18 .receiver = mailbox_id.*,
19 .code = undefined,19 .code = undefined,
20 .args = undefined,20 .args = undefined,
21 .payload = null,21 .payload = null,
22 };22 };
23 }23 }
2424
25 pub fn to(mailbox_id: *const MailboxId, msg_code: usize, args: ...) Message {25 pub fn to(mailbox_id: *const MailboxId, msg_code: usize, args: ...) Message {
26 var message = Message {26 var message = Message{
27 .sender = MailboxId.This,27 .sender = MailboxId.This,
28 .receiver = mailbox_id.*,28 .receiver = mailbox_id.*,
29 .code = msg_code,29 .code = msg_code,
30 .args = undefined,30 .args = undefined,
31 .payload = null,31 .payload = null,
32 };32 };
3333
34 assert (args.len <= message.args.len);34 assert(args.len <= message.args.len);
35 comptime var i = 0;35 comptime var i = 0;
36 inline while (i < args.len) : (i += 1) {36 inline while (i < args.len) : (i += 1) {
37 message.args[i] = args[i];37 message.args[i] = args[i];
...@@ -111,8 +111,7 @@ pub fn read(fd: i32, buf: [*]u8, count: usize) usize {...@@ -111,8 +111,7 @@ pub fn read(fd: i32, buf: [*]u8, count: usize) usize {
111pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {111pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
112 switch (fd) {112 switch (fd) {
113 STDOUT_FILENO, STDERR_FILENO => {113 STDOUT_FILENO, STDERR_FILENO => {
114 send(Message.to(Server.Terminal, 1)114 send(Message.to(Server.Terminal, 1).withPayload(buf[0..count]));
115 .withPayload(buf[0..count]));
116 },115 },
117 else => unreachable,116 else => unreachable,
118 }117 }
...@@ -124,14 +123,14 @@ pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {...@@ -124,14 +123,14 @@ pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
124///////////////////////////123///////////////////////////
125124
126pub const Syscall = enum(usize) {125pub const Syscall = enum(usize) {
127 exit = 0,126 exit = 0,
128 send = 1,127 send = 1,
129 receive = 2,128 receive = 2,
130 subscribeIRQ = 3,129 subscribeIRQ = 3,
131 inb = 4,130 inb = 4,
132 outb = 5,131 outb = 5,
133 map = 6,132 map = 6,
134 createThread = 7,133 createThread = 7,
135};134};
136135
137////////////////////136////////////////////
std/pdb.zig created+646
...@@ -0,0 +1,646 @@
1const builtin = @import("builtin");
2const std = @import("index.zig");
3const io = std.io;
4const math = std.math;
5const mem = std.mem;
6const os = std.os;
7const warn = std.debug.warn;
8const coff = std.coff;
9
10const ArrayList = std.ArrayList;
11
12// https://llvm.org/docs/PDB/DbiStream.html#stream-header
13pub const DbiStreamHeader = packed struct {
14 VersionSignature: i32,
15 VersionHeader: u32,
16 Age: u32,
17 GlobalStreamIndex: u16,
18 BuildNumber: u16,
19 PublicStreamIndex: u16,
20 PdbDllVersion: u16,
21 SymRecordStream: u16,
22 PdbDllRbld: u16,
23 ModInfoSize: u32,
24 SectionContributionSize: u32,
25 SectionMapSize: u32,
26 SourceInfoSize: i32,
27 TypeServerSize: i32,
28 MFCTypeServerIndex: u32,
29 OptionalDbgHeaderSize: i32,
30 ECSubstreamSize: i32,
31 Flags: u16,
32 Machine: u16,
33 Padding: u32,
34};
35
36pub const SectionContribEntry = packed struct {
37 Section: u16,
38 Padding1: [2]u8,
39 Offset: u32,
40 Size: u32,
41 Characteristics: u32,
42 ModuleIndex: u16,
43 Padding2: [2]u8,
44 DataCrc: u32,
45 RelocCrc: u32,
46};
47
48pub const ModInfo = packed struct {
49 Unused1: u32,
50 SectionContr: SectionContribEntry,
51 Flags: u16,
52 ModuleSymStream: u16,
53 SymByteSize: u32,
54 C11ByteSize: u32,
55 C13ByteSize: u32,
56 SourceFileCount: u16,
57 Padding: [2]u8,
58 Unused2: u32,
59 SourceFileNameIndex: u32,
60 PdbFilePathNameIndex: u32,
61 // These fields are variable length
62 //ModuleName: char[],
63 //ObjFileName: char[],
64};
65
66pub const SectionMapHeader = packed struct {
67 Count: u16, /// Number of segment descriptors
68 LogCount: u16, /// Number of logical segment descriptors
69};
70
71pub const SectionMapEntry = packed struct {
72 Flags: u16 , /// See the SectionMapEntryFlags enum below.
73 Ovl: u16 , /// Logical overlay number
74 Group: u16 , /// Group index into descriptor array.
75 Frame: u16 ,
76 SectionName: u16 , /// Byte index of segment / group name in string table, or 0xFFFF.
77 ClassName: u16 , /// Byte index of class in string table, or 0xFFFF.
78 Offset: u32 , /// Byte offset of the logical segment within physical segment. If group is set in flags, this is the offset of the group.
79 SectionLength: u32 , /// Byte count of the segment or group.
80};
81
82pub const StreamType = enum(u16) {
83 Pdb = 1,
84 Tpi = 2,
85 Dbi = 3,
86 Ipi = 4,
87};
88
89/// Duplicate copy of SymbolRecordKind, but using the official CV names. Useful
90/// for reference purposes and when dealing with unknown record types.
91pub const SymbolKind = packed enum(u16) {
92 S_COMPILE = 1,
93 S_REGISTER_16t = 2,
94 S_CONSTANT_16t = 3,
95 S_UDT_16t = 4,
96 S_SSEARCH = 5,
97 S_SKIP = 7,
98 S_CVRESERVE = 8,
99 S_OBJNAME_ST = 9,
100 S_ENDARG = 10,
101 S_COBOLUDT_16t = 11,
102 S_MANYREG_16t = 12,
103 S_RETURN = 13,
104 S_ENTRYTHIS = 14,
105 S_BPREL16 = 256,
106 S_LDATA16 = 257,
107 S_GDATA16 = 258,
108 S_PUB16 = 259,
109 S_LPROC16 = 260,
110 S_GPROC16 = 261,
111 S_THUNK16 = 262,
112 S_BLOCK16 = 263,
113 S_WITH16 = 264,
114 S_LABEL16 = 265,
115 S_CEXMODEL16 = 266,
116 S_VFTABLE16 = 267,
117 S_REGREL16 = 268,
118 S_BPREL32_16t = 512,
119 S_LDATA32_16t = 513,
120 S_GDATA32_16t = 514,
121 S_PUB32_16t = 515,
122 S_LPROC32_16t = 516,
123 S_GPROC32_16t = 517,
124 S_THUNK32_ST = 518,
125 S_BLOCK32_ST = 519,
126 S_WITH32_ST = 520,
127 S_LABEL32_ST = 521,
128 S_CEXMODEL32 = 522,
129 S_VFTABLE32_16t = 523,
130 S_REGREL32_16t = 524,
131 S_LTHREAD32_16t = 525,
132 S_GTHREAD32_16t = 526,
133 S_SLINK32 = 527,
134 S_LPROCMIPS_16t = 768,
135 S_GPROCMIPS_16t = 769,
136 S_PROCREF_ST = 1024,
137 S_DATAREF_ST = 1025,
138 S_ALIGN = 1026,
139 S_LPROCREF_ST = 1027,
140 S_OEM = 1028,
141 S_TI16_MAX = 4096,
142 S_REGISTER_ST = 4097,
143 S_CONSTANT_ST = 4098,
144 S_UDT_ST = 4099,
145 S_COBOLUDT_ST = 4100,
146 S_MANYREG_ST = 4101,
147 S_BPREL32_ST = 4102,
148 S_LDATA32_ST = 4103,
149 S_GDATA32_ST = 4104,
150 S_PUB32_ST = 4105,
151 S_LPROC32_ST = 4106,
152 S_GPROC32_ST = 4107,
153 S_VFTABLE32 = 4108,
154 S_REGREL32_ST = 4109,
155 S_LTHREAD32_ST = 4110,
156 S_GTHREAD32_ST = 4111,
157 S_LPROCMIPS_ST = 4112,
158 S_GPROCMIPS_ST = 4113,
159 S_COMPILE2_ST = 4115,
160 S_MANYREG2_ST = 4116,
161 S_LPROCIA64_ST = 4117,
162 S_GPROCIA64_ST = 4118,
163 S_LOCALSLOT_ST = 4119,
164 S_PARAMSLOT_ST = 4120,
165 S_ANNOTATION = 4121,
166 S_GMANPROC_ST = 4122,
167 S_LMANPROC_ST = 4123,
168 S_RESERVED1 = 4124,
169 S_RESERVED2 = 4125,
170 S_RESERVED3 = 4126,
171 S_RESERVED4 = 4127,
172 S_LMANDATA_ST = 4128,
173 S_GMANDATA_ST = 4129,
174 S_MANFRAMEREL_ST = 4130,
175 S_MANREGISTER_ST = 4131,
176 S_MANSLOT_ST = 4132,
177 S_MANMANYREG_ST = 4133,
178 S_MANREGREL_ST = 4134,
179 S_MANMANYREG2_ST = 4135,
180 S_MANTYPREF = 4136,
181 S_UNAMESPACE_ST = 4137,
182 S_ST_MAX = 4352,
183 S_WITH32 = 4356,
184 S_MANYREG = 4362,
185 S_LPROCMIPS = 4372,
186 S_GPROCMIPS = 4373,
187 S_MANYREG2 = 4375,
188 S_LPROCIA64 = 4376,
189 S_GPROCIA64 = 4377,
190 S_LOCALSLOT = 4378,
191 S_PARAMSLOT = 4379,
192 S_MANFRAMEREL = 4382,
193 S_MANREGISTER = 4383,
194 S_MANSLOT = 4384,
195 S_MANMANYREG = 4385,
196 S_MANREGREL = 4386,
197 S_MANMANYREG2 = 4387,
198 S_UNAMESPACE = 4388,
199 S_DATAREF = 4390,
200 S_ANNOTATIONREF = 4392,
201 S_TOKENREF = 4393,
202 S_GMANPROC = 4394,
203 S_LMANPROC = 4395,
204 S_ATTR_FRAMEREL = 4398,
205 S_ATTR_REGISTER = 4399,
206 S_ATTR_REGREL = 4400,
207 S_ATTR_MANYREG = 4401,
208 S_SEPCODE = 4402,
209 S_LOCAL_2005 = 4403,
210 S_DEFRANGE_2005 = 4404,
211 S_DEFRANGE2_2005 = 4405,
212 S_DISCARDED = 4411,
213 S_LPROCMIPS_ID = 4424,
214 S_GPROCMIPS_ID = 4425,
215 S_LPROCIA64_ID = 4426,
216 S_GPROCIA64_ID = 4427,
217 S_DEFRANGE_HLSL = 4432,
218 S_GDATA_HLSL = 4433,
219 S_LDATA_HLSL = 4434,
220 S_LOCAL_DPC_GROUPSHARED = 4436,
221 S_DEFRANGE_DPC_PTR_TAG = 4439,
222 S_DPC_SYM_TAG_MAP = 4440,
223 S_ARMSWITCHTABLE = 4441,
224 S_POGODATA = 4444,
225 S_INLINESITE2 = 4445,
226 S_MOD_TYPEREF = 4447,
227 S_REF_MINIPDB = 4448,
228 S_PDBMAP = 4449,
229 S_GDATA_HLSL32 = 4450,
230 S_LDATA_HLSL32 = 4451,
231 S_GDATA_HLSL32_EX = 4452,
232 S_LDATA_HLSL32_EX = 4453,
233 S_FASTLINK = 4455,
234 S_INLINEES = 4456,
235 S_END = 6,
236 S_INLINESITE_END = 4430,
237 S_PROC_ID_END = 4431,
238 S_THUNK32 = 4354,
239 S_TRAMPOLINE = 4396,
240 S_SECTION = 4406,
241 S_COFFGROUP = 4407,
242 S_EXPORT = 4408,
243 S_LPROC32 = 4367,
244 S_GPROC32 = 4368,
245 S_LPROC32_ID = 4422,
246 S_GPROC32_ID = 4423,
247 S_LPROC32_DPC = 4437,
248 S_LPROC32_DPC_ID = 4438,
249 S_REGISTER = 4358,
250 S_PUB32 = 4366,
251 S_PROCREF = 4389,
252 S_LPROCREF = 4391,
253 S_ENVBLOCK = 4413,
254 S_INLINESITE = 4429,
255 S_LOCAL = 4414,
256 S_DEFRANGE = 4415,
257 S_DEFRANGE_SUBFIELD = 4416,
258 S_DEFRANGE_REGISTER = 4417,
259 S_DEFRANGE_FRAMEPOINTER_REL = 4418,
260 S_DEFRANGE_SUBFIELD_REGISTER = 4419,
261 S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE = 4420,
262 S_DEFRANGE_REGISTER_REL = 4421,
263 S_BLOCK32 = 4355,
264 S_LABEL32 = 4357,
265 S_OBJNAME = 4353,
266 S_COMPILE2 = 4374,
267 S_COMPILE3 = 4412,
268 S_FRAMEPROC = 4114,
269 S_CALLSITEINFO = 4409,
270 S_FILESTATIC = 4435,
271 S_HEAPALLOCSITE = 4446,
272 S_FRAMECOOKIE = 4410,
273 S_CALLEES = 4442,
274 S_CALLERS = 4443,
275 S_UDT = 4360,
276 S_COBOLUDT = 4361,
277 S_BUILDINFO = 4428,
278 S_BPREL32 = 4363,
279 S_REGREL32 = 4369,
280 S_CONSTANT = 4359,
281 S_MANCONSTANT = 4397,
282 S_LDATA32 = 4364,
283 S_GDATA32 = 4365,
284 S_LMANDATA = 4380,
285 S_GMANDATA = 4381,
286 S_LTHREAD32 = 4370,
287 S_GTHREAD32 = 4371,
288};
289
290pub const TypeIndex = u32;
291
292pub const ProcSym = packed struct {
293 Parent: u32 ,
294 End: u32 ,
295 Next: u32 ,
296 CodeSize: u32 ,
297 DbgStart: u32 ,
298 DbgEnd: u32 ,
299 FunctionType: TypeIndex ,
300 CodeOffset: u32,
301 Segment: u16,
302 Flags: ProcSymFlags,
303 // following is a null terminated string
304 // Name: [*]u8,
305};
306
307pub const ProcSymFlags = packed struct {
308 HasFP: bool,
309 HasIRET: bool,
310 HasFRET: bool,
311 IsNoReturn: bool,
312 IsUnreachable: bool,
313 HasCustomCallingConv: bool,
314 IsNoInline: bool,
315 HasOptimizedDebugInfo: bool,
316};
317
318pub const SectionContrSubstreamVersion = enum(u32) {
319 Ver60 = 0xeffe0000 + 19970605,
320 V2 = 0xeffe0000 + 20140516
321};
322
323pub const RecordPrefix = packed struct {
324 RecordLen: u16, /// Record length, starting from &RecordKind.
325 RecordKind: SymbolKind, /// Record kind enum (SymRecordKind or TypeRecordKind)
326};
327
328pub const LineFragmentHeader = packed struct {
329 RelocOffset: u32, /// Code offset of line contribution.
330 RelocSegment: u16, /// Code segment of line contribution.
331 Flags: LineFlags,
332 CodeSize: u32, /// Code size of this line contribution.
333};
334
335pub const LineFlags = packed struct {
336 LF_HaveColumns: bool, /// CV_LINES_HAVE_COLUMNS
337 unused: u15,
338};
339
340/// The following two variable length arrays appear immediately after the
341/// header. The structure definitions follow.
342/// LineNumberEntry Lines[NumLines];
343/// ColumnNumberEntry Columns[NumLines];
344pub const LineBlockFragmentHeader = packed struct {
345 /// Offset of FileChecksum entry in File
346 /// checksums buffer. The checksum entry then
347 /// contains another offset into the string
348 /// table of the actual name.
349 NameIndex: u32,
350 NumLines: u32,
351 BlockSize: u32, /// code size of block, in bytes
352};
353
354
355pub const LineNumberEntry = packed struct {
356 Offset: u32, /// Offset to start of code bytes for line number
357 Flags: u32,
358
359 /// TODO runtime crash when I make the actual type of Flags this
360 const Flags = packed struct {
361 Start: u24,
362 End: u7,
363 IsStatement: bool,
364 };
365};
366
367pub const ColumnNumberEntry = packed struct {
368 StartColumn: u16,
369 EndColumn: u16,
370};
371
372/// Checksum bytes follow.
373pub const FileChecksumEntryHeader = packed struct {
374 FileNameOffset: u32, /// Byte offset of filename in global string table.
375 ChecksumSize: u8, /// Number of bytes of checksum.
376 ChecksumKind: u8, /// FileChecksumKind
377};
378
379pub const DebugSubsectionKind = packed enum(u32) {
380 None = 0,
381 Symbols = 0xf1,
382 Lines = 0xf2,
383 StringTable = 0xf3,
384 FileChecksums = 0xf4,
385 FrameData = 0xf5,
386 InlineeLines = 0xf6,
387 CrossScopeImports = 0xf7,
388 CrossScopeExports = 0xf8,
389
390 // These appear to relate to .Net assembly info.
391 ILLines = 0xf9,
392 FuncMDTokenMap = 0xfa,
393 TypeMDTokenMap = 0xfb,
394 MergedAssemblyInput = 0xfc,
395
396 CoffSymbolRVA = 0xfd,
397};
398
399
400pub const DebugSubsectionHeader = packed struct {
401 Kind: DebugSubsectionKind, /// codeview::DebugSubsectionKind enum
402 Length: u32, /// number of bytes occupied by this record.
403};
404
405
406pub const PDBStringTableHeader = packed struct {
407 Signature: u32, /// PDBStringTableSignature
408 HashVersion: u32, /// 1 or 2
409 ByteSize: u32, /// Number of bytes of names buffer.
410};
411
412pub const Pdb = struct {
413 in_file: os.File,
414 allocator: *mem.Allocator,
415 coff: *coff.Coff,
416 string_table: *MsfStream,
417 dbi: *MsfStream,
418
419 msf: Msf,
420
421 pub fn openFile(self: *Pdb, coff_ptr: *coff.Coff, file_name: []u8) !void {
422 self.in_file = try os.File.openRead(file_name);
423 self.allocator = coff_ptr.allocator;
424 self.coff = coff_ptr;
425
426 try self.msf.openFile(self.allocator, self.in_file);
427 }
428
429 pub fn getStreamById(self: *Pdb, id: u32) ?*MsfStream {
430 if (id >= self.msf.streams.len)
431 return null;
432 return &self.msf.streams[id];
433 }
434
435 pub fn getStream(self: *Pdb, stream: StreamType) ?*MsfStream {
436 const id = @enumToInt(stream);
437 return self.getStreamById(id);
438 }
439};
440
441// see https://llvm.org/docs/PDB/MsfFile.html
442const Msf = struct {
443 directory: MsfStream,
444 streams: []MsfStream,
445
446 fn openFile(self: *Msf, allocator: *mem.Allocator, file: os.File) !void {
447 var file_stream = io.FileInStream.init(file);
448 const in = &file_stream.stream;
449
450 var superblock: SuperBlock = undefined;
451 try in.readStruct(SuperBlock, &superblock);
452
453 if (!mem.eql(u8, superblock.FileMagic, SuperBlock.file_magic))
454 return error.InvalidDebugInfo;
455
456 switch (superblock.BlockSize) {
457 // llvm only supports 4096 but we can handle any of these values
458 512, 1024, 2048, 4096 => {},
459 else => return error.InvalidDebugInfo
460 }
461
462 if (superblock.NumBlocks * superblock.BlockSize != try file.getEndPos())
463 return error.InvalidDebugInfo;
464
465 self.directory = try MsfStream.init(
466 superblock.BlockSize,
467 blockCountFromSize(superblock.NumDirectoryBytes, superblock.BlockSize),
468 superblock.BlockSize * superblock.BlockMapAddr,
469 file,
470 allocator,
471 );
472
473 const stream_count = try self.directory.stream.readIntLe(u32);
474
475 const stream_sizes = try allocator.alloc(u32, stream_count);
476 for (stream_sizes) |*s| {
477 const size = try self.directory.stream.readIntLe(u32);
478 s.* = blockCountFromSize(size, superblock.BlockSize);
479 }
480
481 self.streams = try allocator.alloc(MsfStream, stream_count);
482 for (self.streams) |*stream, i| {
483 stream.* = try MsfStream.init(
484 superblock.BlockSize,
485 stream_sizes[i],
486 // MsfStream.init expects the file to be at the part where it reads [N]u32
487 try file.getPos(),
488 file,
489 allocator,
490 );
491 }
492 }
493};
494
495fn blockCountFromSize(size: u32, block_size: u32) u32 {
496 return (size + block_size - 1) / block_size;
497}
498
499// https://llvm.org/docs/PDB/MsfFile.html#the-superblock
500const SuperBlock = packed struct {
501 /// The LLVM docs list a space between C / C++ but empirically this is not the case.
502 const file_magic = "Microsoft C/C++ MSF 7.00\r\n\x1a\x44\x53\x00\x00\x00";
503
504 FileMagic: [file_magic.len]u8,
505
506 /// The block size of the internal file system. Valid values are 512, 1024,
507 /// 2048, and 4096 bytes. Certain aspects of the MSF file layout vary depending
508 /// on the block sizes. For the purposes of LLVM, we handle only block sizes of
509 /// 4KiB, and all further discussion assumes a block size of 4KiB.
510 BlockSize: u32,
511
512 /// The index of a block within the file, at which begins a bitfield representing
513 /// the set of all blocks within the file which are “free” (i.e. the data within
514 /// that block is not used). See The Free Block Map for more information. Important:
515 /// FreeBlockMapBlock can only be 1 or 2!
516 FreeBlockMapBlock: u32,
517
518 /// The total number of blocks in the file. NumBlocks * BlockSize should equal the
519 /// size of the file on disk.
520 NumBlocks: u32,
521
522 /// The size of the stream directory, in bytes. The stream directory contains
523 /// information about each stream’s size and the set of blocks that it occupies.
524 /// It will be described in more detail later.
525 NumDirectoryBytes: u32,
526
527 Unknown: u32,
528
529 /// The index of a block within the MSF file. At this block is an array of
530 /// ulittle32_t’s listing the blocks that the stream directory resides on.
531 /// For large MSF files, the stream directory (which describes the block
532 /// layout of each stream) may not fit entirely on a single block. As a
533 /// result, this extra layer of indirection is introduced, whereby this
534 /// block contains the list of blocks that the stream directory occupies,
535 /// and the stream directory itself can be stitched together accordingly.
536 /// The number of ulittle32_t’s in this array is given by
537 /// ceil(NumDirectoryBytes / BlockSize).
538 BlockMapAddr: u32,
539
540};
541
542const MsfStream = struct {
543 in_file: os.File,
544 pos: usize,
545 blocks: []u32,
546 block_size: u32,
547
548 /// Implementation of InStream trait for Pdb.MsfStream
549 stream: Stream,
550
551 pub const Error = @typeOf(read).ReturnType.ErrorSet;
552 pub const Stream = io.InStream(Error);
553
554 fn init(block_size: u32, block_count: u32, pos: usize, file: os.File, allocator: *mem.Allocator) !MsfStream {
555 var stream = MsfStream {
556 .in_file = file,
557 .pos = 0,
558 .blocks = try allocator.alloc(u32, block_count),
559 .block_size = block_size,
560 .stream = Stream {
561 .readFn = readFn,
562 },
563 };
564
565 var file_stream = io.FileInStream.init(file);
566 const in = &file_stream.stream;
567 try file.seekTo(pos);
568
569 var i: u32 = 0;
570 while (i < block_count) : (i += 1) {
571 stream.blocks[i] = try in.readIntLe(u32);
572 }
573
574 return stream;
575 }
576
577 fn readNullTermString(self: *MsfStream, allocator: *mem.Allocator) ![]u8 {
578 var list = ArrayList(u8).init(allocator);
579 defer list.deinit();
580 while (true) {
581 const byte = try self.stream.readByte();
582 if (byte == 0) {
583 return list.toSlice();
584 }
585 try list.append(byte);
586 }
587 }
588
589 fn read(self: *MsfStream, buffer: []u8) !usize {
590 var block_id = self.pos / self.block_size;
591 var block = self.blocks[block_id];
592 var offset = self.pos % self.block_size;
593
594 try self.in_file.seekTo(block * self.block_size + offset);
595 var file_stream = io.FileInStream.init(self.in_file);
596 const in = &file_stream.stream;
597
598 var size: usize = 0;
599 for (buffer) |*byte| {
600 byte.* = try in.readByte();
601
602 offset += 1;
603 size += 1;
604
605 // If we're at the end of a block, go to the next one.
606 if (offset == self.block_size) {
607 offset = 0;
608 block_id += 1;
609 block = self.blocks[block_id];
610 try self.in_file.seekTo(block * self.block_size);
611 }
612 }
613
614 self.pos += size;
615 return size;
616 }
617
618 fn seekForward(self: *MsfStream, len: usize) !void {
619 self.pos += len;
620 if (self.pos >= self.blocks.len * self.block_size)
621 return error.EOF;
622 }
623
624 fn seekTo(self: *MsfStream, len: usize) !void {
625 self.pos = len;
626 if (self.pos >= self.blocks.len * self.block_size)
627 return error.EOF;
628 }
629
630 fn getSize(self: *const MsfStream) usize {
631 return self.blocks.len * self.block_size;
632 }
633
634 fn getFilePos(self: MsfStream) usize {
635 const block_id = self.pos / self.block_size;
636 const block = self.blocks[block_id];
637 const offset = self.pos % self.block_size;
638
639 return block * self.block_size + offset;
640 }
641
642 fn readFn(in_stream: *Stream, buffer: []u8) Error!usize {
643 const self = @fieldParentPtr(MsfStream, "stream", in_stream);
644 return self.read(buffer);
645 }
646};
std/rb.zig+16-14
...@@ -9,9 +9,7 @@ const Color = enum(u1) {...@@ -9,9 +9,7 @@ const Color = enum(u1) {
9const Red = Color.Red;9const Red = Color.Red;
10const Black = Color.Black;10const Black = Color.Black;
1111
12const ReplaceError = error {12const ReplaceError = error{NotEqual};
13 NotEqual,
14};
1513
16/// Insert this into your struct that you want to add to a red-black tree.14/// Insert this into your struct that you want to add to a red-black tree.
17/// Do not use a pointer. Turn the *rb.Node results of the functions in rb15/// Do not use a pointer. Turn the *rb.Node results of the functions in rb
...@@ -21,13 +19,15 @@ const ReplaceError = error {...@@ -21,13 +19,15 @@ const ReplaceError = error {
21/// node: rb.Node,19/// node: rb.Node,
22/// value: i32,20/// value: i32,
23/// };21/// };
24/// fn number(node: *Node) Number {22/// fn number(node: *rb.Node) Number {
25/// return @fieldParentPtr(Number, "node", node);23/// return @fieldParentPtr(Number, "node", node);
26/// }24/// }
27pub const Node = struct {25pub const Node = struct {
28 left: ?*Node,26 left: ?*Node,
29 right: ?*Node,27 right: ?*Node,
30 parent_and_color: usize, /// parent | color28
29 /// parent | color
30 parent_and_color: usize,
3131
32 pub fn next(constnode: *Node) ?*Node {32 pub fn next(constnode: *Node) ?*Node {
33 var node = constnode;33 var node = constnode;
...@@ -130,7 +130,7 @@ pub const Node = struct {...@@ -130,7 +130,7 @@ pub const Node = struct {
130130
131pub const Tree = struct {131pub const Tree = struct {
132 root: ?*Node,132 root: ?*Node,
133 compareFn: fn(*Node, *Node) mem.Compare,133 compareFn: fn (*Node, *Node) mem.Compare,
134134
135 /// If you have a need for a version that caches this, please file a bug.135 /// If you have a need for a version that caches this, please file a bug.
136 pub fn first(tree: *Tree) ?*Node {136 pub fn first(tree: *Tree) ?*Node {
...@@ -180,7 +180,7 @@ pub const Tree = struct {...@@ -180,7 +180,7 @@ pub const Tree = struct {
180 while (node.get_parent()) |*parent| {180 while (node.get_parent()) |*parent| {
181 if (parent.*.is_black())181 if (parent.*.is_black())
182 break;182 break;
183 // the root is always black183 // the root is always black
184 var grandpa = parent.*.get_parent() orelse unreachable;184 var grandpa = parent.*.get_parent() orelse unreachable;
185185
186 if (parent.* == grandpa.left) {186 if (parent.* == grandpa.left) {
...@@ -206,7 +206,7 @@ pub const Tree = struct {...@@ -206,7 +206,7 @@ pub const Tree = struct {
206 }206 }
207 } else {207 } else {
208 var maybe_uncle = grandpa.left;208 var maybe_uncle = grandpa.left;
209 209
210 if (maybe_uncle) |uncle| {210 if (maybe_uncle) |uncle| {
211 if (uncle.is_black())211 if (uncle.is_black())
212 break;212 break;
...@@ -259,7 +259,7 @@ pub const Tree = struct {...@@ -259,7 +259,7 @@ pub const Tree = struct {
259 if (node.left == null) {259 if (node.left == null) {
260 next = node.right.?; // Not both null as per above260 next = node.right.?; // Not both null as per above
261 } else if (node.right == null) {261 } else if (node.right == null) {
262 next = node.left.?; // Not both null as per above262 next = node.left.?; // Not both null as per above
263 } else263 } else
264 next = node.right.?.get_first(); // Just checked for null above264 next = node.right.?.get_first(); // Just checked for null above
265265
...@@ -313,7 +313,7 @@ pub const Tree = struct {...@@ -313,7 +313,7 @@ pub const Tree = struct {
313 var parent = maybe_parent.?;313 var parent = maybe_parent.?;
314 if (node == parent.left) {314 if (node == parent.left) {
315 var sibling = parent.right.?; // Same number of black nodes.315 var sibling = parent.right.?; // Same number of black nodes.
316 316
317 if (sibling.is_red()) {317 if (sibling.is_red()) {
318 sibling.set_color(Black);318 sibling.set_color(Black);
319 parent.set_color(Red);319 parent.set_color(Red);
...@@ -321,7 +321,8 @@ pub const Tree = struct {...@@ -321,7 +321,8 @@ pub const Tree = struct {
321 sibling = parent.right.?; // Just rotated321 sibling = parent.right.?; // Just rotated
322 }322 }
323 if ((if (sibling.left) |n| n.is_black() else true) and323 if ((if (sibling.left) |n| n.is_black() else true) and
324 (if (sibling.right) |n| n.is_black() else true)) {324 (if (sibling.right) |n| n.is_black() else true))
325 {
325 sibling.set_color(Red);326 sibling.set_color(Red);
326 node = parent;327 node = parent;
327 maybe_parent = parent.get_parent();328 maybe_parent = parent.get_parent();
...@@ -341,7 +342,7 @@ pub const Tree = struct {...@@ -341,7 +342,7 @@ pub const Tree = struct {
341 break;342 break;
342 } else {343 } else {
343 var sibling = parent.left.?; // Same number of black nodes.344 var sibling = parent.left.?; // Same number of black nodes.
344 345
345 if (sibling.is_red()) {346 if (sibling.is_red()) {
346 sibling.set_color(Black);347 sibling.set_color(Black);
347 parent.set_color(Red);348 parent.set_color(Red);
...@@ -349,7 +350,8 @@ pub const Tree = struct {...@@ -349,7 +350,8 @@ pub const Tree = struct {
349 sibling = parent.left.?; // Just rotated350 sibling = parent.left.?; // Just rotated
350 }351 }
351 if ((if (sibling.left) |n| n.is_black() else true) and352 if ((if (sibling.left) |n| n.is_black() else true) and
352 (if (sibling.right) |n| n.is_black() else true)) {353 (if (sibling.right) |n| n.is_black() else true))
354 {
353 sibling.set_color(Red);355 sibling.set_color(Red);
354 node = parent;356 node = parent;
355 maybe_parent = parent.get_parent();357 maybe_parent = parent.get_parent();
...@@ -397,7 +399,7 @@ pub const Tree = struct {...@@ -397,7 +399,7 @@ pub const Tree = struct {
397 new.* = old.*;399 new.* = old.*;
398 }400 }
399401
400 pub fn init(tree: *Tree, f: fn(*Node, *Node) mem.Compare) void {402 pub fn init(tree: *Tree, f: fn (*Node, *Node) mem.Compare) void {
401 tree.root = null;403 tree.root = null;
402 tree.compareFn = f;404 tree.compareFn = f;
403 }405 }
std/special/build_runner.zig+2-2
...@@ -49,14 +49,14 @@ pub fn main() !void {...@@ -49,14 +49,14 @@ pub fn main() !void {
4949
50 var stderr_file = io.getStdErr();50 var stderr_file = io.getStdErr();
51 var stderr_file_stream: io.FileOutStream = undefined;51 var stderr_file_stream: io.FileOutStream = undefined;
52 var stderr_stream = if (stderr_file) |*f| x: {52 var stderr_stream = if (stderr_file) |f| x: {
53 stderr_file_stream = io.FileOutStream.init(f);53 stderr_file_stream = io.FileOutStream.init(f);
54 break :x &stderr_file_stream.stream;54 break :x &stderr_file_stream.stream;
55 } else |err| err;55 } else |err| err;
5656
57 var stdout_file = io.getStdOut();57 var stdout_file = io.getStdOut();
58 var stdout_file_stream: io.FileOutStream = undefined;58 var stdout_file_stream: io.FileOutStream = undefined;
59 var stdout_stream = if (stdout_file) |*f| x: {59 var stdout_stream = if (stdout_file) |f| x: {
60 stdout_file_stream = io.FileOutStream.init(f);60 stdout_file_stream = io.FileOutStream.init(f);
61 break :x &stdout_file_stream.stream;61 break :x &stdout_file_stream.stream;
62 } else |err| err;62 } else |err| err;
std/zig/parse.zig+56-13
...@@ -340,7 +340,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -340,7 +340,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
340 const node_ptr = try ctx.container_decl.fields_and_decls.addOne();340 const node_ptr = try ctx.container_decl.fields_and_decls.addOne();
341 node_ptr.* = &node.base;341 node_ptr.* = &node.base;
342342
343 stack.append(State{ .FieldListCommaOrEnd = ctx.container_decl }) catch unreachable;343 try stack.append(State{
344 .FieldListCommaOrEnd = FieldCtx{
345 .doc_comments = &node.doc_comments,
346 .container_decl = ctx.container_decl,
347 },
348 });
344 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.type_expr } });349 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.type_expr } });
345 try stack.append(State{ .ExpectToken = Token.Id.Colon });350 try stack.append(State{ .ExpectToken = Token.Id.Colon });
346 continue;351 continue;
...@@ -458,7 +463,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -458,7 +463,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
458 const node_ptr = try container_decl.fields_and_decls.addOne();463 const node_ptr = try container_decl.fields_and_decls.addOne();
459 node_ptr.* = &node.base;464 node_ptr.* = &node.base;
460465
461 try stack.append(State{ .FieldListCommaOrEnd = container_decl });466 try stack.append(State{
467 .FieldListCommaOrEnd = FieldCtx{
468 .doc_comments = &node.doc_comments,
469 .container_decl = container_decl,
470 },
471 });
462 try stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &node.type_expr } });472 try stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &node.type_expr } });
463 try stack.append(State{ .ExpectToken = Token.Id.Colon });473 try stack.append(State{ .ExpectToken = Token.Id.Colon });
464 continue;474 continue;
...@@ -473,7 +483,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -473,7 +483,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
473 });483 });
474 try container_decl.fields_and_decls.push(&node.base);484 try container_decl.fields_and_decls.push(&node.base);
475485
476 stack.append(State{ .FieldListCommaOrEnd = container_decl }) catch unreachable;486 try stack.append(State{
487 .FieldListCommaOrEnd = FieldCtx{
488 .doc_comments = &node.doc_comments,
489 .container_decl = container_decl,
490 },
491 });
477 try stack.append(State{ .FieldInitValue = OptionalCtx{ .RequiredNull = &node.value_expr } });492 try stack.append(State{ .FieldInitValue = OptionalCtx{ .RequiredNull = &node.value_expr } });
478 try stack.append(State{ .TypeExprBegin = OptionalCtx{ .RequiredNull = &node.type_expr } });493 try stack.append(State{ .TypeExprBegin = OptionalCtx{ .RequiredNull = &node.type_expr } });
479 try stack.append(State{ .IfToken = Token.Id.Colon });494 try stack.append(State{ .IfToken = Token.Id.Colon });
...@@ -488,7 +503,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -488,7 +503,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
488 });503 });
489 try container_decl.fields_and_decls.push(&node.base);504 try container_decl.fields_and_decls.push(&node.base);
490505
491 stack.append(State{ .FieldListCommaOrEnd = container_decl }) catch unreachable;506 try stack.append(State{
507 .FieldListCommaOrEnd = FieldCtx{
508 .doc_comments = &node.doc_comments,
509 .container_decl = container_decl,
510 },
511 });
492 try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &node.value } });512 try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &node.value } });
493 try stack.append(State{ .IfToken = Token.Id.Equal });513 try stack.append(State{ .IfToken = Token.Id.Equal });
494 continue;514 continue;
...@@ -1265,17 +1285,35 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -1265,17 +1285,35 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
1265 },1285 },
1266 }1286 }
1267 },1287 },
1268 State.FieldListCommaOrEnd => |container_decl| {1288 State.FieldListCommaOrEnd => |field_ctx| {
1269 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RBrace)) {1289 const end_token = nextToken(&tok_it, &tree);
1270 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {1290 const end_token_index = end_token.index;
1271 container_decl.rbrace_token = end;1291 const end_token_ptr = end_token.ptr;
1292 switch (end_token_ptr.id) {
1293 Token.Id.Comma => {
1294 if (eatToken(&tok_it, &tree, Token.Id.DocComment)) |doc_comment_token| {
1295 const loc = tree.tokenLocation(end_token_ptr.end, doc_comment_token);
1296 if (loc.line == 0) {
1297 try pushDocComment(arena, doc_comment_token, field_ctx.doc_comments);
1298 } else {
1299 prevToken(&tok_it, &tree);
1300 }
1301 }
1302
1303 try stack.append(State{ .ContainerDecl = field_ctx.container_decl });
1272 continue;1304 continue;
1273 } else {1305 },
1274 try stack.append(State{ .ContainerDecl = container_decl });1306 Token.Id.RBrace => {
1307 field_ctx.container_decl.rbrace_token = end_token_index;
1275 continue;1308 continue;
1276 },1309 },
1277 ExpectCommaOrEndResult.parse_error => |e| {1310 else => {
1278 try tree.errors.push(e);1311 try tree.errors.push(Error{
1312 .ExpectedCommaOrEnd = Error.ExpectedCommaOrEnd{
1313 .token = end_token_index,
1314 .end_id = end_token_ptr.id,
1315 },
1316 });
1279 return tree;1317 return tree;
1280 },1318 },
1281 }1319 }
...@@ -2813,6 +2851,11 @@ const ExprListCtx = struct {...@@ -2813,6 +2851,11 @@ const ExprListCtx = struct {
2813 ptr: *TokenIndex,2851 ptr: *TokenIndex,
2814};2852};
28152853
2854const FieldCtx = struct {
2855 container_decl: *ast.Node.ContainerDecl,
2856 doc_comments: *?*ast.Node.DocComment,
2857};
2858
2816fn ListSave(comptime List: type) type {2859fn ListSave(comptime List: type) type {
2817 return struct {2860 return struct {
2818 list: *List,2861 list: *List,
...@@ -2950,7 +2993,7 @@ const State = union(enum) {...@@ -2950,7 +2993,7 @@ const State = union(enum) {
2950 ExprListCommaOrEnd: ExprListCtx,2993 ExprListCommaOrEnd: ExprListCtx,
2951 FieldInitListItemOrEnd: ListSave(ast.Node.SuffixOp.Op.InitList),2994 FieldInitListItemOrEnd: ListSave(ast.Node.SuffixOp.Op.InitList),
2952 FieldInitListCommaOrEnd: ListSave(ast.Node.SuffixOp.Op.InitList),2995 FieldInitListCommaOrEnd: ListSave(ast.Node.SuffixOp.Op.InitList),
2953 FieldListCommaOrEnd: *ast.Node.ContainerDecl,2996 FieldListCommaOrEnd: FieldCtx,
2954 FieldInitValue: OptionalCtx,2997 FieldInitValue: OptionalCtx,
2955 ErrorTagListItemOrEnd: ListSave(ast.Node.ErrorSetDecl.DeclList),2998 ErrorTagListItemOrEnd: ListSave(ast.Node.ErrorSetDecl.DeclList),
2956 ErrorTagListCommaOrEnd: ListSave(ast.Node.ErrorSetDecl.DeclList),2999 ErrorTagListCommaOrEnd: ListSave(ast.Node.ErrorSetDecl.DeclList),
std/zig/parser_test.zig+18-1
...@@ -1,3 +1,20 @@...@@ -1,3 +1,20 @@
1test "zig fmt: correctly move doc comments on struct fields" {
2 try testTransform(
3 \\pub const section_64 = extern struct {
4 \\ sectname: [16]u8, /// name of this section
5 \\ segname: [16]u8, /// segment this section goes in
6 \\};
7 ,
8 \\pub const section_64 = extern struct {
9 \\ /// name of this section
10 \\ sectname: [16]u8,
11 \\ /// segment this section goes in
12 \\ segname: [16]u8,
13 \\};
14 \\
15 );
16}
17
1test "zig fmt: preserve space between async fn definitions" {18test "zig fmt: preserve space between async fn definitions" {
2 try testCanonical(19 try testCanonical(
3 \\async fn a() void {}20 \\async fn a() void {}
...@@ -1848,7 +1865,7 @@ var fixed_buffer_mem: [100 * 1024]u8 = undefined;...@@ -1848,7 +1865,7 @@ var fixed_buffer_mem: [100 * 1024]u8 = undefined;
18481865
1849fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *bool) ![]u8 {1866fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *bool) ![]u8 {
1850 var stderr_file = try io.getStdErr();1867 var stderr_file = try io.getStdErr();
1851 var stderr = &io.FileOutStream.init(&stderr_file).stream;1868 var stderr = &io.FileOutStream.init(stderr_file).stream;
18521869
1853 var tree = try std.zig.parse(allocator, source);1870 var tree = try std.zig.parse(allocator, source);
1854 defer tree.deinit();1871 defer tree.deinit();
test/behavior.zig+1
...@@ -11,6 +11,7 @@ comptime {...@@ -11,6 +11,7 @@ comptime {
11 _ = @import("cases/bugs/1111.zig");11 _ = @import("cases/bugs/1111.zig");
12 _ = @import("cases/bugs/1230.zig");12 _ = @import("cases/bugs/1230.zig");
13 _ = @import("cases/bugs/1277.zig");13 _ = @import("cases/bugs/1277.zig");
14 _ = @import("cases/bugs/1421.zig");
14 _ = @import("cases/bugs/394.zig");15 _ = @import("cases/bugs/394.zig");
15 _ = @import("cases/bugs/655.zig");16 _ = @import("cases/bugs/655.zig");
16 _ = @import("cases/bugs/656.zig");17 _ = @import("cases/bugs/656.zig");
test/cases/bugs/1421.zig created+14
...@@ -0,0 +1,14 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4
5const S = struct {
6 fn method() builtin.TypeInfo {
7 return @typeInfo(S);
8 }
9};
10
11test "functions with return type required to be comptime are generic" {
12 const ti = S.method();
13 assert(builtin.TypeId(ti) == builtin.TypeId.Struct);
14}
test/cases/cast.zig+38-9
...@@ -487,12 +487,41 @@ fn MakeType(comptime T: type) type {...@@ -487,12 +487,41 @@ fn MakeType(comptime T: type) type {
487}487}
488488
489test "implicit cast from *[N]T to ?[*]T" {489test "implicit cast from *[N]T to ?[*]T" {
490 var x: ?[*]u16 = null;
491 var y: [4]u16 = [4]u16 {0, 1, 2, 3};
492
493 x = &y;
494 assert(std.mem.eql(u16, x.?[0..4], y[0..4]));
495 x.?[0] = 8;
496 y[3] = 6;
497 assert(std.mem.eql(u16, x.?[0..4], y[0..4]));
498}
\ No newline at end of file
490 var x: ?[*]u16 = null;
491 var y: [4]u16 = [4]u16{ 0, 1, 2, 3 };
492
493 x = &y;
494 assert(std.mem.eql(u16, x.?[0..4], y[0..4]));
495 x.?[0] = 8;
496 y[3] = 6;
497 assert(std.mem.eql(u16, x.?[0..4], y[0..4]));
498}
499
500test "implicit cast from *T to ?*c_void" {
501 var a: u8 = 1;
502 incrementVoidPtrValue(&a);
503 std.debug.assert(a == 2);
504}
505
506fn incrementVoidPtrValue(value: ?*c_void) void {
507 @ptrCast(*u8, value.?).* += 1;
508}
509
510test "implicit cast from [*]T to ?*c_void" {
511 var a = []u8{ 3, 2, 1 };
512 incrementVoidPtrArray(a[0..].ptr, 3);
513 assert(std.mem.eql(u8, a, []u8{ 4, 3, 2 }));
514}
515
516fn incrementVoidPtrArray(array: ?*c_void, len: usize) void {
517 var n: usize = 0;
518 while (n < len) : (n += 1) {
519 @ptrCast([*]u8, array.?)[n] += 1;
520 }
521}
522
523test "*usize to *void" {
524 var i = usize(0);
525 var v = @ptrCast(*void, &i);
526 v.* = {};
527}
test/cases/eval.zig+22
...@@ -652,3 +652,25 @@ fn loopNTimes(comptime n: usize) void {...@@ -652,3 +652,25 @@ fn loopNTimes(comptime n: usize) void {
652 comptime var i = 0;652 comptime var i = 0;
653 inline while (i < n) : (i += 1) {}653 inline while (i < n) : (i += 1) {}
654}654}
655
656test "variable inside inline loop that has different types on different iterations" {
657 testVarInsideInlineLoop(true, u32(42));
658}
659
660fn testVarInsideInlineLoop(args: ...) void {
661 comptime var i = 0;
662 inline while (i < args.len) : (i += 1) {
663 const x = args[i];
664 if (i == 0) assert(x);
665 if (i == 1) assert(x == 42);
666 }
667}
668
669test "inline for with same type but different values" {
670 var res: usize = 0;
671 inline for ([]type{ [2]u8, [1]u8, [2]u8 }) |T| {
672 var a: T = undefined;
673 res += a.len;
674 }
675 assert(res == 5);
676}
test/cases/for.zig+2-4
...@@ -71,8 +71,7 @@ fn testBreakOuter() void {...@@ -71,8 +71,7 @@ fn testBreakOuter() void {
71 var array = "aoeu";71 var array = "aoeu";
72 var count: usize = 0;72 var count: usize = 0;
73 outer: for (array) |_| {73 outer: for (array) |_| {
74 // TODO shouldn't get error for redeclaring "_"74 for (array) |_| {
75 for (array) |_2| {
76 count += 1;75 count += 1;
77 break :outer;76 break :outer;
78 }77 }
...@@ -89,8 +88,7 @@ fn testContinueOuter() void {...@@ -89,8 +88,7 @@ fn testContinueOuter() void {
89 var array = "aoeu";88 var array = "aoeu";
90 var counter: usize = 0;89 var counter: usize = 0;
91 outer: for (array) |_| {90 outer: for (array) |_| {
92 // TODO shouldn't get error for redeclaring "_"91 for (array) |_| {
93 for (array) |_2| {
94 counter += 1;92 counter += 1;
95 continue :outer;93 continue :outer;
96 }94 }
test/compare_output.zig+15-15
...@@ -19,7 +19,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -19,7 +19,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
19 \\19 \\
20 \\pub fn main() void {20 \\pub fn main() void {
21 \\ privateFunction();21 \\ privateFunction();
22 \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream);22 \\ const stdout = &FileOutStream.init(getStdOut() catch unreachable).stream;
23 \\ stdout.print("OK 2\n") catch unreachable;23 \\ stdout.print("OK 2\n") catch unreachable;
24 \\}24 \\}
25 \\25 \\
...@@ -34,7 +34,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -34,7 +34,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
34 \\// purposefully conflicting function with main.zig34 \\// purposefully conflicting function with main.zig
35 \\// but it's private so it should be OK35 \\// but it's private so it should be OK
36 \\fn privateFunction() void {36 \\fn privateFunction() void {
37 \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream);37 \\ const stdout = &FileOutStream.init(getStdOut() catch unreachable).stream;
38 \\ stdout.print("OK 1\n") catch unreachable;38 \\ stdout.print("OK 1\n") catch unreachable;
39 \\}39 \\}
40 \\40 \\
...@@ -60,7 +60,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -60,7 +60,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
60 tc.addSourceFile("foo.zig",60 tc.addSourceFile("foo.zig",
61 \\use @import("std").io;61 \\use @import("std").io;
62 \\pub fn foo_function() void {62 \\pub fn foo_function() void {
63 \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream);63 \\ const stdout = &FileOutStream.init(getStdOut() catch unreachable).stream;
64 \\ stdout.print("OK\n") catch unreachable;64 \\ stdout.print("OK\n") catch unreachable;
65 \\}65 \\}
66 );66 );
...@@ -71,7 +71,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -71,7 +71,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
71 \\71 \\
72 \\pub fn bar_function() void {72 \\pub fn bar_function() void {
73 \\ if (foo_function()) {73 \\ if (foo_function()) {
74 \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream);74 \\ const stdout = &FileOutStream.init(getStdOut() catch unreachable).stream;
75 \\ stdout.print("OK\n") catch unreachable;75 \\ stdout.print("OK\n") catch unreachable;
76 \\ }76 \\ }
77 \\}77 \\}
...@@ -103,7 +103,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -103,7 +103,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
103 \\pub const a_text = "OK\n";103 \\pub const a_text = "OK\n";
104 \\104 \\
105 \\pub fn ok() void {105 \\pub fn ok() void {
106 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);106 \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
107 \\ stdout.print(b_text) catch unreachable;107 \\ stdout.print(b_text) catch unreachable;
108 \\}108 \\}
109 );109 );
...@@ -121,7 +121,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -121,7 +121,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
121 \\const io = @import("std").io;121 \\const io = @import("std").io;
122 \\122 \\
123 \\pub fn main() void {123 \\pub fn main() void {
124 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);124 \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
125 \\ stdout.print("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a')) catch unreachable;125 \\ stdout.print("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a')) catch unreachable;
126 \\}126 \\}
127 , "Hello, world!\n0012 012 a\n");127 , "Hello, world!\n0012 012 a\n");
...@@ -274,7 +274,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -274,7 +274,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
274 \\ var x_local : i32 = print_ok(x);274 \\ var x_local : i32 = print_ok(x);
275 \\}275 \\}
276 \\fn print_ok(val: @typeOf(x)) @typeOf(foo) {276 \\fn print_ok(val: @typeOf(x)) @typeOf(foo) {
277 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);277 \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
278 \\ stdout.print("OK\n") catch unreachable;278 \\ stdout.print("OK\n") catch unreachable;
279 \\ return 0;279 \\ return 0;
280 \\}280 \\}
...@@ -356,7 +356,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -356,7 +356,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
356 \\pub fn main() void {356 \\pub fn main() void {
357 \\ const bar = Bar {.field2 = 13,};357 \\ const bar = Bar {.field2 = 13,};
358 \\ const foo = Foo {.field1 = bar,};358 \\ const foo = Foo {.field1 = bar,};
359 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);359 \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
360 \\ if (!foo.method()) {360 \\ if (!foo.method()) {
361 \\ stdout.print("BAD\n") catch unreachable;361 \\ stdout.print("BAD\n") catch unreachable;
362 \\ }362 \\ }
...@@ -370,7 +370,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -370,7 +370,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
370 cases.add("defer with only fallthrough",370 cases.add("defer with only fallthrough",
371 \\const io = @import("std").io;371 \\const io = @import("std").io;
372 \\pub fn main() void {372 \\pub fn main() void {
373 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);373 \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
374 \\ stdout.print("before\n") catch unreachable;374 \\ stdout.print("before\n") catch unreachable;
375 \\ defer stdout.print("defer1\n") catch unreachable;375 \\ defer stdout.print("defer1\n") catch unreachable;
376 \\ defer stdout.print("defer2\n") catch unreachable;376 \\ defer stdout.print("defer2\n") catch unreachable;
...@@ -383,7 +383,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -383,7 +383,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
383 \\const io = @import("std").io;383 \\const io = @import("std").io;
384 \\const os = @import("std").os;384 \\const os = @import("std").os;
385 \\pub fn main() void {385 \\pub fn main() void {
386 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);386 \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
387 \\ stdout.print("before\n") catch unreachable;387 \\ stdout.print("before\n") catch unreachable;
388 \\ defer stdout.print("defer1\n") catch unreachable;388 \\ defer stdout.print("defer1\n") catch unreachable;
389 \\ defer stdout.print("defer2\n") catch unreachable;389 \\ defer stdout.print("defer2\n") catch unreachable;
...@@ -400,7 +400,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -400,7 +400,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
400 \\ do_test() catch return;400 \\ do_test() catch return;
401 \\}401 \\}
402 \\fn do_test() !void {402 \\fn do_test() !void {
403 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);403 \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
404 \\ stdout.print("before\n") catch unreachable;404 \\ stdout.print("before\n") catch unreachable;
405 \\ defer stdout.print("defer1\n") catch unreachable;405 \\ defer stdout.print("defer1\n") catch unreachable;
406 \\ errdefer stdout.print("deferErr\n") catch unreachable;406 \\ errdefer stdout.print("deferErr\n") catch unreachable;
...@@ -419,7 +419,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -419,7 +419,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
419 \\ do_test() catch return;419 \\ do_test() catch return;
420 \\}420 \\}
421 \\fn do_test() !void {421 \\fn do_test() !void {
422 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);422 \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
423 \\ stdout.print("before\n") catch unreachable;423 \\ stdout.print("before\n") catch unreachable;
424 \\ defer stdout.print("defer1\n") catch unreachable;424 \\ defer stdout.print("defer1\n") catch unreachable;
425 \\ errdefer stdout.print("deferErr\n") catch unreachable;425 \\ errdefer stdout.print("deferErr\n") catch unreachable;
...@@ -436,7 +436,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -436,7 +436,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
436 \\const io = @import("std").io;436 \\const io = @import("std").io;
437 \\437 \\
438 \\pub fn main() void {438 \\pub fn main() void {
439 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);439 \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
440 \\ stdout.print(foo_txt) catch unreachable;440 \\ stdout.print(foo_txt) catch unreachable;
441 \\}441 \\}
442 , "1234\nabcd\n");442 , "1234\nabcd\n");
...@@ -456,7 +456,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -456,7 +456,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
456 \\pub fn main() !void {456 \\pub fn main() !void {
457 \\ var args_it = os.args();457 \\ var args_it = os.args();
458 \\ var stdout_file = try io.getStdOut();458 \\ var stdout_file = try io.getStdOut();
459 \\ var stdout_adapter = io.FileOutStream.init(&stdout_file);459 \\ var stdout_adapter = io.FileOutStream.init(stdout_file);
460 \\ const stdout = &stdout_adapter.stream;460 \\ const stdout = &stdout_adapter.stream;
461 \\ var index: usize = 0;461 \\ var index: usize = 0;
462 \\ _ = args_it.skip();462 \\ _ = args_it.skip();
...@@ -497,7 +497,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -497,7 +497,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
497 \\pub fn main() !void {497 \\pub fn main() !void {
498 \\ var args_it = os.args();498 \\ var args_it = os.args();
499 \\ var stdout_file = try io.getStdOut();499 \\ var stdout_file = try io.getStdOut();
500 \\ var stdout_adapter = io.FileOutStream.init(&stdout_file);500 \\ var stdout_adapter = io.FileOutStream.init(stdout_file);
501 \\ const stdout = &stdout_adapter.stream;501 \\ const stdout = &stdout_adapter.stream;
502 \\ var index: usize = 0;502 \\ var index: usize = 0;
503 \\ _ = args_it.skip();503 \\ _ = args_it.skip();
test/compile_errors.zig+43
...@@ -1,6 +1,49 @@...@@ -1,6 +1,49 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: *tests.CompileErrorContext) void {3pub fn addCases(cases: *tests.CompileErrorContext) void {
4 cases.add(
5 "switch with invalid expression parameter",
6 \\export fn entry() void {
7 \\ Test(i32);
8 \\}
9 \\fn Test(comptime T: type) void {
10 \\ const x = switch (T) {
11 \\ []u8 => |x| 123,
12 \\ i32 => |x| 456,
13 \\ else => unreachable,
14 \\ };
15 \\}
16 ,
17 ".tmp_source.zig:7:17: error: switch on type 'type' provides no expression parameter",
18 );
19
20 cases.add(
21 "function protoype with no body",
22 \\fn foo() void;
23 \\export fn entry() void {
24 \\ foo();
25 \\}
26 ,
27 ".tmp_source.zig:1:1: error: non-extern function has no body",
28 );
29
30 cases.add(
31 "@typeInfo causing depend on itself compile error",
32 \\const start = struct {
33 \\ fn crash() bug() {
34 \\ return bug;
35 \\ }
36 \\};
37 \\fn bug() void {
38 \\ _ = @typeInfo(start).Struct;
39 \\}
40 \\export fn entry() void {
41 \\ var boom = start.crash();
42 \\}
43 ,
44 ".tmp_source.zig:2:5: error: 'crash' depends on itself",
45 );
46
4 cases.add(47 cases.add(
5 "@handle() called outside of function definition",48 "@handle() called outside of function definition",
6 \\var handle_undef: promise = undefined;49 \\var handle_undef: promise = undefined;
test/tests.zig+6-6
...@@ -263,8 +263,8 @@ pub const CompareOutputContext = struct {...@@ -263,8 +263,8 @@ pub const CompareOutputContext = struct {
263 var stdout = Buffer.initNull(b.allocator);263 var stdout = Buffer.initNull(b.allocator);
264 var stderr = Buffer.initNull(b.allocator);264 var stderr = Buffer.initNull(b.allocator);
265265
266 var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);266 var stdout_file_in_stream = io.FileInStream.init(child.stdout.?);
267 var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);267 var stderr_file_in_stream = io.FileInStream.init(child.stderr.?);
268268
269 stdout_file_in_stream.stream.readAllBuffer(&stdout, max_stdout_size) catch unreachable;269 stdout_file_in_stream.stream.readAllBuffer(&stdout, max_stdout_size) catch unreachable;
270 stderr_file_in_stream.stream.readAllBuffer(&stderr, max_stdout_size) catch unreachable;270 stderr_file_in_stream.stream.readAllBuffer(&stderr, max_stdout_size) catch unreachable;
...@@ -578,8 +578,8 @@ pub const CompileErrorContext = struct {...@@ -578,8 +578,8 @@ pub const CompileErrorContext = struct {
578 var stdout_buf = Buffer.initNull(b.allocator);578 var stdout_buf = Buffer.initNull(b.allocator);
579 var stderr_buf = Buffer.initNull(b.allocator);579 var stderr_buf = Buffer.initNull(b.allocator);
580580
581 var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);581 var stdout_file_in_stream = io.FileInStream.init(child.stdout.?);
582 var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);582 var stderr_file_in_stream = io.FileInStream.init(child.stderr.?);
583583
584 stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable;584 stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable;
585 stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable;585 stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable;
...@@ -842,8 +842,8 @@ pub const TranslateCContext = struct {...@@ -842,8 +842,8 @@ pub const TranslateCContext = struct {
842 var stdout_buf = Buffer.initNull(b.allocator);842 var stdout_buf = Buffer.initNull(b.allocator);
843 var stderr_buf = Buffer.initNull(b.allocator);843 var stderr_buf = Buffer.initNull(b.allocator);
844844
845 var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);845 var stdout_file_in_stream = io.FileInStream.init(child.stdout.?);
846 var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);846 var stderr_file_in_stream = io.FileInStream.init(child.stderr.?);
847847
848 stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable;848 stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable;
849 stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable;849 stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable;