@zigc/lib 0.17.0-dev.667 → 0.17.0-dev.702
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compiler/Maker/ScannedConfig.zig +1 -0
- package/compiler/Maker.zig +4 -4
- package/package.json +1 -1
- package/std/Build/Cache/Path.zig +8 -15
- package/std/Io/Reader.zig +48 -5
- package/std/array_hash_map.zig +1 -2
- package/std/crypto/aes_siv.zig +4 -2
- package/std/crypto/codecs/asn1/Oid.zig +2 -2
- package/std/crypto/codecs/asn1/der/Decoder.zig +44 -13
- package/std/crypto/codecs/asn1/der/Encoder.zig +101 -38
- package/std/crypto/codecs/asn1/der.zig +42 -0
- package/std/crypto/codecs/asn1.zig +96 -37
- package/std/crypto/codecs.zig +6 -0
- package/std/debug/SelfInfo/Elf.zig +1 -1
- package/std/os/linux/xtensa.zig +26 -4
- package/std/pie.zig +0 -2
- package/std/sort/pdq.zig +69 -8
- package/std/start.zig +16 -8
- package/ubsan_rt.zig +3 -3
|
@@ -350,6 +350,7 @@ pub fn printUsage(sc: *const ScannedConfig, graph: *Graph, w: *Writer) !void {
|
|
|
350
350
|
\\ disallowed Panics when cache would be poisoned
|
|
351
351
|
\\ ignored A little poison never hurt anybody
|
|
352
352
|
\\ --print-configuration Render configuration as .zon to stdout
|
|
353
|
+
\\ --print-configuration-path Print the path to the binary configuration file to stdout
|
|
353
354
|
\\ --build-id[=style] At a minor link-time expense, embeds a build ID in binaries
|
|
354
355
|
\\ fast 8-byte non-cryptographic hash (COFF, ELF, WASM)
|
|
355
356
|
\\ sha1, tree 20-byte cryptographic hash (ELF, WASM)
|
package/compiler/Maker.zig
CHANGED
|
@@ -1843,10 +1843,10 @@ pub fn relativePath(maker: *const Maker, arena: Allocator, relative: Configurati
|
|
|
1843
1843
|
.root_dir = graph.zig_lib_directory,
|
|
1844
1844
|
.sub_path = sub_path,
|
|
1845
1845
|
},
|
|
1846
|
-
.install_prefix => maker.install_paths.prefix,
|
|
1847
|
-
.install_lib => maker.install_paths.lib,
|
|
1848
|
-
.install_bin => maker.install_paths.bin,
|
|
1849
|
-
.install_include => maker.install_paths.include,
|
|
1846
|
+
.install_prefix => try maker.install_paths.prefix.join(arena, sub_path),
|
|
1847
|
+
.install_lib => try maker.install_paths.lib.join(arena, sub_path),
|
|
1848
|
+
.install_bin => try maker.install_paths.bin.join(arena, sub_path),
|
|
1849
|
+
.install_include => try maker.install_paths.include.join(arena, sub_path),
|
|
1850
1850
|
};
|
|
1851
1851
|
}
|
|
1852
1852
|
|
package/package.json
CHANGED
package/std/Build/Cache/Path.zig
CHANGED
|
@@ -178,22 +178,15 @@ pub fn formatEscapeChar(path: Path, writer: *Io.Writer) Io.Writer.Error!void {
|
|
|
178
178
|
|
|
179
179
|
pub fn format(self: Path, writer: *Io.Writer) Io.Writer.Error!void {
|
|
180
180
|
if (Io.Dir.path.isAbsolute(self.sub_path)) {
|
|
181
|
-
|
|
182
|
-
|
|
181
|
+
return writer.writeAll(self.sub_path);
|
|
182
|
+
} else if (self.root_dir.path) |p| {
|
|
183
|
+
var bufs: [3][]const u8 = .{ p, Io.Dir.path.sep_str, self.sub_path };
|
|
184
|
+
return writer.writeVecAll(bufs[0..if (self.sub_path.len > 0) 3 else 1]);
|
|
185
|
+
} else if (self.sub_path.len > 0) {
|
|
186
|
+
return writer.writeAll(self.sub_path);
|
|
187
|
+
} else {
|
|
188
|
+
return writer.writeByte('.');
|
|
183
189
|
}
|
|
184
|
-
if (self.root_dir.path) |p| {
|
|
185
|
-
try writer.writeAll(p);
|
|
186
|
-
if (self.sub_path.len > 0) {
|
|
187
|
-
try writer.writeAll(Io.Dir.path.sep_str);
|
|
188
|
-
try writer.writeAll(self.sub_path);
|
|
189
|
-
}
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
if (self.sub_path.len > 0) {
|
|
193
|
-
try writer.writeAll(self.sub_path);
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
try writer.writeByte('.');
|
|
197
190
|
}
|
|
198
191
|
|
|
199
192
|
pub fn eql(self: Path, other: Path) bool {
|
package/std/Io/Reader.zig
CHANGED
|
@@ -242,11 +242,10 @@ pub fn streamExactPreserve(r: *Reader, w: *Writer, preserve_len: usize, n: usize
|
|
|
242
242
|
remaining -= try r.stream(w, .limited(remaining - preserve_len));
|
|
243
243
|
if (w.end + remaining <= w.buffer.len) return streamExact(r, w, remaining);
|
|
244
244
|
}
|
|
245
|
-
//
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
}
|
|
245
|
+
// Offset the amount preserved by the amount we have left to stream
|
|
246
|
+
// since the remaining bytes are always going to be part of that
|
|
247
|
+
// preservation.
|
|
248
|
+
try w.rebase(preserve_len -| remaining, remaining);
|
|
250
249
|
return streamExact(r, w, remaining);
|
|
251
250
|
}
|
|
252
251
|
|
|
@@ -2300,6 +2299,50 @@ fn testLeb128(comptime T: type, encoded: []const u8) !T {
|
|
|
2300
2299
|
return result;
|
|
2301
2300
|
}
|
|
2302
2301
|
|
|
2302
|
+
test streamExactPreserve {
|
|
2303
|
+
try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 5, .stream_len = 5 });
|
|
2304
|
+
try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 9, .preserve = 5, .stream_len = 2 });
|
|
2305
|
+
try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 5, .stream_len = 6 });
|
|
2306
|
+
try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 6, .stream_len = 6 });
|
|
2307
|
+
try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 5, .stream_len = 10 });
|
|
2308
|
+
try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 6, .stream_len = 10 });
|
|
2309
|
+
try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 6, .stream_len = 11 });
|
|
2310
|
+
try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 6, .stream_len = 80 });
|
|
2311
|
+
try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 6, .stream_len = 85 });
|
|
2312
|
+
try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 10, .stream_len = 6 });
|
|
2313
|
+
try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 10, .stream_len = 11 });
|
|
2314
|
+
try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 10, .stream_len = 80 });
|
|
2315
|
+
try testStreamExactPreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 10, .stream_len = 85 });
|
|
2316
|
+
}
|
|
2317
|
+
|
|
2318
|
+
fn testStreamExactPreserve(options: struct { buf_len: u4, fill_len: u4, preserve: u4, stream_len: u8 }) !void {
|
|
2319
|
+
assert(options.fill_len <= options.buf_len);
|
|
2320
|
+
assert(options.preserve <= options.buf_len);
|
|
2321
|
+
|
|
2322
|
+
var input: [256]u8 = undefined;
|
|
2323
|
+
for (&input, 0..) |*val, i| {
|
|
2324
|
+
val.* = @as(u8, @intCast(i % 26)) + 'a';
|
|
2325
|
+
}
|
|
2326
|
+
const expected_out = input[0 .. options.fill_len + options.stream_len];
|
|
2327
|
+
const expected_preserved = expected_out[expected_out.len -| options.preserve..];
|
|
2328
|
+
|
|
2329
|
+
var r: Reader = .fixed(&input);
|
|
2330
|
+
var out_buf: [256]u8 = undefined;
|
|
2331
|
+
var fw: Writer = .fixed(&out_buf);
|
|
2332
|
+
var indirect_buffer: [16]u8 = undefined;
|
|
2333
|
+
var twi: std.testing.WriterIndirect = .init(&fw, indirect_buffer[0..options.buf_len]);
|
|
2334
|
+
const w = &twi.interface;
|
|
2335
|
+
|
|
2336
|
+
try r.streamExact(w, options.fill_len);
|
|
2337
|
+
try r.streamExactPreserve(w, options.preserve, options.stream_len);
|
|
2338
|
+
|
|
2339
|
+
try std.testing.expectEqualStrings(expected_preserved, w.buffer[w.end -| options.preserve..w.end]);
|
|
2340
|
+
|
|
2341
|
+
try w.flush();
|
|
2342
|
+
|
|
2343
|
+
try std.testing.expectEqualStrings(expected_out, fw.buffered());
|
|
2344
|
+
}
|
|
2345
|
+
|
|
2303
2346
|
test {
|
|
2304
2347
|
_ = Limited;
|
|
2305
2348
|
}
|
package/std/array_hash_map.zig
CHANGED
|
@@ -57,8 +57,7 @@ pub const ArrayHashMap = Custom;
|
|
|
57
57
|
/// the (well defined) behavior when mixing insertions and deletions with iteration.
|
|
58
58
|
///
|
|
59
59
|
/// This type does not store an `Allocator` field - the `Allocator` must be passed in
|
|
60
|
-
/// with each function call that requires it.
|
|
61
|
-
/// an `Allocator` field for convenience.
|
|
60
|
+
/// with each function call that requires it.
|
|
62
61
|
///
|
|
63
62
|
/// Can be initialized directly using the default field values.
|
|
64
63
|
///
|
package/std/crypto/aes_siv.zig
CHANGED
|
@@ -226,9 +226,10 @@ fn AesSiv(comptime Aes: anytype) type {
|
|
|
226
226
|
|
|
227
227
|
/// Encrypts plaintext with multiple associated data components.
|
|
228
228
|
/// This is the most general form of AES-SIV encryption that accepts
|
|
229
|
-
///
|
|
229
|
+
/// a vector of up to 126 associated data strings as specified in RFC 5297.
|
|
230
230
|
pub fn encryptWithAdVector(c: []u8, tag: *[tag_length]u8, m: []const u8, ad: []const []const u8, key: [key_length]u8) void {
|
|
231
231
|
debug.assert(c.len == m.len);
|
|
232
|
+
debug.assert(ad.len <= 126); // AES-SIV supports at most 126 associated data components
|
|
232
233
|
|
|
233
234
|
// Split key into K1 (for S2V) and K2 (for CTR)
|
|
234
235
|
const k1 = key[0 .. Aes.key_bits / 8];
|
|
@@ -260,9 +261,10 @@ fn AesSiv(comptime Aes: anytype) type {
|
|
|
260
261
|
|
|
261
262
|
/// Decrypts ciphertext with multiple associated data components.
|
|
262
263
|
/// This is the most general form of AES-SIV decryption that accepts
|
|
263
|
-
///
|
|
264
|
+
/// a vector of up to 126 associated data strings as specified in RFC 5297.
|
|
264
265
|
pub fn decryptWithAdVector(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const []const u8, key: [key_length]u8) AuthenticationError!void {
|
|
265
266
|
assert(c.len == m.len);
|
|
267
|
+
assert(ad.len <= 126); // AES-SIV supports at most 126 associated data components
|
|
266
268
|
|
|
267
269
|
// Split key into K1 (for S2V) and K2 (for CTR)
|
|
268
270
|
const k1 = key[0 .. Aes.key_bits / 8];
|
|
@@ -47,7 +47,7 @@ test fromDot {
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
pub fn toDot(self: Oid, writer:
|
|
50
|
+
pub fn toDot(self: Oid, writer: *std.Io.Writer) std.Io.Writer.Error!void {
|
|
51
51
|
const encoded = self.encoded;
|
|
52
52
|
const first = @divTrunc(encoded[0], 40);
|
|
53
53
|
const second = encoded[0] - first * 40;
|
|
@@ -81,7 +81,7 @@ test toDot {
|
|
|
81
81
|
for (test_cases) |t| {
|
|
82
82
|
var stream: std.Io.Writer = .fixed(&buf);
|
|
83
83
|
try toDot(Oid{ .encoded = t.encoded }, &stream);
|
|
84
|
-
try std.testing.expectEqualStrings(t.dot_notation, stream.
|
|
84
|
+
try std.testing.expectEqualStrings(t.dot_notation, stream.buffered());
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
|
|
@@ -111,21 +111,33 @@ pub fn view(self: Decoder, elem: Element) []const u8 {
|
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
fn int(comptime T: type, value: []const u8) error{ NonCanonical, LargeValue }!T {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
if (
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
if (bytes[0] == 0xff and @clz(bytes[1]) == 0) return error.NonCanonical;
|
|
114
|
+
const info = @typeInfo(T).int;
|
|
115
|
+
if (info.bits % 8 != 0) @compileError("T must be byte aligned");
|
|
116
|
+
|
|
117
|
+
if (value.len == 0) return error.NonCanonical;
|
|
118
|
+
if (value.len >= 2) {
|
|
119
|
+
if (value[0] == 0x00 and value[1] & 0x80 == 0) return error.NonCanonical;
|
|
120
|
+
if (value[0] == 0xff and value[1] & 0x80 != 0) return error.NonCanonical;
|
|
123
121
|
}
|
|
124
122
|
|
|
125
|
-
|
|
126
|
-
if (
|
|
123
|
+
const had_sign_byte = value.len >= 2 and value[0] == 0x00;
|
|
124
|
+
const bytes = if (had_sign_byte) value[1..] else value;
|
|
125
|
+
const der_negative = !had_sign_byte and bytes[0] & 0x80 != 0;
|
|
126
|
+
|
|
127
|
+
switch (info.signedness) {
|
|
128
|
+
.unsigned => {
|
|
129
|
+
if (der_negative) return error.LargeValue;
|
|
130
|
+
if (bytes.len > @sizeOf(T)) return error.LargeValue;
|
|
131
|
+
},
|
|
132
|
+
.signed => {
|
|
133
|
+
const max_len: usize = if (had_sign_byte) @sizeOf(T) - 1 else @sizeOf(T);
|
|
134
|
+
if (bytes.len > max_len) return error.LargeValue;
|
|
135
|
+
},
|
|
136
|
+
}
|
|
127
137
|
|
|
128
|
-
|
|
138
|
+
var buf: [@sizeOf(T)]u8 = @splat(if (der_negative) 0xff else 0);
|
|
139
|
+
@memcpy(buf[buf.len - bytes.len ..], bytes);
|
|
140
|
+
return std.mem.readInt(T, &buf, .big);
|
|
129
141
|
}
|
|
130
142
|
|
|
131
143
|
test int {
|
|
@@ -135,7 +147,26 @@ test int {
|
|
|
135
147
|
|
|
136
148
|
const big = [_]u8{ 0xef, 0xff };
|
|
137
149
|
try expectError(error.LargeValue, int(u8, &big));
|
|
138
|
-
try
|
|
150
|
+
try expectError(error.LargeValue, int(u16, &big));
|
|
151
|
+
try expectEqual(@as(i16, -4097), try int(i16, &big));
|
|
152
|
+
|
|
153
|
+
try expectEqual(@as(u16, 255), try int(u16, &.{ 0x00, 0xff }));
|
|
154
|
+
try expectEqual(@as(u16, 0x8000), try int(u16, &.{ 0x00, 0x80, 0x00 }));
|
|
155
|
+
|
|
156
|
+
try expectEqual(@as(i8, -1), try int(i8, &.{0xff}));
|
|
157
|
+
try expectEqual(@as(i16, -1), try int(i16, &.{0xff}));
|
|
158
|
+
try expectEqual(@as(i16, -128), try int(i16, &.{0x80}));
|
|
159
|
+
try expectEqual(@as(i16, -129), try int(i16, &.{ 0xff, 0x7f }));
|
|
160
|
+
try expectEqual(@as(i16, 255), try int(i16, &.{ 0x00, 0xff }));
|
|
161
|
+
try expectEqual(@as(i32, 0x7fffffff), try int(i32, &.{ 0x7f, 0xff, 0xff, 0xff }));
|
|
162
|
+
|
|
163
|
+
try expectError(error.LargeValue, int(i8, &.{ 0x00, 0xff }));
|
|
164
|
+
try expectError(error.LargeValue, int(i16, &.{ 0x00, 0x80, 0x00 }));
|
|
165
|
+
try expectError(error.LargeValue, int(i32, &.{ 0x00, 0x80, 0x00, 0x00, 0x00 }));
|
|
166
|
+
|
|
167
|
+
try expectError(error.LargeValue, int(u8, &.{0xff}));
|
|
168
|
+
try expectError(error.LargeValue, int(u16, &.{0x80}));
|
|
169
|
+
try expectError(error.LargeValue, int(u32, &.{ 0x80, 0x00, 0x00, 0x00 }));
|
|
139
170
|
}
|
|
140
171
|
|
|
141
172
|
test Decoder {
|
|
@@ -24,6 +24,7 @@ pub fn any(self: *Encoder, val: anytype) !void {
|
|
|
24
24
|
fn anyTag(self: *Encoder, tag_: Tag, val: anytype) !void {
|
|
25
25
|
const T = @TypeOf(val);
|
|
26
26
|
if (std.meta.hasFn(T, "encodeDer")) return try val.encodeDer(self);
|
|
27
|
+
const outer_field_tag = self.field_tag;
|
|
27
28
|
const start = self.buffer.data.len;
|
|
28
29
|
const merged_tag = self.mergedTag(tag_);
|
|
29
30
|
|
|
@@ -42,8 +43,9 @@ fn anyTag(self: *Encoder, tag_: Tag, val: anytype) !void {
|
|
|
42
43
|
const is_default = if (f_attrs.@"comptime") false else if (f_attrs.defaultValue(f_type)) |default_val| brk: {
|
|
43
44
|
break :brk std.mem.eql(u8, std.mem.asBytes(&default_val), std.mem.asBytes(&field_val));
|
|
44
45
|
} else false;
|
|
46
|
+
const is_null_optional = if (@typeInfo(f_type) == .optional) field_val == null else false;
|
|
45
47
|
|
|
46
|
-
if (!is_default) {
|
|
48
|
+
if (!is_default and !is_null_optional) {
|
|
47
49
|
const start2 = self.buffer.data.len;
|
|
48
50
|
self.field_tag = field_tag;
|
|
49
51
|
// will merge with self.field_tag.
|
|
@@ -58,6 +60,7 @@ fn anyTag(self: *Encoder, tag_: Tag, val: anytype) !void {
|
|
|
58
60
|
}
|
|
59
61
|
}
|
|
60
62
|
}
|
|
63
|
+
self.field_tag = outer_field_tag;
|
|
61
64
|
},
|
|
62
65
|
.bool => try self.buffer.prependSlice(&[_]u8{if (val) 0xff else 0}),
|
|
63
66
|
.int => try self.int(T, val),
|
|
@@ -68,7 +71,7 @@ fn anyTag(self: *Encoder, tag_: Tag, val: anytype) !void {
|
|
|
68
71
|
try self.int(e.tag_type, @intFromEnum(val));
|
|
69
72
|
}
|
|
70
73
|
},
|
|
71
|
-
.optional => if (val) |v| return try self.anyTag(tag_, v),
|
|
74
|
+
.optional => if (val) |v| return try self.anyTag(tag_, v) else return,
|
|
72
75
|
.null => {},
|
|
73
76
|
else => @compileError("cannot encode type " ++ @typeName(T)),
|
|
74
77
|
}
|
|
@@ -80,7 +83,8 @@ fn anyTag(self: *Encoder, tag_: Tag, val: anytype) !void {
|
|
|
80
83
|
/// Encode a tag.
|
|
81
84
|
pub fn tag(self: *Encoder, tag_: Tag) !void {
|
|
82
85
|
const t = self.mergedTag(tag_);
|
|
83
|
-
|
|
86
|
+
var buf: [Tag.max_encoded_len]u8 = undefined;
|
|
87
|
+
try self.buffer.prependSlice(t.encodeToSlice(&buf));
|
|
84
88
|
}
|
|
85
89
|
|
|
86
90
|
fn mergedTag(self: *Encoder, tag_: Tag) Tag {
|
|
@@ -96,19 +100,14 @@ fn mergedTag(self: *Encoder, tag_: Tag) Tag {
|
|
|
96
100
|
|
|
97
101
|
/// Encode a length.
|
|
98
102
|
pub fn length(self: *Encoder, len: usize) !void {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
try writer_.writeInt(u8, @sizeOf(T) | 0x80, .big);
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
return error.InvalidLength;
|
|
103
|
+
if (len < 128) return self.buffer.prependSlice(&.{@intCast(len)});
|
|
104
|
+
const len32 = std.math.cast(u32, len) orelse return error.InvalidLength;
|
|
105
|
+
var buf: [@sizeOf(u32) + 1]u8 = undefined;
|
|
106
|
+
std.mem.writeInt(u32, buf[1..], len32, .big);
|
|
107
|
+
var first: usize = 1;
|
|
108
|
+
while (buf[first] == 0) first += 1;
|
|
109
|
+
buf[first - 1] = @intCast((buf.len - first) | 0x80);
|
|
110
|
+
return self.buffer.prependSlice(buf[first - 1 ..]);
|
|
112
111
|
}
|
|
113
112
|
|
|
114
113
|
/// Encode a tag and length-prefixed bytes.
|
|
@@ -118,28 +117,23 @@ pub fn tagBytes(self: *Encoder, tag_: Tag, bytes: []const u8) !void {
|
|
|
118
117
|
try self.tag(tag_);
|
|
119
118
|
}
|
|
120
119
|
|
|
121
|
-
///
|
|
122
|
-
|
|
123
|
-
|
|
120
|
+
/// Write raw bytes. The encoder builds its output back-to-front, so chained
|
|
121
|
+
/// calls should be made in reverse of the desired on-wire order.
|
|
122
|
+
pub fn prependBytes(self: *Encoder, bytes: []const u8) !void {
|
|
123
|
+
return self.buffer.prependSlice(bytes);
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
fn int(self: *Encoder, comptime T: type, value: T) !void {
|
|
127
|
-
const
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
} else 0;
|
|
138
|
-
const bytes_needed = try std.math.divCeil(usize, bits_needed, 8) + needs_padding;
|
|
139
|
-
|
|
140
|
-
const writer_ = self.writer();
|
|
141
|
-
for (0..bytes_needed - needs_padding) |i| try writer_.writeByte(big_bytes[big_bytes.len - i - 1]);
|
|
142
|
-
if (needs_padding == 1) try writer_.writeByte(0);
|
|
127
|
+
const info = @typeInfo(T).int;
|
|
128
|
+
const Unsigned = @Int(.unsigned, info.bits);
|
|
129
|
+
const pad: u8 = if (info.signedness == .signed and value < 0) 0xff else 0;
|
|
130
|
+
var buf: [@sizeOf(Unsigned) + 1]u8 = undefined;
|
|
131
|
+
buf[0] = pad;
|
|
132
|
+
std.mem.writeInt(Unsigned, buf[1..], @bitCast(value), .big);
|
|
133
|
+
|
|
134
|
+
var first: usize = 0;
|
|
135
|
+
while (first + 1 < buf.len and buf[first] == pad and (buf[first + 1] ^ pad) & 0x80 == 0) first += 1;
|
|
136
|
+
try self.buffer.prependSlice(buf[first..]);
|
|
143
137
|
}
|
|
144
138
|
|
|
145
139
|
test int {
|
|
@@ -148,15 +142,84 @@ test int {
|
|
|
148
142
|
defer encoder.deinit();
|
|
149
143
|
|
|
150
144
|
try encoder.int(u8, 0);
|
|
151
|
-
try std.testing.expectEqualSlices(u8,
|
|
145
|
+
try std.testing.expectEqualSlices(u8, &.{0}, encoder.buffer.data);
|
|
152
146
|
|
|
153
147
|
encoder.buffer.clearAndFree();
|
|
154
148
|
try encoder.int(u16, 0x00ff);
|
|
155
|
-
try std.testing.expectEqualSlices(u8,
|
|
149
|
+
try std.testing.expectEqualSlices(u8, &.{ 0, 0xff }, encoder.buffer.data);
|
|
156
150
|
|
|
157
151
|
encoder.buffer.clearAndFree();
|
|
158
152
|
try encoder.int(u32, 0xffff);
|
|
159
|
-
try std.testing.expectEqualSlices(u8,
|
|
153
|
+
try std.testing.expectEqualSlices(u8, &.{ 0, 0xff, 0xff }, encoder.buffer.data);
|
|
154
|
+
|
|
155
|
+
encoder.buffer.clearAndFree();
|
|
156
|
+
try encoder.int(u32, 0x01020304);
|
|
157
|
+
try std.testing.expectEqualSlices(u8, &.{ 0x01, 0x02, 0x03, 0x04 }, encoder.buffer.data);
|
|
158
|
+
|
|
159
|
+
encoder.buffer.clearAndFree();
|
|
160
|
+
try encoder.int(u8, 127);
|
|
161
|
+
try std.testing.expectEqualSlices(u8, &.{0x7f}, encoder.buffer.data);
|
|
162
|
+
|
|
163
|
+
encoder.buffer.clearAndFree();
|
|
164
|
+
try encoder.int(u16, 128);
|
|
165
|
+
try std.testing.expectEqualSlices(u8, &.{ 0, 0x80 }, encoder.buffer.data);
|
|
166
|
+
|
|
167
|
+
encoder.buffer.clearAndFree();
|
|
168
|
+
try encoder.int(u16, 256);
|
|
169
|
+
try std.testing.expectEqualSlices(u8, &.{ 0x01, 0x00 }, encoder.buffer.data);
|
|
170
|
+
|
|
171
|
+
encoder.buffer.clearAndFree();
|
|
172
|
+
try encoder.int(u8, 128);
|
|
173
|
+
try std.testing.expectEqualSlices(u8, &.{ 0, 0x80 }, encoder.buffer.data);
|
|
174
|
+
|
|
175
|
+
encoder.buffer.clearAndFree();
|
|
176
|
+
try encoder.int(u8, 255);
|
|
177
|
+
try std.testing.expectEqualSlices(u8, &.{ 0, 0xff }, encoder.buffer.data);
|
|
178
|
+
|
|
179
|
+
encoder.buffer.clearAndFree();
|
|
180
|
+
try encoder.int(u16, 0x8000);
|
|
181
|
+
try std.testing.expectEqualSlices(u8, &.{ 0, 0x80, 0 }, encoder.buffer.data);
|
|
182
|
+
|
|
183
|
+
encoder.buffer.clearAndFree();
|
|
184
|
+
try encoder.int(i8, -1);
|
|
185
|
+
try std.testing.expectEqualSlices(u8, &.{0xff}, encoder.buffer.data);
|
|
186
|
+
|
|
187
|
+
encoder.buffer.clearAndFree();
|
|
188
|
+
try encoder.int(i8, -128);
|
|
189
|
+
try std.testing.expectEqualSlices(u8, &.{0x80}, encoder.buffer.data);
|
|
190
|
+
|
|
191
|
+
encoder.buffer.clearAndFree();
|
|
192
|
+
try encoder.int(i16, -129);
|
|
193
|
+
try std.testing.expectEqualSlices(u8, &.{ 0xff, 0x7f }, encoder.buffer.data);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
test length {
|
|
197
|
+
const allocator = std.testing.allocator;
|
|
198
|
+
var encoder = Encoder.init(allocator);
|
|
199
|
+
defer encoder.deinit();
|
|
200
|
+
|
|
201
|
+
try encoder.length(127);
|
|
202
|
+
try std.testing.expectEqualSlices(u8, &.{0x7f}, encoder.buffer.data);
|
|
203
|
+
|
|
204
|
+
encoder.buffer.clearAndFree();
|
|
205
|
+
try encoder.length(128);
|
|
206
|
+
try std.testing.expectEqualSlices(u8, &.{ 0x81, 0x80 }, encoder.buffer.data);
|
|
207
|
+
|
|
208
|
+
encoder.buffer.clearAndFree();
|
|
209
|
+
try encoder.length(255);
|
|
210
|
+
try std.testing.expectEqualSlices(u8, &.{ 0x81, 0xff }, encoder.buffer.data);
|
|
211
|
+
|
|
212
|
+
encoder.buffer.clearAndFree();
|
|
213
|
+
try encoder.length(256);
|
|
214
|
+
try std.testing.expectEqualSlices(u8, &.{ 0x82, 0x01, 0x00 }, encoder.buffer.data);
|
|
215
|
+
|
|
216
|
+
encoder.buffer.clearAndFree();
|
|
217
|
+
try encoder.length(65535);
|
|
218
|
+
try std.testing.expectEqualSlices(u8, &.{ 0x82, 0xff, 0xff }, encoder.buffer.data);
|
|
219
|
+
|
|
220
|
+
encoder.buffer.clearAndFree();
|
|
221
|
+
try encoder.length(65536);
|
|
222
|
+
try std.testing.expectEqualSlices(u8, &.{ 0x83, 0x01, 0x00, 0x00 }, encoder.buffer.data);
|
|
160
223
|
}
|
|
161
224
|
|
|
162
225
|
const std = @import("std");
|
|
@@ -49,6 +49,48 @@ test decode {
|
|
|
49
49
|
try std.testing.expectEqualDeep(test_case.value, decoded);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
test "integer round trip across signed and unsigned boundaries" {
|
|
53
|
+
const allocator = std.testing.allocator;
|
|
54
|
+
inline for (.{ u8, u16, u32, i8, i16, i32 }) |T| {
|
|
55
|
+
const cases = comptime blk: {
|
|
56
|
+
const min = std.math.minInt(T);
|
|
57
|
+
const max = std.math.maxInt(T);
|
|
58
|
+
break :blk [_]T{ 0, 1, max, min, @divTrunc(max, 2), @divTrunc(min, 2) };
|
|
59
|
+
};
|
|
60
|
+
for (cases) |value| {
|
|
61
|
+
const buf = try encode(allocator, value);
|
|
62
|
+
defer allocator.free(buf);
|
|
63
|
+
const decoded = try decode(T, buf);
|
|
64
|
+
try std.testing.expectEqual(value, decoded);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
test "encode skips null optional fields" {
|
|
70
|
+
const Value = struct { a: ?u8, b: u8 };
|
|
71
|
+
const allocator = std.testing.allocator;
|
|
72
|
+
const actual = try encode(allocator, Value{ .a = null, .b = 5 });
|
|
73
|
+
defer allocator.free(actual);
|
|
74
|
+
|
|
75
|
+
try std.testing.expectEqualSlices(u8, &.{ 0x30, 0x03, 0x02, 0x01, 0x05 }, actual);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
test "encode preserves outer sequence tag after implicit field tags" {
|
|
79
|
+
const Value = struct {
|
|
80
|
+
a: u8,
|
|
81
|
+
b: u8,
|
|
82
|
+
|
|
83
|
+
pub const asn1_tags = .{
|
|
84
|
+
.a = asn1.FieldTag.initImplicit(0, .context_specific),
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
const allocator = std.testing.allocator;
|
|
88
|
+
const actual = try encode(allocator, Value{ .a = 1, .b = 2 });
|
|
89
|
+
defer allocator.free(actual);
|
|
90
|
+
|
|
91
|
+
try std.testing.expectEqualSlices(u8, &.{ 0x30, 0x06, 0x80, 0x01, 0x01, 0x02, 0x01, 0x02 }, actual);
|
|
92
|
+
}
|
|
93
|
+
|
|
52
94
|
test {
|
|
53
95
|
_ = Decoder;
|
|
54
96
|
_ = Encoder;
|
|
@@ -71,16 +71,18 @@ pub const Tag = struct {
|
|
|
71
71
|
|
|
72
72
|
pub fn decode(reader: *std.Io.Reader) !Tag {
|
|
73
73
|
const tag1: FirstTag = @bitCast(try reader.takeByte());
|
|
74
|
-
var number:
|
|
75
|
-
|
|
76
|
-
if (tag1.number ==
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
number = (number
|
|
82
|
-
|
|
83
|
-
|
|
74
|
+
var number: std.meta.Tag(Tag.Number) = tag1.number;
|
|
75
|
+
|
|
76
|
+
if (tag1.number == high_tag_marker) {
|
|
77
|
+
number = 0;
|
|
78
|
+
for (0..max_continuations) |i| {
|
|
79
|
+
const next: NextTag = @bitCast(try reader.takeByte());
|
|
80
|
+
if (i == 0 and next.number == 0) return error.InvalidEncoding;
|
|
81
|
+
number = std.math.shlExact(@TypeOf(number), number, 7) catch return error.InvalidEncoding;
|
|
82
|
+
number |= next.number;
|
|
83
|
+
if (!next.continues) break;
|
|
84
|
+
} else return error.InvalidEncoding;
|
|
85
|
+
if (number < high_tag_marker) return error.InvalidEncoding;
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
return Tag{
|
|
@@ -90,40 +92,51 @@ pub const Tag = struct {
|
|
|
90
92
|
};
|
|
91
93
|
}
|
|
92
94
|
|
|
93
|
-
pub fn
|
|
94
|
-
|
|
95
|
+
pub fn encodeToSlice(self: Tag, buf: *[max_encoded_len]u8) []const u8 {
|
|
96
|
+
const n = @intFromEnum(self.number);
|
|
97
|
+
var tag1: FirstTag = .{
|
|
95
98
|
.number = undefined,
|
|
96
99
|
.constructed = self.constructed,
|
|
97
100
|
.class = self.class,
|
|
98
101
|
};
|
|
99
102
|
|
|
100
|
-
|
|
101
|
-
|
|
103
|
+
if (n < high_tag_marker) {
|
|
104
|
+
tag1.number = @intCast(n);
|
|
105
|
+
buf[0] = @bitCast(tag1);
|
|
106
|
+
return buf[0..1];
|
|
107
|
+
}
|
|
102
108
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const tag3 = NextTag{ .number = @truncate(n), .continues = false };
|
|
118
|
-
writer2.writeByte(@bitCast(tag1)) catch unreachable;
|
|
119
|
-
writer2.writeByte(@bitCast(tag2)) catch unreachable;
|
|
120
|
-
writer2.writeByte(@bitCast(tag3)) catch unreachable;
|
|
121
|
-
},
|
|
109
|
+
tag1.number = high_tag_marker;
|
|
110
|
+
buf[0] = @bitCast(tag1);
|
|
111
|
+
|
|
112
|
+
const bits_used = @bitSizeOf(@TypeOf(n)) - @clz(n);
|
|
113
|
+
const len = std.math.divCeil(usize, bits_used, 7) catch unreachable;
|
|
114
|
+
|
|
115
|
+
var remaining = n;
|
|
116
|
+
var i = len;
|
|
117
|
+
while (i > 0) : (i -= 1) {
|
|
118
|
+
buf[i] = @bitCast(NextTag{
|
|
119
|
+
.number = @truncate(remaining),
|
|
120
|
+
.continues = i != len,
|
|
121
|
+
});
|
|
122
|
+
remaining >>= 7;
|
|
122
123
|
}
|
|
124
|
+
return buf[0 .. 1 + len];
|
|
125
|
+
}
|
|
123
126
|
|
|
124
|
-
|
|
127
|
+
pub fn encode(self: Tag, writer: *std.Io.Writer) std.Io.Writer.Error!void {
|
|
128
|
+
var buf: [max_encoded_len]u8 = undefined;
|
|
129
|
+
try writer.writeAll(self.encodeToSlice(&buf));
|
|
125
130
|
}
|
|
126
131
|
|
|
132
|
+
pub const max_encoded_len = 1 + (std.math.divCeil(
|
|
133
|
+
comptime_int,
|
|
134
|
+
@bitSizeOf(std.meta.Tag(Tag.Number)),
|
|
135
|
+
7,
|
|
136
|
+
) catch unreachable);
|
|
137
|
+
const max_continuations = max_encoded_len - 1;
|
|
138
|
+
const high_tag_marker = std.math.maxInt(u5);
|
|
139
|
+
|
|
127
140
|
const FirstTag = packed struct(u8) { number: u5, constructed: bool, class: Tag.Class };
|
|
128
141
|
const NextTag = packed struct(u8) { number: u7, continues: bool };
|
|
129
142
|
|
|
@@ -165,6 +178,42 @@ test Tag {
|
|
|
165
178
|
try std.testing.expectEqual(Tag.init(@enumFromInt(3), true, .context_specific), t);
|
|
166
179
|
}
|
|
167
180
|
|
|
181
|
+
test "Tag.encode produces the exact bytes from X.690" {
|
|
182
|
+
const cases = [_]struct { number: u16, expected: []const u8 }{
|
|
183
|
+
.{ .number = 0, .expected = &.{0x00} },
|
|
184
|
+
.{ .number = 30, .expected = &.{0x1e} },
|
|
185
|
+
.{ .number = 31, .expected = &.{ 0x1f, 0x1f } },
|
|
186
|
+
.{ .number = 127, .expected = &.{ 0x1f, 0x7f } },
|
|
187
|
+
.{ .number = 128, .expected = &.{ 0x1f, 0x81, 0x00 } },
|
|
188
|
+
.{ .number = 16383, .expected = &.{ 0x1f, 0xff, 0x7f } },
|
|
189
|
+
.{ .number = 16384, .expected = &.{ 0x1f, 0x81, 0x80, 0x00 } },
|
|
190
|
+
.{ .number = 65535, .expected = &.{ 0x1f, 0x83, 0xff, 0x7f } },
|
|
191
|
+
};
|
|
192
|
+
for (cases) |c| {
|
|
193
|
+
const tag = Tag.init(@enumFromInt(c.number), false, .universal);
|
|
194
|
+
var buf: [Tag.max_encoded_len]u8 = undefined;
|
|
195
|
+
try std.testing.expectEqualSlices(u8, c.expected, tag.encodeToSlice(&buf));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
test "Tag.encode/decode round trip" {
|
|
200
|
+
for ([_]u16{ 0, 30, 31, 32, 127, 128, 16383, 16384, 65535 }) |n| {
|
|
201
|
+
const tag = Tag.init(@enumFromInt(n), false, .universal);
|
|
202
|
+
var buf: [Tag.max_encoded_len]u8 = undefined;
|
|
203
|
+
const encoded = tag.encodeToSlice(&buf);
|
|
204
|
+
var reader: std.Io.Reader = .fixed(encoded);
|
|
205
|
+
try std.testing.expectEqual(tag, try Tag.decode(&reader));
|
|
206
|
+
try std.testing.expectEqual(encoded.len, reader.seek);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
test "Tag.decode rejects non-minimal high-tag form" {
|
|
211
|
+
for ([_][]const u8{ &.{ 0x1f, 0x1e }, &.{ 0x1f, 0x80, 0x01 } }) |bytes| {
|
|
212
|
+
var reader: std.Io.Reader = .fixed(bytes);
|
|
213
|
+
try std.testing.expectError(error.InvalidEncoding, Tag.decode(&reader));
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
168
217
|
/// A decoded view.
|
|
169
218
|
pub const Element = struct {
|
|
170
219
|
tag: Tag,
|
|
@@ -183,13 +232,14 @@ pub const Element = struct {
|
|
|
183
232
|
}
|
|
184
233
|
};
|
|
185
234
|
|
|
186
|
-
pub const DecodeError = error{EndOfStream};
|
|
235
|
+
pub const DecodeError = error{ EndOfStream, InvalidEncoding };
|
|
187
236
|
|
|
188
237
|
/// Safely decode a DER/BER/CER element at `index`:
|
|
189
238
|
/// - Ensures length uses shortest form
|
|
190
239
|
/// - Ensures length is within `bytes`
|
|
191
240
|
/// - Ensures length is less than `std.math.maxInt(Index)`
|
|
192
241
|
pub fn decode(bytes: []const u8, index: Index) DecodeError!Element {
|
|
242
|
+
if (index > bytes.len) return error.EndOfStream;
|
|
193
243
|
var reader: std.Io.Reader = .fixed(bytes[index..]);
|
|
194
244
|
|
|
195
245
|
const tag = Tag.decode(&reader) catch |err| switch (err) {
|
|
@@ -327,13 +377,22 @@ pub const BitString = struct {
|
|
|
327
377
|
}
|
|
328
378
|
|
|
329
379
|
pub fn encodeDer(self: BitString, encoder: *der.Encoder) !void {
|
|
330
|
-
try encoder.
|
|
331
|
-
try encoder.
|
|
380
|
+
try encoder.prependBytes(self.bytes);
|
|
381
|
+
try encoder.prependBytes(&.{self.right_padding});
|
|
332
382
|
try encoder.length(self.bytes.len + 1);
|
|
333
383
|
try encoder.tag(asn1_tag);
|
|
334
384
|
}
|
|
335
385
|
};
|
|
336
386
|
|
|
387
|
+
test BitString {
|
|
388
|
+
const bs = BitString{ .bytes = &.{ 0x6e, 0x5d, 0xc0 }, .right_padding = 6 };
|
|
389
|
+
const allocator = std.testing.allocator;
|
|
390
|
+
const buf = try der.encode(allocator, bs);
|
|
391
|
+
defer allocator.free(buf);
|
|
392
|
+
try std.testing.expectEqualSlices(u8, &.{ 0x03, 0x04, 0x06, 0x6e, 0x5d, 0xc0 }, buf);
|
|
393
|
+
try std.testing.expectEqualDeep(bs, try der.decode(BitString, buf));
|
|
394
|
+
}
|
|
395
|
+
|
|
337
396
|
pub fn Opaque(comptime tag: Tag) type {
|
|
338
397
|
return struct {
|
|
339
398
|
bytes: []const u8,
|
package/std/crypto/codecs.zig
CHANGED
|
@@ -116,7 +116,7 @@ pub const can_unwind: bool = s: {
|
|
|
116
116
|
.x86,
|
|
117
117
|
.x86_64,
|
|
118
118
|
},
|
|
119
|
-
// Not supported yet: arm/armeb/thumb/thumbeb, hppa, hppa64, microblaze/microblazeel
|
|
119
|
+
// Not supported yet: arm/armeb/thumb/thumbeb, hppa, hppa64, microblaze/microblazeel
|
|
120
120
|
.linux => &.{
|
|
121
121
|
.aarch64,
|
|
122
122
|
.aarch64_be,
|
package/std/os/linux/xtensa.zig
CHANGED
|
@@ -115,9 +115,10 @@ pub fn clone() callconv(.naked) u32 {
|
|
|
115
115
|
//
|
|
116
116
|
// syscall(SYS_clone, flags, stack, ptid, tls, ctid)
|
|
117
117
|
// a2 a6, a3, a4, a5, a8
|
|
118
|
-
asm volatile (
|
|
118
|
+
if (builtin.abi != .call0) asm volatile (
|
|
119
119
|
\\ entry sp, 16
|
|
120
|
-
|
|
120
|
+
);
|
|
121
|
+
asm volatile (
|
|
121
122
|
\\ movi a8, -16
|
|
122
123
|
\\ and a3, a3, a8
|
|
123
124
|
\\
|
|
@@ -128,10 +129,29 @@ pub fn clone() callconv(.naked) u32 {
|
|
|
128
129
|
\\ mov a8, a6
|
|
129
130
|
\\ mov a6, a4
|
|
130
131
|
\\ mov a4, a8
|
|
132
|
+
);
|
|
133
|
+
if (builtin.abi == .call0) asm volatile (
|
|
134
|
+
\\ l32i a8, sp, 0
|
|
135
|
+
) else asm volatile (
|
|
131
136
|
\\ l32i a8, sp, 16
|
|
137
|
+
);
|
|
138
|
+
asm volatile (
|
|
132
139
|
\\ movi a2, 116 // SYS_clone
|
|
133
140
|
\\ syscall
|
|
141
|
+
);
|
|
142
|
+
if (builtin.abi == .call0) asm volatile (
|
|
143
|
+
\\ beqz a2, 1f
|
|
144
|
+
\\ // parent
|
|
145
|
+
\\ ret
|
|
134
146
|
\\
|
|
147
|
+
\\ // child
|
|
148
|
+
\\1:
|
|
149
|
+
\\ movi a15, 0
|
|
150
|
+
\\ movi a0, 0
|
|
151
|
+
\\
|
|
152
|
+
\\ mov a2, a10
|
|
153
|
+
\\ callx0 a9
|
|
154
|
+
) else asm volatile (
|
|
135
155
|
\\ beqz a2, 1f
|
|
136
156
|
\\ // parent
|
|
137
157
|
\\ retw
|
|
@@ -141,8 +161,10 @@ pub fn clone() callconv(.naked) u32 {
|
|
|
141
161
|
\\ movi a7, 0
|
|
142
162
|
\\ movi a0, 0
|
|
143
163
|
\\
|
|
144
|
-
\\ mov
|
|
145
|
-
\\
|
|
164
|
+
\\ mov a6, a10
|
|
165
|
+
\\ callx4 a9
|
|
166
|
+
);
|
|
167
|
+
asm volatile (
|
|
146
168
|
\\ movi a2, 118 // SYS_exit
|
|
147
169
|
\\ syscall
|
|
148
170
|
);
|
package/std/pie.zig
CHANGED
|
@@ -270,9 +270,7 @@ inline fn getDynamicSymbol() [*]const elf.Dyn {
|
|
|
270
270
|
// embedded constant. Note that `call0` is a 3-byte instruction, so we need both
|
|
271
271
|
// `.balign` directives to be safe.
|
|
272
272
|
\\ .balign 4
|
|
273
|
-
\\ .begin no-transform
|
|
274
273
|
\\ call0 1f
|
|
275
|
-
\\ .end no-transform
|
|
276
274
|
\\ .balign 4
|
|
277
275
|
\\ .word _DYNAMIC - .
|
|
278
276
|
\\1:
|
package/std/sort/pdq.zig
CHANGED
|
@@ -175,17 +175,78 @@ fn partition(a: usize, b: usize, pivot: *usize, context: anytype) bool {
|
|
|
175
175
|
i += 1;
|
|
176
176
|
j -= 1;
|
|
177
177
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
178
|
+
const block_size = 64;
|
|
179
|
+
var offsets_l: [block_size]u8 align(std.atomic.cache_line) = undefined;
|
|
180
|
+
var offsets_r: [block_size]u8 align(std.atomic.cache_line) = undefined;
|
|
181
|
+
|
|
182
|
+
var offsets_l_base = i;
|
|
183
|
+
var offsets_r_base = j;
|
|
184
|
+
var num_l: usize = 0;
|
|
185
|
+
var num_r: usize = 0;
|
|
186
|
+
var start_l: usize = 0;
|
|
187
|
+
var start_r: usize = 0;
|
|
188
|
+
|
|
189
|
+
while (i <= j) {
|
|
190
|
+
const num_unknown = j + 1 - i;
|
|
191
|
+
const left_split = if (num_l == 0)
|
|
192
|
+
@min(block_size, if (num_r == 0) num_unknown / 2 else num_unknown)
|
|
193
|
+
else
|
|
194
|
+
0;
|
|
195
|
+
const right_split = if (num_r == 0)
|
|
196
|
+
@min(block_size, num_unknown - left_split)
|
|
197
|
+
else
|
|
198
|
+
0;
|
|
199
|
+
|
|
200
|
+
for (0..left_split) |k| {
|
|
201
|
+
offsets_l[num_l] = @intCast(k);
|
|
202
|
+
num_l += @intFromBool(!context.lessThan(i + k, a));
|
|
203
|
+
}
|
|
204
|
+
i += left_split;
|
|
182
205
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
206
|
+
for (0..right_split) |k| {
|
|
207
|
+
offsets_r[num_r] = @intCast(k);
|
|
208
|
+
num_r += @intFromBool(context.lessThan(j - k, a));
|
|
209
|
+
}
|
|
210
|
+
j -= right_split;
|
|
211
|
+
|
|
212
|
+
const num = @min(num_l, num_r);
|
|
213
|
+
for (0..num) |m| {
|
|
214
|
+
context.swap(
|
|
215
|
+
offsets_l_base + offsets_l[start_l + m],
|
|
216
|
+
offsets_r_base - offsets_r[start_r + m],
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
num_l -= num;
|
|
220
|
+
num_r -= num;
|
|
221
|
+
start_l += num;
|
|
222
|
+
start_r += num;
|
|
223
|
+
|
|
224
|
+
if (num_l == 0) {
|
|
225
|
+
start_l = 0;
|
|
226
|
+
offsets_l_base = i;
|
|
227
|
+
}
|
|
228
|
+
if (num_r == 0) {
|
|
229
|
+
start_r = 0;
|
|
230
|
+
offsets_r_base = j;
|
|
231
|
+
}
|
|
186
232
|
}
|
|
187
233
|
|
|
188
|
-
|
|
234
|
+
if (num_l > 0) {
|
|
235
|
+
while (num_l > 0) {
|
|
236
|
+
num_l -= 1;
|
|
237
|
+
context.swap(offsets_l_base + offsets_l[start_l + num_l], j);
|
|
238
|
+
j -= 1;
|
|
239
|
+
}
|
|
240
|
+
i = j + 1;
|
|
241
|
+
}
|
|
242
|
+
if (num_r > 0) {
|
|
243
|
+
while (num_r > 0) {
|
|
244
|
+
num_r -= 1;
|
|
245
|
+
context.swap(offsets_r_base - offsets_r[start_r + num_r], i);
|
|
246
|
+
i += 1;
|
|
247
|
+
}
|
|
248
|
+
j = i - 1;
|
|
249
|
+
}
|
|
189
250
|
|
|
190
251
|
context.swap(j, a);
|
|
191
252
|
pivot.* = j;
|
package/std/start.zig
CHANGED
|
@@ -487,14 +487,22 @@ fn _start() callconv(.naked) noreturn {
|
|
|
487
487
|
\\ sub %%sp, 2047, %%sp
|
|
488
488
|
\\ ba,a %[posixCallMainAndExit]
|
|
489
489
|
,
|
|
490
|
-
.xtensa, .xtensaeb =>
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
490
|
+
.xtensa, .xtensaeb => if (builtin.abi == .call0)
|
|
491
|
+
// a0 = LR, a15 = FP, a1 = SP
|
|
492
|
+
\\ movi a0, 0
|
|
493
|
+
\\ movi a15, 0
|
|
494
|
+
\\ mov a2, sp
|
|
495
|
+
\\ movi a8, -16
|
|
496
|
+
\\ and sp, sp, a8
|
|
497
|
+
\\ call0 %[posixCallMainAndExit]
|
|
498
|
+
else
|
|
499
|
+
// a0 = LR, a7 = FP, a1 = SP
|
|
500
|
+
\\ movi a0, 0
|
|
501
|
+
\\ movi a7, 0
|
|
502
|
+
\\ mov a6, sp
|
|
503
|
+
\\ movi a8, -16
|
|
504
|
+
\\ and sp, sp, a8
|
|
505
|
+
\\ call4 %[posixCallMainAndExit]
|
|
498
506
|
,
|
|
499
507
|
else => @compileError("unsupported arch"),
|
|
500
508
|
}
|
package/ubsan_rt.zig
CHANGED
|
@@ -492,10 +492,10 @@ const NonNullReturnData = extern struct {
|
|
|
492
492
|
attribute_loc: SourceLocation,
|
|
493
493
|
};
|
|
494
494
|
|
|
495
|
-
fn nonNullReturnAbort(data: *const NonNullReturnData) callconv(.c) noreturn {
|
|
496
|
-
nonNullReturn(data);
|
|
495
|
+
fn nonNullReturnAbort(data: *const NonNullReturnData, where: *const SourceLocation) callconv(.c) noreturn {
|
|
496
|
+
nonNullReturn(data, where);
|
|
497
497
|
}
|
|
498
|
-
fn nonNullReturn(_: *const NonNullReturnData) callconv(.c) noreturn {
|
|
498
|
+
fn nonNullReturn(_: *const NonNullReturnData, _: *const SourceLocation) callconv(.c) noreturn {
|
|
499
499
|
panic(@returnAddress(), "null pointer returned from function declared to never return null", .{});
|
|
500
500
|
}
|
|
501
501
|
|