-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Integrate libc-test cases into the build system #25270
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
pub fn addCases(cases: *tests.LibcContext) void { | ||
cases.addLibcTestCase("api/main.c", true, .{}); | ||
|
||
cases.addLibcTestCase("functional/argv.c", true, .{}); | ||
cases.addLibcTestCase("functional/basename.c", true, .{}); | ||
cases.addLibcTestCase("functional/clocale_mbfuncs.c", true, .{}); | ||
cases.addLibcTestCase("functional/clock_gettime.c", true, .{}); | ||
cases.addLibcTestCase("functional/crypt.c", true, .{}); | ||
cases.addLibcTestCase("functional/dirname.c", true, .{}); | ||
cases.addLibcTestCase("functional/env.c", true, .{}); | ||
cases.addLibcTestCase("functional/fcntl.c", false, .{}); | ||
cases.addLibcTestCase("functional/fdopen.c", false, .{}); | ||
cases.addLibcTestCase("functional/fnmatch.c", true, .{}); | ||
cases.addLibcTestCase("functional/fscanf.c", false, .{}); | ||
cases.addLibcTestCase("functional/fwscanf.c", false, .{}); | ||
cases.addLibcTestCase("functional/iconv_open.c", true, .{}); | ||
cases.addLibcTestCase("functional/inet_pton.c", false, .{}); | ||
// "functional/ipc_msg.c": Probably a bug in qemu | ||
// "functional/ipc_sem.c": Probably a bug in qemu | ||
// "functional/ipc_shm.c": Probably a bug in qemu | ||
cases.addLibcTestCase("functional/mbc.c", true, .{}); | ||
cases.addLibcTestCase("functional/memstream.c", true, .{}); | ||
// "functional/mntent.c": https://www.openwall.com/lists/musl/2024/10/22/1 | ||
cases.addLibcTestCase("functional/popen.c", false, .{}); | ||
cases.addLibcTestCase("functional/pthread_cancel-points.c", false, .{}); | ||
cases.addLibcTestCase("functional/pthread_cancel.c", false, .{}); | ||
cases.addLibcTestCase("functional/pthread_cond.c", false, .{}); | ||
cases.addLibcTestCase("functional/pthread_mutex.c", false, .{}); | ||
// "functional/pthread_mutex_pi.c": Probably a bug in qemu (big/little endian FUTEX_LOCK_PI) | ||
// "functional/pthread_robust.c": https://gitlab.com/qemu-project/qemu/-/issues/2424 | ||
cases.addLibcTestCase("functional/pthread_tsd.c", false, .{}); | ||
cases.addLibcTestCase("functional/qsort.c", true, .{}); | ||
cases.addLibcTestCase("functional/random.c", true, .{}); | ||
cases.addLibcTestCase("functional/search_hsearch.c", false, .{}); // The test suite of wasi-libc runs this test case | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the only non-pthread test included in the tests of wasi-libc, which fails with zig. It seems to be caused by a difference in memory allocation: #include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
int main(void) {
printf("%p, %s\n", malloc(SIZE_MAX), strerror(errno));
}
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's pretty odd... I don't think we do anything differently from upstream wasi-libc with regards to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, we do actually! wasi-libc defaults to dlmalloc, but we default to emmalloc. That might explain it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cc @jedisct1 do you know why we do this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. emmalloc has better performance. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
cases.addLibcTestCase("functional/search_insque.c", true, .{}); | ||
cases.addLibcTestCase("functional/search_lsearch.c", true, .{}); | ||
cases.addLibcTestCase("functional/search_tsearch.c", true, .{}); | ||
cases.addLibcTestCase("functional/sem_init.c", false, .{}); | ||
cases.addLibcTestCase("functional/sem_open.c", false, .{}); | ||
cases.addLibcTestCase("functional/setjmp.c", false, .{}); | ||
cases.addLibcTestCase("functional/snprintf.c", true, .{}); | ||
cases.addLibcTestCase("functional/socket.c", false, .{}); | ||
cases.addLibcTestCase("functional/spawn.c", false, .{}); | ||
cases.addLibcTestCase("functional/sscanf.c", true, .{}); | ||
cases.addLibcTestCase("functional/sscanf_long.c", false, .{}); | ||
cases.addLibcTestCase("functional/stat.c", false, .{}); | ||
cases.addLibcTestCase("functional/strftime.c", true, .{}); | ||
cases.addLibcTestCase("functional/string.c", true, .{}); | ||
cases.addLibcTestCase("functional/string_memcpy.c", true, .{}); | ||
cases.addLibcTestCase("functional/string_memmem.c", true, .{}); | ||
cases.addLibcTestCase("functional/string_memset.c", true, .{}); | ||
cases.addLibcTestCase("functional/string_strchr.c", true, .{}); | ||
cases.addLibcTestCase("functional/string_strcspn.c", true, .{}); | ||
cases.addLibcTestCase("functional/string_strstr.c", true, .{}); | ||
cases.addLibcTestCase("functional/strtod.c", true, .{}); | ||
cases.addLibcTestCase("functional/strtod_long.c", true, .{}); | ||
cases.addLibcTestCase("functional/strtod_simple.c", true, .{}); | ||
cases.addLibcTestCase("functional/strtof.c", true, .{}); | ||
cases.addLibcTestCase("functional/strtol.c", true, .{}); | ||
cases.addLibcTestCase("functional/strtold.c", true, .{}); | ||
cases.addLibcTestCase("functional/swprintf.c", true, .{}); | ||
cases.addLibcTestCase("functional/tgmath.c", true, .{}); | ||
cases.addLibcTestCase("functional/time.c", false, .{}); | ||
cases.addLibcTestCase("functional/tls_align.c", true, .{ .additional_src_file = "functional/tls_align_dso.c" }); | ||
cases.addLibcTestCase("functional/tls_init.c", false, .{}); | ||
cases.addLibcTestCase("functional/tls_local_exec.c", false, .{}); | ||
cases.addLibcTestCase("functional/udiv.c", true, .{}); | ||
cases.addLibcTestCase("functional/ungetc.c", false, .{}); | ||
cases.addLibcTestCase("functional/utime.c", false, .{}); | ||
cases.addLibcTestCase("functional/vfork.c", false, .{}); | ||
cases.addLibcTestCase("functional/wcsstr.c", true, .{}); | ||
cases.addLibcTestCase("functional/wcstol.c", true, .{}); | ||
|
||
cases.addLibcTestCase("regression/daemon-failure.c", false, .{}); | ||
cases.addLibcTestCase("regression/dn_expand-empty.c", false, .{}); | ||
cases.addLibcTestCase("regression/dn_expand-ptr-0.c", false, .{}); | ||
cases.addLibcTestCase("regression/execle-env.c", false, .{}); | ||
cases.addLibcTestCase("regression/fflush-exit.c", false, .{}); | ||
cases.addLibcTestCase("regression/fgets-eof.c", true, .{}); | ||
cases.addLibcTestCase("regression/fgetwc-buffering.c", false, .{}); | ||
cases.addLibcTestCase("regression/flockfile-list.c", false, .{}); | ||
cases.addLibcTestCase("regression/fpclassify-invalid-ld80.c", true, .{}); | ||
cases.addLibcTestCase("regression/ftello-unflushed-append.c", false, .{}); | ||
cases.addLibcTestCase("regression/getpwnam_r-crash.c", false, .{}); | ||
cases.addLibcTestCase("regression/getpwnam_r-errno.c", false, .{}); | ||
cases.addLibcTestCase("regression/iconv-roundtrips.c", true, .{}); | ||
cases.addLibcTestCase("regression/inet_ntop-v4mapped.c", true, .{}); | ||
cases.addLibcTestCase("regression/inet_pton-empty-last-field.c", true, .{}); | ||
cases.addLibcTestCase("regression/iswspace-null.c", true, .{}); | ||
cases.addLibcTestCase("regression/lrand48-signextend.c", true, .{}); | ||
cases.addLibcTestCase("regression/lseek-large.c", false, .{}); | ||
cases.addLibcTestCase("regression/malloc-0.c", true, .{}); | ||
// "regression/malloc-brk-fail.c": QEMU OOM | ||
cases.addLibcTestCase("regression/malloc-oom.c", false, .{}); // wasi-libc: requires t_memfill | ||
cases.addLibcTestCase("regression/mbsrtowcs-overflow.c", true, .{}); | ||
cases.addLibcTestCase("regression/memmem-oob-read.c", true, .{}); | ||
cases.addLibcTestCase("regression/memmem-oob.c", true, .{}); | ||
cases.addLibcTestCase("regression/mkdtemp-failure.c", false, .{}); | ||
cases.addLibcTestCase("regression/mkstemp-failure.c", false, .{}); | ||
cases.addLibcTestCase("regression/printf-1e9-oob.c", true, .{}); | ||
cases.addLibcTestCase("regression/printf-fmt-g-round.c", true, .{}); | ||
cases.addLibcTestCase("regression/printf-fmt-g-zeros.c", true, .{}); | ||
cases.addLibcTestCase("regression/printf-fmt-n.c", true, .{}); | ||
// "regression/pthread-robust-detach.c": https://gitlab.com/qemu-project/qemu/-/issues/2424 | ||
cases.addLibcTestCase("regression/pthread_atfork-errno-clobber.c", false, .{}); | ||
cases.addLibcTestCase("regression/pthread_cancel-sem_wait.c", false, .{}); | ||
cases.addLibcTestCase("regression/pthread_cond-smasher.c", false, .{}); | ||
cases.addLibcTestCase("regression/pthread_cond_wait-cancel_ignored.c", false, .{}); | ||
cases.addLibcTestCase("regression/pthread_condattr_setclock.c", false, .{}); | ||
// "regression/pthread_create-oom.c": QEMU OOM | ||
cases.addLibcTestCase("regression/pthread_exit-cancel.c", false, .{}); | ||
cases.addLibcTestCase("regression/pthread_exit-dtor.c", false, .{}); | ||
cases.addLibcTestCase("regression/pthread_once-deadlock.c", false, .{}); | ||
cases.addLibcTestCase("regression/pthread_rwlock-ebusy.c", false, .{}); | ||
cases.addLibcTestCase("regression/putenv-doublefree.c", true, .{}); | ||
cases.addLibcTestCase("regression/raise-race.c", false, .{}); | ||
cases.addLibcTestCase("regression/regex-backref-0.c", true, .{}); | ||
cases.addLibcTestCase("regression/regex-bracket-icase.c", true, .{}); | ||
cases.addLibcTestCase("regression/regex-ere-backref.c", true, .{}); | ||
cases.addLibcTestCase("regression/regex-escaped-high-byte.c", true, .{}); | ||
cases.addLibcTestCase("regression/regex-negated-range.c", true, .{}); | ||
cases.addLibcTestCase("regression/regexec-nosub.c", true, .{}); | ||
cases.addLibcTestCase("regression/rewind-clear-error.c", false, .{}); | ||
cases.addLibcTestCase("regression/rlimit-open-files.c", false, .{}); | ||
cases.addLibcTestCase("regression/scanf-bytes-consumed.c", true, .{}); | ||
cases.addLibcTestCase("regression/scanf-match-literal-eof.c", true, .{}); | ||
cases.addLibcTestCase("regression/scanf-nullbyte-char.c", true, .{}); | ||
cases.addLibcTestCase("regression/sem_close-unmap.c", false, .{}); | ||
// "regression/setenv-oom.c": QEMU OOM | ||
cases.addLibcTestCase("regression/setvbuf-unget.c", true, .{}); | ||
cases.addLibcTestCase("regression/sigaltstack.c", false, .{}); | ||
cases.addLibcTestCase("regression/sigprocmask-internal.c", false, .{}); | ||
cases.addLibcTestCase("regression/sigreturn.c", true, .{}); | ||
cases.addLibcTestCase("regression/sscanf-eof.c", true, .{}); | ||
cases.addLibcTestCase("regression/strverscmp.c", true, .{}); | ||
cases.addLibcTestCase("regression/syscall-sign-extend.c", false, .{}); | ||
cases.addLibcTestCase("regression/uselocale-0.c", true, .{}); | ||
cases.addLibcTestCase("regression/wcsncpy-read-overflow.c", true, .{}); | ||
cases.addLibcTestCase("regression/wcsstr-false-negative.c", true, .{}); | ||
} | ||
|
||
const std = @import("std"); | ||
const tests = @import("tests.zig"); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
b: *std.Build, | ||
options: Options, | ||
root_step: *std.Build.Step, | ||
|
||
libc_test_src_path: std.Build.LazyPath, | ||
|
||
test_cases: std.ArrayList(TestCase) = .empty, | ||
|
||
pub const Options = struct { | ||
optimize_modes: []const std.builtin.OptimizeMode, | ||
test_filters: []const []const u8, | ||
test_target_filters: []const []const u8, | ||
}; | ||
|
||
const TestCase = struct { | ||
name: []const u8, | ||
src_file: std.Build.LazyPath, | ||
additional_src_file: ?std.Build.LazyPath, | ||
supports_wasi_libc: bool, | ||
}; | ||
|
||
pub const LibcTestCaseOption = struct { | ||
additional_src_file: ?[]const u8 = null, | ||
}; | ||
|
||
pub fn addLibcTestCase( | ||
libc: *Libc, | ||
path: []const u8, | ||
supports_wasi_libc: bool, | ||
options: LibcTestCaseOption, | ||
) void { | ||
const name = libc.b.dupe(path[0 .. path.len - std.fs.path.extension(path).len]); | ||
std.mem.replaceScalar(u8, name, '/', '.'); | ||
libc.test_cases.append(libc.b.allocator, .{ | ||
.name = name, | ||
.src_file = libc.libc_test_src_path.path(libc.b, path), | ||
.additional_src_file = if (options.additional_src_file) |additional_src_file| libc.libc_test_src_path.path(libc.b, additional_src_file) else null, | ||
.supports_wasi_libc = supports_wasi_libc, | ||
}) catch @panic("OOM"); | ||
} | ||
|
||
pub fn addTarget(libc: *const Libc, target: std.Build.ResolvedTarget) void { | ||
if (libc.options.test_target_filters.len > 0) { | ||
const triple_txt = target.query.zigTriple(libc.b.allocator) catch @panic("OOM"); | ||
for (libc.options.test_target_filters) |filter| { | ||
if (std.mem.indexOf(u8, triple_txt, filter)) |_| break; | ||
} else return; | ||
} | ||
|
||
const common = libc.libc_test_src_path.path(libc.b, "common"); | ||
|
||
for (libc.options.optimize_modes) |optimize| { | ||
const libtest_mod = libc.b.createModule(.{ | ||
.target = target, | ||
.optimize = optimize, | ||
.link_libc = true, | ||
}); | ||
|
||
var libtest_c_source_files: []const []const u8 = &.{ "print.c", "rand.c", "setrlim.c", "memfill.c", "vmfill.c", "fdfill.c", "utf8.c" }; | ||
libtest_mod.addCSourceFiles(.{ | ||
.root = common, | ||
.files = libtest_c_source_files[0..if (target.result.isMuslLibC()) 7 else 2], | ||
.flags = &.{"-fno-builtin"}, | ||
}); | ||
|
||
const libtest = libc.b.addLibrary(.{ | ||
.name = "test", | ||
.root_module = libtest_mod, | ||
}); | ||
|
||
for (libc.test_cases.items) |*test_case| { | ||
if (target.result.isWasiLibC() and !test_case.supports_wasi_libc) | ||
continue; | ||
|
||
const annotated_case_name = libc.b.fmt("run libc-test {s} ({t})", .{ test_case.name, optimize }); | ||
for (libc.options.test_filters) |test_filter| { | ||
if (std.mem.indexOf(u8, annotated_case_name, test_filter)) |_| break; | ||
} else if (libc.options.test_filters.len > 0) continue; | ||
|
||
const mod = libc.b.createModule(.{ | ||
.target = target, | ||
.optimize = optimize, | ||
.link_libc = true, | ||
}); | ||
mod.addIncludePath(common); | ||
if (target.result.isWasiLibC()) | ||
mod.addCMacro("_WASI_EMULATED_SIGNAL", ""); | ||
mod.addCSourceFile(.{ | ||
.file = test_case.src_file, | ||
.flags = &.{"-fno-builtin"}, | ||
}); | ||
if (test_case.additional_src_file) |additional_src_file| { | ||
mod.addCSourceFile(.{ | ||
.file = additional_src_file, | ||
.flags = &.{"-fno-builtin"}, | ||
}); | ||
} | ||
mod.linkLibrary(libtest); | ||
|
||
const exe = libc.b.addExecutable(.{ | ||
.name = test_case.name, | ||
.root_module = mod, | ||
}); | ||
|
||
const run = libc.b.addRunArtifact(exe); | ||
run.setName(annotated_case_name); | ||
run.skip_foreign_checks = true; | ||
run.expectStdErrEqual(""); | ||
run.expectStdOutEqual(""); | ||
run.expectExitCode(0); | ||
|
||
libc.root_step.dependOn(&run.step); | ||
} | ||
} | ||
} | ||
|
||
const Libc = @This(); | ||
const std = @import("std"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: This doesn’t actually run any of the api tests. In the original Makefile build,
main
is compiled by including all of the object files undersrc/api
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
api
tests make sure that the libc headers are correct. I did not include the tests, since I don't think it's planned to modify the headers (@alexrp correct me if that's wrong).I included the
main.c
test to have one test, which does not depend on the used functions but signals bigger errors like bugs in the C startup code on failure.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's right. The goal for libzigc is to be API/ABI compatible with established libcs (at least when targeting them).
I imagine our regular module tests would already catch this. But I also don't have any particular objection to including this test either.