authorgravatar for jan.hafer@rwth-aachen.deJan Philipp Hafer <jan.hafer@rwth-aachen.de> 2023-03-05 18:41:52+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-08 13:00:06-05:00
log06b263825a67e68cec128c640a6287fa1716dc63
treef9f3d68397896b22051241785620a2baa08e3f90
parentecc0108cea97772b6e921b36d8fdc8f90d5fc6cb

std.os: add missing mmap errors

Man page for posix lists EMFILE, man page for linux ENFILE. Also posix says "The mmap() function adds an extra reference to the file associated with the file descriptor fildes which is not removed by a subsequent close() on that file descriptor. This reference is removed when there are no more mappings to the file." It sounds counter-intuitive, that a process limit but no system limit can be exceeeded. As far as I understand, fildes is only used for file descriptor backed mmaps.

2 files changed, 26 insertions(+), 18 deletions(-)

lib/std/Thread.zig+3
...@@ -945,6 +945,7 @@ const LinuxThreadImpl = struct {...@@ -945,6 +945,7 @@ const LinuxThreadImpl = struct {
945945
946 // map all memory needed without read/write permissions946 // map all memory needed without read/write permissions
947 // to avoid committing the whole region right away947 // to avoid committing the whole region right away
948 // anonymous mapping ensures file descriptor limits are not exceeded
948 const mapped = os.mmap(949 const mapped = os.mmap(
949 null,950 null,
950 map_bytes,951 map_bytes,
...@@ -956,6 +957,8 @@ const LinuxThreadImpl = struct {...@@ -956,6 +957,8 @@ const LinuxThreadImpl = struct {
956 error.MemoryMappingNotSupported => unreachable,957 error.MemoryMappingNotSupported => unreachable,
957 error.AccessDenied => unreachable,958 error.AccessDenied => unreachable,
958 error.PermissionDenied => unreachable,959 error.PermissionDenied => unreachable,
960 error.ProcessFdQuotaExceeded => unreachable,
961 error.SystemFdQuotaExceeded => unreachable,
959 else => |e| return e,962 else => |e| return e,
960 };963 };
961 assert(mapped.len >= map_bytes);964 assert(mapped.len >= map_bytes);
lib/std/os.zig+23-18
...@@ -253,6 +253,25 @@ pub var argv: [][*:0]u8 = if (builtin.link_libc) undefined else switch (builtin....@@ -253,6 +253,25 @@ pub var argv: [][*:0]u8 = if (builtin.link_libc) undefined else switch (builtin.
253 else => undefined,253 else => undefined,
254};254};
255255
256pub const have_sigpipe_support = @hasDecl(@This(), "SIG") and @hasDecl(SIG, "PIPE");
257
258fn noopSigHandler(_: c_int) callconv(.C) void {}
259
260/// On default executed by posix startup code before main(), if SIGPIPE is supported.
261pub fn maybeIgnoreSigpipe() void {
262 if (have_sigpipe_support and !std.options.keep_sigpipe) {
263 const act = Sigaction{
264 // We set handler to a noop function instead of SIG.IGN so we don't leak our
265 // signal disposition to a child process
266 .handler = .{ .handler = noopSigHandler },
267 .mask = empty_sigset,
268 .flags = 0,
269 };
270 sigaction(SIG.PIPE, &act, null) catch |err|
271 std.debug.panic("failed to install noop SIGPIPE handler with '{s}'", .{@errorName(err)});
272 }
273}
274
256/// To obtain errno, call this function with the return value of the275/// To obtain errno, call this function with the return value of the
257/// system function call. For some systems this will obtain the value directly276/// system function call. For some systems this will obtain the value directly
258/// from the return code; for others it will use a thread-local errno variable.277/// from the return code; for others it will use a thread-local errno variable.
...@@ -4306,6 +4325,8 @@ pub const MMapError = error{...@@ -4306,6 +4325,8 @@ pub const MMapError = error{
4306 /// a filesystem that was mounted no-exec.4325 /// a filesystem that was mounted no-exec.
4307 PermissionDenied,4326 PermissionDenied,
4308 LockedMemoryLimitExceeded,4327 LockedMemoryLimitExceeded,
4328 ProcessFdQuotaExceeded,
4329 SystemFdQuotaExceeded,
4309 OutOfMemory,4330 OutOfMemory,
4310} || UnexpectedError;4331} || UnexpectedError;
43114332
...@@ -4347,6 +4368,8 @@ pub fn mmap(...@@ -4347,6 +4368,8 @@ pub fn mmap(
4347 .OVERFLOW => unreachable, // The number of pages used for length + offset would overflow.4368 .OVERFLOW => unreachable, // The number of pages used for length + offset would overflow.
4348 .NODEV => return error.MemoryMappingNotSupported,4369 .NODEV => return error.MemoryMappingNotSupported,
4349 .INVAL => unreachable, // Invalid parameters to mmap()4370 .INVAL => unreachable, // Invalid parameters to mmap()
4371 .MFILE => return error.ProcessFdQuotaExceeded,
4372 .NFILE => return error.SystemFdQuotaExceeded,
4350 .NOMEM => return error.OutOfMemory,4373 .NOMEM => return error.OutOfMemory,
4351 else => return unexpectedErrno(err),4374 else => return unexpectedErrno(err),
4352 }4375 }
...@@ -7081,21 +7104,3 @@ pub fn timerfd_gettime(fd: i32) TimerFdGetError!linux.itimerspec {...@@ -7081,21 +7104,3 @@ pub fn timerfd_gettime(fd: i32) TimerFdGetError!linux.itimerspec {
7081 else => |err| return unexpectedErrno(err),7104 else => |err| return unexpectedErrno(err),
7082 };7105 };
7083}7106}
7084
7085pub const have_sigpipe_support = @hasDecl(@This(), "SIG") and @hasDecl(SIG, "PIPE");
7086
7087fn noopSigHandler(_: c_int) callconv(.C) void {}
7088
7089pub fn maybeIgnoreSigpipe() void {
7090 if (have_sigpipe_support and !std.options.keep_sigpipe) {
7091 const act = Sigaction{
7092 // We set handler to a noop function instead of SIG.IGN so we don't leak our
7093 // signal disposition to a child process
7094 .handler = .{ .handler = noopSigHandler },
7095 .mask = empty_sigset,
7096 .flags = 0,
7097 };
7098 sigaction(SIG.PIPE, &act, null) catch |err|
7099 std.debug.panic("failed to install noop SIGPIPE handler with '{s}'", .{@errorName(err)});
7100 }
7101}