@zigc/lib 0.17.0-dev.657 → 0.17.0-dev.690
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.zig +2 -2
- package/libc/include/powerpc-linux-gnu/bits/struct_mutex.h +2 -2
- package/libc/include/s390x-linux-gnu/bits/fenv.h +2 -2
- package/libc/include/s390x-linux-gnu/bits/struct_mutex.h +2 -2
- package/libc/include/x86-linux-gnu/bits/struct_mutex.h +2 -2
- package/package.json +1 -1
- package/std/Build/Cache/Path.zig +8 -15
- package/std/crypto/aes/aesni.zig +1 -1
- package/std/crypto/aes/armcrypto.zig +4 -4
- package/std/crypto/aes/soft.zig +4 -4
- package/std/crypto/aes.zig +12 -0
- 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/debug/SelfInfo/MachO.zig +42 -15
- package/std/os/linux/xtensa.zig +26 -4
- package/std/pie.zig +0 -2
- package/std/sort/pdq.zig +91 -13
- package/std/start.zig +16 -8
- package/std/zon/parse.zig +25 -0
- package/ubsan_rt.zig +3 -3
package/compiler/Maker.zig
CHANGED
|
@@ -194,7 +194,7 @@ pub fn main(init: process.Init.Minimal) !void {
|
|
|
194
194
|
var max_rss: u64 = 0;
|
|
195
195
|
var skip_oom_steps = false;
|
|
196
196
|
var test_timeout_ns: ?u64 = null;
|
|
197
|
-
var color: Color = .
|
|
197
|
+
var color: Color = .settingFromEnvironment(&graph.environ_map);
|
|
198
198
|
var watch = false;
|
|
199
199
|
var fuzz: ?Fuzz.Mode = null;
|
|
200
200
|
var debounce_interval_ms: u16 = 50;
|
|
@@ -533,7 +533,7 @@ pub fn main(init: process.Init.Minimal) !void {
|
|
|
533
533
|
}
|
|
534
534
|
|
|
535
535
|
const main_progress_node = std.Progress.start(io, .{
|
|
536
|
-
.disable_printing = (
|
|
536
|
+
.disable_printing = (graph.stderr_mode.? == .no_color),
|
|
537
537
|
});
|
|
538
538
|
defer main_progress_node.end();
|
|
539
539
|
|
|
@@ -32,7 +32,7 @@ struct __pthread_mutex_s
|
|
|
32
32
|
int __kind;
|
|
33
33
|
#if __WORDSIZE == 64
|
|
34
34
|
short __spins;
|
|
35
|
-
short
|
|
35
|
+
short __glibc_reserved;
|
|
36
36
|
__pthread_list_t __list;
|
|
37
37
|
# define __PTHREAD_MUTEX_HAVE_PREV 1
|
|
38
38
|
#else
|
|
@@ -59,4 +59,4 @@ struct __pthread_mutex_s
|
|
|
59
59
|
0, 0, 0, __kind, 0, { { 0, 0 } }
|
|
60
60
|
#endif
|
|
61
61
|
|
|
62
|
-
#endif
|
|
62
|
+
#endif
|
|
@@ -76,7 +76,7 @@ typedef unsigned int fexcept_t; /* size of fpc */
|
|
|
76
76
|
typedef struct
|
|
77
77
|
{
|
|
78
78
|
fexcept_t __fpc;
|
|
79
|
-
void *
|
|
79
|
+
void *__glibc_reserved;
|
|
80
80
|
/* The field __unused (formerly __ieee_instruction_pointer) is a relict from
|
|
81
81
|
commit "Remove PTRACE_PEEKUSER" (87b9b50f0d4b92248905e95a06a13c513dc45e59)
|
|
82
82
|
and isn't used anymore. */
|
|
@@ -96,4 +96,4 @@ typedef unsigned int femode_t;
|
|
|
96
96
|
|
|
97
97
|
/* Default floating-point control modes. */
|
|
98
98
|
# define FE_DFL_MODE ((const femode_t *) -1L)
|
|
99
|
-
#endif
|
|
99
|
+
#endif
|
|
@@ -32,7 +32,7 @@ struct __pthread_mutex_s
|
|
|
32
32
|
int __kind;
|
|
33
33
|
#if __WORDSIZE == 64
|
|
34
34
|
short __spins;
|
|
35
|
-
short
|
|
35
|
+
short __glibc_reserved;
|
|
36
36
|
__pthread_list_t __list;
|
|
37
37
|
# define __PTHREAD_MUTEX_HAVE_PREV 1
|
|
38
38
|
#else
|
|
@@ -59,4 +59,4 @@ struct __pthread_mutex_s
|
|
|
59
59
|
0, 0, 0, __kind, 0, { { 0, 0 } }
|
|
60
60
|
#endif
|
|
61
61
|
|
|
62
|
-
#endif
|
|
62
|
+
#endif
|
|
@@ -32,7 +32,7 @@ struct __pthread_mutex_s
|
|
|
32
32
|
int __kind;
|
|
33
33
|
#ifdef __x86_64__
|
|
34
34
|
short __spins;
|
|
35
|
-
short
|
|
35
|
+
short __glibc_reserved;
|
|
36
36
|
__pthread_list_t __list;
|
|
37
37
|
# define __PTHREAD_MUTEX_HAVE_PREV 1
|
|
38
38
|
#else
|
|
@@ -59,4 +59,4 @@ struct __pthread_mutex_s
|
|
|
59
59
|
0, 0, 0, __kind, 0, { { 0, 0 } }
|
|
60
60
|
#endif
|
|
61
61
|
|
|
62
|
-
#endif
|
|
62
|
+
#endif
|
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/crypto/aes/aesni.zig
CHANGED
|
@@ -312,7 +312,7 @@ pub fn BlockVec(comptime blocks_count: comptime_int) type {
|
|
|
312
312
|
}
|
|
313
313
|
|
|
314
314
|
/// Apply the bitwise OR operation to the content of two block vectors.
|
|
315
|
-
pub fn orBlocks(block_vec1: Self, block_vec2:
|
|
315
|
+
pub fn orBlocks(block_vec1: Self, block_vec2: Self) Self {
|
|
316
316
|
var out: Self = undefined;
|
|
317
317
|
inline for (0..native_words) |i| {
|
|
318
318
|
out.repr[i] = block_vec1.repr[i] | block_vec2.repr[i];
|
|
@@ -216,10 +216,10 @@ pub fn BlockVec(comptime blocks_count: comptime_int) type {
|
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
/// XOR the block vector with a byte sequence.
|
|
219
|
-
pub fn xorBytes(block_vec: Self, bytes: *const [blocks_count * 16]u8) [
|
|
220
|
-
var out:
|
|
219
|
+
pub fn xorBytes(block_vec: Self, bytes: *const [blocks_count * 16]u8) [blocks_count * 16]u8 {
|
|
220
|
+
var out: [blocks_count * 16]u8 = undefined;
|
|
221
221
|
inline for (0..native_words) |i| {
|
|
222
|
-
out
|
|
222
|
+
out[i * native_word_size ..][0..native_word_size].* = block_vec.repr[i].xorBytes(bytes[i * native_word_size ..][0..native_word_size]);
|
|
223
223
|
}
|
|
224
224
|
return out;
|
|
225
225
|
}
|
|
@@ -279,7 +279,7 @@ pub fn BlockVec(comptime blocks_count: comptime_int) type {
|
|
|
279
279
|
}
|
|
280
280
|
|
|
281
281
|
/// Apply the bitwise OR operation to the content of two block vectors.
|
|
282
|
-
pub fn orBlocks(block_vec1: Self, block_vec2:
|
|
282
|
+
pub fn orBlocks(block_vec1: Self, block_vec2: Self) Self {
|
|
283
283
|
var out: Self = undefined;
|
|
284
284
|
inline for (0..native_words) |i| {
|
|
285
285
|
out.repr[i] = block_vec1.repr[i].orBlocks(block_vec2.repr[i]);
|
package/std/crypto/aes/soft.zig
CHANGED
|
@@ -391,10 +391,10 @@ pub fn BlockVec(comptime blocks_count: comptime_int) type {
|
|
|
391
391
|
}
|
|
392
392
|
|
|
393
393
|
/// XOR the block vector with a byte sequence.
|
|
394
|
-
pub fn xorBytes(block_vec: Self, bytes: *const [blocks_count * 16]u8) [
|
|
395
|
-
var out:
|
|
394
|
+
pub fn xorBytes(block_vec: Self, bytes: *const [blocks_count * 16]u8) [blocks_count * 16]u8 {
|
|
395
|
+
var out: [blocks_count * 16]u8 = undefined;
|
|
396
396
|
for (0..native_words) |i| {
|
|
397
|
-
out
|
|
397
|
+
out[i * native_word_size ..][0..native_word_size].* = block_vec.repr[i].xorBytes(bytes[i * native_word_size ..][0..native_word_size]);
|
|
398
398
|
}
|
|
399
399
|
return out;
|
|
400
400
|
}
|
|
@@ -454,7 +454,7 @@ pub fn BlockVec(comptime blocks_count: comptime_int) type {
|
|
|
454
454
|
}
|
|
455
455
|
|
|
456
456
|
/// Apply the bitwise OR operation to the content of two block vectors.
|
|
457
|
-
pub fn orBlocks(block_vec1: Self, block_vec2:
|
|
457
|
+
pub fn orBlocks(block_vec1: Self, block_vec2: Self) Self {
|
|
458
458
|
var out: Self = undefined;
|
|
459
459
|
for (0..native_words) |i| {
|
|
460
460
|
out.repr[i] = block_vec1.repr[i].orBlocks(block_vec2.repr[i]);
|
package/std/crypto/aes.zig
CHANGED
|
@@ -137,6 +137,18 @@ test "BlockVec invMixColumns" {
|
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
+
test "BlockVec bitwise operations" {
|
|
141
|
+
const a_bytes: [32]u8 = @splat(0xaa);
|
|
142
|
+
const b_bytes: [32]u8 = @splat(0xbb);
|
|
143
|
+
const a = BlockVec(2).fromBytes(&a_bytes);
|
|
144
|
+
const b = BlockVec(2).fromBytes(&b_bytes);
|
|
145
|
+
|
|
146
|
+
try testing.expectEqual(@as([32]u8, @splat(0x11)), a.xorBytes(&b_bytes));
|
|
147
|
+
try testing.expectEqual(@as([32]u8, @splat(0x11)), a.xorBlocks(b).toBytes());
|
|
148
|
+
try testing.expectEqual(@as([32]u8, @splat(0xbb)), a.orBlocks(b).toBytes());
|
|
149
|
+
try testing.expectEqual(@as([32]u8, @splat(0xaa)), a.andBlocks(b).toBytes());
|
|
150
|
+
}
|
|
151
|
+
|
|
140
152
|
test "expand 256-bit key" {
|
|
141
153
|
const key = [_]u8{
|
|
142
154
|
0x60, 0x3d, 0xeb, 0x10,
|
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,
|
|
@@ -93,12 +93,28 @@ pub fn getSymbols(
|
|
|
93
93
|
pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 {
|
|
94
94
|
_ = si;
|
|
95
95
|
_ = io;
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
96
|
+
return getModuleNameInner(address) orelse return error.MissingDebugInfo;
|
|
97
|
+
}
|
|
98
|
+
fn getModuleNameInner(address: usize) ?[]const u8 {
|
|
99
|
+
switch (builtin.target.os.tag) {
|
|
100
|
+
.macos => {
|
|
101
|
+
// This function is marked as deprecated; however, it is significantly more performant
|
|
102
|
+
// than `dladdr` (since the latter also does a very slow symbol lookup), so let's just
|
|
103
|
+
// use it for the better performance since it's still available.
|
|
104
|
+
return std.mem.span(std.c.dyld_image_path_containing_address(
|
|
105
|
+
@ptrFromInt(address),
|
|
106
|
+
) orelse return null);
|
|
107
|
+
},
|
|
108
|
+
else => {
|
|
109
|
+
// On other Darwin systems, the function used above is entirely unavailable, so we have
|
|
110
|
+
// no choice but to use the slow `dladdr`.
|
|
111
|
+
var info: std.c.dl_info = undefined;
|
|
112
|
+
if (std.c.dladdr(@ptrFromInt(address), &info) == 0) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
return std.mem.span(info.fname);
|
|
116
|
+
},
|
|
117
|
+
}
|
|
102
118
|
}
|
|
103
119
|
pub fn getModuleSlide(si: *SelfInfo, io: Io, address: usize) Error!usize {
|
|
104
120
|
const gpa = std.debug.getDebugInfoAllocator();
|
|
@@ -446,12 +462,25 @@ fn unwindFrameInner(si: *SelfInfo, io: Io, context: *UnwindContext) !usize {
|
|
|
446
462
|
|
|
447
463
|
/// Acquires the mutex on success.
|
|
448
464
|
fn findModule(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!*Module {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
465
|
+
const text_base: *anyopaque = switch (builtin.target.os.tag) {
|
|
466
|
+
.macos => base: {
|
|
467
|
+
// This function is marked as deprecated; however, it is significantly more performant
|
|
468
|
+
// than `dladdr` (since the latter also does a very slow symbol lookup), so let's just
|
|
469
|
+
// use it for the better performance since it's still available.
|
|
470
|
+
break :base std.c._dyld_get_image_header_containing_address(
|
|
471
|
+
@ptrFromInt(address),
|
|
472
|
+
) orelse return error.MissingDebugInfo;
|
|
473
|
+
},
|
|
474
|
+
else => base: {
|
|
475
|
+
// On other Darwin systems, the function used above is entirely unavailable, so we have
|
|
476
|
+
// no choice but to use the slow `dladdr`.
|
|
477
|
+
var info: std.c.dl_info = undefined;
|
|
478
|
+
if (std.c.dladdr(@ptrFromInt(address), &info) == 0) {
|
|
479
|
+
return error.MissingDebugInfo;
|
|
480
|
+
}
|
|
481
|
+
break :base info.fbase;
|
|
482
|
+
},
|
|
483
|
+
};
|
|
455
484
|
try si.mutex.lock(io);
|
|
456
485
|
errdefer si.mutex.unlock(io);
|
|
457
486
|
const gop = try si.modules.getOrPutAdapted(gpa, @intFromPtr(text_base), Module.Adapter{});
|
|
@@ -563,9 +592,7 @@ const Module = struct {
|
|
|
563
592
|
|
|
564
593
|
fn getFile(module: *Module, gpa: Allocator, io: Io) Error!*MachOFile {
|
|
565
594
|
if (module.file == null) {
|
|
566
|
-
const path =
|
|
567
|
-
std.c.dyld_image_path_containing_address(@ptrFromInt(module.text_base)).?,
|
|
568
|
-
);
|
|
595
|
+
const path = getModuleNameInner(module.text_base).?;
|
|
569
596
|
module.file = MachOFile.load(gpa, io, path, builtin.cpu.arch) catch |err| switch (err) {
|
|
570
597
|
error.InvalidMachO, error.InvalidDwarf => error.InvalidDebugInfo,
|
|
571
598
|
error.MissingDebugInfo, error.OutOfMemory, error.UnsupportedDebugInfo, error.ReadFailed => |e| e,
|
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
|
@@ -47,10 +47,10 @@ pub fn pdqContext(a: usize, b: usize, context: anytype) void {
|
|
|
47
47
|
const max_limit = std.math.floorPowerOfTwo(usize, b - a) + 1;
|
|
48
48
|
|
|
49
49
|
// set upper bound on stack memory usage.
|
|
50
|
-
const Range = struct { a: usize, b: usize, limit: usize };
|
|
50
|
+
const Range = struct { a: usize, b: usize, limit: usize, leftmost: bool };
|
|
51
51
|
const stack_size = math.log2(math.maxInt(usize) + 1);
|
|
52
52
|
var stack: [stack_size]Range = undefined;
|
|
53
|
-
var range = Range{ .a = a, .b = b, .limit = max_limit };
|
|
53
|
+
var range = Range{ .a = a, .b = b, .limit = max_limit, .leftmost = true };
|
|
54
54
|
var top: usize = 0;
|
|
55
55
|
|
|
56
56
|
while (true) {
|
|
@@ -62,7 +62,11 @@ pub fn pdqContext(a: usize, b: usize, context: anytype) void {
|
|
|
62
62
|
|
|
63
63
|
// very short slices get sorted using insertion sort.
|
|
64
64
|
if (len <= max_insertion) {
|
|
65
|
-
|
|
65
|
+
if (range.leftmost) {
|
|
66
|
+
break sort.insertionContext(range.a, range.b, context);
|
|
67
|
+
} else {
|
|
68
|
+
break unguardedInsertionContext(range.a, range.b, context);
|
|
69
|
+
}
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
// if too many bad pivot choices were made, simply fall back to heapsort in order to
|
|
@@ -115,12 +119,13 @@ pub fn pdqContext(a: usize, b: usize, context: anytype) void {
|
|
|
115
119
|
const balanced_threshold = len / 8;
|
|
116
120
|
if (left_len < right_len) {
|
|
117
121
|
was_balanced = left_len >= balanced_threshold;
|
|
118
|
-
stack[top] = .{ .a = range.a, .b = mid, .limit = range.limit };
|
|
122
|
+
stack[top] = .{ .a = range.a, .b = mid, .limit = range.limit, .leftmost = range.leftmost };
|
|
119
123
|
top += 1;
|
|
120
124
|
range.a = mid + 1;
|
|
125
|
+
range.leftmost = false;
|
|
121
126
|
} else {
|
|
122
127
|
was_balanced = right_len >= balanced_threshold;
|
|
123
|
-
stack[top] = .{ .a = mid + 1, .b = range.b, .limit = range.limit };
|
|
128
|
+
stack[top] = .{ .a = mid + 1, .b = range.b, .limit = range.limit, .leftmost = false };
|
|
124
129
|
top += 1;
|
|
125
130
|
range.b = mid;
|
|
126
131
|
}
|
|
@@ -131,6 +136,18 @@ pub fn pdqContext(a: usize, b: usize, context: anytype) void {
|
|
|
131
136
|
}
|
|
132
137
|
}
|
|
133
138
|
|
|
139
|
+
/// Insertion sort that assumes `items[a-1]` exists and is <= all elements in `[a, b)`,
|
|
140
|
+
/// allowing the inner loop to skip the bounds check.
|
|
141
|
+
fn unguardedInsertionContext(a: usize, b: usize, context: anytype) void {
|
|
142
|
+
var i = a + 1;
|
|
143
|
+
while (i < b) : (i += 1) {
|
|
144
|
+
var j = i;
|
|
145
|
+
while (context.lessThan(j, j - 1)) : (j -= 1) {
|
|
146
|
+
context.swap(j, j - 1);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
134
151
|
/// partitions `items[a..b]` into elements smaller than `items[pivot]`,
|
|
135
152
|
/// followed by elements greater than or equal to `items[pivot]`.
|
|
136
153
|
///
|
|
@@ -158,17 +175,78 @@ fn partition(a: usize, b: usize, pivot: *usize, context: anytype) bool {
|
|
|
158
175
|
i += 1;
|
|
159
176
|
j -= 1;
|
|
160
177
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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;
|
|
165
205
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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
|
+
}
|
|
169
232
|
}
|
|
170
233
|
|
|
171
|
-
|
|
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
|
+
}
|
|
172
250
|
|
|
173
251
|
context.swap(j, a);
|
|
174
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/std/zon/parse.zig
CHANGED
|
@@ -1094,6 +1094,7 @@ const Parser = struct {
|
|
|
1094
1094
|
name: []const u8,
|
|
1095
1095
|
) error{ OutOfMemory, ParseZon } {
|
|
1096
1096
|
@branchHint(.cold);
|
|
1097
|
+
if (self.diag == null) return error.ParseZon;
|
|
1097
1098
|
const gpa = self.gpa;
|
|
1098
1099
|
const token = if (field) |f| b: {
|
|
1099
1100
|
var buf: [2]Ast.Node.Index = undefined;
|
|
@@ -1150,6 +1151,7 @@ const Parser = struct {
|
|
|
1150
1151
|
field: usize,
|
|
1151
1152
|
) error{ OutOfMemory, ParseZon } {
|
|
1152
1153
|
@branchHint(.cold);
|
|
1154
|
+
if (self.diag == null) return error.ParseZon;
|
|
1153
1155
|
const ast_node = node.getAstNode(self.zoir);
|
|
1154
1156
|
var buf: [2]Ast.Node.Index = undefined;
|
|
1155
1157
|
const token = if (self.ast.fullStructInit(&buf, ast_node)) |struct_init| b: {
|
|
@@ -3540,3 +3542,26 @@ test "std.zon no alloc" {
|
|
|
3540
3542
|
try fromZoirNode(Nested, ast, zoir, .root, null, .{}),
|
|
3541
3543
|
);
|
|
3542
3544
|
}
|
|
3545
|
+
|
|
3546
|
+
test "std.zon errors without diagnostics" {
|
|
3547
|
+
const gpa = std.testing.allocator;
|
|
3548
|
+
|
|
3549
|
+
const Enum = enum {
|
|
3550
|
+
foo,
|
|
3551
|
+
bar,
|
|
3552
|
+
baz,
|
|
3553
|
+
};
|
|
3554
|
+
try std.testing.expectError(error.ParseZon, fromSliceAlloc(Enum, gpa, ".nothing", null, .{}));
|
|
3555
|
+
|
|
3556
|
+
const Struct = struct {
|
|
3557
|
+
name: []const u8,
|
|
3558
|
+
};
|
|
3559
|
+
try std.testing.expectError(error.ParseZon, fromSliceAlloc(Struct, gpa, ".{ .name = \"Alice\", .age = 25 }", null, .{}));
|
|
3560
|
+
|
|
3561
|
+
const Union = union(enum) {
|
|
3562
|
+
x,
|
|
3563
|
+
y: u32,
|
|
3564
|
+
};
|
|
3565
|
+
try std.testing.expectError(error.ParseZon, fromSliceAlloc(Union, gpa, ".a", null, .{}));
|
|
3566
|
+
try std.testing.expectError(error.ParseZon, fromSliceAlloc(Union, gpa, ".{ .b = 8 }", null, .{}));
|
|
3567
|
+
}
|
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
|
|