| author | |
| committer | |
| log | b5222f86eec68088b9bd83ad2f648654242082ec |
| tree | efeb5346647a475de4743a42b07316f2c16eb5bb |
| parent | 7d0d99aac0c3e47ab4f82a43525a6f4a18334d43 |
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| ... | @@ -1080,3 +1080,103 @@ test "isatty" { | ... | @@ -1080,3 +1080,103 @@ test "isatty" { |
| 1080 | var file = try tmp.dir.createFile("foo", .{}); | 1080 | var file = try tmp.dir.createFile("foo", .{}); |
| 1081 | try expectEqual(os.isatty(file.handle), false); | 1081 | try expectEqual(os.isatty(file.handle), false); |
| 1082 | } | 1082 | } |
| 1083 | |||
| 1084 | test "read with empty buffer" { | ||
| 1085 | if (native_os == .wasi) return error.SkipZigTest; | ||
| 1086 | |||
| 1087 | var tmp = tmpDir(.{}); | ||
| 1088 | defer tmp.cleanup(); | ||
| 1089 | |||
| 1090 | var arena = ArenaAllocator.init(testing.allocator); | ||
| 1091 | defer arena.deinit(); | ||
| 1092 | const allocator = arena.allocator(); | ||
| 1093 | |||
| 1094 | // Get base abs path | ||
| 1095 | const base_path = blk: { | ||
| 1096 | const relative_path = try fs.path.join(allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..] }); | ||
| 1097 | break :blk try fs.realpathAlloc(allocator, relative_path); | ||
| 1098 | }; | ||
| 1099 | |||
| 1100 | var file_path: []u8 = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" }); | ||
| 1101 | var file = try fs.cwd().createFile(file_path, .{ .read = true }); | ||
| 1102 | defer file.close(); | ||
| 1103 | |||
| 1104 | var bytes = try allocator.alloc(u8, 0); | ||
| 1105 | |||
| 1106 | _ = try os.read(file.handle, bytes); | ||
| 1107 | } | ||
| 1108 | |||
| 1109 | test "pread with empty buffer" { | ||
| 1110 | if (native_os == .wasi) return error.SkipZigTest; | ||
| 1111 | |||
| 1112 | var tmp = tmpDir(.{}); | ||
| 1113 | defer tmp.cleanup(); | ||
| 1114 | |||
| 1115 | var arena = ArenaAllocator.init(testing.allocator); | ||
| 1116 | defer arena.deinit(); | ||
| 1117 | const allocator = arena.allocator(); | ||
| 1118 | |||
| 1119 | // Get base abs path | ||
| 1120 | const base_path = blk: { | ||
| 1121 | const relative_path = try fs.path.join(allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..] }); | ||
| 1122 | break :blk try fs.realpathAlloc(allocator, relative_path); | ||
| 1123 | }; | ||
| 1124 | |||
| 1125 | var file_path: []u8 = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" }); | ||
| 1126 | var file = try fs.cwd().createFile(file_path, .{ .read = true }); | ||
| 1127 | defer file.close(); | ||
| 1128 | |||
| 1129 | var bytes = try allocator.alloc(u8, 0); | ||
| 1130 | |||
| 1131 | _ = try os.pread(file.handle, bytes, 0); | ||
| 1132 | } | ||
| 1133 | |||
| 1134 | test "write with empty buffer" { | ||
| 1135 | if (native_os == .wasi) return error.SkipZigTest; | ||
| 1136 | |||
| 1137 | var tmp = tmpDir(.{}); | ||
| 1138 | defer tmp.cleanup(); | ||
| 1139 | |||
| 1140 | var arena = ArenaAllocator.init(testing.allocator); | ||
| 1141 | defer arena.deinit(); | ||
| 1142 | const allocator = arena.allocator(); | ||
| 1143 | |||
| 1144 | // Get base abs path | ||
| 1145 | const base_path = blk: { | ||
| 1146 | const relative_path = try fs.path.join(allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..] }); | ||
| 1147 | break :blk try fs.realpathAlloc(allocator, relative_path); | ||
| 1148 | }; | ||
| 1149 | |||
| 1150 | var file_path: []u8 = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" }); | ||
| 1151 | var file = try fs.cwd().createFile(file_path, .{}); | ||
| 1152 | defer file.close(); | ||
| 1153 | |||
| 1154 | var bytes = try allocator.alloc(u8, 0); | ||
| 1155 | |||
| 1156 | _ = try os.write(file.handle, bytes); | ||
| 1157 | } | ||
| 1158 | |||
| 1159 | test "pwrite with empty buffer" { | ||
| 1160 | if (native_os == .wasi) return error.SkipZigTest; | ||
| 1161 | |||
| 1162 | var tmp = tmpDir(.{}); | ||
| 1163 | defer tmp.cleanup(); | ||
| 1164 | |||
| 1165 | var arena = ArenaAllocator.init(testing.allocator); | ||
| 1166 | defer arena.deinit(); | ||
| 1167 | const allocator = arena.allocator(); | ||
| 1168 | |||
| 1169 | // Get base abs path | ||
| 1170 | const base_path = blk: { | ||
| 1171 | const relative_path = try fs.path.join(allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..] }); | ||
| 1172 | break :blk try fs.realpathAlloc(allocator, relative_path); | ||
| 1173 | }; | ||
| 1174 | |||
| 1175 | var file_path: []u8 = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" }); | ||
| 1176 | var file = try fs.cwd().createFile(file_path, .{}); | ||
| 1177 | defer file.close(); | ||
| 1178 | |||
| 1179 | var bytes = try allocator.alloc(u8, 0); | ||
| 1180 | |||
| 1181 | _ = try os.pwrite(file.handle, bytes, 0); | ||
| 1182 | } |