| author | |
| committer | |
| log | d44486b274a916823fcf6045a6400ef51e07d544 |
| tree | c12a3a3923b644d219f815630941073d99d31889 |
| parent | 2aff27d92247eed3b64ffc68da8fae9e5994ea0b |
Unlike glibc and musl, MinGW provides no libssp symbols leading to
countless compile errors if FORTIFY_SOURCE is defined.
Add a (incomplete) implementation of libssp written in Zig so that
linking succeeds.
Closes #64925 files changed, 276 insertions(+), 53 deletions(-)
lib/std/special/c.zig+113-33| ... | @@ -35,6 +35,10 @@ comptime { | ... | @@ -35,6 +35,10 @@ comptime { |
| 35 | @export(strncmp, .{ .name = "strncmp", .linkage = .Strong }); | 35 | @export(strncmp, .{ .name = "strncmp", .linkage = .Strong }); |
| 36 | @export(strerror, .{ .name = "strerror", .linkage = .Strong }); | 36 | @export(strerror, .{ .name = "strerror", .linkage = .Strong }); |
| 37 | @export(strlen, .{ .name = "strlen", .linkage = .Strong }); | 37 | @export(strlen, .{ .name = "strlen", .linkage = .Strong }); |
| 38 | @export(strcpy, .{ .name = "strcpy", .linkage = .Strong }); | ||
| 39 | @export(strncpy, .{ .name = "strncpy", .linkage = .Strong }); | ||
| 40 | @export(strcat, .{ .name = "strcat", .linkage = .Strong }); | ||
| 41 | @export(strncat, .{ .name = "strncat", .linkage = .Strong }); | ||
| 38 | } else if (is_msvc) { | 42 | } else if (is_msvc) { |
| 39 | @export(_fltused, .{ .name = "_fltused", .linkage = .Strong }); | 43 | @export(_fltused, .{ .name = "_fltused", .linkage = .Strong }); |
| 40 | } | 44 | } |
| ... | @@ -47,6 +51,90 @@ fn wasm_start() callconv(.C) void { | ... | @@ -47,6 +51,90 @@ fn wasm_start() callconv(.C) void { |
| 47 | _ = main(0, undefined); | 51 | _ = main(0, undefined); |
| 48 | } | 52 | } |
| 49 | 53 | ||
| 54 | fn strcpy(dest: [*:0]u8, src: [*:0]const u8) callconv(.C) [*:0]u8 { | ||
| 55 | var i: usize = 0; | ||
| 56 | while (src[i] != 0) : (i += 1) { | ||
| 57 | dest[i] = src[i]; | ||
| 58 | } | ||
| 59 | dest[i] = 0; | ||
| 60 | |||
| 61 | return dest; | ||
| 62 | } | ||
| 63 | |||
| 64 | test "strcpy" { | ||
| 65 | var s1: [9:0]u8 = undefined; | ||
| 66 | |||
| 67 | s1[0] = 0; | ||
| 68 | _ = strcpy(&s1, "foobarbaz"); | ||
| 69 | std.testing.expectEqualSlices(u8, "foobarbaz", std.mem.spanZ(&s1)); | ||
| 70 | } | ||
| 71 | |||
| 72 | fn strncpy(dest: [*:0]u8, src: [*:0]const u8, n: usize) callconv(.C) [*:0]u8 { | ||
| 73 | var i: usize = 0; | ||
| 74 | while (i < n and src[i] != 0) : (i += 1) { | ||
| 75 | dest[i] = src[i]; | ||
| 76 | } | ||
| 77 | while (i < n) : (i += 1) { | ||
| 78 | dest[i] = 0; | ||
| 79 | } | ||
| 80 | |||
| 81 | return dest; | ||
| 82 | } | ||
| 83 | |||
| 84 | test "strncpy" { | ||
| 85 | var s1: [9:0]u8 = undefined; | ||
| 86 | |||
| 87 | s1[0] = 0; | ||
| 88 | _ = strncpy(&s1, "foobarbaz", 9); | ||
| 89 | std.testing.expectEqualSlices(u8, "foobarbaz", std.mem.spanZ(&s1)); | ||
| 90 | } | ||
| 91 | |||
| 92 | fn strcat(dest: [*:0]u8, src: [*:0]const u8) callconv(.C) [*:0]u8 { | ||
| 93 | var dest_end: usize = 0; | ||
| 94 | while (dest[dest_end] != 0) : (dest_end += 1) {} | ||
| 95 | |||
| 96 | var i: usize = 0; | ||
| 97 | while (src[i] != 0) : (i += 1) { | ||
| 98 | dest[dest_end + i] = src[i]; | ||
| 99 | } | ||
| 100 | dest[dest_end + i] = 0; | ||
| 101 | |||
| 102 | return dest; | ||
| 103 | } | ||
| 104 | |||
| 105 | test "strcat" { | ||
| 106 | var s1: [9:0]u8 = undefined; | ||
| 107 | |||
| 108 | s1[0] = 0; | ||
| 109 | _ = strcat(&s1, "foo"); | ||
| 110 | _ = strcat(&s1, "bar"); | ||
| 111 | _ = strcat(&s1, "baz"); | ||
| 112 | std.testing.expectEqualSlices(u8, "foobarbaz", std.mem.spanZ(&s1)); | ||
| 113 | } | ||
| 114 | |||
| 115 | fn strncat(dest: [*:0]u8, src: [*:0]const u8, avail: usize) callconv(.C) [*:0]u8 { | ||
| 116 | var dest_end: usize = 0; | ||
| 117 | while (dest[dest_end] != 0) : (dest_end += 1) {} | ||
| 118 | |||
| 119 | var i: usize = 0; | ||
| 120 | while (i < avail and src[i] != 0) : (i += 1) { | ||
| 121 | dest[dest_end + i] = src[i]; | ||
| 122 | } | ||
| 123 | dest[dest_end + i] = 0; | ||
| 124 | |||
| 125 | return dest; | ||
| 126 | } | ||
| 127 | |||
| 128 | test "strncat" { | ||
| 129 | var s1: [9:0]u8 = undefined; | ||
| 130 | |||
| 131 | s1[0] = 0; | ||
| 132 | _ = strncat(&s1, "foo1111", 3); | ||
| 133 | _ = strncat(&s1, "bar1111", 3); | ||
| 134 | _ = strncat(&s1, "baz1111", 3); | ||
| 135 | std.testing.expectEqualSlices(u8, "foobarbaz", std.mem.spanZ(&s1)); | ||
| 136 | } | ||
| 137 | |||
| 50 | fn strcmp(s1: [*:0]const u8, s2: [*:0]const u8) callconv(.C) c_int { | 138 | fn strcmp(s1: [*:0]const u8, s2: [*:0]const u8) callconv(.C) c_int { |
| 51 | return std.cstr.cmp(s1, s2); | 139 | return std.cstr.cmp(s1, s2); |
| 52 | } | 140 | } |
| ... | @@ -92,7 +180,7 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn | ... | @@ -92,7 +180,7 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn |
| 92 | while (true) {} | 180 | while (true) {} |
| 93 | } | 181 | } |
| 94 | 182 | ||
| 95 | export fn memset(dest: ?[*]u8, c: u8, n: usize) ?[*]u8 { | 183 | export fn memset(dest: ?[*]u8, c: u8, n: usize) callconv(.C) ?[*]u8 { |
| 96 | @setRuntimeSafety(false); | 184 | @setRuntimeSafety(false); |
| 97 | 185 | ||
| 98 | var index: usize = 0; | 186 | var index: usize = 0; |
| ... | @@ -102,7 +190,13 @@ export fn memset(dest: ?[*]u8, c: u8, n: usize) ?[*]u8 { | ... | @@ -102,7 +190,13 @@ export fn memset(dest: ?[*]u8, c: u8, n: usize) ?[*]u8 { |
| 102 | return dest; | 190 | return dest; |
| 103 | } | 191 | } |
| 104 | 192 | ||
| 105 | export fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) ?[*]u8 { | 193 | export fn __memset(dest: ?[*]u8, c: u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 { |
| 194 | if (dest_n < n) | ||
| 195 | @panic("buffer overflow"); | ||
| 196 | return memset(dest, c, n); | ||
| 197 | } | ||
| 198 | |||
| 199 | export fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8 { | ||
| 106 | @setRuntimeSafety(false); | 200 | @setRuntimeSafety(false); |
| 107 | 201 | ||
| 108 | var index: usize = 0; | 202 | var index: usize = 0; |
| ... | @@ -112,7 +206,7 @@ export fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) ?[*] | ... | @@ -112,7 +206,7 @@ export fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) ?[*] |
| 112 | return dest; | 206 | return dest; |
| 113 | } | 207 | } |
| 114 | 208 | ||
| 115 | export fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) ?[*]u8 { | 209 | export fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8 { |
| 116 | @setRuntimeSafety(false); | 210 | @setRuntimeSafety(false); |
| 117 | 211 | ||
| 118 | if (@ptrToInt(dest) < @ptrToInt(src)) { | 212 | if (@ptrToInt(dest) < @ptrToInt(src)) { |
| ... | @@ -131,7 +225,7 @@ export fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) ?[*]u8 { | ... | @@ -131,7 +225,7 @@ export fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) ?[*]u8 { |
| 131 | return dest; | 225 | return dest; |
| 132 | } | 226 | } |
| 133 | 227 | ||
| 134 | export fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) isize { | 228 | export fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) callconv(.C) isize { |
| 135 | @setRuntimeSafety(false); | 229 | @setRuntimeSafety(false); |
| 136 | 230 | ||
| 137 | var index: usize = 0; | 231 | var index: usize = 0; |
| ... | @@ -146,17 +240,17 @@ export fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) isize { | ... | @@ -146,17 +240,17 @@ export fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) isize { |
| 146 | } | 240 | } |
| 147 | 241 | ||
| 148 | test "test_memcmp" { | 242 | test "test_memcmp" { |
| 149 | const base_arr = []u8{ 1, 1, 1 }; | 243 | const base_arr = &[_]u8{ 1, 1, 1 }; |
| 150 | const arr1 = []u8{ 1, 1, 1 }; | 244 | const arr1 = &[_]u8{ 1, 1, 1 }; |
| 151 | const arr2 = []u8{ 1, 0, 1 }; | 245 | const arr2 = &[_]u8{ 1, 0, 1 }; |
| 152 | const arr3 = []u8{ 1, 2, 1 }; | 246 | const arr3 = &[_]u8{ 1, 2, 1 }; |
| 153 | 247 | ||
| 154 | std.testing.expect(memcmp(base_arr[0..].ptr, arr1[0..].ptr, base_arr.len) == 0); | 248 | std.testing.expect(memcmp(base_arr[0..], arr1[0..], base_arr.len) == 0); |
| 155 | std.testing.expect(memcmp(base_arr[0..].ptr, arr2[0..].ptr, base_arr.len) > 0); | 249 | std.testing.expect(memcmp(base_arr[0..], arr2[0..], base_arr.len) > 0); |
| 156 | std.testing.expect(memcmp(base_arr[0..].ptr, arr3[0..].ptr, base_arr.len) < 0); | 250 | std.testing.expect(memcmp(base_arr[0..], arr3[0..], base_arr.len) < 0); |
| 157 | } | 251 | } |
| 158 | 252 | ||
| 159 | export fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) isize { | 253 | export fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) callconv(.C) isize { |
| 160 | @setRuntimeSafety(false); | 254 | @setRuntimeSafety(false); |
| 161 | 255 | ||
| 162 | var index: usize = 0; | 256 | var index: usize = 0; |
| ... | @@ -170,30 +264,21 @@ export fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) i | ... | @@ -170,30 +264,21 @@ export fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) i |
| 170 | } | 264 | } |
| 171 | 265 | ||
| 172 | test "test_bcmp" { | 266 | test "test_bcmp" { |
| 173 | const base_arr = []u8{ 1, 1, 1 }; | 267 | const base_arr = &[_]u8{ 1, 1, 1 }; |
| 174 | const arr1 = []u8{ 1, 1, 1 }; | 268 | const arr1 = &[_]u8{ 1, 1, 1 }; |
| 175 | const arr2 = []u8{ 1, 0, 1 }; | 269 | const arr2 = &[_]u8{ 1, 0, 1 }; |
| 176 | const arr3 = []u8{ 1, 2, 1 }; | 270 | const arr3 = &[_]u8{ 1, 2, 1 }; |
| 177 | 271 | ||
| 178 | std.testing.expect(bcmp(base_arr[0..].ptr, arr1[0..].ptr, base_arr.len) == 0); | 272 | std.testing.expect(bcmp(base_arr[0..], arr1[0..], base_arr.len) == 0); |
| 179 | std.testing.expect(bcmp(base_arr[0..].ptr, arr2[0..].ptr, base_arr.len) != 0); | 273 | std.testing.expect(bcmp(base_arr[0..], arr2[0..], base_arr.len) != 0); |
| 180 | std.testing.expect(bcmp(base_arr[0..].ptr, arr3[0..].ptr, base_arr.len) != 0); | 274 | std.testing.expect(bcmp(base_arr[0..], arr3[0..], base_arr.len) != 0); |
| 181 | } | 275 | } |
| 182 | 276 | ||
| 183 | comptime { | 277 | comptime { |
| 184 | if (builtin.mode != builtin.Mode.ReleaseFast and | ||
| 185 | builtin.mode != builtin.Mode.ReleaseSmall and | ||
| 186 | builtin.os.tag != .windows) | ||
| 187 | { | ||
| 188 | @export(__stack_chk_fail, .{ .name = "__stack_chk_fail" }); | ||
| 189 | } | ||
| 190 | if (builtin.os.tag == .linux) { | 278 | if (builtin.os.tag == .linux) { |
| 191 | @export(clone, .{ .name = "clone" }); | 279 | @export(clone, .{ .name = "clone" }); |
| 192 | } | 280 | } |
| 193 | } | 281 | } |
| 194 | fn __stack_chk_fail() callconv(.C) noreturn { | ||
| 195 | @panic("stack smashing detected"); | ||
| 196 | } | ||
| 197 | 282 | ||
| 198 | // TODO we should be able to put this directly in std/linux/x86_64.zig but | 283 | // TODO we should be able to put this directly in std/linux/x86_64.zig but |
| 199 | // it causes a segfault in release mode. this is a workaround of calling it | 284 | // it causes a segfault in release mode. this is a workaround of calling it |
| ... | @@ -416,7 +501,6 @@ fn clone() callconv(.Naked) void { | ... | @@ -416,7 +501,6 @@ fn clone() callconv(.Naked) void { |
| 416 | \\ # move syscall number into r0 | 501 | \\ # move syscall number into r0 |
| 417 | \\ li 0, 120 | 502 | \\ li 0, 120 |
| 418 | \\ sc | 503 | \\ sc |
| 419 | |||
| 420 | \\ # check for syscall error | 504 | \\ # check for syscall error |
| 421 | \\ bns+ 1f # jump to label 1 if no summary overflow. | 505 | \\ bns+ 1f # jump to label 1 if no summary overflow. |
| 422 | \\ #else | 506 | \\ #else |
| ... | @@ -424,10 +508,8 @@ fn clone() callconv(.Naked) void { | ... | @@ -424,10 +508,8 @@ fn clone() callconv(.Naked) void { |
| 424 | \\1: | 508 | \\1: |
| 425 | \\ # compare sc result with 0 | 509 | \\ # compare sc result with 0 |
| 426 | \\ cmpwi cr7, 3, 0 | 510 | \\ cmpwi cr7, 3, 0 |
| 427 | |||
| 428 | \\ # if not 0, jump to end | 511 | \\ # if not 0, jump to end |
| 429 | \\ bne cr7, 2f | 512 | \\ bne cr7, 2f |
| 430 | |||
| 431 | \\ #else: we're the child | 513 | \\ #else: we're the child |
| 432 | \\ #call funcptr: move arg (d) into r3 | 514 | \\ #call funcptr: move arg (d) into r3 |
| 433 | \\ mr 3, 31 | 515 | \\ mr 3, 31 |
| ... | @@ -438,13 +520,11 @@ fn clone() callconv(.Naked) void { | ... | @@ -438,13 +520,11 @@ fn clone() callconv(.Naked) void { |
| 438 | \\ # mov SYS_exit into r0 (the exit param is already in r3) | 520 | \\ # mov SYS_exit into r0 (the exit param is already in r3) |
| 439 | \\ li 0, 1 | 521 | \\ li 0, 1 |
| 440 | \\ sc | 522 | \\ sc |
| 441 | |||
| 442 | \\2: | 523 | \\2: |
| 443 | \\ # restore stack | 524 | \\ # restore stack |
| 444 | \\ lwz 30, 0(1) | 525 | \\ lwz 30, 0(1) |
| 445 | \\ lwz 31, 4(1) | 526 | \\ lwz 31, 4(1) |
| 446 | \\ addi 1, 1, 16 | 527 | \\ addi 1, 1, 16 |
| 447 | |||
| 448 | \\ blr | 528 | \\ blr |
| 449 | ); | 529 | ); |
| 450 | }, | 530 | }, |
lib/std/special/compiler_rt.zig-19| ... | @@ -284,11 +284,6 @@ comptime { | ... | @@ -284,11 +284,6 @@ comptime { |
| 284 | @export(@import("compiler_rt/stack_probe.zig").__chkstk, .{ .name = "__chkstk", .linkage = strong_linkage }); | 284 | @export(@import("compiler_rt/stack_probe.zig").__chkstk, .{ .name = "__chkstk", .linkage = strong_linkage }); |
| 285 | } | 285 | } |
| 286 | 286 | ||
| 287 | if (is_mingw) { | ||
| 288 | @export(__stack_chk_fail, .{ .name = "__stack_chk_fail", .linkage = strong_linkage }); | ||
| 289 | @export(__stack_chk_guard, .{ .name = "__stack_chk_guard", .linkage = strong_linkage }); | ||
| 290 | } | ||
| 291 | |||
| 292 | switch (builtin.arch) { | 287 | switch (builtin.arch) { |
| 293 | .i386 => { | 288 | .i386 => { |
| 294 | @export(@import("compiler_rt/divti3.zig").__divti3, .{ .name = "__divti3", .linkage = linkage }); | 289 | @export(@import("compiler_rt/divti3.zig").__divti3, .{ .name = "__divti3", .linkage = linkage }); |
| ... | @@ -311,9 +306,6 @@ comptime { | ... | @@ -311,9 +306,6 @@ comptime { |
| 311 | else => {}, | 306 | else => {}, |
| 312 | } | 307 | } |
| 313 | } else { | 308 | } else { |
| 314 | if (std.Target.current.isGnuLibC() and builtin.link_libc) { | ||
| 315 | @export(__stack_chk_guard, .{ .name = "__stack_chk_guard", .linkage = linkage }); | ||
| 316 | } | ||
| 317 | @export(@import("compiler_rt/divti3.zig").__divti3, .{ .name = "__divti3", .linkage = linkage }); | 309 | @export(@import("compiler_rt/divti3.zig").__divti3, .{ .name = "__divti3", .linkage = linkage }); |
| 318 | @export(@import("compiler_rt/modti3.zig").__modti3, .{ .name = "__modti3", .linkage = linkage }); | 310 | @export(@import("compiler_rt/modti3.zig").__modti3, .{ .name = "__modti3", .linkage = linkage }); |
| 319 | @export(@import("compiler_rt/multi3.zig").__multi3, .{ .name = "__multi3", .linkage = linkage }); | 311 | @export(@import("compiler_rt/multi3.zig").__multi3, .{ .name = "__multi3", .linkage = linkage }); |
| ... | @@ -337,14 +329,3 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn | ... | @@ -337,14 +329,3 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn |
| 337 | unreachable; | 329 | unreachable; |
| 338 | } | 330 | } |
| 339 | } | 331 | } |
| 340 | |||
| 341 | fn __stack_chk_fail() callconv(.C) noreturn { | ||
| 342 | @panic("stack smashing detected"); | ||
| 343 | } | ||
| 344 | |||
| 345 | var __stack_chk_guard: usize = blk: { | ||
| 346 | var buf = [1]u8{0} ** @sizeOf(usize); | ||
| 347 | buf[@sizeOf(usize) - 1] = 255; | ||
| 348 | buf[@sizeOf(usize) - 2] = '\n'; | ||
| 349 | break :blk @bitCast(usize, buf); | ||
| 350 | }; |
lib/std/special/ssp.zig created+141| ... | @@ -0,0 +1,141 @@ | ||
| 1 | // SPDX-License-Identifier: MIT | ||
| 2 | // Copyright (c) 2015-2020 Zig Contributors | ||
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | ||
| 4 | // The MIT license requires this copyright notice to be included in all copies | ||
| 5 | // and substantial portions of the software. | ||
| 6 | // | ||
| 7 | // Small Zig reimplementation of gcc's libssp. | ||
| 8 | // | ||
| 9 | // This library implements most of the builtins required by the stack smashing | ||
| 10 | // protection as implemented by gcc&clang. | ||
| 11 | const std = @import("std"); | ||
| 12 | const builtin = std.builtin; | ||
| 13 | |||
| 14 | // Missing exports: | ||
| 15 | // - __gets_chk | ||
| 16 | // - __mempcpy_chk | ||
| 17 | // - __snprintf_chk | ||
| 18 | // - __sprintf_chk | ||
| 19 | // - __stpcpy_chk | ||
| 20 | // - __vsnprintf_chk | ||
| 21 | // - __vsprintf_chk | ||
| 22 | |||
| 23 | extern fn strncpy(dest: [*:0]u8, src: [*:0]const u8, n: usize) callconv(.C) [*:0]u8; | ||
| 24 | extern fn memset(dest: ?[*]u8, c: u8, n: usize) callconv(.C) ?[*]u8; | ||
| 25 | extern fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8; | ||
| 26 | extern fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8; | ||
| 27 | |||
| 28 | // Avoid dragging in the runtime safety mechanisms into this .o file. | ||
| 29 | pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn { | ||
| 30 | @setCold(true); | ||
| 31 | if (@hasDecl(std.os, "abort")) | ||
| 32 | std.os.abort(); | ||
| 33 | while (true) {} | ||
| 34 | } | ||
| 35 | |||
| 36 | export fn __stack_chk_fail() callconv(.C) noreturn { | ||
| 37 | @panic("stack smashing detected"); | ||
| 38 | } | ||
| 39 | |||
| 40 | export fn __chk_fail() callconv(.C) noreturn { | ||
| 41 | @panic("buffer overflow detected"); | ||
| 42 | } | ||
| 43 | |||
| 44 | // Emitted when targeting some architectures (eg. i386) | ||
| 45 | // XXX: This symbol should be hidden | ||
| 46 | export fn __stack_chk_fail_local() callconv(.C) noreturn { | ||
| 47 | __stack_chk_fail(); | ||
| 48 | } | ||
| 49 | |||
| 50 | // XXX: Initialize the canary with random data | ||
| 51 | export var __stack_chk_guard: usize = blk: { | ||
| 52 | var buf = [1]u8{0} ** @sizeOf(usize); | ||
| 53 | buf[@sizeOf(usize) - 1] = 255; | ||
| 54 | buf[@sizeOf(usize) - 2] = '\n'; | ||
| 55 | break :blk @bitCast(usize, buf); | ||
| 56 | }; | ||
| 57 | |||
| 58 | export fn __strcpy_chk(dest: [*:0]u8, src: [*:0]const u8, dest_n: usize) callconv(.C) [*:0]u8 { | ||
| 59 | @setRuntimeSafety(false); | ||
| 60 | |||
| 61 | var i: usize = 0; | ||
| 62 | while (i < dest_n and src[i] != 0) : (i += 1) { | ||
| 63 | dest[i] = src[i]; | ||
| 64 | } | ||
| 65 | |||
| 66 | if (i == dest_n) __chk_fail(); | ||
| 67 | |||
| 68 | dest[i] = 0; | ||
| 69 | |||
| 70 | return dest; | ||
| 71 | } | ||
| 72 | |||
| 73 | export fn __strncpy_chk(dest: [*:0]u8, src: [*:0]const u8, n: usize, dest_n: usize) callconv(.C) [*:0]u8 { | ||
| 74 | if (dest_n < n) __chk_fail(); | ||
| 75 | return strncpy(dest, src, n); | ||
| 76 | } | ||
| 77 | |||
| 78 | export fn __strcat_chk(dest: [*:0]u8, src: [*:0]const u8, dest_n: usize) callconv(.C) [*:0]u8 { | ||
| 79 | @setRuntimeSafety(false); | ||
| 80 | |||
| 81 | var avail = dest_n; | ||
| 82 | |||
| 83 | var dest_end: usize = 0; | ||
| 84 | while (avail > 0 and dest[dest_end] != 0) : (dest_end += 1) { | ||
| 85 | avail -= 1; | ||
| 86 | } | ||
| 87 | |||
| 88 | if (avail < 1) __chk_fail(); | ||
| 89 | |||
| 90 | var i: usize = 0; | ||
| 91 | while (avail > 0 and src[i] != 0) : (i += 1) { | ||
| 92 | dest[dest_end + i] = src[i]; | ||
| 93 | avail -= 1; | ||
| 94 | } | ||
| 95 | |||
| 96 | if (avail < 1) __chk_fail(); | ||
| 97 | |||
| 98 | dest[dest_end + i] = 0; | ||
| 99 | |||
| 100 | return dest; | ||
| 101 | } | ||
| 102 | |||
| 103 | export fn __strncat_chk(dest: [*:0]u8, src: [*:0]const u8, n: usize, dest_n: usize) callconv(.C) [*:0]u8 { | ||
| 104 | @setRuntimeSafety(false); | ||
| 105 | |||
| 106 | var avail = dest_n; | ||
| 107 | |||
| 108 | var dest_end: usize = 0; | ||
| 109 | while (avail > 0 and dest[dest_end] != 0) : (dest_end += 1) { | ||
| 110 | avail -= 1; | ||
| 111 | } | ||
| 112 | |||
| 113 | if (avail < 1) __chk_fail(); | ||
| 114 | |||
| 115 | var i: usize = 0; | ||
| 116 | while (avail > 0 and i < n and src[i] != 0) : (i += 1) { | ||
| 117 | dest[dest_end + i] = src[i]; | ||
| 118 | avail -= 1; | ||
| 119 | } | ||
| 120 | |||
| 121 | if (avail < 1) __chk_fail(); | ||
| 122 | |||
| 123 | dest[dest_end + i] = 0; | ||
| 124 | |||
| 125 | return dest; | ||
| 126 | } | ||
| 127 | |||
| 128 | export fn __memcpy_chk(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 { | ||
| 129 | if (dest_n < n) __chk_fail(); | ||
| 130 | return memcpy(dest, src, n); | ||
| 131 | } | ||
| 132 | |||
| 133 | export fn __memmove_chk(dest: ?[*]u8, src: ?[*]const u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 { | ||
| 134 | if (dest_n < n) __chk_fail(); | ||
| 135 | return memmove(dest, src, n); | ||
| 136 | } | ||
| 137 | |||
| 138 | export fn __memset_chk(dest: ?[*]u8, c: u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 { | ||
| 139 | if (dest_n < n) __chk_fail(); | ||
| 140 | return memset(dest, c, n); | ||
| 141 | } | ||
src/Compilation.zig+17| ... | @@ -84,6 +84,9 @@ libcxxabi_static_lib: ?CRTFile = null, | ... | @@ -84,6 +84,9 @@ libcxxabi_static_lib: ?CRTFile = null, |
| 84 | /// Populated when we build the libunwind static library. A Job to build this is placed in the queue | 84 | /// Populated when we build the libunwind static library. A Job to build this is placed in the queue |
| 85 | /// and resolved before calling linker.flush(). | 85 | /// and resolved before calling linker.flush(). |
| 86 | libunwind_static_lib: ?CRTFile = null, | 86 | libunwind_static_lib: ?CRTFile = null, |
| 87 | /// Populated when we build the libssp static library. A Job to build this is placed in the queue | ||
| 88 | /// and resolved before calling linker.flush(). | ||
| 89 | libssp_static_lib: ?CRTFile = null, | ||
| 87 | /// Populated when we build the libc static library. A Job to build this is placed in the queue | 90 | /// Populated when we build the libc static library. A Job to build this is placed in the queue |
| 88 | /// and resolved before calling linker.flush(). | 91 | /// and resolved before calling linker.flush(). |
| 89 | libc_static_lib: ?CRTFile = null, | 92 | libc_static_lib: ?CRTFile = null, |
| ... | @@ -160,6 +163,7 @@ const Job = union(enum) { | ... | @@ -160,6 +163,7 @@ const Job = union(enum) { |
| 160 | libunwind: void, | 163 | libunwind: void, |
| 161 | libcxx: void, | 164 | libcxx: void, |
| 162 | libcxxabi: void, | 165 | libcxxabi: void, |
| 166 | libssp: void, | ||
| 163 | /// needed when producing a dynamic library or executable | 167 | /// needed when producing a dynamic library or executable |
| 164 | libcompiler_rt: void, | 168 | libcompiler_rt: void, |
| 165 | /// needed when not linking libc and using LLVM for code generation because it generates | 169 | /// needed when not linking libc and using LLVM for code generation because it generates |
| ... | @@ -927,6 +931,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -927,6 +931,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 927 | (comp.getTarget().isWasm() and comp.bin_file.options.output_mode != .Obj); | 931 | (comp.getTarget().isWasm() and comp.bin_file.options.output_mode != .Obj); |
| 928 | if (needs_compiler_rt_and_c and build_options.is_stage1) { | 932 | if (needs_compiler_rt_and_c and build_options.is_stage1) { |
| 929 | try comp.work_queue.writeItem(.{ .libcompiler_rt = {} }); | 933 | try comp.work_queue.writeItem(.{ .libcompiler_rt = {} }); |
| 934 | // MinGW provides no libssp, use our own implementation. | ||
| 935 | if (comp.getTarget().isMinGW()) { | ||
| 936 | try comp.work_queue.writeItem(.{ .libssp = {} }); | ||
| 937 | } | ||
| 930 | if (!comp.bin_file.options.link_libc) { | 938 | if (!comp.bin_file.options.link_libc) { |
| 931 | try comp.work_queue.writeItem(.{ .zig_libc = {} }); | 939 | try comp.work_queue.writeItem(.{ .zig_libc = {} }); |
| 932 | } | 940 | } |
| ... | @@ -978,6 +986,9 @@ pub fn destroy(self: *Compilation) void { | ... | @@ -978,6 +986,9 @@ pub fn destroy(self: *Compilation) void { |
| 978 | if (self.compiler_rt_static_lib) |*crt_file| { | 986 | if (self.compiler_rt_static_lib) |*crt_file| { |
| 979 | crt_file.deinit(gpa); | 987 | crt_file.deinit(gpa); |
| 980 | } | 988 | } |
| 989 | if (self.libssp_static_lib) |*crt_file| { | ||
| 990 | crt_file.deinit(gpa); | ||
| 991 | } | ||
| 981 | if (self.libc_static_lib) |*crt_file| { | 992 | if (self.libc_static_lib) |*crt_file| { |
| 982 | crt_file.deinit(gpa); | 993 | crt_file.deinit(gpa); |
| 983 | } | 994 | } |
| ... | @@ -1329,6 +1340,12 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor | ... | @@ -1329,6 +1340,12 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor |
| 1329 | fatal("unable to build compiler_rt: {}", .{@errorName(err)}); | 1340 | fatal("unable to build compiler_rt: {}", .{@errorName(err)}); |
| 1330 | }; | 1341 | }; |
| 1331 | }, | 1342 | }, |
| 1343 | .libssp => { | ||
| 1344 | self.buildStaticLibFromZig("ssp.zig", &self.libssp_static_lib) catch |err| { | ||
| 1345 | // TODO Expose this as a normal compile error rather than crashing here. | ||
| 1346 | fatal("unable to build libssp: {}", .{@errorName(err)}); | ||
| 1347 | }; | ||
| 1348 | }, | ||
| 1332 | .zig_libc => { | 1349 | .zig_libc => { |
| 1333 | self.buildStaticLibFromZig("c.zig", &self.libc_static_lib) catch |err| { | 1350 | self.buildStaticLibFromZig("c.zig", &self.libc_static_lib) catch |err| { |
| 1334 | // TODO Expose this as a normal compile error rather than crashing here. | 1351 | // TODO Expose this as a normal compile error rather than crashing here. |
src/link/Coff.zig+5-1| ... | @@ -1117,11 +1117,15 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { | ... | @@ -1117,11 +1117,15 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { |
| 1117 | try argv.append(comp.libunwind_static_lib.?.full_object_path); | 1117 | try argv.append(comp.libunwind_static_lib.?.full_object_path); |
| 1118 | } | 1118 | } |
| 1119 | 1119 | ||
| 1120 | // compiler-rt and libc | 1120 | // compiler-rt, libc and libssp |
| 1121 | if (is_exe_or_dyn_lib and !self.base.options.is_compiler_rt_or_libc) { | 1121 | if (is_exe_or_dyn_lib and !self.base.options.is_compiler_rt_or_libc) { |
| 1122 | if (!self.base.options.link_libc) { | 1122 | if (!self.base.options.link_libc) { |
| 1123 | try argv.append(comp.libc_static_lib.?.full_object_path); | 1123 | try argv.append(comp.libc_static_lib.?.full_object_path); |
| 1124 | } | 1124 | } |
| 1125 | // MinGW doesn't provide libssp symbols | ||
| 1126 | if (target.abi.isGnu()) { | ||
| 1127 | try argv.append(comp.libssp_static_lib.?.full_object_path); | ||
| 1128 | } | ||
| 1125 | // MSVC compiler_rt is missing some stuff, so we build it unconditionally but | 1129 | // MSVC compiler_rt is missing some stuff, so we build it unconditionally but |
| 1126 | // and rely on weak linkage to allow MSVC compiler_rt functions to override ours. | 1130 | // and rely on weak linkage to allow MSVC compiler_rt functions to override ours. |
| 1127 | try argv.append(comp.compiler_rt_static_lib.?.full_object_path); | 1131 | try argv.append(comp.compiler_rt_static_lib.?.full_object_path); |