diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2019-02-15 18:05:50 -0500 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2019-02-15 18:05:50 -0500 |
| commit | 7293e012d7956b892380517e914108ffadc6941b (patch) | |
| tree | 420049c2174484e2c536d2e36b5b1bb906b921b3 /std | |
| parent | 567c9b688effdb64e3995df09af4b45105515c2c (diff) | |
| download | zig-7293e012d7956b892380517e914108ffadc6941b.tar.gz zig-7293e012d7956b892380517e914108ffadc6941b.zip | |
breaking: fix @sizeOf to be alloc size rather than store size
* Fixes breaches of the guarantee that `@sizeOf(T) >= @alignOf(T)`
* Fixes std.mem.secureZero for integers where this guarantee previously
was breached
* Fixes std.mem.Allocator for integers where this guarantee previously
was breached
Closes #1851
Closes #1864
Diffstat (limited to 'std')
| -rw-r--r-- | std/io.zig | 13 | ||||
| -rw-r--r-- | std/mem.zig | 49 |
2 files changed, 25 insertions, 37 deletions
diff --git a/std/io.zig b/std/io.zig index d7e8507f9b..6c70834b52 100644 --- a/std/io.zig +++ b/std/io.zig @@ -935,8 +935,6 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type { }; } - - pub const BufferedAtomicFile = struct { atomic_file: os.AtomicFile, file_stream: os.File.OutStream, @@ -978,7 +976,6 @@ pub const BufferedAtomicFile = struct { } }; - pub fn readLine(buf: *std.Buffer) ![]u8 { var stdin = try getStdIn(); var stdin_stream = stdin.inStream(); @@ -1073,13 +1070,13 @@ pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime E else => in_stream, } }; } - + pub fn alignToByte(self: *Self) void { - if(!is_packed) return; + if (!is_packed) return; self.in_stream.alignToByte(); } - //@BUG: inferred error issue. See: #1386 + //@BUG: inferred error issue. See: #1386 fn deserializeInt(self: *Self, comptime T: type) (Error || error{EndOfStream})!T { comptime assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T)); @@ -1088,7 +1085,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime E const U = @IntType(false, t_bit_count); const Log2U = math.Log2Int(U); - const int_size = @sizeOf(U); + const int_size = (U.bit_count + 7) / 8; if (is_packed) { const result = try self.in_stream.readBitsNoEof(U, t_bit_count); @@ -1301,7 +1298,7 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime is_packed: bool, com const U = @IntType(false, t_bit_count); const Log2U = math.Log2Int(U); - const int_size = @sizeOf(U); + const int_size = (U.bit_count + 7) / 8; const u_value = @bitCast(U, value); diff --git a/std/mem.zig b/std/mem.zig index 1c7523bf13..39b9701754 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -423,8 +423,7 @@ pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: builtin. /// This function cannot fail and cannot cause undefined behavior. /// Assumes the endianness of memory is native. This means the function can /// simply pointer cast memory. -pub fn readIntNative(comptime T: type, bytes: *const [@sizeOf(T)]u8) T { - comptime assert(T.bit_count % 8 == 0); +pub fn readIntNative(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8) T { return @ptrCast(*align(1) const T, bytes).*; } @@ -432,7 +431,7 @@ pub fn readIntNative(comptime T: type, bytes: *const [@sizeOf(T)]u8) T { /// The bit count of T must be evenly divisible by 8. /// This function cannot fail and cannot cause undefined behavior. /// Assumes the endianness of memory is foreign, so it must byte-swap. -pub fn readIntForeign(comptime T: type, bytes: *const [@sizeOf(T)]u8) T { +pub fn readIntForeign(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8) T { return @bswap(T, readIntNative(T, bytes)); } @@ -446,22 +445,20 @@ pub const readIntBig = switch (builtin.endian) { builtin.Endian.Big => readIntNative, }; -/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 +/// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0 /// and ignores extra bytes. -/// Note that @sizeOf(u24) is 3. /// The bit count of T must be evenly divisible by 8. /// Assumes the endianness of memory is native. This means the function can /// simply pointer cast memory. pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T { - assert(@sizeOf(u24) == 3); - assert(bytes.len >= @sizeOf(T)); + const n = @divExact(T.bit_count, 8); + assert(bytes.len >= n); // TODO https://github.com/ziglang/zig/issues/863 - return readIntNative(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr)); + return readIntNative(T, @ptrCast(*const [n]u8, bytes.ptr)); } -/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 +/// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0 /// and ignores extra bytes. -/// Note that @sizeOf(u24) is 3. /// The bit count of T must be evenly divisible by 8. /// Assumes the endianness of memory is foreign, so it must byte-swap. pub fn readIntSliceForeign(comptime T: type, bytes: []const u8) T { @@ -481,7 +478,7 @@ pub const readIntSliceBig = switch (builtin.endian) { /// Reads an integer from memory with bit count specified by T. /// The bit count of T must be evenly divisible by 8. /// This function cannot fail and cannot cause undefined behavior. -pub fn readInt(comptime T: type, bytes: *const [@sizeOf(T)]u8, endian: builtin.Endian) T { +pub fn readInt(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8, endian: builtin.Endian) T { if (endian == builtin.endian) { return readIntNative(T, bytes); } else { @@ -489,15 +486,14 @@ pub fn readInt(comptime T: type, bytes: *const [@sizeOf(T)]u8, endian: builtin.E } } -/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 +/// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0 /// and ignores extra bytes. -/// Note that @sizeOf(u24) is 3. /// The bit count of T must be evenly divisible by 8. pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T { - assert(@sizeOf(u24) == 3); - assert(bytes.len >= @sizeOf(T)); + const n = @divExact(T.bit_count, 8); + assert(bytes.len >= n); // TODO https://github.com/ziglang/zig/issues/863 - return readInt(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr), endian); + return readInt(T, @ptrCast(*const [n]u8, bytes.ptr), endian); } test "comptime read/write int" { @@ -540,7 +536,7 @@ test "readIntBig and readIntLittle" { /// accepts any integer bit width. /// This function stores in native endian, which means it is implemented as a simple /// memory store. -pub fn writeIntNative(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { +pub fn writeIntNative(comptime T: type, buf: *[(T.bit_count + 7) / 8]u8, value: T) void { @ptrCast(*align(1) T, buf).* = value; } @@ -548,7 +544,7 @@ pub fn writeIntNative(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { /// This function always succeeds, has defined behavior for all inputs, but /// the integer bit width must be divisible by 8. /// This function stores in foreign endian, which means it does a @bswap first. -pub fn writeIntForeign(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { +pub fn writeIntForeign(comptime T: type, buf: *[@divExact(T.bit_count, 8)]u8, value: T) void { writeIntNative(T, buf, @bswap(T, value)); } @@ -565,8 +561,7 @@ pub const writeIntBig = switch (builtin.endian) { /// Writes an integer to memory, storing it in twos-complement. /// This function always succeeds, has defined behavior for all inputs, but /// the integer bit width must be divisible by 8. -pub fn writeInt(comptime T: type, buffer: *[@sizeOf(T)]u8, value: T, endian: builtin.Endian) void { - comptime assert(T.bit_count % 8 == 0); +pub fn writeInt(comptime T: type, buffer: *[@divExact(T.bit_count, 8)]u8, value: T, endian: builtin.Endian) void { if (endian == builtin.endian) { return writeIntNative(T, buffer, value); } else { @@ -575,15 +570,13 @@ pub fn writeInt(comptime T: type, buffer: *[@sizeOf(T)]u8, value: T, endian: bui } /// Writes a twos-complement little-endian integer to memory. -/// Asserts that buf.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. +/// Asserts that buf.len >= T.bit_count / 8. /// The bit count of T must be divisible by 8. /// Any extra bytes in buffer after writing the integer are set to zero. To /// avoid the branch to check for extra buffer bytes, use writeIntLittle /// instead. pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void { - comptime assert(@sizeOf(u24) == 3); - comptime assert(T.bit_count % 8 == 0); - assert(buffer.len >= @sizeOf(T)); + assert(buffer.len >= @divExact(T.bit_count, 8)); // TODO I want to call writeIntLittle here but comptime eval facilities aren't good enough const uint = @IntType(false, T.bit_count); @@ -595,14 +588,12 @@ pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void { } /// Writes a twos-complement big-endian integer to memory. -/// Asserts that buffer.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. +/// Asserts that buffer.len >= T.bit_count / 8. /// The bit count of T must be divisible by 8. /// Any extra bytes in buffer before writing the integer are set to zero. To /// avoid the branch to check for extra buffer bytes, use writeIntBig instead. pub fn writeIntSliceBig(comptime T: type, buffer: []u8, value: T) void { - comptime assert(@sizeOf(u24) == 3); - comptime assert(T.bit_count % 8 == 0); - assert(buffer.len >= @sizeOf(T)); + assert(buffer.len >= @divExact(T.bit_count, 8)); // TODO I want to call writeIntBig here but comptime eval facilities aren't good enough const uint = @IntType(false, T.bit_count); @@ -626,7 +617,7 @@ pub const writeIntSliceForeign = switch (builtin.endian) { }; /// Writes a twos-complement integer to memory, with the specified endianness. -/// Asserts that buf.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. +/// Asserts that buf.len >= T.bit_count / 8. /// The bit count of T must be evenly divisible by 8. /// Any extra bytes in buffer not part of the integer are set to zero, with /// respect to endianness. To avoid the branch to check for extra buffer bytes, |
