authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-12 10:48:38-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-12 10:48:38-07:00
logaf4cc20ce275aeb0e59eee3d893b2f310c1f0239
treecc3ff8fa792c20ff0fc0f1e19e98998cc76c07c2
parent03a23418ff13e6ff64cdeed3ef4b54f99c533d88
parent9fe4c89230df2d78c8bf37b4b1d7a9bedb92677b

Merge remote-tracking branch 'origin/master' into stage2-zig-cc

Master branch added in the concept of library versioning being optional to main.cpp. It will need to be re-added into this branch before merging back into master.

34 files changed, 1680 insertions(+), 119 deletions(-)

README.md+18
...@@ -76,3 +76,21 @@ Hopefully this will be fixed upstream with LLVM 10.0.1....@@ -76,3 +76,21 @@ Hopefully this will be fixed upstream with LLVM 10.0.1.
76##### Windows76##### Windows
7777
78See https://github.com/ziglang/zig/wiki/Building-Zig-on-Windows78See https://github.com/ziglang/zig/wiki/Building-Zig-on-Windows
79
80## License
81
82The ultimate goal of the Zig project is to serve users. As a first-order
83effect, this means users of the compiler, helping programmers to write better
84code. Even more important, however, are the end users.
85
86Zig is intended to be used to help end users accomplish their goals. For
87example, it would be inappropriate and offensive to use Zig to implement
88[dark patterns](https://en.wikipedia.org/wiki/Dark_pattern) and it would be
89shameful to utilize Zig to exploit people instead of benefit them.
90
91However, such problems are best solved with social norms, not with software
92licenses. Any attempt to complicate the software license of Zig would risk
93compromising the value Zig provides to users.
94
95Therefore, Zig is available under the MIT (Expat) License, and comes with a
96humble request: use it to make software better serve the needs of end users.
build.zig+1
...@@ -65,6 +65,7 @@ pub fn build(b: *Builder) !void {...@@ -65,6 +65,7 @@ pub fn build(b: *Builder) !void {
65 "README.md",65 "README.md",
66 ".z.0",66 ".z.0",
67 ".z.9",67 ".z.9",
68 ".gz",
68 "rfc1951.txt",69 "rfc1951.txt",
69 },70 },
70 });71 });
lib/std/build.zig+80-44
...@@ -258,9 +258,14 @@ pub const Builder = struct {...@@ -258,9 +258,14 @@ pub const Builder = struct {
258 }));258 }));
259 }259 }
260260
261 pub fn addSharedLibrary(self: *Builder, name: []const u8, root_src: ?[]const u8, ver: Version) *LibExeObjStep {261 pub fn addSharedLibrary(
262 self: *Builder,
263 name: []const u8,
264 root_src: ?[]const u8,
265 kind: LibExeObjStep.SharedLibKind,
266 ) *LibExeObjStep {
262 const root_src_param = if (root_src) |p| @as(FileSource, .{ .path = p }) else null;267 const root_src_param = if (root_src) |p| @as(FileSource, .{ .path = p }) else null;
263 return LibExeObjStep.createSharedLibrary(self, name, root_src_param, ver);268 return LibExeObjStep.createSharedLibrary(self, name, root_src_param, kind);
264 }269 }
265270
266 pub fn addStaticLibrary(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {271 pub fn addStaticLibrary(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
...@@ -338,11 +343,13 @@ pub const Builder = struct {...@@ -338,11 +343,13 @@ pub const Builder = struct {
338 return TranslateCStep.create(self, source);343 return TranslateCStep.create(self, source);
339 }344 }
340345
341 pub fn version(self: *const Builder, major: u32, minor: u32, patch: u32) Version {346 pub fn version(self: *const Builder, major: u32, minor: u32, patch: u32) LibExeObjStep.SharedLibKind {
342 return Version{347 return .{
343 .major = major,348 .versioned = .{
344 .minor = minor,349 .major = major,
345 .patch = patch,350 .minor = minor,
351 .patch = patch,
352 },
346 };353 };
347 }354 }
348355
...@@ -1048,6 +1055,7 @@ pub const Builder = struct {...@@ -1048,6 +1055,7 @@ pub const Builder = struct {
1048 .Bin => self.exe_dir,1055 .Bin => self.exe_dir,
1049 .Lib => self.lib_dir,1056 .Lib => self.lib_dir,
1050 .Header => self.h_dir,1057 .Header => self.h_dir,
1058 .Custom => |path| fs.path.join(self.allocator, &[_][]const u8{ self.install_path, path }) catch unreachable,
1051 };1059 };
1052 return fs.path.resolve(1060 return fs.path.resolve(
1053 self.allocator,1061 self.allocator,
...@@ -1166,7 +1174,7 @@ pub const LibExeObjStep = struct {...@@ -1166,7 +1174,7 @@ pub const LibExeObjStep = struct {
1166 version_script: ?[]const u8 = null,1174 version_script: ?[]const u8 = null,
1167 out_filename: []const u8,1175 out_filename: []const u8,
1168 is_dynamic: bool,1176 is_dynamic: bool,
1169 version: Version,1177 version: ?Version,
1170 build_mode: builtin.Mode,1178 build_mode: builtin.Mode,
1171 kind: Kind,1179 kind: Kind,
1172 major_only_filename: []const u8,1180 major_only_filename: []const u8,
...@@ -1212,6 +1220,8 @@ pub const LibExeObjStep = struct {...@@ -1212,6 +1220,8 @@ pub const LibExeObjStep = struct {
1212 is_linking_libc: bool = false,1220 is_linking_libc: bool = false,
1213 vcpkg_bin_path: ?[]const u8 = null,1221 vcpkg_bin_path: ?[]const u8 = null,
12141222
1223 /// This may be set in order to override the default install directory
1224 override_dest_dir: ?InstallDir,
1215 installed_path: ?[]const u8,1225 installed_path: ?[]const u8,
1216 install_step: ?*InstallArtifactStep,1226 install_step: ?*InstallArtifactStep,
12171227
...@@ -1268,33 +1278,41 @@ pub const LibExeObjStep = struct {...@@ -1268,33 +1278,41 @@ pub const LibExeObjStep = struct {
1268 Test,1278 Test,
1269 };1279 };
12701280
1271 pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?FileSource, ver: Version) *LibExeObjStep {1281 const SharedLibKind = union(enum) {
1282 versioned: Version,
1283 unversioned: void,
1284 };
1285
1286 pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?FileSource, kind: SharedLibKind) *LibExeObjStep {
1272 const self = builder.allocator.create(LibExeObjStep) catch unreachable;1287 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
1273 self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, ver);1288 self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, switch (kind) {
1289 .versioned => |ver| ver,
1290 .unversioned => null,
1291 });
1274 return self;1292 return self;
1275 }1293 }
12761294
1277 pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep {1295 pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep {
1278 const self = builder.allocator.create(LibExeObjStep) catch unreachable;1296 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
1279 self.* = initExtraArgs(builder, name, root_src, Kind.Lib, false, builder.version(0, 0, 0));1297 self.* = initExtraArgs(builder, name, root_src, Kind.Lib, false, null);
1280 return self;1298 return self;
1281 }1299 }
12821300
1283 pub fn createObject(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep {1301 pub fn createObject(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep {
1284 const self = builder.allocator.create(LibExeObjStep) catch unreachable;1302 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
1285 self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0));1303 self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, null);
1286 return self;1304 return self;
1287 }1305 }
12881306
1289 pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?FileSource, is_dynamic: bool) *LibExeObjStep {1307 pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?FileSource, is_dynamic: bool) *LibExeObjStep {
1290 const self = builder.allocator.create(LibExeObjStep) catch unreachable;1308 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
1291 self.* = initExtraArgs(builder, name, root_src, Kind.Exe, is_dynamic, builder.version(0, 0, 0));1309 self.* = initExtraArgs(builder, name, root_src, Kind.Exe, is_dynamic, null);
1292 return self;1310 return self;
1293 }1311 }
12941312
1295 pub fn createTest(builder: *Builder, name: []const u8, root_src: FileSource) *LibExeObjStep {1313 pub fn createTest(builder: *Builder, name: []const u8, root_src: FileSource) *LibExeObjStep {
1296 const self = builder.allocator.create(LibExeObjStep) catch unreachable;1314 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
1297 self.* = initExtraArgs(builder, name, root_src, Kind.Test, false, builder.version(0, 0, 0));1315 self.* = initExtraArgs(builder, name, root_src, Kind.Test, false, null);
1298 return self;1316 return self;
1299 }1317 }
13001318
...@@ -1304,7 +1322,7 @@ pub const LibExeObjStep = struct {...@@ -1304,7 +1322,7 @@ pub const LibExeObjStep = struct {
1304 root_src: ?FileSource,1322 root_src: ?FileSource,
1305 kind: Kind,1323 kind: Kind,
1306 is_dynamic: bool,1324 is_dynamic: bool,
1307 ver: Version,1325 ver: ?Version,
1308 ) LibExeObjStep {1326 ) LibExeObjStep {
1309 if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) {1327 if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) {
1310 panic("invalid name: '{}'. It looks like a file path, but it is supposed to be the library or application name.", .{name});1328 panic("invalid name: '{}'. It looks like a file path, but it is supposed to be the library or application name.", .{name});
...@@ -1348,6 +1366,7 @@ pub const LibExeObjStep = struct {...@@ -1348,6 +1366,7 @@ pub const LibExeObjStep = struct {
1348 .rdynamic = false,1366 .rdynamic = false,
1349 .output_dir = null,1367 .output_dir = null,
1350 .single_threaded = false,1368 .single_threaded = false,
1369 .override_dest_dir = null,
1351 .installed_path = null,1370 .installed_path = null,
1352 .install_step = null,1371 .install_step = null,
1353 };1372 };
...@@ -1375,17 +1394,17 @@ pub const LibExeObjStep = struct {...@@ -1375,17 +1394,17 @@ pub const LibExeObjStep = struct {
1375 self.target.staticLibSuffix(),1394 self.target.staticLibSuffix(),
1376 });1395 });
1377 self.out_lib_filename = self.out_filename;1396 self.out_lib_filename = self.out_filename;
1378 } else {1397 } else if (self.version) |version| {
1379 if (self.target.isDarwin()) {1398 if (self.target.isDarwin()) {
1380 self.out_filename = self.builder.fmt("lib{}.{d}.{d}.{d}.dylib", .{1399 self.out_filename = self.builder.fmt("lib{}.{d}.{d}.{d}.dylib", .{
1381 self.name,1400 self.name,
1382 self.version.major,1401 version.major,
1383 self.version.minor,1402 version.minor,
1384 self.version.patch,1403 version.patch,
1385 });1404 });
1386 self.major_only_filename = self.builder.fmt("lib{}.{d}.dylib", .{1405 self.major_only_filename = self.builder.fmt("lib{}.{d}.dylib", .{
1387 self.name,1406 self.name,
1388 self.version.major,1407 version.major,
1389 });1408 });
1390 self.name_only_filename = self.builder.fmt("lib{}.dylib", .{self.name});1409 self.name_only_filename = self.builder.fmt("lib{}.dylib", .{self.name});
1391 self.out_lib_filename = self.out_filename;1410 self.out_lib_filename = self.out_filename;
...@@ -1395,14 +1414,25 @@ pub const LibExeObjStep = struct {...@@ -1395,14 +1414,25 @@ pub const LibExeObjStep = struct {
1395 } else {1414 } else {
1396 self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}", .{1415 self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}", .{
1397 self.name,1416 self.name,
1398 self.version.major,1417 version.major,
1399 self.version.minor,1418 version.minor,
1400 self.version.patch,1419 version.patch,
1401 });1420 });
1402 self.major_only_filename = self.builder.fmt("lib{}.so.{d}", .{ self.name, self.version.major });1421 self.major_only_filename = self.builder.fmt("lib{}.so.{d}", .{ self.name, version.major });
1403 self.name_only_filename = self.builder.fmt("lib{}.so", .{self.name});1422 self.name_only_filename = self.builder.fmt("lib{}.so", .{self.name});
1404 self.out_lib_filename = self.out_filename;1423 self.out_lib_filename = self.out_filename;
1405 }1424 }
1425 } else {
1426 if (self.target.isDarwin()) {
1427 self.out_filename = self.builder.fmt("lib{}.dylib", .{self.name});
1428 self.out_lib_filename = self.out_filename;
1429 } else if (self.target.isWindows()) {
1430 self.out_filename = self.builder.fmt("{}.dll", .{self.name});
1431 self.out_lib_filename = self.builder.fmt("{}.lib", .{self.name});
1432 } else {
1433 self.out_filename = self.builder.fmt("lib{}.so", .{self.name});
1434 self.out_lib_filename = self.out_filename;
1435 }
1406 }1436 }
1407 },1437 },
1408 }1438 }
...@@ -2037,14 +2067,16 @@ pub const LibExeObjStep = struct {...@@ -2037,14 +2067,16 @@ pub const LibExeObjStep = struct {
2037 zig_args.append(self.name) catch unreachable;2067 zig_args.append(self.name) catch unreachable;
20382068
2039 if (self.kind == Kind.Lib and self.is_dynamic) {2069 if (self.kind == Kind.Lib and self.is_dynamic) {
2040 zig_args.append("--ver-major") catch unreachable;2070 if (self.version) |version| {
2041 zig_args.append(builder.fmt("{}", .{self.version.major})) catch unreachable;2071 zig_args.append("--ver-major") catch unreachable;
2072 zig_args.append(builder.fmt("{}", .{version.major})) catch unreachable;
20422073
2043 zig_args.append("--ver-minor") catch unreachable;2074 zig_args.append("--ver-minor") catch unreachable;
2044 zig_args.append(builder.fmt("{}", .{self.version.minor})) catch unreachable;2075 zig_args.append(builder.fmt("{}", .{version.minor})) catch unreachable;
20452076
2046 zig_args.append("--ver-patch") catch unreachable;2077 zig_args.append("--ver-patch") catch unreachable;
2047 zig_args.append(builder.fmt("{}", .{self.version.patch})) catch unreachable;2078 zig_args.append(builder.fmt("{}", .{version.patch})) catch unreachable;
2079 }
2048 }2080 }
2049 if (self.is_dynamic) {2081 if (self.is_dynamic) {
2050 try zig_args.append("-dynamic");2082 try zig_args.append("-dynamic");
...@@ -2285,7 +2317,7 @@ pub const LibExeObjStep = struct {...@@ -2285,7 +2317,7 @@ pub const LibExeObjStep = struct {
2285 }2317 }
2286 }2318 }
22872319
2288 if (self.kind == Kind.Lib and self.is_dynamic and self.target.wantSharedLibSymLinks()) {2320 if (self.kind == Kind.Lib and self.is_dynamic and self.version != null and self.target.wantSharedLibSymLinks()) {
2289 try doAtomicSymLinks(builder.allocator, self.getOutputPath(), self.major_only_filename, self.name_only_filename);2321 try doAtomicSymLinks(builder.allocator, self.getOutputPath(), self.major_only_filename, self.name_only_filename);
2290 }2322 }
2291 }2323 }
...@@ -2309,17 +2341,17 @@ pub const InstallArtifactStep = struct {...@@ -2309,17 +2341,17 @@ pub const InstallArtifactStep = struct {
2309 .builder = builder,2341 .builder = builder,
2310 .step = Step.init(.InstallArtifact, builder.fmt("install {}", .{artifact.step.name}), builder.allocator, make),2342 .step = Step.init(.InstallArtifact, builder.fmt("install {}", .{artifact.step.name}), builder.allocator, make),
2311 .artifact = artifact,2343 .artifact = artifact,
2312 .dest_dir = switch (artifact.kind) {2344 .dest_dir = artifact.override_dest_dir orelse switch (artifact.kind) {
2313 .Obj => unreachable,2345 .Obj => unreachable,
2314 .Test => unreachable,2346 .Test => unreachable,
2315 .Exe => .Bin,2347 .Exe => InstallDir{ .Bin = {} },
2316 .Lib => .Lib,2348 .Lib => InstallDir{ .Lib = {} },
2317 },2349 },
2318 .pdb_dir = if (artifact.producesPdbFile()) blk: {2350 .pdb_dir = if (artifact.producesPdbFile()) blk: {
2319 if (artifact.kind == .Exe) {2351 if (artifact.kind == .Exe) {
2320 break :blk InstallDir.Bin;2352 break :blk InstallDir{ .Bin = {} };
2321 } else {2353 } else {
2322 break :blk InstallDir.Lib;2354 break :blk InstallDir{ .Lib = {} };
2323 }2355 }
2324 } else null,2356 } else null,
2325 .h_dir = if (artifact.kind == .Lib and artifact.emit_h) .Header else null,2357 .h_dir = if (artifact.kind == .Lib and artifact.emit_h) .Header else null,
...@@ -2329,8 +2361,10 @@ pub const InstallArtifactStep = struct {...@@ -2329,8 +2361,10 @@ pub const InstallArtifactStep = struct {
23292361
2330 builder.pushInstalledFile(self.dest_dir, artifact.out_filename);2362 builder.pushInstalledFile(self.dest_dir, artifact.out_filename);
2331 if (self.artifact.isDynamicLibrary()) {2363 if (self.artifact.isDynamicLibrary()) {
2332 builder.pushInstalledFile(.Lib, artifact.major_only_filename);2364 if (self.artifact.version != null) {
2333 builder.pushInstalledFile(.Lib, artifact.name_only_filename);2365 builder.pushInstalledFile(.Lib, artifact.major_only_filename);
2366 builder.pushInstalledFile(.Lib, artifact.name_only_filename);
2367 }
2334 if (self.artifact.target.isWindows()) {2368 if (self.artifact.target.isWindows()) {
2335 builder.pushInstalledFile(.Lib, artifact.out_lib_filename);2369 builder.pushInstalledFile(.Lib, artifact.out_lib_filename);
2336 }2370 }
...@@ -2350,7 +2384,7 @@ pub const InstallArtifactStep = struct {...@@ -2350,7 +2384,7 @@ pub const InstallArtifactStep = struct {
23502384
2351 const full_dest_path = builder.getInstallPath(self.dest_dir, self.artifact.out_filename);2385 const full_dest_path = builder.getInstallPath(self.dest_dir, self.artifact.out_filename);
2352 try builder.updateFile(self.artifact.getOutputPath(), full_dest_path);2386 try builder.updateFile(self.artifact.getOutputPath(), full_dest_path);
2353 if (self.artifact.isDynamicLibrary() and self.artifact.target.wantSharedLibSymLinks()) {2387 if (self.artifact.isDynamicLibrary() and self.artifact.version != null and self.artifact.target.wantSharedLibSymLinks()) {
2354 try doAtomicSymLinks(builder.allocator, full_dest_path, self.artifact.major_only_filename, self.artifact.name_only_filename);2388 try doAtomicSymLinks(builder.allocator, full_dest_path, self.artifact.major_only_filename, self.artifact.name_only_filename);
2355 }2389 }
2356 if (self.pdb_dir) |pdb_dir| {2390 if (self.pdb_dir) |pdb_dir| {
...@@ -2615,11 +2649,13 @@ const VcpkgRootStatus = enum {...@@ -2615,11 +2649,13 @@ const VcpkgRootStatus = enum {
26152649
2616pub const VcpkgLinkage = std.builtin.LinkMode;2650pub const VcpkgLinkage = std.builtin.LinkMode;
26172651
2618pub const InstallDir = enum {2652pub const InstallDir = union(enum) {
2619 Prefix,2653 Prefix: void,
2620 Lib,2654 Lib: void,
2621 Bin,2655 Bin: void,
2622 Header,2656 Header: void,
2657 /// A path relative to the prefix
2658 Custom: []const u8,
2623};2659};
26242660
2625pub const InstalledFile = struct {2661pub const InstalledFile = struct {
lib/std/c.zig+11-4
...@@ -132,8 +132,6 @@ pub usingnamespace switch (builtin.os.tag) {...@@ -132,8 +132,6 @@ pub usingnamespace switch (builtin.os.tag) {
132 },132 },
133};133};
134134
135pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
136pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;
137pub extern "c" fn rmdir(path: [*:0]const u8) c_int;135pub extern "c" fn rmdir(path: [*:0]const u8) c_int;
138pub extern "c" fn getenv(name: [*:0]const u8) ?[*:0]u8;136pub extern "c" fn getenv(name: [*:0]const u8) ?[*:0]u8;
139pub extern "c" fn sysctl(name: [*]const c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;137pub extern "c" fn sysctl(name: [*]const c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
...@@ -237,8 +235,15 @@ pub usingnamespace switch (builtin.os.tag) {...@@ -237,8 +235,15 @@ pub usingnamespace switch (builtin.os.tag) {
237235
238pub extern "c" fn kill(pid: pid_t, sig: c_int) c_int;236pub extern "c" fn kill(pid: pid_t, sig: c_int) c_int;
239pub extern "c" fn getdirentries(fd: fd_t, buf_ptr: [*]u8, nbytes: usize, basep: *i64) isize;237pub extern "c" fn getdirentries(fd: fd_t, buf_ptr: [*]u8, nbytes: usize, basep: *i64) isize;
240pub extern "c" fn setgid(ruid: c_uint, euid: c_uint) c_int;238
241pub extern "c" fn setuid(uid: c_uint) c_int;239pub extern "c" fn setuid(uid: uid_t) c_int;
240pub extern "c" fn setgid(gid: gid_t) c_int;
241pub extern "c" fn seteuid(euid: uid_t) c_int;
242pub extern "c" fn setegid(egid: gid_t) c_int;
243pub extern "c" fn setreuid(ruid: uid_t, euid: uid_t) c_int;
244pub extern "c" fn setregid(rgid: gid_t, egid: gid_t) c_int;
245pub extern "c" fn setresuid(ruid: uid_t, euid: uid_t, suid: uid_t) c_int;
246pub extern "c" fn setresgid(rgid: gid_t, egid: gid_t, sgid: gid_t) c_int;
242247
243pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?*c_void;248pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?*c_void;
244pub extern "c" fn malloc(usize) ?*c_void;249pub extern "c" fn malloc(usize) ?*c_void;
...@@ -335,3 +340,5 @@ pub extern "c" fn sync() void;...@@ -335,3 +340,5 @@ pub extern "c" fn sync() void;
335pub extern "c" fn syncfs(fd: c_int) c_int;340pub extern "c" fn syncfs(fd: c_int) c_int;
336pub extern "c" fn fsync(fd: c_int) c_int;341pub extern "c" fn fsync(fd: c_int) c_int;
337pub extern "c" fn fdatasync(fd: c_int) c_int;342pub extern "c" fn fdatasync(fd: c_int) c_int;
343
344pub extern "c" fn prctl(option: c_int, ...) c_int;
lib/std/compress.zig+2
...@@ -6,8 +6,10 @@...@@ -6,8 +6,10 @@
6const std = @import("std.zig");6const std = @import("std.zig");
77
8pub const deflate = @import("compress/deflate.zig");8pub const deflate = @import("compress/deflate.zig");
9pub const gzip = @import("compress/gzip.zig");
9pub const zlib = @import("compress/zlib.zig");10pub const zlib = @import("compress/zlib.zig");
1011
11test "" {12test "" {
13 _ = gzip;
12 _ = zlib;14 _ = zlib;
13}15}
lib/std/compress/deflate.zig+149-35
...@@ -21,48 +21,121 @@ const MAXDCODES = 30;...@@ -21,48 +21,121 @@ const MAXDCODES = 30;
21const MAXCODES = MAXLCODES + MAXDCODES;21const MAXCODES = MAXLCODES + MAXDCODES;
22const FIXLCODES = 288;22const FIXLCODES = 288;
2323
24// The maximum length of a Huffman code's prefix we can decode using the fast
25// path. The factor 9 is inherited from Zlib, tweaking the value showed little
26// or no changes in the profiler output.
27const PREFIX_LUT_BITS = 9;
28
24const Huffman = struct {29const Huffman = struct {
30 // Number of codes for each possible length
25 count: [MAXBITS + 1]u16,31 count: [MAXBITS + 1]u16,
32 // Mapping between codes and symbols
26 symbol: [MAXCODES]u16,33 symbol: [MAXCODES]u16,
2734
28 fn construct(self: *Huffman, length: []const u16) !void {35 // The decoding process uses a trick explained by Mark Adler in [1].
36 // We basically precompute for a fixed number of codes (0 <= x <= 2^N-1)
37 // the symbol and the effective code length we'd get if the decoder was run
38 // on the given N-bit sequence.
39 // A code with length 0 means the sequence is not a valid prefix for this
40 // canonical Huffman code and we have to decode it using a slower method.
41 //
42 // [1] https://github.com/madler/zlib/blob/v1.2.11/doc/algorithm.txt#L58
43 prefix_lut: [1 << PREFIX_LUT_BITS]u16,
44 prefix_lut_len: [1 << PREFIX_LUT_BITS]u16,
45 // The following info refer to the codes of length PREFIX_LUT_BITS+1 and are
46 // used to bootstrap the bit-by-bit reading method if the fast-path fails.
47 last_code: u16,
48 last_index: u16,
49
50 fn construct(self: *Huffman, code_length: []const u16) !void {
29 for (self.count) |*val| {51 for (self.count) |*val| {
30 val.* = 0;52 val.* = 0;
31 }53 }
3254
33 for (length) |val| {55 for (code_length) |len| {
34 self.count[val] += 1;56 self.count[len] += 1;
35 }57 }
3658
37 if (self.count[0] == length.len)59 // All zero.
60 if (self.count[0] == code_length.len)
38 return;61 return;
3962
40 var left: isize = 1;63 var left: isize = 1;
41 for (self.count[1..]) |val| {64 for (self.count[1..]) |val| {
65 // Each added bit doubles the amount of codes.
42 left *= 2;66 left *= 2;
67 // Make sure the number of codes with this length isn't too high.
43 left -= @as(isize, @bitCast(i16, val));68 left -= @as(isize, @bitCast(i16, val));
44 if (left < 0)69 if (left < 0)
45 return error.InvalidTree;70 return error.InvalidTree;
46 }71 }
4772
48 var offs: [MAXBITS + 1]u16 = undefined;73 // Compute the offset of the first symbol represented by a code of a
74 // given length in the symbol table, together with the first canonical
75 // Huffman code for that length.
76 var offset: [MAXBITS + 1]u16 = undefined;
77 var codes: [MAXBITS + 1]u16 = undefined;
49 {78 {
79 offset[1] = 0;
80 codes[1] = 0;
50 var len: usize = 1;81 var len: usize = 1;
51 offs[1] = 0;
52 while (len < MAXBITS) : (len += 1) {82 while (len < MAXBITS) : (len += 1) {
53 offs[len + 1] = offs[len] + self.count[len];83 offset[len + 1] = offset[len] + self.count[len];
84 codes[len + 1] = (codes[len] + self.count[len]) << 1;
54 }85 }
55 }86 }
5687
57 for (length) |val, symbol| {88 self.prefix_lut_len = mem.zeroes(@TypeOf(self.prefix_lut_len));
58 if (val != 0) {89
59 self.symbol[offs[val]] = @truncate(u16, symbol);90 for (code_length) |len, symbol| {
60 offs[val] += 1;91 if (len != 0) {
92 // Fill the symbol table.
93 // The symbols are assigned sequentially for each length.
94 self.symbol[offset[len]] = @truncate(u16, symbol);
95 // Track the last assigned offset
96 offset[len] += 1;
97 }
98
99 if (len == 0 or len > PREFIX_LUT_BITS)
100 continue;
101
102 // Given a Huffman code of length N we have to massage it so
103 // that it becomes an index in the lookup table.
104 // The bit order is reversed as the fast path reads the bit
105 // sequence MSB to LSB using an &, the order is flipped wrt the
106 // one obtained by reading bit-by-bit.
107 // The codes are prefix-free, if the prefix matches we can
108 // safely ignore the trail bits. We do so by replicating the
109 // symbol info for each combination of the trailing bits.
110 const bits_to_fill = @intCast(u5, PREFIX_LUT_BITS - len);
111 const rev_code = bitReverse(codes[len], len);
112 // Track the last used code, but only for lengths < PREFIX_LUT_BITS
113 codes[len] += 1;
114
115 var j: usize = 0;
116 while (j < @as(usize, 1) << bits_to_fill) : (j += 1) {
117 const index = rev_code | (j << @intCast(u5, len));
118 assert(self.prefix_lut_len[index] == 0);
119 self.prefix_lut[index] = @truncate(u16, symbol);
120 self.prefix_lut_len[index] = @truncate(u16, len);
61 }121 }
62 }122 }
123
124 self.last_code = codes[PREFIX_LUT_BITS + 1];
125 self.last_index = offset[PREFIX_LUT_BITS + 1] - self.count[PREFIX_LUT_BITS + 1];
63 }126 }
64};127};
65128
129// Reverse bit-by-bit a N-bit value
130fn bitReverse(x: usize, N: usize) usize {
131 var tmp: usize = 0;
132 var i: usize = 0;
133 while (i < N) : (i += 1) {
134 tmp |= ((x >> @intCast(u5, i)) & 1) << @intCast(u5, N - i - 1);
135 }
136 return tmp;
137}
138
66pub fn InflateStream(comptime ReaderType: type) type {139pub fn InflateStream(comptime ReaderType: type) type {
67 return struct {140 return struct {
68 const Self = @This();141 const Self = @This();
...@@ -83,7 +156,7 @@ pub fn InflateStream(comptime ReaderType: type) type {...@@ -83,7 +156,7 @@ pub fn InflateStream(comptime ReaderType: type) type {
83 };156 };
84 pub const Reader = io.Reader(*Self, Error, read);157 pub const Reader = io.Reader(*Self, Error, read);
85158
86 bit_reader: io.BitReader(.Little, ReaderType),159 inner_reader: ReaderType,
87160
88 // True if the decoder met the end of the compressed stream, no further161 // True if the decoder met the end of the compressed stream, no further
89 // data can be decompressed162 // data can be decompressed
...@@ -135,7 +208,7 @@ pub fn InflateStream(comptime ReaderType: type) type {...@@ -135,7 +208,7 @@ pub fn InflateStream(comptime ReaderType: type) type {
135208
136 // Insert a single byte into the window.209 // Insert a single byte into the window.
137 // Assumes there's enough space.210 // Assumes there's enough space.
138 fn appendUnsafe(self: *WSelf, value: u8) void {211 inline fn appendUnsafe(self: *WSelf, value: u8) void {
139 self.buf[self.wi] = value;212 self.buf[self.wi] = value;
140 self.wi = (self.wi + 1) & (self.buf.len - 1);213 self.wi = (self.wi + 1) & (self.buf.len - 1);
141 self.el += 1;214 self.el += 1;
...@@ -180,7 +253,7 @@ pub fn InflateStream(comptime ReaderType: type) type {...@@ -180,7 +253,7 @@ pub fn InflateStream(comptime ReaderType: type) type {
180 // of the window memory for the non-overlapping case.253 // of the window memory for the non-overlapping case.
181 var i: usize = 0;254 var i: usize = 0;
182 while (i < N) : (i += 1) {255 while (i < N) : (i += 1) {
183 const index = (self.wi -% distance) % self.buf.len;256 const index = (self.wi -% distance) & (self.buf.len - 1);
184 self.appendUnsafe(self.buf[index]);257 self.appendUnsafe(self.buf[index]);
185 }258 }
186259
...@@ -196,13 +269,36 @@ pub fn InflateStream(comptime ReaderType: type) type {...@@ -196,13 +269,36 @@ pub fn InflateStream(comptime ReaderType: type) type {
196 hdist: *Huffman,269 hdist: *Huffman,
197 hlen: *Huffman,270 hlen: *Huffman,
198271
272 // Temporary buffer for the bitstream, only bits 0..`bits_left` are
273 // considered valid.
274 bits: u32,
275 bits_left: usize,
276
277 fn peekBits(self: *Self, bits: usize) !u32 {
278 while (self.bits_left < bits) {
279 const byte = try self.inner_reader.readByte();
280 self.bits |= @as(u32, byte) << @intCast(u5, self.bits_left);
281 self.bits_left += 8;
282 }
283 return self.bits & ((@as(u32, 1) << @intCast(u5, bits)) - 1);
284 }
285 fn readBits(self: *Self, bits: usize) !u32 {
286 const val = self.peekBits(bits);
287 self.discardBits(bits);
288 return val;
289 }
290 fn discardBits(self: *Self, bits: usize) void {
291 self.bits >>= @intCast(u5, bits);
292 self.bits_left -= bits;
293 }
294
199 fn stored(self: *Self) !void {295 fn stored(self: *Self) !void {
200 // Discard the remaining bits, the lenght field is always296 // Discard the remaining bits, the lenght field is always
201 // byte-aligned (and so is the data)297 // byte-aligned (and so is the data)
202 self.bit_reader.alignToByte();298 self.discardBits(self.bits_left);
203299
204 const length = (try self.bit_reader.readBitsNoEof(u16, 16));300 const length = try self.inner_reader.readIntLittle(u16);
205 const length_cpl = (try self.bit_reader.readBitsNoEof(u16, 16));301 const length_cpl = try self.inner_reader.readIntLittle(u16);
206302
207 if (length != ~length_cpl)303 if (length != ~length_cpl)
208 return error.InvalidStoredSize;304 return error.InvalidStoredSize;
...@@ -237,11 +333,11 @@ pub fn InflateStream(comptime ReaderType: type) type {...@@ -237,11 +333,11 @@ pub fn InflateStream(comptime ReaderType: type) type {
237333
238 fn dynamic(self: *Self) !void {334 fn dynamic(self: *Self) !void {
239 // Number of length codes335 // Number of length codes
240 const nlen = (try self.bit_reader.readBitsNoEof(usize, 5)) + 257;336 const nlen = (try self.readBits(5)) + 257;
241 // Number of distance codes337 // Number of distance codes
242 const ndist = (try self.bit_reader.readBitsNoEof(usize, 5)) + 1;338 const ndist = (try self.readBits(5)) + 1;
243 // Number of code length codes339 // Number of code length codes
244 const ncode = (try self.bit_reader.readBitsNoEof(usize, 4)) + 4;340 const ncode = (try self.readBits(4)) + 4;
245341
246 if (nlen > MAXLCODES or ndist > MAXDCODES)342 if (nlen > MAXLCODES or ndist > MAXDCODES)
247 return error.BadCounts;343 return error.BadCounts;
...@@ -259,7 +355,7 @@ pub fn InflateStream(comptime ReaderType: type) type {...@@ -259,7 +355,7 @@ pub fn InflateStream(comptime ReaderType: type) type {
259355
260 // Read the code lengths, missing ones are left as zero356 // Read the code lengths, missing ones are left as zero
261 for (ORDER[0..ncode]) |val| {357 for (ORDER[0..ncode]) |val| {
262 lengths[val] = try self.bit_reader.readBitsNoEof(u16, 3);358 lengths[val] = @intCast(u16, try self.readBits(3));
263 }359 }
264360
265 try lencode.construct(lengths[0..]);361 try lencode.construct(lengths[0..]);
...@@ -284,7 +380,7 @@ pub fn InflateStream(comptime ReaderType: type) type {...@@ -284,7 +380,7 @@ pub fn InflateStream(comptime ReaderType: type) type {
284 if (i == 0) return error.NoLastLength;380 if (i == 0) return error.NoLastLength;
285381
286 const last_length = lengths[i - 1];382 const last_length = lengths[i - 1];
287 const repeat = 3 + (try self.bit_reader.readBitsNoEof(usize, 2));383 const repeat = 3 + (try self.readBits(2));
288 const last_index = i + repeat;384 const last_index = i + repeat;
289 while (i < last_index) : (i += 1) {385 while (i < last_index) : (i += 1) {
290 lengths[i] = last_length;386 lengths[i] = last_length;
...@@ -292,11 +388,11 @@ pub fn InflateStream(comptime ReaderType: type) type {...@@ -292,11 +388,11 @@ pub fn InflateStream(comptime ReaderType: type) type {
292 },388 },
293 17 => {389 17 => {
294 // repeat zero 3..10 times390 // repeat zero 3..10 times
295 i += 3 + (try self.bit_reader.readBitsNoEof(usize, 3));391 i += 3 + (try self.readBits(3));
296 },392 },
297 18 => {393 18 => {
298 // repeat zero 11..138 times394 // repeat zero 11..138 times
299 i += 11 + (try self.bit_reader.readBitsNoEof(usize, 7));395 i += 11 + (try self.readBits(7));
300 },396 },
301 else => return error.InvalidSymbol,397 else => return error.InvalidSymbol,
302 }398 }
...@@ -359,11 +455,11 @@ pub fn InflateStream(comptime ReaderType: type) type {...@@ -359,11 +455,11 @@ pub fn InflateStream(comptime ReaderType: type) type {
359 // Length/distance pair455 // Length/distance pair
360 const length_symbol = symbol - 257;456 const length_symbol = symbol - 257;
361 const length = LENS[length_symbol] +457 const length = LENS[length_symbol] +
362 try self.bit_reader.readBitsNoEof(u16, LEXT[length_symbol]);458 @intCast(u16, try self.readBits(LEXT[length_symbol]));
363459
364 const distance_symbol = try self.decode(distcode);460 const distance_symbol = try self.decode(distcode);
365 const distance = DISTS[distance_symbol] +461 const distance = DISTS[distance_symbol] +
366 try self.bit_reader.readBitsNoEof(u16, DEXT[distance_symbol]);462 @intCast(u16, try self.readBits(DEXT[distance_symbol]));
367463
368 if (distance > self.window.buf.len)464 if (distance > self.window.buf.len)
369 return error.InvalidDistance;465 return error.InvalidDistance;
...@@ -385,13 +481,29 @@ pub fn InflateStream(comptime ReaderType: type) type {...@@ -385,13 +481,29 @@ pub fn InflateStream(comptime ReaderType: type) type {
385 }481 }
386482
387 fn decode(self: *Self, h: *Huffman) !u16 {483 fn decode(self: *Self, h: *Huffman) !u16 {
388 var len: usize = 1;484 // Fast path, read some bits and hope they're prefixes of some code
389 var code: usize = 0;485 const prefix = try self.peekBits(PREFIX_LUT_BITS);
390 var first: usize = 0;486 if (h.prefix_lut_len[prefix] != 0) {
391 var index: usize = 0;487 self.discardBits(h.prefix_lut_len[prefix]);
488 return h.prefix_lut[prefix];
489 }
490
491 // The sequence we've read is not a prefix of any code of length <=
492 // PREFIX_LUT_BITS, keep decoding it using a slower method
493 self.discardBits(PREFIX_LUT_BITS);
494
495 // Speed up the decoding by starting from the first code length
496 // that's not covered by the table
497 var len: usize = PREFIX_LUT_BITS + 1;
498 var first: usize = h.last_code;
499 var index: usize = h.last_index;
500
501 // Reverse the prefix so that the LSB becomes the MSB and make space
502 // for the next bit
503 var code = bitReverse(prefix, PREFIX_LUT_BITS + 1);
392504
393 while (len <= MAXBITS) : (len += 1) {505 while (len <= MAXBITS) : (len += 1) {
394 code |= try self.bit_reader.readBitsNoEof(usize, 1);506 code |= try self.readBits(1);
395 const count = h.count[len];507 const count = h.count[len];
396 if (code < first + count)508 if (code < first + count)
397 return h.symbol[index + (code - first)];509 return h.symbol[index + (code - first)];
...@@ -411,8 +523,8 @@ pub fn InflateStream(comptime ReaderType: type) type {...@@ -411,8 +523,8 @@ pub fn InflateStream(comptime ReaderType: type) type {
411 // The compressed stream is done523 // The compressed stream is done
412 if (self.seen_eos) return;524 if (self.seen_eos) return;
413525
414 const last = try self.bit_reader.readBitsNoEof(u1, 1);526 const last = @intCast(u1, try self.readBits(1));
415 const kind = try self.bit_reader.readBitsNoEof(u2, 2);527 const kind = @intCast(u2, try self.readBits(2));
416528
417 self.seen_eos = last != 0;529 self.seen_eos = last != 0;
418530
...@@ -439,7 +551,7 @@ pub fn InflateStream(comptime ReaderType: type) type {...@@ -439,7 +551,7 @@ pub fn InflateStream(comptime ReaderType: type) type {
439 var i: usize = 0;551 var i: usize = 0;
440 while (i < N) : (i += 1) {552 while (i < N) : (i += 1) {
441 var tmp: [1]u8 = undefined;553 var tmp: [1]u8 = undefined;
442 if ((try self.bit_reader.read(&tmp)) != 1) {554 if ((try self.inner_reader.read(&tmp)) != 1) {
443 // Unexpected end of stream, keep this error555 // Unexpected end of stream, keep this error
444 // consistent with the use of readBitsNoEof556 // consistent with the use of readBitsNoEof
445 return error.EndOfStream;557 return error.EndOfStream;
...@@ -478,12 +590,14 @@ pub fn InflateStream(comptime ReaderType: type) type {...@@ -478,12 +590,14 @@ pub fn InflateStream(comptime ReaderType: type) type {
478 assert(math.isPowerOfTwo(window_slice.len));590 assert(math.isPowerOfTwo(window_slice.len));
479591
480 return Self{592 return Self{
481 .bit_reader = io.bitReader(.Little, source),593 .inner_reader = source,
482 .window = .{ .buf = window_slice },594 .window = .{ .buf = window_slice },
483 .seen_eos = false,595 .seen_eos = false,
484 .state = .DecodeBlockHeader,596 .state = .DecodeBlockHeader,
485 .hdist = undefined,597 .hdist = undefined,
486 .hlen = undefined,598 .hlen = undefined,
599 .bits = 0,
600 .bits_left = 0,
487 };601 };
488 }602 }
489603
lib/std/compress/gzip.zig created+248
...@@ -0,0 +1,248 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6//
7// Decompressor for GZIP data streams (RFC1952)
8
9const std = @import("std");
10const io = std.io;
11const fs = std.fs;
12const testing = std.testing;
13const mem = std.mem;
14const deflate = std.compress.deflate;
15
16// Flags for the FLG field in the header
17const FTEXT = 1 << 0;
18const FHCRC = 1 << 1;
19const FEXTRA = 1 << 2;
20const FNAME = 1 << 3;
21const FCOMMENT = 1 << 4;
22
23pub fn GzipStream(comptime ReaderType: type) type {
24 return struct {
25 const Self = @This();
26
27 pub const Error = ReaderType.Error ||
28 deflate.InflateStream(ReaderType).Error ||
29 error{ CorruptedData, WrongChecksum };
30 pub const Reader = io.Reader(*Self, Error, read);
31
32 allocator: *mem.Allocator,
33 inflater: deflate.InflateStream(ReaderType),
34 in_reader: ReaderType,
35 hasher: std.hash.Crc32,
36 window_slice: []u8,
37 read_amt: usize,
38
39 info: struct {
40 filename: ?[]const u8,
41 comment: ?[]const u8,
42 modification_time: u32,
43 },
44
45 fn init(allocator: *mem.Allocator, source: ReaderType) !Self {
46 // gzip header format is specified in RFC1952
47 const header = try source.readBytesNoEof(10);
48
49 // Check the ID1/ID2 fields
50 if (header[0] != 0x1f or header[1] != 0x8b)
51 return error.BadHeader;
52
53 const CM = header[2];
54 // The CM field must be 8 to indicate the use of DEFLATE
55 if (CM != 8) return error.InvalidCompression;
56 // Flags
57 const FLG = header[3];
58 // Modification time, as a Unix timestamp.
59 // If zero there's no timestamp available.
60 const MTIME = mem.readIntLittle(u32, header[4..8]);
61 // Extra flags
62 const XFL = header[8];
63 // Operating system where the compression took place
64 const OS = header[9];
65
66 if (FLG & FEXTRA != 0) {
67 // Skip the extra data, we could read and expose it to the user
68 // if somebody needs it.
69 const len = try source.readIntLittle(u16);
70 try source.skipBytes(len, .{});
71 }
72
73 var filename: ?[]const u8 = null;
74 if (FLG & FNAME != 0) {
75 filename = try source.readUntilDelimiterAlloc(
76 allocator,
77 0,
78 std.math.maxInt(usize),
79 );
80 }
81 errdefer if (filename) |p| allocator.free(p);
82
83 var comment: ?[]const u8 = null;
84 if (FLG & FCOMMENT != 0) {
85 comment = try source.readUntilDelimiterAlloc(
86 allocator,
87 0,
88 std.math.maxInt(usize),
89 );
90 }
91 errdefer if (comment) |p| allocator.free(p);
92
93 if (FLG & FHCRC != 0) {
94 // TODO: Evaluate and check the header checksum. The stdlib has
95 // no CRC16 yet :(
96 _ = try source.readIntLittle(u16);
97 }
98
99 // The RFC doesn't say anything about the DEFLATE window size to be
100 // used, default to 32K.
101 var window_slice = try allocator.alloc(u8, 32 * 1024);
102
103 return Self{
104 .allocator = allocator,
105 .inflater = deflate.inflateStream(source, window_slice),
106 .in_reader = source,
107 .hasher = std.hash.Crc32.init(),
108 .window_slice = window_slice,
109 .info = .{
110 .filename = filename,
111 .comment = comment,
112 .modification_time = MTIME,
113 },
114 .read_amt = 0,
115 };
116 }
117
118 pub fn deinit(self: *Self) void {
119 self.allocator.free(self.window_slice);
120 if (self.info.filename) |filename|
121 self.allocator.free(filename);
122 if (self.info.comment) |comment|
123 self.allocator.free(comment);
124 }
125
126 // Implements the io.Reader interface
127 pub fn read(self: *Self, buffer: []u8) Error!usize {
128 if (buffer.len == 0)
129 return 0;
130
131 // Read from the compressed stream and update the computed checksum
132 const r = try self.inflater.read(buffer);
133 if (r != 0) {
134 self.hasher.update(buffer[0..r]);
135 self.read_amt += r;
136 return r;
137 }
138
139 // We've reached the end of stream, check if the checksum matches
140 const hash = try self.in_reader.readIntLittle(u32);
141 if (hash != self.hasher.final())
142 return error.WrongChecksum;
143
144 // The ISIZE field is the size of the uncompressed input modulo 2^32
145 const input_size = try self.in_reader.readIntLittle(u32);
146 if (self.read_amt & 0xffffffff != input_size)
147 return error.CorruptedData;
148
149 return 0;
150 }
151
152 pub fn reader(self: *Self) Reader {
153 return .{ .context = self };
154 }
155 };
156}
157
158pub fn gzipStream(allocator: *mem.Allocator, reader: anytype) !GzipStream(@TypeOf(reader)) {
159 return GzipStream(@TypeOf(reader)).init(allocator, reader);
160}
161
162fn testReader(data: []const u8, comptime expected: []const u8) !void {
163 var in_stream = io.fixedBufferStream(data);
164
165 var gzip_stream = try gzipStream(testing.allocator, in_stream.reader());
166 defer gzip_stream.deinit();
167
168 // Read and decompress the whole file
169 const buf = try gzip_stream.reader().readAllAlloc(testing.allocator, std.math.maxInt(usize));
170 defer testing.allocator.free(buf);
171 // Calculate its SHA256 hash and check it against the reference
172 var hash: [32]u8 = undefined;
173 std.crypto.hash.sha2.Sha256.hash(buf, hash[0..], .{});
174
175 assertEqual(expected, &hash);
176}
177
178// Assert `expected` == `input` where `input` is a bytestring.
179pub fn assertEqual(comptime expected: []const u8, input: []const u8) void {
180 var expected_bytes: [expected.len / 2]u8 = undefined;
181 for (expected_bytes) |*r, i| {
182 r.* = std.fmt.parseInt(u8, expected[2 * i .. 2 * i + 2], 16) catch unreachable;
183 }
184
185 testing.expectEqualSlices(u8, &expected_bytes, input);
186}
187
188// All the test cases are obtained by compressing the RFC1952 text
189//
190// https://tools.ietf.org/rfc/rfc1952.txt length=25037 bytes
191// SHA256=164ef0897b4cbec63abf1b57f069f3599bd0fb7c72c2a4dee21bd7e03ec9af67
192test "compressed data" {
193 try testReader(
194 @embedFile("rfc1952.txt.gz"),
195 "164ef0897b4cbec63abf1b57f069f3599bd0fb7c72c2a4dee21bd7e03ec9af67",
196 );
197}
198
199test "sanity checks" {
200 // Truncated header
201 testing.expectError(
202 error.EndOfStream,
203 testReader(&[_]u8{ 0x1f, 0x8B }, ""),
204 );
205 // Wrong CM
206 testing.expectError(
207 error.InvalidCompression,
208 testReader(&[_]u8{
209 0x1f, 0x8b, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00,
210 0x00, 0x03,
211 }, ""),
212 );
213 // Wrong checksum
214 testing.expectError(
215 error.WrongChecksum,
216 testReader(&[_]u8{
217 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
218 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01,
219 0x00, 0x00, 0x00, 0x00,
220 }, ""),
221 );
222 // Truncated checksum
223 testing.expectError(
224 error.EndOfStream,
225 testReader(&[_]u8{
226 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
227 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00,
228 }, ""),
229 );
230 // Wrong initial size
231 testing.expectError(
232 error.CorruptedData,
233 testReader(&[_]u8{
234 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
235 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
236 0x00, 0x00, 0x00, 0x01,
237 }, ""),
238 );
239 // Truncated initial size field
240 testing.expectError(
241 error.EndOfStream,
242 testReader(&[_]u8{
243 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
244 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
245 0x00, 0x00, 0x00,
246 }, ""),
247 );
248}
lib/std/compress/rfc1952.txt.gz created
Binary files /dev/null and b/lib/std/compress/rfc1952.txt.gz differ
lib/std/event/loop.zig+2-1
...@@ -112,7 +112,8 @@ pub const Loop = struct {...@@ -112,7 +112,8 @@ pub const Loop = struct {
112 /// have the correct pointer value.112 /// have the correct pointer value.
113 /// https://github.com/ziglang/zig/issues/2761 and https://github.com/ziglang/zig/issues/2765113 /// https://github.com/ziglang/zig/issues/2761 and https://github.com/ziglang/zig/issues/2765
114 pub fn init(self: *Loop) !void {114 pub fn init(self: *Loop) !void {
115 if (builtin.single_threaded) {115 if (builtin.single_threaded
116 or (@hasDecl(root, "event_loop_mode") and root.event_loop_mode == .single_threaded)) {
116 return self.initSingleThreaded();117 return self.initSingleThreaded();
117 } else {118 } else {
118 return self.initMultiThreaded();119 return self.initMultiThreaded();
lib/std/fs/file.zig+5-3
...@@ -728,7 +728,7 @@ pub const File = struct {...@@ -728,7 +728,7 @@ pub const File = struct {
728 }728 }
729 var i: usize = 0;729 var i: usize = 0;
730 while (i < trailers.len) {730 while (i < trailers.len) {
731 while (amt >= headers[i].iov_len) {731 while (amt >= trailers[i].iov_len) {
732 amt -= trailers[i].iov_len;732 amt -= trailers[i].iov_len;
733 i += 1;733 i += 1;
734 if (i >= trailers.len) return;734 if (i >= trailers.len) return;
...@@ -740,14 +740,16 @@ pub const File = struct {...@@ -740,14 +740,16 @@ pub const File = struct {
740 }740 }
741741
742 pub const Reader = io.Reader(File, ReadError, read);742 pub const Reader = io.Reader(File, ReadError, read);
743
743 /// Deprecated: use `Reader`744 /// Deprecated: use `Reader`
744 pub const InStream = Reader;745 pub const InStream = Reader;
745746
746 pub fn reader(file: File) io.Reader(File, ReadError, read) {747 pub fn reader(file: File) Reader {
747 return .{ .context = file };748 return .{ .context = file };
748 }749 }
750
749 /// Deprecated: use `reader`751 /// Deprecated: use `reader`
750 pub fn inStream(file: File) io.InStream(File, ReadError, read) {752 pub fn inStream(file: File) Reader {
751 return .{ .context = file };753 return .{ .context = file };
752 }754 }
753755
lib/std/os.zig+41-2
...@@ -2515,9 +2515,9 @@ pub fn readlinkatZ(dirfd: fd_t, file_path: [*:0]const u8, out_buffer: []u8) Read...@@ -2515,9 +2515,9 @@ pub fn readlinkatZ(dirfd: fd_t, file_path: [*:0]const u8, out_buffer: []u8) Read
2515pub const SetEidError = error{2515pub const SetEidError = error{
2516 InvalidUserId,2516 InvalidUserId,
2517 PermissionDenied,2517 PermissionDenied,
2518};2518} || UnexpectedError;
25192519
2520pub const SetIdError = error{ResourceLimitReached} || SetEidError || UnexpectedError;2520pub const SetIdError = error{ResourceLimitReached} || SetEidError;
25212521
2522pub fn setuid(uid: uid_t) SetIdError!void {2522pub fn setuid(uid: uid_t) SetIdError!void {
2523 switch (errno(system.setuid(uid))) {2523 switch (errno(system.setuid(uid))) {
...@@ -5418,3 +5418,42 @@ pub fn fdatasync(fd: fd_t) SyncError!void {...@@ -5418,3 +5418,42 @@ pub fn fdatasync(fd: fd_t) SyncError!void {
5418 else => |err| return std.os.unexpectedErrno(err),5418 else => |err| return std.os.unexpectedErrno(err),
5419 }5419 }
5420}5420}
5421
5422pub const PrctlError = error{
5423 /// Can only occur with PR_SET_SECCOMP/SECCOMP_MODE_FILTER or
5424 /// PR_SET_MM/PR_SET_MM_EXE_FILE
5425 AccessDenied,
5426 /// Can only occur with PR_SET_MM/PR_SET_MM_EXE_FILE
5427 InvalidFileDescriptor,
5428 InvalidAddress,
5429 /// Can only occur with PR_SET_SPECULATION_CTRL, PR_MPX_ENABLE_MANAGEMENT,
5430 /// or PR_MPX_DISABLE_MANAGEMENT
5431 UnsupportedFeature,
5432 /// Can only occur wih PR_SET_FP_MODE
5433 OperationNotSupported,
5434 PermissionDenied,
5435} || UnexpectedError;
5436
5437pub fn prctl(option: i32, args: anytype) PrctlError!u31 {
5438 if (@typeInfo(@TypeOf(args)) != .Struct)
5439 @compileError("Expected tuple or struct argument, found " ++ @typeName(@TypeOf(args)));
5440 if (args.len > 4)
5441 @compileError("prctl takes a maximum of 4 optional arguments");
5442
5443 var buf: [4]usize = undefined;
5444 inline for (args) |arg, i| buf[i] = arg;
5445
5446 const rc = system.prctl(option, buf[0], buf[1], buf[2], buf[3]);
5447 switch (errno(rc)) {
5448 0 => return @intCast(u31, rc),
5449 EACCES => return error.AccessDenied,
5450 EBADF => return error.InvalidFileDescriptor,
5451 EFAULT => return error.InvalidAddress,
5452 EINVAL => unreachable,
5453 ENODEV, ENXIO => return error.UnsupportedFeature,
5454 EOPNOTSUPP => return error.OperationNotSupported,
5455 EPERM, EBUSY => return error.PermissionDenied,
5456 ERANGE => unreachable,
5457 else => |err| return std.os.unexpectedErrno(err),
5458 }
5459}
lib/std/os/bits/linux.zig+3
...@@ -20,10 +20,13 @@ pub usingnamespace switch (builtin.arch) {...@@ -20,10 +20,13 @@ pub usingnamespace switch (builtin.arch) {
20 .arm => @import("linux/arm-eabi.zig"),20 .arm => @import("linux/arm-eabi.zig"),
21 .riscv64 => @import("linux/riscv64.zig"),21 .riscv64 => @import("linux/riscv64.zig"),
22 .mips, .mipsel => @import("linux/mips.zig"),22 .mips, .mipsel => @import("linux/mips.zig"),
23 .powerpc64, .powerpc64le => @import("linux/powerpc64.zig"),
23 else => struct {},24 else => struct {},
24};25};
2526
26pub usingnamespace @import("linux/netlink.zig");27pub usingnamespace @import("linux/netlink.zig");
28pub usingnamespace @import("linux/prctl.zig");
29pub usingnamespace @import("linux/securebits.zig");
2730
28const is_mips = builtin.arch.isMIPS();31const is_mips = builtin.arch.isMIPS();
2932
lib/std/os/bits/linux/powerpc64.zig created+602
...@@ -0,0 +1,602 @@
1const std = @import("../../../std.zig");
2const linux = std.os.linux;
3const socklen_t = linux.socklen_t;
4const iovec = linux.iovec;
5const iovec_const = linux.iovec_const;
6const uid_t = linux.uid_t;
7const gid_t = linux.gid_t;
8const pid_t = linux.pid_t;
9const stack_t = linux.stack_t;
10const sigset_t = linux.sigset_t;
11pub const SYS = extern enum(usize) {
12 restart_syscall = 0,
13 exit = 1,
14 fork = 2,
15 read = 3,
16 write = 4,
17 open = 5,
18 close = 6,
19 waitpid = 7,
20 creat = 8,
21 link = 9,
22 unlink = 10,
23 execve = 11,
24 chdir = 12,
25 time = 13,
26 mknod = 14,
27 chmod = 15,
28 lchown = 16,
29 @"break" = 17,
30 oldstat = 18,
31 lseek = 19,
32 getpid = 20,
33 mount = 21,
34 umount = 22,
35 setuid = 23,
36 getuid = 24,
37 stime = 25,
38 ptrace = 26,
39 alarm = 27,
40 oldfstat = 28,
41 pause = 29,
42 utime = 30,
43 stty = 31,
44 gtty = 32,
45 access = 33,
46 nice = 34,
47 ftime = 35,
48 sync = 36,
49 kill = 37,
50 rename = 38,
51 mkdir = 39,
52 rmdir = 40,
53 dup = 41,
54 pipe = 42,
55 times = 43,
56 prof = 44,
57 brk = 45,
58 setgid = 46,
59 getgid = 47,
60 signal = 48,
61 geteuid = 49,
62 getegid = 50,
63 acct = 51,
64 umount2 = 52,
65 lock = 53,
66 ioctl = 54,
67 fcntl = 55,
68 mpx = 56,
69 setpgid = 57,
70 ulimit = 58,
71 oldolduname = 59,
72 umask = 60,
73 chroot = 61,
74 ustat = 62,
75 dup2 = 63,
76 getppid = 64,
77 getpgrp = 65,
78 setsid = 66,
79 sigaction = 67,
80 sgetmask = 68,
81 ssetmask = 69,
82 setreuid = 70,
83 setregid = 71,
84 sigsuspend = 72,
85 sigpending = 73,
86 sethostname = 74,
87 setrlimit = 75,
88 getrlimit = 76,
89 getrusage = 77,
90 gettimeofday = 78,
91 settimeofday = 79,
92 getgroups = 80,
93 setgroups = 81,
94 select = 82,
95 symlink = 83,
96 oldlstat = 84,
97 readlink = 85,
98 uselib = 86,
99 swapon = 87,
100 reboot = 88,
101 readdir = 89,
102 mmap = 90,
103 munmap = 91,
104 truncate = 92,
105 ftruncate = 93,
106 fchmod = 94,
107 fchown = 95,
108 getpriority = 96,
109 setpriority = 97,
110 profil = 98,
111 statfs = 99,
112 fstatfs = 100,
113 ioperm = 101,
114 socketcall = 102,
115 syslog = 103,
116 setitimer = 104,
117 getitimer = 105,
118 stat = 106,
119 lstat = 107,
120 fstat = 108,
121 olduname = 109,
122 iopl = 110,
123 vhangup = 111,
124 idle = 112,
125 vm86 = 113,
126 wait4 = 114,
127 swapoff = 115,
128 sysinfo = 116,
129 ipc = 117,
130 fsync = 118,
131 sigreturn = 119,
132 clone = 120,
133 setdomainname = 121,
134 uname = 122,
135 modify_ldt = 123,
136 adjtimex = 124,
137 mprotect = 125,
138 sigprocmask = 126,
139 create_module = 127,
140 init_module = 128,
141 delete_module = 129,
142 get_kernel_syms = 130,
143 quotactl = 131,
144 getpgid = 132,
145 fchdir = 133,
146 bdflush = 134,
147 sysfs = 135,
148 personality = 136,
149 afs_syscall = 137,
150 setfsuid = 138,
151 setfsgid = 139,
152 _llseek = 140,
153 getdents = 141,
154 _newselect = 142,
155 flock = 143,
156 msync = 144,
157 readv = 145,
158 writev = 146,
159 getsid = 147,
160 fdatasync = 148,
161 _sysctl = 149,
162 mlock = 150,
163 munlock = 151,
164 mlockall = 152,
165 munlockall = 153,
166 sched_setparam = 154,
167 sched_getparam = 155,
168 sched_setscheduler = 156,
169 sched_getscheduler = 157,
170 sched_yield = 158,
171 sched_get_priority_max = 159,
172 sched_get_priority_min = 160,
173 sched_rr_get_interval = 161,
174 nanosleep = 162,
175 mremap = 163,
176 setresuid = 164,
177 getresuid = 165,
178 query_module = 166,
179 poll = 167,
180 nfsservctl = 168,
181 setresgid = 169,
182 getresgid = 170,
183 prctl = 171,
184 rt_sigreturn = 172,
185 rt_sigaction = 173,
186 rt_sigprocmask = 174,
187 rt_sigpending = 175,
188 rt_sigtimedwait = 176,
189 rt_sigqueueinfo = 177,
190 rt_sigsuspend = 178,
191 pread64 = 179,
192 pwrite64 = 180,
193 chown = 181,
194 getcwd = 182,
195 capget = 183,
196 capset = 184,
197 sigaltstack = 185,
198 sendfile = 186,
199 getpmsg = 187,
200 putpmsg = 188,
201 vfork = 189,
202 ugetrlimit = 190,
203 readahead = 191,
204 pciconfig_read = 198,
205 pciconfig_write = 199,
206 pciconfig_iobase = 200,
207 multiplexer = 201,
208 getdents64 = 202,
209 pivot_root = 203,
210 madvise = 205,
211 mincore = 206,
212 gettid = 207,
213 tkill = 208,
214 setxattr = 209,
215 lsetxattr = 210,
216 fsetxattr = 211,
217 getxattr = 212,
218 lgetxattr = 213,
219 fgetxattr = 214,
220 listxattr = 215,
221 llistxattr = 216,
222 flistxattr = 217,
223 removexattr = 218,
224 lremovexattr = 219,
225 fremovexattr = 220,
226 futex = 221,
227 sched_setaffinity = 222,
228 sched_getaffinity = 223,
229 tuxcall = 225,
230 io_setup = 227,
231 io_destroy = 228,
232 io_getevents = 229,
233 io_submit = 230,
234 io_cancel = 231,
235 set_tid_address = 232,
236 fadvise64 = 233,
237 exit_group = 234,
238 lookup_dcookie = 235,
239 epoll_create = 236,
240 epoll_ctl = 237,
241 epoll_wait = 238,
242 remap_file_pages = 239,
243 timer_create = 240,
244 timer_settime = 241,
245 timer_gettime = 242,
246 timer_getoverrun = 243,
247 timer_delete = 244,
248 clock_settime = 245,
249 clock_gettime = 246,
250 clock_getres = 247,
251 clock_nanosleep = 248,
252 swapcontext = 249,
253 tgkill = 250,
254 utimes = 251,
255 statfs64 = 252,
256 fstatfs64 = 253,
257 rtas = 255,
258 sys_debug_setcontext = 256,
259 migrate_pages = 258,
260 mbind = 259,
261 get_mempolicy = 260,
262 set_mempolicy = 261,
263 mq_open = 262,
264 mq_unlink = 263,
265 mq_timedsend = 264,
266 mq_timedreceive = 265,
267 mq_notify = 266,
268 mq_getsetattr = 267,
269 kexec_load = 268,
270 add_key = 269,
271 request_key = 270,
272 keyctl = 271,
273 waitid = 272,
274 ioprio_set = 273,
275 ioprio_get = 274,
276 inotify_init = 275,
277 inotify_add_watch = 276,
278 inotify_rm_watch = 277,
279 spu_run = 278,
280 spu_create = 279,
281 pselect6 = 280,
282 ppoll = 281,
283 unshare = 282,
284 splice = 283,
285 tee = 284,
286 vmsplice = 285,
287 openat = 286,
288 mkdirat = 287,
289 mknodat = 288,
290 fchownat = 289,
291 futimesat = 290,
292 newfstatat = 291,
293 unlinkat = 292,
294 renameat = 293,
295 linkat = 294,
296 symlinkat = 295,
297 readlinkat = 296,
298 fchmodat = 297,
299 faccessat = 298,
300 get_robust_list = 299,
301 set_robust_list = 300,
302 move_pages = 301,
303 getcpu = 302,
304 epoll_pwait = 303,
305 utimensat = 304,
306 signalfd = 305,
307 timerfd_create = 306,
308 eventfd = 307,
309 sync_file_range2 = 308,
310 fallocate = 309,
311 subpage_prot = 310,
312 timerfd_settime = 311,
313 timerfd_gettime = 312,
314 signalfd4 = 313,
315 eventfd2 = 314,
316 epoll_create1 = 315,
317 dup3 = 316,
318 pipe2 = 317,
319 inotify_init1 = 318,
320 perf_event_open = 319,
321 preadv = 320,
322 pwritev = 321,
323 rt_tgsigqueueinfo = 322,
324 fanotify_init = 323,
325 fanotify_mark = 324,
326 prlimit64 = 325,
327 socket = 326,
328 bind = 327,
329 connect = 328,
330 listen = 329,
331 accept = 330,
332 getsockname = 331,
333 getpeername = 332,
334 socketpair = 333,
335 send = 334,
336 sendto = 335,
337 recv = 336,
338 recvfrom = 337,
339 shutdown = 338,
340 setsockopt = 339,
341 getsockopt = 340,
342 sendmsg = 341,
343 recvmsg = 342,
344 recvmmsg = 343,
345 accept4 = 344,
346 name_to_handle_at = 345,
347 open_by_handle_at = 346,
348 clock_adjtime = 347,
349 syncfs = 348,
350 sendmmsg = 349,
351 setns = 350,
352 process_vm_readv = 351,
353 process_vm_writev = 352,
354 finit_module = 353,
355 kcmp = 354,
356 sched_setattr = 355,
357 sched_getattr = 356,
358 renameat2 = 357,
359 seccomp = 358,
360 getrandom = 359,
361 memfd_create = 360,
362 bpf = 361,
363 execveat = 362,
364 switch_endian = 363,
365 userfaultfd = 364,
366 membarrier = 365,
367 mlock2 = 378,
368 copy_file_range = 379,
369 preadv2 = 380,
370 pwritev2 = 381,
371 kexec_file_load = 382,
372 statx = 383,
373 pkey_alloc = 384,
374 pkey_free = 385,
375 pkey_mprotect = 386,
376 rseq = 387,
377 io_pgetevents = 388,
378 semtimedop = 392,
379 semget = 393,
380 semctl = 394,
381 shmget = 395,
382 shmctl = 396,
383 shmat = 397,
384 shmdt = 398,
385 msgget = 399,
386 msgsnd = 400,
387 msgrcv = 401,
388 msgctl = 402,
389 pidfd_send_signal = 424,
390 io_uring_setup = 425,
391 io_uring_enter = 426,
392 io_uring_register = 427,
393 open_tree = 428,
394 move_mount = 429,
395 fsopen = 430,
396 fsconfig = 431,
397 fsmount = 432,
398 fspick = 433,
399 pidfd_open = 434,
400 clone3 = 435,
401 openat2 = 437,
402 pidfd_getfd = 438,
403
404 _,
405};
406
407pub const O_CREAT = 0o100;
408pub const O_EXCL = 0o200;
409pub const O_NOCTTY = 0o400;
410pub const O_TRUNC = 0o1000;
411pub const O_APPEND = 0o2000;
412pub const O_NONBLOCK = 0o4000;
413pub const O_DSYNC = 0o10000;
414pub const O_SYNC = 0o4010000;
415pub const O_RSYNC = 0o4010000;
416pub const O_DIRECTORY = 0o40000;
417pub const O_NOFOLLOW = 0o100000;
418pub const O_CLOEXEC = 0o2000000;
419
420pub const O_ASYNC = 0o20000;
421pub const O_DIRECT = 0o400000;
422pub const O_LARGEFILE = 0o200000;
423pub const O_NOATIME = 0o1000000;
424pub const O_PATH = 0o10000000;
425pub const O_TMPFILE = 0o20200000;
426pub const O_NDELAY = O_NONBLOCK;
427
428pub const F_DUPFD = 0;
429pub const F_GETFD = 1;
430pub const F_SETFD = 2;
431pub const F_GETFL = 3;
432pub const F_SETFL = 4;
433
434pub const F_SETOWN = 8;
435pub const F_GETOWN = 9;
436pub const F_SETSIG = 10;
437pub const F_GETSIG = 11;
438
439pub const F_GETLK = 5;
440pub const F_SETLK = 6;
441pub const F_SETLKW = 7;
442
443pub const F_RDLCK = 0;
444pub const F_WRLCK = 1;
445pub const F_UNLCK = 2;
446
447pub const LOCK_SH = 1;
448pub const LOCK_EX = 2;
449pub const LOCK_UN = 8;
450pub const LOCK_NB = 4;
451
452pub const F_SETOWN_EX = 15;
453pub const F_GETOWN_EX = 16;
454
455pub const F_GETOWNER_UIDS = 17;
456
457/// stack-like segment
458pub const MAP_GROWSDOWN = 0x0100;
459
460/// ETXTBSY
461pub const MAP_DENYWRITE = 0x0800;
462
463/// mark it as an executable
464pub const MAP_EXECUTABLE = 0x1000;
465
466/// pages are locked
467pub const MAP_LOCKED = 0x0080;
468
469/// don't check for reservations
470pub const MAP_NORESERVE = 0x0040;
471
472pub const VDSO_CGT_SYM = "__kernel_clock_gettime";
473pub const VDSO_CGT_VER = "LINUX_2.6.15";
474
475pub const Flock = extern struct {
476 l_type: i16,
477 l_whence: i16,
478 l_start: off_t,
479 l_len: off_t,
480 l_pid: pid_t,
481 __unused: [4]u8,
482};
483
484pub const msghdr = extern struct {
485 msg_name: ?*sockaddr,
486 msg_namelen: socklen_t,
487 msg_iov: [*]iovec,
488 msg_iovlen: usize,
489 msg_control: ?*c_void,
490 msg_controllen: usize,
491 msg_flags: i32,
492};
493
494pub const msghdr_const = extern struct {
495 msg_name: ?*const sockaddr,
496 msg_namelen: socklen_t,
497 msg_iov: [*]iovec_const,
498 msg_iovlen: usize,
499 msg_control: ?*c_void,
500 msg_controllen: usize,
501 msg_flags: i32,
502};
503
504pub const blksize_t = i64;
505pub const nlink_t = u64;
506pub const time_t = i64;
507pub const mode_t = u32;
508pub const off_t = i64;
509pub const ino_t = u64;
510pub const dev_t = u64;
511pub const blkcnt_t = i64;
512
513/// Renamed to Stat to not conflict with the stat function.
514/// atime, mtime, and ctime have functions to return `timespec`,
515/// because although this is a POSIX API, the layout and names of
516/// the structs are inconsistent across operating systems, and
517/// in C, macros are used to hide the differences. Here we use
518/// methods to accomplish this.
519pub const Stat = extern struct {
520 dev: dev_t,
521 ino: ino_t,
522 nlink: nlink_t,
523 mode: mode_t,
524 uid: uid_t,
525 gid: gid_t,
526 rdev: dev_t,
527 size: off_t,
528 blksize: blksize_t,
529 blocks: blkcnt_t,
530 atim: timespec,
531 mtim: timespec,
532 ctim: timespec,
533 __unused: [3]u64,
534
535 pub fn atime(self: Stat) timespec {
536 return self.atim;
537 }
538
539 pub fn mtime(self: Stat) timespec {
540 return self.mtim;
541 }
542
543 pub fn ctime(self: Stat) timespec {
544 return self.ctim;
545 }
546};
547
548pub const timespec = extern struct {
549 tv_sec: time_t,
550 tv_nsec: isize,
551};
552
553pub const timeval = extern struct {
554 tv_sec: isize,
555 tv_usec: isize,
556};
557
558pub const timezone = extern struct {
559 tz_minuteswest: i32,
560 tz_dsttime: i32,
561};
562
563pub const greg_t = u64;
564pub const gregset_t = [48]greg_t;
565pub const fpregset_t = [33]f64;
566
567/// The position of the vscr register depends on endianness.
568/// On C, macros are used to change vscr_word's offset to
569/// account for this. Here we'll just define vscr_word_le
570/// and vscr_word_be. Code must take care to use the correct one.
571pub const vrregset = extern struct {
572 vrregs: [32][4]u32 align(16),
573 vscr_word_le: u32,
574 _pad1: [2]u32,
575 vscr_word_be: u32,
576 vrsave: u32,
577 _pad2: [3]u32,
578};
579pub const vrregset_t = vrregset;
580
581pub const mcontext_t = extern struct {
582 __unused: [4]u64,
583 signal: i32,
584 _pad0: i32,
585 handler: u64,
586 oldmask: u64,
587 regs: ?*c_void,
588 gp_regs: gregset_t,
589 fp_regs: fpregset_t,
590 v_regs: *vrregset_t,
591 vmx_reserve: [34 + 34 + 32 + 1]i64,
592};
593
594pub const ucontext_t = extern struct {
595 flags: u32,
596 link: *ucontext_t,
597 stack: stack_t,
598 sigmask: sigset_t,
599 mcontext: mcontext_t,
600};
601
602pub const Elf_Symndx = u32;
lib/std/os/bits/linux/prctl.zig created+158
...@@ -0,0 +1,158 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7pub const PR_SET_PDEATHSIG = 1;
8pub const PR_GET_PDEATHSIG = 2;
9
10pub const PR_GET_DUMPABLE = 3;
11pub const PR_SET_DUMPABLE = 4;
12
13pub const PR_GET_UNALIGN = 5;
14pub const PR_SET_UNALIGN = 6;
15pub const PR_UNALIGN_NOPRINT = 1;
16pub const PR_UNALIGN_SIGBUS = 2;
17
18pub const PR_GET_KEEPCAPS = 7;
19pub const PR_SET_KEEPCAPS = 8;
20
21pub const PR_GET_FPEMU = 9;
22pub const PR_SET_FPEMU = 10;
23pub const PR_FPEMU_NOPRINT = 1;
24pub const PR_FPEMU_SIGFPE = 2;
25
26pub const PR_GET_FPEXC = 11;
27pub const PR_SET_FPEXC = 12;
28pub const PR_FP_EXC_SW_ENABLE = 0x80;
29pub const PR_FP_EXC_DIV = 0x010000;
30pub const PR_FP_EXC_OVF = 0x020000;
31pub const PR_FP_EXC_UND = 0x040000;
32pub const PR_FP_EXC_RES = 0x080000;
33pub const PR_FP_EXC_INV = 0x100000;
34pub const PR_FP_EXC_DISABLED = 0;
35pub const PR_FP_EXC_NONRECOV = 1;
36pub const PR_FP_EXC_ASYNC = 2;
37pub const PR_FP_EXC_PRECISE = 3;
38
39pub const PR_GET_TIMING = 13;
40pub const PR_SET_TIMING = 14;
41pub const PR_TIMING_STATISTICAL = 0;
42pub const PR_TIMING_TIMESTAMP = 1;
43
44pub const PR_SET_NAME = 15;
45pub const PR_GET_NAME = 16;
46
47pub const PR_GET_ENDIAN = 19;
48pub const PR_SET_ENDIAN = 20;
49pub const PR_ENDIAN_BIG = 0;
50pub const PR_ENDIAN_LITTLE = 1;
51pub const PR_ENDIAN_PPC_LITTLE = 2;
52
53pub const PR_GET_SECCOMP = 21;
54pub const PR_SET_SECCOMP = 22;
55
56pub const PR_CAPBSET_READ = 23;
57pub const PR_CAPBSET_DROP = 24;
58
59pub const PR_GET_TSC = 25;
60pub const PR_SET_TSC = 26;
61pub const PR_TSC_ENABLE = 1;
62pub const PR_TSC_SIGSEGV = 2;
63
64pub const PR_GET_SECUREBITS = 27;
65pub const PR_SET_SECUREBITS = 28;
66
67pub const PR_SET_TIMERSLACK = 29;
68pub const PR_GET_TIMERSLACK = 30;
69
70pub const PR_TASK_PERF_EVENTS_DISABLE = 31;
71pub const PR_TASK_PERF_EVENTS_ENABLE = 32;
72
73pub const PR_MCE_KILL = 33;
74pub const PR_MCE_KILL_CLEAR = 0;
75pub const PR_MCE_KILL_SET = 1;
76
77pub const PR_MCE_KILL_LATE = 0;
78pub const PR_MCE_KILL_EARLY = 1;
79pub const PR_MCE_KILL_DEFAULT = 2;
80
81pub const PR_MCE_KILL_GET = 34;
82
83pub const PR_SET_MM = 35;
84pub const PR_SET_MM_START_CODE = 1;
85pub const PR_SET_MM_END_CODE = 2;
86pub const PR_SET_MM_START_DATA = 3;
87pub const PR_SET_MM_END_DATA = 4;
88pub const PR_SET_MM_START_STACK = 5;
89pub const PR_SET_MM_START_BRK = 6;
90pub const PR_SET_MM_BRK = 7;
91pub const PR_SET_MM_ARG_START = 8;
92pub const PR_SET_MM_ARG_END = 9;
93pub const PR_SET_MM_ENV_START = 10;
94pub const PR_SET_MM_ENV_END = 11;
95pub const PR_SET_MM_AUXV = 12;
96pub const PR_SET_MM_EXE_FILE = 13;
97pub const PR_SET_MM_MAP = 14;
98pub const PR_SET_MM_MAP_SIZE = 15;
99
100pub const prctl_mm_map = extern struct {
101 start_code: u64,
102 end_code: u64,
103 start_data: u64,
104 end_data: u64,
105 start_brk: u64,
106 brk: u64,
107 start_stack: u64,
108 arg_start: u64,
109 arg_end: u64,
110 env_start: u64,
111 env_end: u64,
112 auxv: *u64,
113 auxv_size: u32,
114 exe_fd: u32,
115};
116
117pub const PR_SET_PTRACER = 0x59616d61;
118pub const PR_SET_PTRACER_ANY = std.math.maxInt(c_ulong);
119
120pub const PR_SET_CHILD_SUBREAPER = 36;
121pub const PR_GET_CHILD_SUBREAPER = 37;
122
123pub const PR_SET_NO_NEW_PRIVS = 38;
124pub const PR_GET_NO_NEW_PRIVS = 39;
125
126pub const PR_GET_TID_ADDRESS = 40;
127
128pub const PR_SET_THP_DISABLE = 41;
129pub const PR_GET_THP_DISABLE = 42;
130
131pub const PR_MPX_ENABLE_MANAGEMENT = 43;
132pub const PR_MPX_DISABLE_MANAGEMENT = 44;
133
134pub const PR_SET_FP_MODE = 45;
135pub const PR_GET_FP_MODE = 46;
136pub const PR_FP_MODE_FR = 1 << 0;
137pub const PR_FP_MODE_FRE = 1 << 1;
138
139pub const PR_CAP_AMBIENT = 47;
140pub const PR_CAP_AMBIENT_IS_SET = 1;
141pub const PR_CAP_AMBIENT_RAISE = 2;
142pub const PR_CAP_AMBIENT_LOWER = 3;
143pub const PR_CAP_AMBIENT_CLEAR_ALL = 4;
144
145pub const PR_SVE_SET_VL = 50;
146pub const PR_SVE_SET_VL_ONEXEC = 1 << 18;
147pub const PR_SVE_GET_VL = 51;
148pub const PR_SVE_VL_LEN_MASK = 0xffff;
149pub const PR_SVE_VL_INHERIT = 1 << 17;
150
151pub const PR_GET_SPECULATION_CTRL = 52;
152pub const PR_SET_SPECULATION_CTRL = 53;
153pub const PR_SPEC_STORE_BYPASS = 0;
154pub const PR_SPEC_NOT_AFFECTED = 0;
155pub const PR_SPEC_PRCTL = 1 << 0;
156pub const PR_SPEC_ENABLE = 1 << 1;
157pub const PR_SPEC_DISABLE = 1 << 2;
158pub const PR_SPEC_FORCE_DISABLE = 1 << 3;
lib/std/os/bits/linux/securebits.zig created+41
...@@ -0,0 +1,41 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7fn issecure_mask(comptime x: comptime_int) comptime_int {
8 return 1 << x;
9}
10
11pub const SECUREBITS_DEFAULT = 0x00000000;
12
13pub const SECURE_NOROOT = 0;
14pub const SECURE_NOROOT_LOCKED = 1;
15
16pub const SECBIT_NOROOT = issecure_mask(SECURE_NOROOT);
17pub const SECBIT_NOROOT_LOCKED = issecure_mask(SECURE_NOROOT_LOCKED);
18
19pub const SECURE_NO_SETUID_FIXUP = 2;
20pub const SECURE_NO_SETUID_FIXUP_LOCKED = 3;
21
22pub const SECBIT_NO_SETUID_FIXUP = issecure_mask(SECURE_NO_SETUID_FIXUP);
23pub const SECBIT_NO_SETUID_FIXUP_LOCKED = issecure_mask(SECURE_NO_SETUID_FIXUP_LOCKED);
24
25pub const SECURE_KEEP_CAPS = 4;
26pub const SECURE_KEEP_CAPS_LOCKED = 5;
27
28pub const SECBIT_KEEP_CAPS = issecure_mask(SECURE_KEEP_CAPS);
29pub const SECBIT_KEEP_CAPS_LOCKED = issecure_mask(SECURE_KEEP_CAPS_LOCKED);
30
31pub const SECURE_NO_CAP_AMBIENT_RAISE = 6;
32pub const SECURE_NO_CAP_AMBIENT_RAISE_LOCKED = 7;
33
34pub const SECBIT_NO_CAP_AMBIENT_RAISE = issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE);
35pub const SECBIT_NO_CAP_AMBIENT_RAISE_LOCKED = issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE_LOCKED);
36
37pub const SECURE_ALL_BITS = issecure_mask(SECURE_NOROOT) |
38 issecure_mask(SECURE_NO_SETUID_FIXUP) |
39 issecure_mask(SECURE_KEEP_CAPS) |
40 issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE);
41pub const SECURE_ALL_LOCKS = SECURE_ALL_BITS << 1;
lib/std/os/linux.zig+5
...@@ -25,6 +25,7 @@ pub usingnamespace switch (builtin.arch) {...@@ -25,6 +25,7 @@ pub usingnamespace switch (builtin.arch) {
25 .arm => @import("linux/arm-eabi.zig"),25 .arm => @import("linux/arm-eabi.zig"),
26 .riscv64 => @import("linux/riscv64.zig"),26 .riscv64 => @import("linux/riscv64.zig"),
27 .mips, .mipsel => @import("linux/mips.zig"),27 .mips, .mipsel => @import("linux/mips.zig"),
28 .powerpc64, .powerpc64le => @import("linux/powerpc64.zig"),
28 else => struct {},29 else => struct {},
29};30};
30pub usingnamespace @import("bits.zig");31pub usingnamespace @import("bits.zig");
...@@ -1258,6 +1259,10 @@ pub fn fdatasync(fd: fd_t) usize {...@@ -1258,6 +1259,10 @@ pub fn fdatasync(fd: fd_t) usize {
1258 return syscall1(.fdatasync, @bitCast(usize, @as(isize, fd)));1259 return syscall1(.fdatasync, @bitCast(usize, @as(isize, fd)));
1259}1260}
12601261
1262pub fn prctl(option: i32, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize {
1263 return syscall5(.prctl, @bitCast(usize, @as(isize, option)), arg2, arg3, arg4, arg5);
1264}
1265
1261test "" {1266test "" {
1262 if (builtin.os.tag == .linux) {1267 if (builtin.os.tag == .linux) {
1263 _ = @import("linux/test.zig");1268 _ = @import("linux/test.zig");
lib/std/os/linux/powerpc64.zig created+127
...@@ -0,0 +1,127 @@
1usingnamespace @import("../bits.zig");
2
3pub fn syscall0(number: SYS) usize {
4 return asm volatile (
5 \\ sc
6 \\ bns+ 1f
7 \\ neg 3, 3
8 \\ 1:
9 : [ret] "={r3}" (-> usize)
10 : [number] "{r0}" (@enumToInt(number))
11 : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
12 );
13}
14
15pub fn syscall1(number: SYS, arg1: usize) usize {
16 return asm volatile (
17 \\ sc
18 \\ bns+ 1f
19 \\ neg 3, 3
20 \\ 1:
21 : [ret] "={r3}" (-> usize)
22 : [number] "{r0}" (@enumToInt(number)),
23 [arg1] "{r3}" (arg1)
24 : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
25 );
26}
27
28pub fn syscall2(number: SYS, arg1: usize, arg2: usize) usize {
29 return asm volatile (
30 \\ sc
31 \\ bns+ 1f
32 \\ neg 3, 3
33 \\ 1:
34 : [ret] "={r3}" (-> usize)
35 : [number] "{r0}" (@enumToInt(number)),
36 [arg1] "{r3}" (arg1),
37 [arg2] "{r4}" (arg2)
38 : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
39 );
40}
41
42pub fn syscall3(number: SYS, arg1: usize, arg2: usize, arg3: usize) usize {
43 return asm volatile (
44 \\ sc
45 \\ bns+ 1f
46 \\ neg 3, 3
47 \\ 1:
48 : [ret] "={r3}" (-> usize)
49 : [number] "{r0}" (@enumToInt(number)),
50 [arg1] "{r3}" (arg1),
51 [arg2] "{r4}" (arg2),
52 [arg3] "{r5}" (arg3)
53 : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
54 );
55}
56
57pub fn syscall4(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize {
58 return asm volatile (
59 \\ sc
60 \\ bns+ 1f
61 \\ neg 3, 3
62 \\ 1:
63 : [ret] "={r3}" (-> usize)
64 : [number] "{r0}" (@enumToInt(number)),
65 [arg1] "{r3}" (arg1),
66 [arg2] "{r4}" (arg2),
67 [arg3] "{r5}" (arg3),
68 [arg4] "{r6}" (arg4)
69 : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
70 );
71}
72
73pub fn syscall5(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize {
74 return asm volatile (
75 \\ sc
76 \\ bns+ 1f
77 \\ neg 3, 3
78 \\ 1:
79 : [ret] "={r3}" (-> usize)
80 : [number] "{r0}" (@enumToInt(number)),
81 [arg1] "{r3}" (arg1),
82 [arg2] "{r4}" (arg2),
83 [arg3] "{r5}" (arg3),
84 [arg4] "{r6}" (arg4),
85 [arg5] "{r7}" (arg5)
86 : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
87 );
88}
89
90pub fn syscall6(
91 number: SYS,
92 arg1: usize,
93 arg2: usize,
94 arg3: usize,
95 arg4: usize,
96 arg5: usize,
97 arg6: usize,
98) usize {
99 return asm volatile (
100 \\ sc
101 \\ bns+ 1f
102 \\ neg 3, 3
103 \\ 1:
104 : [ret] "={r3}" (-> usize)
105 : [number] "{r0}" (@enumToInt(number)),
106 [arg1] "{r3}" (arg1),
107 [arg2] "{r4}" (arg2),
108 [arg3] "{r5}" (arg3),
109 [arg4] "{r6}" (arg4),
110 [arg5] "{r7}" (arg5),
111 [arg6] "{r8}" (arg6)
112 : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
113 );
114}
115
116/// This matches the libc clone function.
117pub extern fn clone(func: fn (arg: usize) callconv(.C) u8, stack: usize, flags: usize, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
118
119pub const restore = restore_rt;
120
121pub fn restore_rt() callconv(.Naked) void {
122 return asm volatile ("sc"
123 :
124 : [number] "{r0}" (@enumToInt(SYS.rt_sigreturn))
125 : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
126 );
127}
lib/std/os/linux/tls.zig+10-3
...@@ -53,7 +53,7 @@ const TLSVariant = enum {...@@ -53,7 +53,7 @@ const TLSVariant = enum {
53};53};
5454
55const tls_variant = switch (builtin.arch) {55const tls_variant = switch (builtin.arch) {
56 .arm, .armeb, .aarch64, .aarch64_be, .riscv32, .riscv64, .mips, .mipsel => TLSVariant.VariantI,56 .arm, .armeb, .aarch64, .aarch64_be, .riscv32, .riscv64, .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => TLSVariant.VariantI,
57 .x86_64, .i386 => TLSVariant.VariantII,57 .x86_64, .i386 => TLSVariant.VariantII,
58 else => @compileError("undefined tls_variant for this architecture"),58 else => @compileError("undefined tls_variant for this architecture"),
59};59};
...@@ -77,12 +77,12 @@ const tls_tp_points_past_tcb = switch (builtin.arch) {...@@ -77,12 +77,12 @@ const tls_tp_points_past_tcb = switch (builtin.arch) {
77// make the generated code more efficient77// make the generated code more efficient
7878
79const tls_tp_offset = switch (builtin.arch) {79const tls_tp_offset = switch (builtin.arch) {
80 .mips, .mipsel => 0x7000,80 .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => 0x7000,
81 else => 0,81 else => 0,
82};82};
8383
84const tls_dtv_offset = switch (builtin.arch) {84const tls_dtv_offset = switch (builtin.arch) {
85 .mips, .mipsel => 0x8000,85 .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => 0x8000,
86 .riscv32, .riscv64 => 0x800,86 .riscv32, .riscv64 => 0x800,
87 else => 0,87 else => 0,
88};88};
...@@ -165,6 +165,13 @@ pub fn setThreadPointer(addr: usize) void {...@@ -165,6 +165,13 @@ pub fn setThreadPointer(addr: usize) void {
165 const rc = std.os.linux.syscall1(.set_thread_area, addr);165 const rc = std.os.linux.syscall1(.set_thread_area, addr);
166 assert(rc == 0);166 assert(rc == 0);
167 },167 },
168 .powerpc, .powerpc64, .powerpc64le => {
169 asm volatile (
170 \\ mr 13, %[addr]
171 :
172 : [addr] "r" (addr)
173 );
174 },
168 else => @compileError("Unsupported architecture"),175 else => @compileError("Unsupported architecture"),
169 }176 }
170}177}
lib/std/priority_queue.zig+10-1
...@@ -195,7 +195,7 @@ pub fn PriorityQueue(comptime T: type) type {...@@ -195,7 +195,7 @@ pub fn PriorityQueue(comptime T: type) type {
195 count: usize,195 count: usize,
196196
197 pub fn next(it: *Iterator) ?T {197 pub fn next(it: *Iterator) ?T {
198 if (it.count > it.queue.len - 1) return null;198 if (it.count >= it.queue.len) return null;
199 const out = it.count;199 const out = it.count;
200 it.count += 1;200 it.count += 1;
201 return it.queue.items[out];201 return it.queue.items[out];
...@@ -428,3 +428,12 @@ test "std.PriorityQueue: remove at index" {...@@ -428,3 +428,12 @@ test "std.PriorityQueue: remove at index" {
428 expectEqual(queue.remove(), 3);428 expectEqual(queue.remove(), 3);
429 expectEqual(queue.removeOrNull(), null);429 expectEqual(queue.removeOrNull(), null);
430}430}
431
432test "std.PriorityQueue: iterator while empty" {
433 var queue = PQ.init(testing.allocator, lessThan);
434 defer queue.deinit();
435
436 var it = queue.iterator();
437
438 expectEqual(it.next(), null);
439}
lib/std/process.zig+8-6
...@@ -593,8 +593,10 @@ pub fn getUserInfo(name: []const u8) !UserInfo {...@@ -593,8 +593,10 @@ pub fn getUserInfo(name: []const u8) !UserInfo {
593/// TODO this reads /etc/passwd. But sometimes the user/id mapping is in something else593/// TODO this reads /etc/passwd. But sometimes the user/id mapping is in something else
594/// like NIS, AD, etc. See `man nss` or look at an strace for `id myuser`.594/// like NIS, AD, etc. See `man nss` or look at an strace for `id myuser`.
595pub fn posixGetUserInfo(name: []const u8) !UserInfo {595pub fn posixGetUserInfo(name: []const u8) !UserInfo {
596 var reader = try io.Reader.open("/etc/passwd", null);596 const file = try std.fs.openFileAbsolute("/etc/passwd", .{});
597 defer reader.close();597 defer file.close();
598
599 const reader = file.reader();
598600
599 const State = enum {601 const State = enum {
600 Start,602 Start,
...@@ -650,8 +652,8 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {...@@ -650,8 +652,8 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {
650 '0'...'9' => byte - '0',652 '0'...'9' => byte - '0',
651 else => return error.CorruptPasswordFile,653 else => return error.CorruptPasswordFile,
652 };654 };
653 if (@mulWithOverflow(u32, uid, 10, *uid)) return error.CorruptPasswordFile;655 if (@mulWithOverflow(u32, uid, 10, &uid)) return error.CorruptPasswordFile;
654 if (@addWithOverflow(u32, uid, digit, *uid)) return error.CorruptPasswordFile;656 if (@addWithOverflow(u32, uid, digit, &uid)) return error.CorruptPasswordFile;
655 },657 },
656 },658 },
657 .ReadGroupId => switch (byte) {659 .ReadGroupId => switch (byte) {
...@@ -666,8 +668,8 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {...@@ -666,8 +668,8 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {
666 '0'...'9' => byte - '0',668 '0'...'9' => byte - '0',
667 else => return error.CorruptPasswordFile,669 else => return error.CorruptPasswordFile,
668 };670 };
669 if (@mulWithOverflow(u32, gid, 10, *gid)) return error.CorruptPasswordFile;671 if (@mulWithOverflow(u32, gid, 10, &gid)) return error.CorruptPasswordFile;
670 if (@addWithOverflow(u32, gid, digit, *gid)) return error.CorruptPasswordFile;672 if (@addWithOverflow(u32, gid, digit, &gid)) return error.CorruptPasswordFile;
671 },673 },
672 },674 },
673 }675 }
lib/std/special/c.zig+55
...@@ -394,6 +394,61 @@ fn clone() callconv(.Naked) void {...@@ -394,6 +394,61 @@ fn clone() callconv(.Naked) void {
394 \\ syscall394 \\ syscall
395 );395 );
396 },396 },
397
398 .powerpc64, .powerpc64le => {
399 asm volatile (
400 \\ # store non-volatile regs r30, r31 on stack in order to put our
401 \\ # start func and its arg there
402 \\ stwu 30, -16(1)
403 \\ stw 31, 4(1)
404 \\ # save r3 (func) into r30, and r6(arg) into r31
405 \\ mr 30, 3
406 \\ mr 31, 6
407 \\ # create initial stack frame for new thread
408 \\ clrrwi 4, 4, 4
409 \\ li 0, 0
410 \\ stwu 0, -16(4)
411 \\ #move c into first arg
412 \\ mr 3, 5
413 \\ mr 5, 7
414 \\ mr 6, 8
415 \\ mr 7, 9
416 \\ # move syscall number into r0
417 \\ li 0, 120
418 \\ sc
419
420 \\ # check for syscall error
421 \\ bns+ 1f # jump to label 1 if no summary overflow.
422 \\ #else
423 \\ neg 3, 3 #negate the result (errno)
424 \\1:
425 \\ # compare sc result with 0
426 \\ cmpwi cr7, 3, 0
427
428 \\ # if not 0, jump to end
429 \\ bne cr7, 2f
430
431 \\ #else: we're the child
432 \\ #call funcptr: move arg (d) into r3
433 \\ mr 3, 31
434 \\ #move r30 (funcptr) into CTR reg
435 \\ mtctr 30
436 \\ # call CTR reg
437 \\ bctrl
438 \\ # mov SYS_exit into r0 (the exit param is already in r3)
439 \\ li 0, 1
440 \\ sc
441
442 \\2:
443 \\ # restore stack
444 \\ lwz 30, 0(1)
445 \\ lwz 31, 4(1)
446 \\ addi 1, 1, 16
447
448 \\ blr
449 );
450 },
451
397 else => @compileError("Implement clone() for this arch."),452 else => @compileError("Implement clone() for this arch."),
398 }453 }
399}454}
lib/std/start.zig+15
...@@ -121,6 +121,21 @@ fn _start() callconv(.Naked) noreturn {...@@ -121,6 +121,21 @@ fn _start() callconv(.Naked) noreturn {
121 : [argc] "=r" (-> [*]usize)121 : [argc] "=r" (-> [*]usize)
122 );122 );
123 },123 },
124 .powerpc64le => {
125 // Before returning the stack pointer, we have to set up a backchain
126 // and a few other registers required by the ELFv2 ABI.
127 // TODO: Support powerpc64 (big endian) on ELFv2.
128 starting_stack_ptr = asm (
129 \\ mr 4, 1
130 \\ subi 1, 1, 32
131 \\ li 5, 0
132 \\ std 5, 0(1)
133 \\ mr %[argc], 4
134 : [argc] "=r" (-> [*]usize)
135 :
136 : "r4", "r5"
137 );
138 },
124 else => @compileError("unsupported arch"),139 else => @compileError("unsupported arch"),
125 }140 }
126 // If LLVM inlines stack variables into _start, they will overwrite141 // If LLVM inlines stack variables into _start, they will overwrite
src-self-hosted/translate_c.zig+38
...@@ -5899,6 +5899,10 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.N...@@ -5899,6 +5899,10 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.N
5899 saw_l_paren = true;5899 saw_l_paren = true;
5900 _ = m.next();5900 _ = m.next();
5901 },5901 },
5902 // (type)sizeof(x)
5903 .Keyword_sizeof,
5904 // (type)alignof(x)
5905 .Keyword_alignof,
5902 // (type)identifier5906 // (type)identifier
5903 .Identifier => {},5907 .Identifier => {},
5904 // (type)integer5908 // (type)integer
...@@ -6309,6 +6313,40 @@ fn parseCPrefixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast....@@ -6309,6 +6313,40 @@ fn parseCPrefixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.
6309 node.rhs = try parseCPrefixOpExpr(c, m, scope);6313 node.rhs = try parseCPrefixOpExpr(c, m, scope);
6310 return &node.base;6314 return &node.base;
6311 },6315 },
6316 .Keyword_sizeof => {
6317 const inner = if (m.peek().? == .LParen) blk: {
6318 _ = m.next();
6319 const inner = try parseCExpr(c, m, scope);
6320 if (m.next().? != .RParen) {
6321 try m.fail(c, "unable to translate C expr: expected ')'", .{});
6322 return error.ParseError;
6323 }
6324 break :blk inner;
6325 } else try parseCPrefixOpExpr(c, m, scope);
6326
6327 const builtin_call = try c.createBuiltinCall("@sizeOf", 1);
6328 builtin_call.params()[0] = inner;
6329 builtin_call.rparen_token = try appendToken(c, .RParen, ")");
6330 return &builtin_call.base;
6331 },
6332 .Keyword_alignof => {
6333 // TODO this won't work if using <stdalign.h>'s
6334 // #define alignof _Alignof
6335 if (m.next().? != .LParen) {
6336 try m.fail(c, "unable to translate C expr: expected '('", .{});
6337 return error.ParseError;
6338 }
6339 const inner = try parseCExpr(c, m, scope);
6340 if (m.next().? != .RParen) {
6341 try m.fail(c, "unable to translate C expr: expected ')'", .{});
6342 return error.ParseError;
6343 }
6344
6345 const builtin_call = try c.createBuiltinCall("@alignOf", 1);
6346 builtin_call.params()[0] = inner;
6347 builtin_call.rparen_token = try appendToken(c, .RParen, ")");
6348 return &builtin_call.base;
6349 },
6312 else => {6350 else => {
6313 m.i -= 1;6351 m.i -= 1;
6314 return try parseCSuffixOpExpr(c, m, scope);6352 return try parseCSuffixOpExpr(c, m, scope);
src/all_types.hpp+1
...@@ -2265,6 +2265,7 @@ struct CodeGen {...@@ -2265,6 +2265,7 @@ struct CodeGen {
22652265
2266 Stage2LibCInstallation *libc;2266 Stage2LibCInstallation *libc;
22672267
2268 bool is_versioned;
2268 size_t version_major;2269 size_t version_major;
2269 size_t version_minor;2270 size_t version_minor;
2270 size_t version_patch;2271 size_t version_patch;
src/analyze.cpp+2-1
...@@ -1009,7 +1009,8 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) {...@@ -1009,7 +1009,8 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) {
1009 g->zig_target->arch == ZigLLVM_x86_64 ||1009 g->zig_target->arch == ZigLLVM_x86_64 ||
1010 target_is_arm(g->zig_target) ||1010 target_is_arm(g->zig_target) ||
1011 target_is_riscv(g->zig_target) ||1011 target_is_riscv(g->zig_target) ||
1012 target_is_wasm(g->zig_target))1012 target_is_wasm(g->zig_target) ||
1013 target_is_ppc(g->zig_target))
1013 {1014 {
1014 X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type);1015 X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type);
1015 return abi_class == X64CABIClass_MEMORY || abi_class == X64CABIClass_MEMORY_nobyval;1016 return abi_class == X64CABIClass_MEMORY || abi_class == X64CABIClass_MEMORY_nobyval;
src/codegen.cpp+4-2
...@@ -90,7 +90,8 @@ void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix) {...@@ -90,7 +90,8 @@ void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix) {
90 g->test_name_prefix = prefix;90 g->test_name_prefix = prefix;
91}91}
9292
93void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch) {93void codegen_set_lib_version(CodeGen *g, bool is_versioned, size_t major, size_t minor, size_t patch) {
94 g->is_versioned = is_versioned;
94 g->version_major = major;95 g->version_major = major;
95 g->version_minor = minor;96 g->version_minor = minor;
96 g->version_patch = patch;97 g->version_patch = patch;
...@@ -10823,6 +10824,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {...@@ -10823,6 +10824,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
10823 cache_bool(ch, g->emit_bin);10824 cache_bool(ch, g->emit_bin);
10824 cache_bool(ch, g->emit_llvm_ir);10825 cache_bool(ch, g->emit_llvm_ir);
10825 cache_bool(ch, g->emit_asm);10826 cache_bool(ch, g->emit_asm);
10827 cache_bool(ch, g->is_versioned);
10826 cache_usize(ch, g->version_major);10828 cache_usize(ch, g->version_major);
10827 cache_usize(ch, g->version_minor);10829 cache_usize(ch, g->version_minor);
10828 cache_usize(ch, g->version_patch);10830 cache_usize(ch, g->version_patch);
...@@ -10893,7 +10895,7 @@ static void resolve_out_paths(CodeGen *g) {...@@ -10893,7 +10895,7 @@ static void resolve_out_paths(CodeGen *g) {
10893 buf_resize(out_basename, 0);10895 buf_resize(out_basename, 0);
10894 buf_append_str(out_basename, target_lib_file_prefix(g->zig_target));10896 buf_append_str(out_basename, target_lib_file_prefix(g->zig_target));
10895 buf_append_buf(out_basename, g->root_out_name);10897 buf_append_buf(out_basename, g->root_out_name);
10896 buf_append_str(out_basename, target_lib_file_ext(g->zig_target, !g->is_dynamic,10898 buf_append_str(out_basename, target_lib_file_ext(g->zig_target, !g->is_dynamic, g->is_versioned,
10897 g->version_major, g->version_minor, g->version_patch));10899 g->version_major, g->version_minor, g->version_patch));
10898 break;10900 break;
10899 }10901 }
src/codegen.hpp+1-1
...@@ -38,7 +38,7 @@ void codegen_set_rdynamic(CodeGen *g, bool rdynamic);...@@ -38,7 +38,7 @@ void codegen_set_rdynamic(CodeGen *g, bool rdynamic);
38void codegen_set_linker_script(CodeGen *g, const char *linker_script);38void codegen_set_linker_script(CodeGen *g, const char *linker_script);
39void codegen_set_test_filter(CodeGen *g, Buf *filter);39void codegen_set_test_filter(CodeGen *g, Buf *filter);
40void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix);40void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix);
41void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch);41void codegen_set_lib_version(CodeGen *g, bool is_versioned, size_t major, size_t minor, size_t patch);
42void codegen_add_time_event(CodeGen *g, const char *name);42void codegen_add_time_event(CodeGen *g, const char *name);
43void codegen_print_timing_report(CodeGen *g, FILE *f);43void codegen_print_timing_report(CodeGen *g, FILE *f);
44void codegen_link(CodeGen *g);44void codegen_link(CodeGen *g);
src/glibc.cpp+1-1
...@@ -335,7 +335,7 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con...@@ -335,7 +335,7 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con
335 bool is_ld = (strcmp(lib->name, "ld") == 0);335 bool is_ld = (strcmp(lib->name, "ld") == 0);
336336
337 CodeGen *child_gen = create_child_codegen(g, zig_file_path, OutTypeLib, nullptr, lib->name, progress_node);337 CodeGen *child_gen = create_child_codegen(g, zig_file_path, OutTypeLib, nullptr, lib->name, progress_node);
338 codegen_set_lib_version(child_gen, lib->sover, 0, 0);338 codegen_set_lib_version(child_gen, true, lib->sover, 0, 0);
339 child_gen->is_dynamic = true;339 child_gen->is_dynamic = true;
340 child_gen->is_dummy_so = true;340 child_gen->is_dummy_so = true;
341 child_gen->version_script_path = map_file_path;341 child_gen->version_script_path = map_file_path;
src/main.cpp+5-1
...@@ -415,6 +415,7 @@ static int main0(int argc, char **argv) {...@@ -415,6 +415,7 @@ static int main0(int argc, char **argv) {
415 const char *test_filter = nullptr;415 const char *test_filter = nullptr;
416 const char *test_name_prefix = nullptr;416 const char *test_name_prefix = nullptr;
417 bool test_evented_io = false;417 bool test_evented_io = false;
418 bool is_versioned = false;
418 size_t ver_major = 0;419 size_t ver_major = 0;
419 size_t ver_minor = 0;420 size_t ver_minor = 0;
420 size_t ver_patch = 0;421 size_t ver_patch = 0;
...@@ -870,10 +871,13 @@ static int main0(int argc, char **argv) {...@@ -870,10 +871,13 @@ static int main0(int argc, char **argv) {
870 } else if (strcmp(arg, "--test-name-prefix") == 0) {871 } else if (strcmp(arg, "--test-name-prefix") == 0) {
871 test_name_prefix = argv[i];872 test_name_prefix = argv[i];
872 } else if (strcmp(arg, "--ver-major") == 0) {873 } else if (strcmp(arg, "--ver-major") == 0) {
874 is_versioned = true;
873 ver_major = atoi(argv[i]);875 ver_major = atoi(argv[i]);
874 } else if (strcmp(arg, "--ver-minor") == 0) {876 } else if (strcmp(arg, "--ver-minor") == 0) {
877 is_versioned = true;
875 ver_minor = atoi(argv[i]);878 ver_minor = atoi(argv[i]);
876 } else if (strcmp(arg, "--ver-patch") == 0) {879 } else if (strcmp(arg, "--ver-patch") == 0) {
880 is_versioned = true;
877 ver_patch = atoi(argv[i]);881 ver_patch = atoi(argv[i]);
878 } else if (strcmp(arg, "--test-cmd") == 0) {882 } else if (strcmp(arg, "--test-cmd") == 0) {
879 test_exec_args.append(argv[i]);883 test_exec_args.append(argv[i]);
...@@ -1223,7 +1227,7 @@ static int main0(int argc, char **argv) {...@@ -1223,7 +1227,7 @@ static int main0(int argc, char **argv) {
1223 g->emit_llvm_ir = emit_llvm_ir;1227 g->emit_llvm_ir = emit_llvm_ir;
12241228
1225 codegen_set_out_name(g, buf_out_name);1229 codegen_set_out_name(g, buf_out_name);
1226 codegen_set_lib_version(g, ver_major, ver_minor, ver_patch);1230 codegen_set_lib_version(g, is_versioned, ver_major, ver_minor, ver_patch);
1227 g->want_single_threaded = want_single_threaded;1231 g->want_single_threaded = want_single_threaded;
1228 codegen_set_linker_script(g, linker_script);1232 codegen_set_linker_script(g, linker_script);
1229 g->version_script_path = version_script; 1233 g->version_script_path = version_script;
src/target.cpp+21-8
...@@ -779,7 +779,7 @@ const char *target_lib_file_prefix(const ZigTarget *target) {...@@ -779,7 +779,7 @@ const char *target_lib_file_prefix(const ZigTarget *target) {
779 }779 }
780}780}
781781
782const char *target_lib_file_ext(const ZigTarget *target, bool is_static,782const char *target_lib_file_ext(const ZigTarget *target, bool is_static, bool is_versioned,
783 size_t version_major, size_t version_minor, size_t version_patch)783 size_t version_major, size_t version_minor, size_t version_patch)
784{784{
785 if (target_is_wasm(target)) {785 if (target_is_wasm(target)) {
...@@ -799,11 +799,19 @@ const char *target_lib_file_ext(const ZigTarget *target, bool is_static,...@@ -799,11 +799,19 @@ const char *target_lib_file_ext(const ZigTarget *target, bool is_static,
799 if (is_static) {799 if (is_static) {
800 return ".a";800 return ".a";
801 } else if (target_os_is_darwin(target->os)) {801 } else if (target_os_is_darwin(target->os)) {
802 return buf_ptr(buf_sprintf(".%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".dylib",802 if (is_versioned) {
803 version_major, version_minor, version_patch));803 return buf_ptr(buf_sprintf(".%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".dylib",
804 version_major, version_minor, version_patch));
805 } else {
806 return ".dylib";
807 }
804 } else {808 } else {
805 return buf_ptr(buf_sprintf(".so.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize,809 if (is_versioned) {
806 version_major, version_minor, version_patch));810 return buf_ptr(buf_sprintf(".so.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize,
811 version_major, version_minor, version_patch));
812 } else {
813 return ".so";
814 }
807 }815 }
808 }816 }
809}817}
...@@ -853,6 +861,9 @@ const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch) {...@@ -853,6 +861,9 @@ const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch) {
853 case ZigLLVM_riscv32:861 case ZigLLVM_riscv32:
854 case ZigLLVM_riscv64:862 case ZigLLVM_riscv64:
855 case ZigLLVM_mipsel:863 case ZigLLVM_mipsel:
864 case ZigLLVM_ppc:
865 case ZigLLVM_ppc64:
866 case ZigLLVM_ppc64le:
856 return "sp";867 return "sp";
857868
858 case ZigLLVM_wasm32:869 case ZigLLVM_wasm32:
...@@ -879,7 +890,6 @@ const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch) {...@@ -879,7 +890,6 @@ const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch) {
879 case ZigLLVM_msp430:890 case ZigLLVM_msp430:
880 case ZigLLVM_nvptx:891 case ZigLLVM_nvptx:
881 case ZigLLVM_nvptx64:892 case ZigLLVM_nvptx64:
882 case ZigLLVM_ppc64le:
883 case ZigLLVM_r600:893 case ZigLLVM_r600:
884 case ZigLLVM_renderscript32:894 case ZigLLVM_renderscript32:
885 case ZigLLVM_renderscript64:895 case ZigLLVM_renderscript64:
...@@ -893,8 +903,6 @@ const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch) {...@@ -893,8 +903,6 @@ const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch) {
893 case ZigLLVM_tce:903 case ZigLLVM_tce:
894 case ZigLLVM_tcele:904 case ZigLLVM_tcele:
895 case ZigLLVM_xcore:905 case ZigLLVM_xcore:
896 case ZigLLVM_ppc:
897 case ZigLLVM_ppc64:
898 case ZigLLVM_ve:906 case ZigLLVM_ve:
899 zig_panic("TODO populate this table with stack pointer register name for this CPU architecture");907 zig_panic("TODO populate this table with stack pointer register name for this CPU architecture");
900 }908 }
...@@ -1325,6 +1333,11 @@ bool target_is_mips(const ZigTarget *target) {...@@ -1325,6 +1333,11 @@ bool target_is_mips(const ZigTarget *target) {
1325 target->arch == ZigLLVM_mips64 || target->arch == ZigLLVM_mips64el;1333 target->arch == ZigLLVM_mips64 || target->arch == ZigLLVM_mips64el;
1326}1334}
13271335
1336bool target_is_ppc(const ZigTarget *target) {
1337 return target->arch == ZigLLVM_ppc || target->arch == ZigLLVM_ppc64 ||
1338 target->arch == ZigLLVM_ppc64le;
1339}
1340
1328unsigned target_fn_align(const ZigTarget *target) {1341unsigned target_fn_align(const ZigTarget *target) {
1329 return 16;1342 return 16;
1330}1343}
src/target.hpp+2-1
...@@ -87,7 +87,7 @@ const char *target_asm_file_ext(const ZigTarget *target);...@@ -87,7 +87,7 @@ const char *target_asm_file_ext(const ZigTarget *target);
87const char *target_llvm_ir_file_ext(const ZigTarget *target);87const char *target_llvm_ir_file_ext(const ZigTarget *target);
88const char *target_exe_file_ext(const ZigTarget *target);88const char *target_exe_file_ext(const ZigTarget *target);
89const char *target_lib_file_prefix(const ZigTarget *target);89const char *target_lib_file_prefix(const ZigTarget *target);
90const char *target_lib_file_ext(const ZigTarget *target, bool is_static,90const char *target_lib_file_ext(const ZigTarget *target, bool is_static, bool is_versioned,
91 size_t version_major, size_t version_minor, size_t version_patch);91 size_t version_major, size_t version_minor, size_t version_patch);
9292
93bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target);93bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target);
...@@ -95,6 +95,7 @@ ZigLLVM_OSType get_llvm_os_type(Os os_type);...@@ -95,6 +95,7 @@ ZigLLVM_OSType get_llvm_os_type(Os os_type);
9595
96bool target_is_arm(const ZigTarget *target);96bool target_is_arm(const ZigTarget *target);
97bool target_is_mips(const ZigTarget *target);97bool target_is_mips(const ZigTarget *target);
98bool target_is_ppc(const ZigTarget *target);
98bool target_allows_addr_zero(const ZigTarget *target);99bool target_allows_addr_zero(const ZigTarget *target);
99bool target_has_valgrind_support(const ZigTarget *target);100bool target_has_valgrind_support(const ZigTarget *target);
100bool target_os_is_darwin(Os os);101bool target_os_is_darwin(Os os);
test/stack_traces.zig+3-3
...@@ -282,10 +282,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -282,10 +282,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
282 \\source.zig:10:8: [address] in main (test)282 \\source.zig:10:8: [address] in main (test)
283 \\ foo();283 \\ foo();
284 \\ ^284 \\ ^
285 \\start.zig:254:29: [address] in std.start.posixCallMainAndExit (test)285 \\start.zig:269:29: [address] in std.start.posixCallMainAndExit (test)
286 \\ return root.main();286 \\ return root.main();
287 \\ ^287 \\ ^
288 \\start.zig:128:5: [address] in std.start._start (test)288 \\start.zig:143:5: [address] in std.start._start (test)
289 \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});289 \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
290 \\ ^290 \\ ^
291 \\291 \\
...@@ -294,7 +294,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -294,7 +294,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
294 switch (std.Target.current.cpu.arch) {294 switch (std.Target.current.cpu.arch) {
295 .aarch64 => "", // TODO disabled; results in segfault295 .aarch64 => "", // TODO disabled; results in segfault
296 else => 296 else =>
297 \\start.zig:128:5: [address] in std.start._start (test)297 \\start.zig:143:5: [address] in std.start._start (test)
298 \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});298 \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
299 \\ ^299 \\ ^
300 \\300 \\
test/stage1/behavior/translate_c_macros.h+4-1
...@@ -6,4 +6,7 @@ typedef struct Color {...@@ -6,4 +6,7 @@ typedef struct Color {
6 unsigned char a;6 unsigned char a;
7} Color;7} Color;
8#define CLITERAL(type) (type)8#define CLITERAL(type) (type)
9#define LIGHTGRAY CLITERAL(Color){ 200, 200, 200, 255 } // Light Gray
\ No newline at end of file
9#define LIGHTGRAY CLITERAL(Color){ 200, 200, 200, 255 } // Light Gray
10
11#define MY_SIZEOF(x) ((int)sizeof(x))
12#define MY_SIZEOF2(x) ((int)sizeof x)
test/stage1/behavior/translate_c_macros.zig+7-1
...@@ -1,12 +1,18 @@...@@ -1,12 +1,18 @@
1const expect = @import("std").testing.expect;1const expect = @import("std").testing.expect;
2const expectEqual = @import("std").testing.expectEqual;
23
3const h = @cImport(@cInclude("stage1/behavior/translate_c_macros.h"));4const h = @cImport(@cInclude("stage1/behavior/translate_c_macros.h"));
45
5test "initializer list expression" {6test "initializer list expression" {
6 @import("std").testing.expectEqual(h.Color{7 expectEqual(h.Color{
7 .r = 200,8 .r = 200,
8 .g = 200,9 .g = 200,
9 .b = 200,10 .b = 200,
10 .a = 255,11 .a = 255,
11 }, h.LIGHTGRAY);12 }, h.LIGHTGRAY);
12}13}
14
15test "sizeof in macros" {
16 expectEqual(@as(c_int, @sizeOf(u32)), h.MY_SIZEOF(u32));
17 expectEqual(@as(c_int, @sizeOf(u32)), h.MY_SIZEOF2(u32));
18}