| author | |
| committer | |
| log | d0eef26687ca2b4b206b70f001741314d4b8bae8 |
| tree | 412effd210ef65092381783da7397e4376a7280a |
| parent | 09cc6b4b9e76434d734ed131ed48ca849bf8a6ba |
This helps prevent errors related to undefined pointers being passed
through to some OS apis when slices have 0 length.
Tests have also been added to catch these cases.2 files changed, 104 insertions(+), 0 deletions(-)
lib/std/os.zig+4| ... | @@ -660,6 +660,7 @@ pub const ReadError = error{ | ... | @@ -660,6 +660,7 @@ pub const ReadError = error{ |
| 660 | /// The limit on Darwin is `0x7fffffff`, trying to read more than that returns EINVAL. | 660 | /// The limit on Darwin is `0x7fffffff`, trying to read more than that returns EINVAL. |
| 661 | /// The corresponding POSIX limit is `math.maxInt(isize)`. | 661 | /// The corresponding POSIX limit is `math.maxInt(isize)`. |
| 662 | pub fn read(fd: fd_t, buf: []u8) ReadError!usize { | 662 | pub fn read(fd: fd_t, buf: []u8) ReadError!usize { |
| 663 | if (buf.len == 0) return 0; | ||
| 663 | if (builtin.os.tag == .windows) { | 664 | if (builtin.os.tag == .windows) { |
| 664 | return windows.ReadFile(fd, buf, null, std.io.default_mode); | 665 | return windows.ReadFile(fd, buf, null, std.io.default_mode); |
| 665 | } | 666 | } |
| ... | @@ -787,6 +788,7 @@ pub const PReadError = ReadError || error{Unseekable}; | ... | @@ -787,6 +788,7 @@ pub const PReadError = ReadError || error{Unseekable}; |
| 787 | /// The limit on Darwin is `0x7fffffff`, trying to read more than that returns EINVAL. | 788 | /// The limit on Darwin is `0x7fffffff`, trying to read more than that returns EINVAL. |
| 788 | /// The corresponding POSIX limit is `math.maxInt(isize)`. | 789 | /// The corresponding POSIX limit is `math.maxInt(isize)`. |
| 789 | pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize { | 790 | pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize { |
| 791 | if (buf.len == 0) return 0; | ||
| 790 | if (builtin.os.tag == .windows) { | 792 | if (builtin.os.tag == .windows) { |
| 791 | return windows.ReadFile(fd, buf, offset, std.io.default_mode); | 793 | return windows.ReadFile(fd, buf, offset, std.io.default_mode); |
| 792 | } | 794 | } |
| ... | @@ -1045,6 +1047,7 @@ pub const WriteError = error{ | ... | @@ -1045,6 +1047,7 @@ pub const WriteError = error{ |
| 1045 | /// The limit on Darwin is `0x7fffffff`, trying to read more than that returns EINVAL. | 1047 | /// The limit on Darwin is `0x7fffffff`, trying to read more than that returns EINVAL. |
| 1046 | /// The corresponding POSIX limit is `math.maxInt(isize)`. | 1048 | /// The corresponding POSIX limit is `math.maxInt(isize)`. |
| 1047 | pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize { | 1049 | pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize { |
| 1050 | if (bytes.len == 0) return 0; | ||
| 1048 | if (builtin.os.tag == .windows) { | 1051 | if (builtin.os.tag == .windows) { |
| 1049 | return windows.WriteFile(fd, bytes, null, std.io.default_mode); | 1052 | return windows.WriteFile(fd, bytes, null, std.io.default_mode); |
| 1050 | } | 1053 | } |
| ... | @@ -1197,6 +1200,7 @@ pub const PWriteError = WriteError || error{Unseekable}; | ... | @@ -1197,6 +1200,7 @@ pub const PWriteError = WriteError || error{Unseekable}; |
| 1197 | /// The limit on Darwin is `0x7fffffff`, trying to write more than that returns EINVAL. | 1200 | /// The limit on Darwin is `0x7fffffff`, trying to write more than that returns EINVAL. |
| 1198 | /// The corresponding POSIX limit is `math.maxInt(isize)`. | 1201 | /// The corresponding POSIX limit is `math.maxInt(isize)`. |
| 1199 | pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize { | 1202 | pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize { |
| 1203 | if (bytes.len == 0) return 0; | ||
| 1200 | if (builtin.os.tag == .windows) { | 1204 | if (builtin.os.tag == .windows) { |
| 1201 | return windows.WriteFile(fd, bytes, offset, std.io.default_mode); | 1205 | return windows.WriteFile(fd, bytes, offset, std.io.default_mode); |
| 1202 | } | 1206 | } |
lib/std/os/test.zig+100| ... | @@ -1068,3 +1068,103 @@ test "isatty" { | ... | @@ -1068,3 +1068,103 @@ test "isatty" { |
| 1068 | var file = try tmp.dir.createFile("foo", .{}); | 1068 | var file = try tmp.dir.createFile("foo", .{}); |
| 1069 | try expectEqual(os.isatty(file.handle), false); | 1069 | try expectEqual(os.isatty(file.handle), false); |
| 1070 | } | 1070 | } |
| 1071 | |||
| 1072 | test "read with empty buffer" { | ||
| 1073 | if (native_os == .wasi) return error.SkipZigTest; | ||
| 1074 | |||
| 1075 | var tmp = tmpDir(.{}); | ||
| 1076 | defer tmp.cleanup(); | ||
| 1077 | |||
| 1078 | var arena = ArenaAllocator.init(testing.allocator); | ||
| 1079 | defer arena.deinit(); | ||
| 1080 | const allocator = arena.allocator(); | ||
| 1081 | |||
| 1082 | // Get base abs path | ||
| 1083 | const base_path = blk: { | ||
| 1084 | const relative_path = try fs.path.join(allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..] }); | ||
| 1085 | break :blk try fs.realpathAlloc(allocator, relative_path); | ||
| 1086 | }; | ||
| 1087 | |||
| 1088 | var file_path: []u8 = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" }); | ||
| 1089 | var file = try fs.cwd().createFile(file_path, .{ .read = true }); | ||
| 1090 | defer file.close(); | ||
| 1091 | |||
| 1092 | var bytes = try allocator.alloc(u8, 0); | ||
| 1093 | |||
| 1094 | _ = try os.read(file.handle, bytes); | ||
| 1095 | } | ||
| 1096 | |||
| 1097 | test "pread with empty buffer" { | ||
| 1098 | if (native_os == .wasi) return error.SkipZigTest; | ||
| 1099 | |||
| 1100 | var tmp = tmpDir(.{}); | ||
| 1101 | defer tmp.cleanup(); | ||
| 1102 | |||
| 1103 | var arena = ArenaAllocator.init(testing.allocator); | ||
| 1104 | defer arena.deinit(); | ||
| 1105 | const allocator = arena.allocator(); | ||
| 1106 | |||
| 1107 | // Get base abs path | ||
| 1108 | const base_path = blk: { | ||
| 1109 | const relative_path = try fs.path.join(allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..] }); | ||
| 1110 | break :blk try fs.realpathAlloc(allocator, relative_path); | ||
| 1111 | }; | ||
| 1112 | |||
| 1113 | var file_path: []u8 = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" }); | ||
| 1114 | var file = try fs.cwd().createFile(file_path, .{ .read = true }); | ||
| 1115 | defer file.close(); | ||
| 1116 | |||
| 1117 | var bytes = try allocator.alloc(u8, 0); | ||
| 1118 | |||
| 1119 | _ = try os.pread(file.handle, bytes, 0); | ||
| 1120 | } | ||
| 1121 | |||
| 1122 | test "write with empty buffer" { | ||
| 1123 | if (native_os == .wasi) return error.SkipZigTest; | ||
| 1124 | |||
| 1125 | var tmp = tmpDir(.{}); | ||
| 1126 | defer tmp.cleanup(); | ||
| 1127 | |||
| 1128 | var arena = ArenaAllocator.init(testing.allocator); | ||
| 1129 | defer arena.deinit(); | ||
| 1130 | const allocator = arena.allocator(); | ||
| 1131 | |||
| 1132 | // Get base abs path | ||
| 1133 | const base_path = blk: { | ||
| 1134 | const relative_path = try fs.path.join(allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..] }); | ||
| 1135 | break :blk try fs.realpathAlloc(allocator, relative_path); | ||
| 1136 | }; | ||
| 1137 | |||
| 1138 | var file_path: []u8 = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" }); | ||
| 1139 | var file = try fs.cwd().createFile(file_path, .{}); | ||
| 1140 | defer file.close(); | ||
| 1141 | |||
| 1142 | var bytes = try allocator.alloc(u8, 0); | ||
| 1143 | |||
| 1144 | _ = try os.write(file.handle, bytes); | ||
| 1145 | } | ||
| 1146 | |||
| 1147 | test "pwrite with empty buffer" { | ||
| 1148 | if (native_os == .wasi) return error.SkipZigTest; | ||
| 1149 | |||
| 1150 | var tmp = tmpDir(.{}); | ||
| 1151 | defer tmp.cleanup(); | ||
| 1152 | |||
| 1153 | var arena = ArenaAllocator.init(testing.allocator); | ||
| 1154 | defer arena.deinit(); | ||
| 1155 | const allocator = arena.allocator(); | ||
| 1156 | |||
| 1157 | // Get base abs path | ||
| 1158 | const base_path = blk: { | ||
| 1159 | const relative_path = try fs.path.join(allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..] }); | ||
| 1160 | break :blk try fs.realpathAlloc(allocator, relative_path); | ||
| 1161 | }; | ||
| 1162 | |||
| 1163 | var file_path: []u8 = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" }); | ||
| 1164 | var file = try fs.cwd().createFile(file_path, .{}); | ||
| 1165 | defer file.close(); | ||
| 1166 | |||
| 1167 | var bytes = try allocator.alloc(u8, 0); | ||
| 1168 | |||
| 1169 | _ = try os.pwrite(file.handle, bytes, 0); | ||
| 1170 | } |