From 44556bfebe8d06133c4dfc3cc2685ecb9d3babcd Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 14 Dec 2020 18:59:24 +0100 Subject: [PATCH 1/3] std: non-byte-multiple sized integers have no definite representation Closes #7445 --- lib/std/meta/trait.zig | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/std/meta/trait.zig b/lib/std/meta/trait.zig index eb294a857c..1656a93798 100644 --- a/lib/std/meta/trait.zig +++ b/lib/std/meta/trait.zig @@ -481,10 +481,13 @@ pub fn hasUniqueRepresentation(comptime T: type) bool { .Enum, .ErrorSet, .Fn, - .Int, // TODO check that it is still true .Pointer, => return true, + // The padding bits are undefined. + .Int => |info| return (info.bits % 8) == 0 and + (info.bits == 0 or std.math.isPowerOfTwo(info.bits)), + .Array => |info| return comptime hasUniqueRepresentation(info.child), .Struct => |info| { @@ -525,14 +528,10 @@ test "std.meta.trait.hasUniqueRepresentation" { testing.expect(hasUniqueRepresentation(TestStruct3)); - testing.expect(hasUniqueRepresentation(i1)); - testing.expect(hasUniqueRepresentation(u2)); - testing.expect(hasUniqueRepresentation(i3)); - testing.expect(hasUniqueRepresentation(u4)); - testing.expect(hasUniqueRepresentation(i5)); - testing.expect(hasUniqueRepresentation(u6)); - testing.expect(hasUniqueRepresentation(i7)); - testing.expect(hasUniqueRepresentation(u8)); - testing.expect(hasUniqueRepresentation(i9)); - testing.expect(hasUniqueRepresentation(u10)); + inline for ([_]type{ i0, u8, i16, u32, i64 }) |T| { + testing.expect(hasUniqueRepresentation(T)); + } + inline for ([_]type{ i1, u9, i17, u33, i24 }) |T| { + testing.expect(!hasUniqueRepresentation(T)); + } } From 9e5869262a5f07300b7f4ff65dfe60810f22afee Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 14 Dec 2020 19:05:57 +0100 Subject: [PATCH 2/3] std: Bool has no definite representation too The padding bits are undefined. --- lib/std/meta/trait.zig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/std/meta/trait.zig b/lib/std/meta/trait.zig index 1656a93798..ae3b77b8cc 100644 --- a/lib/std/meta/trait.zig +++ b/lib/std/meta/trait.zig @@ -476,7 +476,6 @@ pub fn hasUniqueRepresentation(comptime T: type) bool { else => return false, // TODO can we know if it's true for some of these types ? .AnyFrame, - .Bool, .BoundFn, .Enum, .ErrorSet, @@ -484,6 +483,8 @@ pub fn hasUniqueRepresentation(comptime T: type) bool { .Pointer, => return true, + .Bool => return false, + // The padding bits are undefined. .Int => |info| return (info.bits % 8) == 0 and (info.bits == 0 or std.math.isPowerOfTwo(info.bits)), From 135f4791e5cbffc75f51d404ef1abb6aca5de0e3 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Thu, 17 Dec 2020 12:00:48 +0100 Subject: [PATCH 3/3] std: Don't hash undefined bits auto_hash must be extra careful when hashing integers whose bit size is not a multiple of 8 as, when reinterpreted with mem.asBytes, may contain undefined non-zero bits too. --- lib/std/hash/auto_hash.zig | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/std/hash/auto_hash.zig b/lib/std/hash/auto_hash.zig index 2e707d5450..e42d55a0a9 100644 --- a/lib/std/hash/auto_hash.zig +++ b/lib/std/hash/auto_hash.zig @@ -99,7 +99,16 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { // Help the optimizer see that hashing an int is easy by inlining! // TODO Check if the situation is better after #561 is resolved. - .Int => @call(.{ .modifier = .always_inline }, hasher.update, .{std.mem.asBytes(&key)}), + .Int => { + if (comptime meta.trait.hasUniqueRepresentation(Key)) { + @call(.{ .modifier = .always_inline }, hasher.update, .{std.mem.asBytes(&key)}); + } else { + // Take only the part containing the key value, the remaining + // bytes are undefined and must not be hashed! + const byte_size = comptime std.math.divCeil(comptime_int, @bitSizeOf(Key), 8) catch unreachable; + @call(.{ .modifier = .always_inline }, hasher.update, .{std.mem.asBytes(&key)[0..byte_size]}); + } + }, .Bool => hash(hasher, @boolToInt(key), strat), .Enum => hash(hasher, @enumToInt(key), strat),