Skip to content

Commit 2a51461

Browse files
committed
Fix failing extensive tests
1 parent f4bd37d commit 2a51461

17 files changed

Lines changed: 731 additions & 166 deletions

build.zig

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,17 @@ fn serializeForeignRun(run: *std.Build.Step.Run) void {
4646
foreign_run_serial = &run.step;
4747
}
4848

49+
fn configureExternalHelperRunner(run: *std.Build.Step.Run, exe: *std.Build.Step.Compile) void {
50+
// The helper tools (`testenv`, `parityenv`) are always built for the host.
51+
// Tell them when the child program itself must be launched under an emulator
52+
// so emulator-specific path/argv handling stays in the harness only.
53+
switch (externalRunnerFor(exe)) {
54+
.darling => run.setEnvironmentVariable("ZIGLIBC_EXTERNAL_RUNNER", "darling"),
55+
.wine => run.setEnvironmentVariable("ZIGLIBC_EXTERNAL_RUNNER", "wine"),
56+
.none => {},
57+
}
58+
}
59+
4960
fn addRunArtifactCompat(b: *std.Build, exe: *std.Build.Step.Compile) *std.Build.Step.Run {
5061
return switch (externalRunnerFor(exe)) {
5162
.none => b.addRunArtifact(exe),
@@ -66,7 +77,11 @@ fn addRunArtifactCompat(b: *std.Build, exe: *std.Build.Step.Compile) *std.Build.
6677
\\err="$(mktemp)"
6778
\\darling "$abs" "${mapped[@]}" 2>"$err"
6879
\\rc=$?
69-
\\grep -v -E '^sig:[0-9]+$' "$err" >&2 || true
80+
\\# Darling sometimes emits host-side diagnostics for ioctls it does not
81+
\\# translate, even when the target program completed successfully. Filter
82+
\\# only those emulator-only lines here; never change libc behavior or
83+
\\# native-test expectations to compensate for emulator chatter.
84+
\\grep -v -E '^(sig:[0-9]+|Passing thru unhandled ioctl 0x[0-9a-fA-F]+ on fd [0-9]+)$' "$err" >&2 || true
7085
\\rm -f "$err"
7186
\\[ "$rc" -eq 0 ] || [ "$rc" -eq 127 ]
7287
,
@@ -209,13 +224,13 @@ pub fn build(b: *std.Build) void {
209224
const test_env_exe = addExecutableCompat(b, .{
210225
.name = "testenv",
211226
.root_source_file = lazyPath(b, "tools" ++ std.fs.path.sep_str ++ "testenv.zig"),
212-
.target = target,
227+
.target = b.graph.host,
213228
.optimize = optimize,
214229
});
215230
const parity_env_exe = addExecutableCompat(b, .{
216231
.name = "parityenv",
217232
.root_source_file = lazyPath(b, "tools" ++ std.fs.path.sep_str ++ "parityenv.zig"),
218-
.target = target,
233+
.target = b.graph.host,
219234
.optimize = optimize,
220235
});
221236

@@ -255,24 +270,21 @@ pub fn build(b: *std.Build) void {
255270
if (externalRunnerFor(exe) != .darling) {
256271
const run_step = addRunArtifactCompat(b, test_env_exe);
257272
addArtifactArgCompat(run_step, b, exe);
273+
configureExternalHelperRunner(run_step, exe);
258274
run_step.addCheck(.{ .expect_stdout_exact = "Success!\n" });
259275
test_step.dependOn(&run_step.step);
260276
}
261-
// Darling corrupts argv before our macOS-target getopt_long parser can
262-
// even read argv[optind]. Keep native targets covering this surface;
263-
// the emulator is not a reliable signal here.
277+
// Darling still corrupts argv during the GNU long-option/argp path for
278+
// this binary specifically. Keep native macOS covering the surface; the
279+
// emulator is useful for the broader POSIX/socket/pthread regressions,
280+
// but not as a trustworthy signal for this argv-heavy GNU test.
264281
}
265282
{
266283
const exe = addTest("socket_extensive", b, target, optimize, libc_only_std_static, zig_start);
267284
addPosix(exe, libc_only_posix);
268-
if (externalRunnerFor(exe) != .darling) {
269-
const run_step = addRunArtifactCompat(b, exe);
270-
run_step.addCheck(.{ .expect_stdout_exact = "Success!\n" });
271-
test_step.dependOn(&run_step.step);
272-
}
273-
// Darling's socket layer is not a reliable stand-in for native Darwin.
274-
// Keep this coverage on native targets instead of treating emulator
275-
// failures as libc regressions.
285+
const run_step = addRunArtifactCompat(b, exe);
286+
run_step.addCheck(.{ .expect_stdout_exact = "Success!\n" });
287+
test_step.dependOn(&run_step.step);
276288
}
277289
{
278290
const exe = addExecutableCompat(b, .{
@@ -291,26 +303,27 @@ pub fn build(b: *std.Build) void {
291303
exe.linkSystemLibrary("kernel32");
292304
}
293305
if (externalRunnerFor(exe) != .darling) {
294-
// This test uses Zig's own thread runtime to exercise our pthread
295-
// mutex/cond ABI surface. Native macOS runs it fine, but Darling
296-
// frequently returns 127 before `main`, which is a runner/runtime
297-
// limitation rather than a libc semantic failure.
298306
const run_step = addRunArtifactCompat(b, exe);
299307
run_step.addCheck(.{ .expect_stdout_exact = "Success!\n" });
300308
test_step.dependOn(&run_step.step);
301309
}
310+
// Darling still falls over in Zig's threaded runtime before this test can
311+
// reliably exercise `main()`. Keep native macOS covering pthread ABI
312+
// behavior; the emulator remains useful for the other Darwin-target paths.
302313
}
303314
{
304315
const exe = addTest("fs", b, target, optimize, libc_only_std_static, zig_start);
305316
const run_step = addRunArtifactCompat(b, test_env_exe);
306317
addArtifactArgCompat(run_step, b, exe);
318+
configureExternalHelperRunner(run_step, exe);
307319
run_step.addCheck(.{ .expect_stdout_exact = "Success!\n" });
308320
test_step.dependOn(&run_step.step);
309321
}
310322
{
311323
const exe = addTest("format", b, target, optimize, libc_only_std_static, zig_start);
312324
const run_step = addRunArtifactCompat(b, test_env_exe);
313325
addArtifactArgCompat(run_step, b, exe);
326+
configureExternalHelperRunner(run_step, exe);
314327
run_step.addCheck(.{ .expect_stdout_exact = "Success!\n" });
315328
test_step.dependOn(&run_step.step);
316329
}
@@ -343,13 +356,15 @@ pub fn build(b: *std.Build) void {
343356
const exe = addTest("stdio_extensive", b, target, optimize, libc_only_std_static, zig_start);
344357
const run_step = addRunArtifactCompat(b, test_env_exe);
345358
addArtifactArgCompat(run_step, b, exe);
359+
configureExternalHelperRunner(run_step, exe);
346360
run_step.addCheck(.{ .expect_stdout_exact = "Success!\n" });
347361
test_step.dependOn(&run_step.step);
348362
}
349363
{
350364
const exe = addTest("panic_replacements", b, target, optimize, libc_only_std_static, zig_start);
351365
const run_step = addRunArtifactCompat(b, test_env_exe);
352366
addArtifactArgCompat(run_step, b, exe);
367+
configureExternalHelperRunner(run_step, exe);
353368
run_step.addCheck(.{ .expect_stdout_exact = "Success!\n" });
354369
test_step.dependOn(&run_step.step);
355370
}
@@ -359,9 +374,14 @@ pub fn build(b: *std.Build) void {
359374
if (externalRunnerFor(exe) != .darling) {
360375
const run_step = addRunArtifactCompat(b, test_env_exe);
361376
addArtifactArgCompat(run_step, b, exe);
377+
configureExternalHelperRunner(run_step, exe);
362378
run_step.addCheck(.{ .expect_stdout_exact = "Success!\n" });
363379
test_step.dependOn(&run_step.step);
364380
}
381+
// Darling still has a non-deterministic startup/runtime fault on this
382+
// large POSIX coverage binary even after the target libc paths were fixed.
383+
// Keep native macOS as the source of truth for this surface; the emulator
384+
// remains enabled for the narrower Darwin-target tests that are stable.
365385
}
366386
{
367387
const exe = addTest("getopt", b, target, optimize, libc_only_std_static, zig_start);
@@ -399,16 +419,17 @@ pub fn build(b: *std.Build) void {
399419
}
400420
}
401421

402-
const parity_run: ?*std.Build.Step.Run = if (externalRunnerForTarget(target.result) != .darling) blk: {
422+
const parity_run: ?*std.Build.Step.Run = blk: {
403423
const system_exe = addSystemParityProbe(b, target, optimize);
404424
const zig_exe = addZigParityProbe(b, target, optimize, libc_only_std_static, zig_start, libc_only_posix);
405425
const run_step = addRunArtifactCompat(b, parity_env_exe);
406426
addArtifactArgCompat(run_step, b, system_exe);
407427
addArtifactArgCompat(run_step, b, zig_exe);
428+
configureExternalHelperRunner(run_step, zig_exe);
408429
run_step.addCheck(.{ .expect_stdout_exact = "Success!\n" });
409430
test_step.dependOn(&run_step.step);
410431
break :blk run_step;
411-
} else null;
432+
};
412433

413434
if (supportsSetjmp(target.result)) {
414435
const exe = addTest("jmp", b, target, optimize, libc_only_std_static, zig_start);

inc/posix/netinet/in.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ struct in_addr {
2222
#define INADDR_LOOPBACK ((in_addr_t)0x7f000001)
2323

2424
struct sockaddr_in {
25+
#ifdef __APPLE__
26+
uint8_t sin_len;
27+
#endif
2528
sa_family_t sin_family;
2629
unsigned short sin_port;
2730
struct in_addr sin_addr;

inc/posix/private/sa_family_t.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
#ifndef _PRIVATE_SA_FAMILY_T_H
22
#define _PRIVATE_SA_FAMILY_T_H
33

4+
#ifdef __APPLE__
5+
#include "../../libc/private/uint8_t.h"
6+
typedef uint8_t sa_family_t;
7+
#else
48
typedef unsigned short sa_family_t;
9+
#endif
510

611
#endif /* _PRIVATE_SA_FAMILY_T_H */

inc/posix/private/sockaddr.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
#ifndef _PRIVATE_SOCKADDR_H
22
#define _PRIVATE_SOCKADDR_H
33

4+
#include "../../libc/private/uint8_t.h"
45
#include "sa_family_t.h"
56

67
struct sockaddr {
8+
#ifdef __APPLE__
9+
uint8_t sa_len;
10+
#endif
711
sa_family_t sa_family;
812
char sa_data[14];
913
};

inc/posix/pthread.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,24 +29,57 @@
2929
typedef int pthread_attr_t;
3030
typedef int pthread_barrier_t;
3131
typedef int pthread_barrierattr_t;
32+
#ifdef __APPLE__
33+
#if defined(__LP64__)
34+
#define __ZIGLIBC_PTHREAD_MUTEX_SIZE 56
35+
#define __ZIGLIBC_PTHREAD_COND_SIZE 40
36+
#else
37+
#define __ZIGLIBC_PTHREAD_MUTEX_SIZE 40
38+
#define __ZIGLIBC_PTHREAD_COND_SIZE 24
39+
#endif
40+
typedef struct {
41+
long __sig;
42+
char __opaque[__ZIGLIBC_PTHREAD_COND_SIZE];
43+
} pthread_cond_t;
44+
#else
3245
typedef int pthread_cond_t;
46+
#endif
3347
typedef int pthread_condattr_t;
3448
typedef int pthread_key_t;
49+
#ifdef __APPLE__
50+
typedef struct {
51+
long __sig;
52+
char __opaque[__ZIGLIBC_PTHREAD_MUTEX_SIZE];
53+
} pthread_mutex_t;
54+
#else
3555
typedef int pthread_mutex_t;
56+
#endif
3657
typedef int pthread_mutexattr_t;
3758
typedef int pthread_once_t;
3859
typedef int pthread_rwlock_t;
3960
typedef int pthread_rwlockattr_t;
4061
typedef int pthread_spinlock_t;
4162
typedef int pthread_t;
4263

64+
#ifdef __APPLE__
65+
#define _PTHREAD_MUTEX_SIG_init 0x32AAABA7L
66+
#define _PTHREAD_COND_SIG_init 0x3CB0B1BBL
67+
#define PTHREAD_MUTEX_INITIALIZER {_PTHREAD_MUTEX_SIG_init, {0}}
68+
int pthread_mutex_init(pthread_mutex_t *restrict, const pthread_mutexattr_t *restrict);
69+
int pthread_mutex_destroy(pthread_mutex_t *);
70+
int pthread_mutex_lock(pthread_mutex_t *);
71+
int pthread_mutex_unlock(pthread_mutex_t *);
72+
73+
#define PTHREAD_COND_INITIALIZER {_PTHREAD_COND_SIG_init, {0}}
74+
#else
4375
#define PTHREAD_MUTEX_INITIALIZER 0
4476
int pthread_mutex_init(pthread_mutex_t *restrict, const pthread_mutexattr_t *restrict);
4577
int pthread_mutex_destroy(pthread_mutex_t *);
4678
int pthread_mutex_lock(pthread_mutex_t *);
4779
int pthread_mutex_unlock(pthread_mutex_t *);
4880

4981
#define PTHREAD_COND_INITIALIZER 0
82+
#endif
5083
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
5184
int pthread_cond_destroy(pthread_cond_t *cond);
5285
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);

inc/posix/sys/socket.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
#define AF_INET 2
1515
#define PF_INET AF_INET
1616

17-
#ifdef _WIN32
17+
#if defined(_WIN32) || defined(__APPLE__)
1818
#define SOL_SOCKET 0xffff
1919
#define SO_KEEPALIVE 0x0008
2020
#define SO_SNDBUF 0x1001

inc/posix/termios.h

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,17 @@ struct termios {
4242
int tcgetattr(int, struct termios *);
4343
int tcsetattr(int fildes, int optional_actions, const struct termios *termios_p);
4444

45-
/* I think these definitions are specific to linux but go in termios.h */
46-
#if 1
45+
#if defined(__APPLE__)
46+
#define TIOCGWINSZ 0x40087468
47+
#else
4748
#define TIOCGWINSZ 0x5413
48-
struct winsize {
49-
unsigned short ws_row;
50-
unsigned short ws_col;
51-
unsigned short ws_xpixel;
52-
unsigned short ws_ypixel;
53-
};
5449
#endif
5550

51+
struct winsize {
52+
unsigned short ws_row;
53+
unsigned short ws_col;
54+
unsigned short ws_xpixel;
55+
unsigned short ws_ypixel;
56+
};
57+
5658
#endif /* _TERMIOS_H */

src/cstd.zig

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,48 +1156,41 @@ export fn strerror(errnum: c_int) callconv(.c) [*:0]const u8 {
11561156
// --------------------------------------------------------------------------------
11571157
// signal
11581158
// --------------------------------------------------------------------------------
1159-
const SignalFn = switch (builtin.zig_backend) {
1160-
.stage1 => fn (c_int) callconv(.c) void,
1161-
// `SIG_ERR` is represented as `(void (*)(int))-1`, which is intentionally
1162-
// not guaranteed to satisfy function-pointer alignment.
1163-
else => *align(1) const fn (c_int) callconv(.c) void,
1164-
};
1165-
1166-
export fn signal(sig: c_int, func: SignalFn) callconv(.c) ?SignalFn {
1167-
const sig_err = @as(?SignalFn, @ptrFromInt(@as(usize, @bitCast(@as(isize, -1)))));
1159+
fn _zsignalRaw(sig: c_int, func_ptr: usize) callconv(.c) usize {
1160+
const sig_err = @as(usize, @bitCast(@as(isize, -1)));
11681161
if (builtin.os.tag == .windows) {
11691162
var action = std.mem.zeroes(c.struct_sigaction);
1170-
action.sa_handler = @as(@TypeOf(action.sa_handler), @ptrFromInt(@intFromPtr(func)));
1163+
action.sa_handler = @as(@TypeOf(action.sa_handler), @ptrFromInt(func_ptr));
11711164

11721165
var old_action = std.mem.zeroes(c.struct_sigaction);
11731166
if (__zwindows_sigaction(sig, &action, &old_action) != 0) {
11741167
return sig_err;
11751168
}
11761169
return if (old_action.sa_handler) |h|
1177-
@as(?SignalFn, @ptrFromInt(@intFromPtr(h)))
1170+
@intFromPtr(h)
11781171
else
1179-
null;
1172+
0;
11801173
}
11811174
if (sig < 0 or sig > std.math.maxInt(u6)) {
11821175
errno = c.EINVAL;
11831176
return sig_err;
11841177
}
11851178
if (builtin.os.tag.isDarwin()) {
11861179
var action = std.mem.zeroes(c.struct_sigaction);
1187-
action.sa_handler = @as(@TypeOf(action.sa_handler), @ptrFromInt(@intFromPtr(func)));
1180+
action.sa_handler = @as(@TypeOf(action.sa_handler), @ptrFromInt(func_ptr));
11881181
action.sa_flags = @as(c_int, @bitCast(@as(c_uint, @intCast(std.posix.SA.RESTART))));
11891182

11901183
var old_action = std.mem.zeroes(c.struct_sigaction);
11911184
if (c.sigaction(sig, &action, &old_action) != 0) {
11921185
return sig_err;
11931186
}
11941187
return if (old_action.sa_handler) |h|
1195-
@as(?SignalFn, @ptrFromInt(@intFromPtr(h)))
1188+
@intFromPtr(h)
11961189
else
1197-
null;
1190+
0;
11981191
}
11991192
var action = std.mem.zeroes(c.struct_sigaction);
1200-
action.sa_handler = @as(@TypeOf(action.sa_handler), @ptrFromInt(@intFromPtr(func)));
1193+
action.sa_handler = @as(@TypeOf(action.sa_handler), @ptrFromInt(func_ptr));
12011194
action.sa_flags = @as(c_int, @bitCast(@as(c_uint, @intCast(std.posix.SA.RESTART))));
12021195

12031196
var old_action: std.posix.Sigaction = undefined;
@@ -1206,14 +1199,22 @@ export fn signal(sig: c_int, func: SignalFn) callconv(.c) ?SignalFn {
12061199
@ptrCast(&action),
12071200
&old_action,
12081201
))) {
1209-
.SUCCESS => return @as(?SignalFn, @ptrCast(old_action.handler.handler)),
1202+
.SUCCESS => return @intFromPtr(old_action.handler.handler),
12101203
else => |e| {
12111204
errno = @intFromEnum(e);
12121205
return sig_err;
12131206
},
12141207
}
12151208
}
12161209

1210+
comptime {
1211+
if (builtin.target.ofmt == .coff) {
1212+
@export(&_zsignalRaw, .{ .name = "_zsignalRaw" });
1213+
} else {
1214+
@export(&_zsignalRaw, .{ .name = "_zsignalRaw", .visibility = .hidden });
1215+
}
1216+
}
1217+
12171218
// --------------------------------------------------------------------------------
12181219
// stdio
12191220
// --------------------------------------------------------------------------------

src/posix.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,11 @@ static int zgnu_getopt_long_common(
127127

128128
int __ziglibc_getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex)
129129
{
130-
// Keep the long-option parser in C. The Zig version matched Linux but crashed
131-
// in macOS-target/Darling runs before entering user-visible logic, which is
132-
// consistent with a target-specific ABI/codegen issue rather than parser
133-
// semantics. Export the standard GNU names for ABI compatibility, but keep
134-
// the implementation under a private alias so our own macOS-target callers
135-
// do not rely on Darling resolving the public symbol back into the same
136-
// image correctly.
130+
// Keep the long-option parser in C. This path needs a conservative C ABI
131+
// surface because the earlier Zig implementation hit target-specific ABI /
132+
// codegen problems before any parser semantics were observable. Export the
133+
// standard GNU names for compatibility, but keep the implementation under a
134+
// private alias so the public symbol remains a thin, stable entry point.
137135
return zgnu_getopt_long_common(argc, argv, optstring, longopts, longindex, 0);
138136
}
139137

0 commit comments

Comments
 (0)