Skip to content
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

Runtime page size detection #20511

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/fuzzer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ pub const MemoryMappedList = struct {
/// of this ArrayList in accordance with the respective documentation. In
/// all cases, "invalidated" means that the memory has been passed to this
/// allocator's resize or free function.
items: []align(std.mem.page_size) volatile u8,
items: []align(std.heap.min_page_size) volatile u8,
/// How many bytes this list can hold without allocating additional memory.
capacity: usize,

Expand Down
2 changes: 1 addition & 1 deletion lib/std/Build/Fuzz/WebServer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const fuzzer_arch_os_abi = "wasm32-freestanding";
const fuzzer_cpu_features = "baseline+atomics+bulk_memory+multivalue+mutable_globals+nontrapping_fptoint+reference_types+sign_ext";

const CoverageMap = struct {
mapped_memory: []align(std.mem.page_size) const u8,
mapped_memory: []align(std.heap.min_page_size) const u8,
coverage: Coverage,
source_locations: []Coverage.SourceLocation,
/// Elements are indexes into `source_locations` pointing to the unit tests that are being fuzz tested.
Expand Down
6 changes: 3 additions & 3 deletions lib/std/Thread.zig
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ const PosixThreadImpl = struct {
// Use the same set of parameters used by the libc-less impl.
const stack_size = @max(config.stack_size, 16 * 1024);
assert(c.pthread_attr_setstacksize(&attr, stack_size) == .SUCCESS);
assert(c.pthread_attr_setguardsize(&attr, std.mem.page_size) == .SUCCESS);
assert(c.pthread_attr_setguardsize(&attr, std.heap.pageSize()) == .SUCCESS);

var handle: c.pthread_t = undefined;
switch (c.pthread_create(
Expand Down Expand Up @@ -1150,7 +1150,7 @@ const LinuxThreadImpl = struct {
completion: Completion = Completion.init(.running),
child_tid: std.atomic.Value(i32) = std.atomic.Value(i32).init(1),
parent_tid: i32 = undefined,
mapped: []align(std.mem.page_size) u8,
mapped: []align(std.heap.min_page_size) u8,

/// Calls `munmap(mapped.ptr, mapped.len)` then `exit(1)` without touching the stack (which lives in `mapped.ptr`).
/// Ported over from musl libc's pthread detached implementation:
Expand Down Expand Up @@ -1357,7 +1357,7 @@ const LinuxThreadImpl = struct {
};

fn spawn(config: SpawnConfig, comptime f: anytype, args: anytype) !Impl {
const page_size = std.mem.page_size;
const page_size = std.heap.pageSize();
const Args = @TypeOf(args);
const Instance = struct {
fn_args: Args,
Expand Down
59 changes: 48 additions & 11 deletions lib/std/c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const builtin = @import("builtin");
const c = @This();
const maxInt = std.math.maxInt;
const assert = std.debug.assert;
const page_size = std.mem.page_size;
const min_page_size = std.heap.min_page_size;
const native_abi = builtin.abi;
const native_arch = builtin.cpu.arch;
const native_os = builtin.os.tag;
Expand Down Expand Up @@ -2210,6 +2210,39 @@ pub const SC = switch (native_os) {
.linux => linux.SC,
else => void,
};

pub const _SC = switch (native_os) {
archbirdplus marked this conversation as resolved.
Show resolved Hide resolved
.bridgeos, .driverkit, .ios, .macos, .tvos, .visionos, .watchos => enum(c_int) {
PAGESIZE = 29,
},
.dragonfly => enum(c_int) {
PAGESIZE = 47,
},
.freebsd => enum(c_int) {
PAGESIZE = 47,
},
.fuchsia => enum(c_int) {
PAGESIZE = 30,
},
.haiku => enum(c_int) {
PAGESIZE = 27,
},
.linux => enum(c_int) {
PAGESIZE = 30,
},
.netbsd => enum(c_int) {
PAGESIZE = 28,
},
.openbsd => enum(c_int) {
PAGESIZE = 28,
},
.solaris, .illumos => enum(c_int) {
PAGESIZE = 11,
NPROCESSORS_ONLN = 15,
},
else => void,
};

pub const SEEK = switch (native_os) {
.linux => linux.SEEK,
.emscripten => emscripten.SEEK,
Expand Down Expand Up @@ -9038,7 +9071,7 @@ pub extern "c" fn getpwnam(name: [*:0]const u8) ?*passwd;
pub extern "c" fn getpwuid(uid: uid_t) ?*passwd;
pub extern "c" fn getrlimit64(resource: rlimit_resource, rlim: *rlimit) c_int;
pub extern "c" fn lseek64(fd: fd_t, offset: i64, whence: c_int) i64;
pub extern "c" fn mmap64(addr: ?*align(std.mem.page_size) anyopaque, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: i64) *anyopaque;
pub extern "c" fn mmap64(addr: ?*align(min_page_size) anyopaque, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: i64) *anyopaque;
pub extern "c" fn open64(path: [*:0]const u8, oflag: O, ...) c_int;
pub extern "c" fn openat64(fd: c_int, path: [*:0]const u8, oflag: O, ...) c_int;
pub extern "c" fn pread64(fd: fd_t, buf: [*]u8, nbyte: usize, offset: i64) isize;
Expand Down Expand Up @@ -9126,13 +9159,13 @@ pub extern "c" fn signalfd(fd: fd_t, mask: *const sigset_t, flags: u32) c_int;

pub extern "c" fn prlimit(pid: pid_t, resource: rlimit_resource, new_limit: *const rlimit, old_limit: *rlimit) c_int;
pub extern "c" fn mincore(
addr: *align(std.mem.page_size) anyopaque,
addr: *align(min_page_size) anyopaque,
length: usize,
vec: [*]u8,
) c_int;

pub extern "c" fn madvise(
addr: *align(std.mem.page_size) anyopaque,
addr: *align(min_page_size) anyopaque,
length: usize,
advice: u32,
) c_int;
Expand Down Expand Up @@ -9230,6 +9263,10 @@ pub const posix_memalign = switch (native_os) {
.dragonfly, .netbsd, .freebsd, .solaris, .openbsd, .linux, .macos, .ios, .tvos, .watchos, .visionos => private.posix_memalign,
else => {},
};
pub const sysconf = switch (native_os) {
.solaris => solaris.sysconf,
else => private.sysconf,
};

pub const sf_hdtr = switch (native_os) {
.freebsd, .macos, .ios, .tvos, .watchos, .visionos => extern struct {
Expand Down Expand Up @@ -9271,9 +9308,9 @@ pub extern "c" fn writev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint) i
pub extern "c" fn pwritev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: off_t) isize;
pub extern "c" fn write(fd: fd_t, buf: [*]const u8, nbyte: usize) isize;
pub extern "c" fn pwrite(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: off_t) isize;
pub extern "c" fn mmap(addr: ?*align(page_size) anyopaque, len: usize, prot: c_uint, flags: MAP, fd: fd_t, offset: off_t) *anyopaque;
pub extern "c" fn munmap(addr: *align(page_size) const anyopaque, len: usize) c_int;
pub extern "c" fn mprotect(addr: *align(page_size) anyopaque, len: usize, prot: c_uint) c_int;
pub extern "c" fn mmap(addr: ?*align(min_page_size) anyopaque, len: usize, prot: c_uint, flags: MAP, fd: fd_t, offset: off_t) *anyopaque;
pub extern "c" fn munmap(addr: *align(min_page_size) const anyopaque, len: usize) c_int;
pub extern "c" fn mprotect(addr: *align(min_page_size) anyopaque, len: usize, prot: c_uint) c_int;
pub extern "c" fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8) c_int;
pub extern "c" fn linkat(oldfd: fd_t, oldpath: [*:0]const u8, newfd: fd_t, newpath: [*:0]const u8, flags: c_int) c_int;
pub extern "c" fn unlink(path: [*:0]const u8) c_int;
Expand Down Expand Up @@ -9625,7 +9662,6 @@ pub const SCM = solaris.SCM;
pub const SETCONTEXT = solaris.SETCONTEXT;
pub const SETUSTACK = solaris.GETUSTACK;
pub const SFD = solaris.SFD;
pub const _SC = solaris._SC;
pub const cmsghdr = solaris.cmsghdr;
pub const ctid_t = solaris.ctid_t;
pub const file_obj = solaris.file_obj;
Expand All @@ -9642,7 +9678,6 @@ pub const priority = solaris.priority;
pub const procfs = solaris.procfs;
pub const projid_t = solaris.projid_t;
pub const signalfd_siginfo = solaris.signalfd_siginfo;
pub const sysconf = solaris.sysconf;
pub const taskid_t = solaris.taskid_t;
pub const zoneid_t = solaris.zoneid_t;

Expand Down Expand Up @@ -9796,6 +9831,7 @@ pub const dispatch_semaphore_wait = darwin.dispatch_semaphore_wait;
pub const dispatch_time = darwin.dispatch_time;
pub const fcopyfile = darwin.fcopyfile;
pub const kern_return_t = darwin.kern_return_t;
pub const vm_size_t = darwin.vm_size_t;
pub const kevent64 = darwin.kevent64;
pub const mach_absolute_time = darwin.mach_absolute_time;
pub const mach_continuous_time = darwin.mach_continuous_time;
Expand Down Expand Up @@ -9908,7 +9944,7 @@ const private = struct {
};
extern "c" fn getrusage(who: c_int, usage: *rusage) c_int;
extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
extern "c" fn msync(addr: *align(page_size) const anyopaque, len: usize, flags: c_int) c_int;
extern "c" fn msync(addr: *align(min_page_size) const anyopaque, len: usize, flags: c_int) c_int;
extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
extern "c" fn pipe2(fds: *[2]fd_t, flags: O) c_int;
extern "c" fn readdir(dir: *DIR) ?*dirent;
Expand All @@ -9921,6 +9957,7 @@ const private = struct {
extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;
extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *Stat) c_int;
extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
extern "c" fn sysconf(sc: c_int) c_long;

extern "c" fn pthread_setname_np(thread: pthread_t, name: [*:0]const u8) c_int;
extern "c" fn getcontext(ucp: *ucontext_t) c_int;
Expand Down Expand Up @@ -9955,7 +9992,7 @@ const private = struct {
extern "c" fn __getrusage50(who: c_int, usage: *rusage) c_int;
extern "c" fn __gettimeofday50(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
extern "c" fn __libc_thr_yield() c_int;
extern "c" fn __msync13(addr: *align(std.mem.page_size) const anyopaque, len: usize, flags: c_int) c_int;
extern "c" fn __msync13(addr: *align(min_page_size) const anyopaque, len: usize, flags: c_int) c_int;
extern "c" fn __nanosleep50(rqtp: *const timespec, rmtp: ?*timespec) c_int;
extern "c" fn __sigaction14(sig: c_int, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) c_int;
extern "c" fn __sigfillset14(set: ?*sigset_t) void;
Expand Down
4 changes: 0 additions & 4 deletions lib/std/c/solaris.zig
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,6 @@ pub const AF_SUN = struct {
pub const NOPLM = 0x00000004;
};

pub const _SC = struct {
pub const NPROCESSORS_ONLN = 15;
};

pub const procfs = struct {
pub const misc_header = extern struct {
size: u32,
Expand Down
5 changes: 3 additions & 2 deletions lib/std/crypto/tlcsprng.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
const std = @import("std");
const builtin = @import("builtin");
const mem = std.mem;
const heap = std.heap;
const native_os = builtin.os.tag;
const posix = std.posix;

Expand Down Expand Up @@ -42,7 +43,7 @@ var install_atfork_handler = std.once(struct {
}
}.do);

threadlocal var wipe_mem: []align(mem.page_size) u8 = &[_]u8{};
threadlocal var wipe_mem: []align(heap.min_page_size) u8 = &[_]u8{};

fn tlsCsprngFill(_: *anyopaque, buffer: []u8) void {
if (os_has_arc4random) {
Expand Down Expand Up @@ -77,7 +78,7 @@ fn tlsCsprngFill(_: *anyopaque, buffer: []u8) void {
} else {
// Use a static thread-local buffer.
const S = struct {
threadlocal var buf: Context align(mem.page_size) = .{
threadlocal var buf: Context align(heap.min_page_size) = .{
.init_state = .uninitialized,
.rng = undefined,
};
Expand Down
17 changes: 9 additions & 8 deletions lib/std/debug.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const builtin = @import("builtin");
const std = @import("std.zig");
const math = std.math;
const mem = std.mem;
const heap = std.heap;
const io = std.io;
const posix = std.posix;
const fs = std.fs;
Expand Down Expand Up @@ -1021,7 +1022,7 @@ fn printLineFromFileAnyOs(out_stream: anytype, source_location: SourceLocation)
defer f.close();
// TODO fstat and make sure that the file has the correct size

var buf: [mem.page_size]u8 = undefined;
var buf: [4096]u8 = undefined;
var amt_read = try f.read(buf[0..]);
const line_start = seek: {
var current_line_start: usize = 0;
Expand Down Expand Up @@ -1124,7 +1125,7 @@ test printLineFromFileAnyOs {

const overlap = 10;
var writer = file.writer();
try writer.writeByteNTimes('a', mem.page_size - overlap);
try writer.writeByteNTimes('a', heap.min_page_size - overlap);
try writer.writeByte('\n');
try writer.writeByteNTimes('a', overlap);

Expand All @@ -1139,10 +1140,10 @@ test printLineFromFileAnyOs {
defer allocator.free(path);

var writer = file.writer();
try writer.writeByteNTimes('a', mem.page_size);
try writer.writeByteNTimes('a', heap.max_page_size);

try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 });
try expectEqualStrings(("a" ** mem.page_size) ++ "\n", output.items);
try expectEqualStrings(("a" ** heap.max_page_size) ++ "\n", output.items);
output.clearRetainingCapacity();
}
{
Expand All @@ -1152,18 +1153,18 @@ test printLineFromFileAnyOs {
defer allocator.free(path);

var writer = file.writer();
try writer.writeByteNTimes('a', 3 * mem.page_size);
try writer.writeByteNTimes('a', 3 * heap.max_page_size);

try expectError(error.EndOfFile, printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 }));

try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 });
try expectEqualStrings(("a" ** (3 * mem.page_size)) ++ "\n", output.items);
try expectEqualStrings(("a" ** (3 * heap.max_page_size)) ++ "\n", output.items);
output.clearRetainingCapacity();

try writer.writeAll("a\na");

try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 });
try expectEqualStrings(("a" ** (3 * mem.page_size)) ++ "a\n", output.items);
try expectEqualStrings(("a" ** (3 * heap.max_page_size)) ++ "a\n", output.items);
output.clearRetainingCapacity();

try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 });
Expand All @@ -1177,7 +1178,7 @@ test printLineFromFileAnyOs {
defer allocator.free(path);

var writer = file.writer();
const real_file_start = 3 * mem.page_size;
const real_file_start = 3 * heap.min_page_size;
try writer.writeByteNTimes('\n', real_file_start);
try writer.writeAll("abc\ndef");

Expand Down
10 changes: 5 additions & 5 deletions lib/std/debug/Dwarf.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2110,8 +2110,8 @@ fn pcRelBase(field_ptr: usize, pc_rel_offset: i64) !usize {
pub const ElfModule = struct {
base_address: usize,
dwarf: Dwarf,
mapped_memory: []align(std.mem.page_size) const u8,
external_mapped_memory: ?[]align(std.mem.page_size) const u8,
mapped_memory: []align(std.heap.min_page_size) const u8,
external_mapped_memory: ?[]align(std.heap.min_page_size) const u8,

pub fn deinit(self: *@This(), allocator: Allocator) void {
self.dwarf.deinit(allocator);
Expand Down Expand Up @@ -2157,11 +2157,11 @@ pub const ElfModule = struct {
/// sections from an external file.
pub fn load(
gpa: Allocator,
mapped_mem: []align(std.mem.page_size) const u8,
mapped_mem: []align(std.heap.min_page_size) const u8,
build_id: ?[]const u8,
expected_crc: ?u32,
parent_sections: *Dwarf.SectionArray,
parent_mapped_mem: ?[]align(std.mem.page_size) const u8,
parent_mapped_mem: ?[]align(std.heap.min_page_size) const u8,
elf_filename: ?[]const u8,
) LoadError!Dwarf.ElfModule {
if (expected_crc) |crc| if (crc != std.hash.crc.Crc32.hash(mapped_mem)) return error.InvalidDebugInfo;
Expand Down Expand Up @@ -2413,7 +2413,7 @@ pub const ElfModule = struct {
build_id: ?[]const u8,
expected_crc: ?u32,
parent_sections: *Dwarf.SectionArray,
parent_mapped_mem: ?[]align(std.mem.page_size) const u8,
parent_mapped_mem: ?[]align(std.heap.min_page_size) const u8,
) LoadError!Dwarf.ElfModule {
const elf_file = elf_file_path.root_dir.handle.openFile(elf_file_path.sub_path, .{}) catch |err| switch (err) {
error.FileNotFound => return missing(),
Expand Down
1 change: 0 additions & 1 deletion lib/std/debug/Info.zig
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ const std = @import("../std.zig");
const Allocator = std.mem.Allocator;
const Path = std.Build.Cache.Path;
const Dwarf = std.debug.Dwarf;
const page_size = std.mem.page_size;
const assert = std.debug.assert;
const Coverage = std.debug.Coverage;
const SourceLocation = std.debug.Coverage.SourceLocation;
Expand Down
9 changes: 5 additions & 4 deletions lib/std/debug/MemoryAccessor.zig
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const native_os = builtin.os.tag;
const std = @import("../std.zig");
const posix = std.posix;
const File = std.fs.File;
const page_size = std.mem.page_size;
const min_page_size = std.heap.min_page_size;

const MemoryAccessor = @This();

Expand Down Expand Up @@ -81,9 +81,10 @@ pub fn isValidMemory(address: usize) bool {
// We are unable to determine validity of memory for freestanding targets
if (native_os == .freestanding or native_os == .uefi) return true;

const aligned_address = address & ~@as(usize, @intCast((page_size - 1)));
const page_size = std.heap.pageSize();
const aligned_address = address & ~(page_size - 1);
if (aligned_address == 0) return false;
const aligned_memory = @as([*]align(page_size) u8, @ptrFromInt(aligned_address))[0..page_size];
const aligned_memory = @as([*]align(min_page_size) u8, @ptrFromInt(aligned_address))[0..page_size];

if (native_os == .windows) {
const windows = std.os.windows;
Expand All @@ -92,7 +93,7 @@ pub fn isValidMemory(address: usize) bool {

// The only error this function can throw is ERROR_INVALID_PARAMETER.
// supply an address that invalid i'll be thrown.
const rc = windows.VirtualQuery(aligned_memory, &memory_info, aligned_memory.len) catch {
const rc = windows.VirtualQuery(@ptrCast(aligned_memory), &memory_info, aligned_memory.len) catch {
return false;
};

Expand Down
6 changes: 3 additions & 3 deletions lib/std/debug/SelfInfo.zig
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ pub const Module = switch (native_os) {
.macos, .ios, .watchos, .tvos, .visionos => struct {
base_address: usize,
vmaddr_slide: usize,
mapped_memory: []align(mem.page_size) const u8,
mapped_memory: []align(std.heap.min_page_size) const u8,
symbols: []const MachoSymbol,
strings: [:0]const u8,
ofiles: OFileTable,
Expand Down Expand Up @@ -1046,7 +1046,7 @@ pub fn readElfDebugInfo(
build_id: ?[]const u8,
expected_crc: ?u32,
parent_sections: *Dwarf.SectionArray,
parent_mapped_mem: ?[]align(mem.page_size) const u8,
parent_mapped_mem: ?[]align(std.heap.min_page_size) const u8,
) !Dwarf.ElfModule {
nosuspend {
const elf_file = (if (elf_filename) |filename| blk: {
Expand Down Expand Up @@ -1088,7 +1088,7 @@ const MachoSymbol = struct {

/// Takes ownership of file, even on error.
/// TODO it's weird to take ownership even on error, rework this code.
fn mapWholeFile(file: File) ![]align(mem.page_size) const u8 {
fn mapWholeFile(file: File) ![]align(std.heap.min_page_size) const u8 {
nosuspend {
defer file.close();

Expand Down
Loading
Loading