Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

ssp.zig

Small Zig reimplementation of gcc's libssp.

This library implements most of the builtins required by the stack smashing protection as implemented by gcc&clang. Missing exports:

File

Code

//!
//! Small Zig reimplementation of gcc's libssp.
//!
//! This library implements most of the builtins required by the stack smashing
//! protection as implemented by gcc&clang.
//! Missing exports:
//! - __gets_chk
//! - __mempcpy_chk
//! - __snprintf_chk
//! - __sprintf_chk
//! - __stpcpy_chk
//! - __vsnprintf_chk
//! - __vsprintf_chk

const std = @import("std");
const compiler_rt = @import("../compiler_rt.zig");
const symbol = compiler_rt.symbol;
const builtin = @import("builtin");

extern fn memset(dest: ?[*]u8, c: c_int, n: usize) callconv(.c) ?[*]u8;
extern fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) callconv(.c) ?[*]u8;
extern fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) callconv(.c) ?[*]u8;

comptime {
    @export(&__stack_chk_fail, .{ .name = if (builtin.os.tag == .openbsd) "__stack_smash_handler" else "__stack_chk_fail", .linkage = compiler_rt.linkage, .visibility = compiler_rt.visibility });
    symbol(&__chk_fail, "__chk_fail");
    symbol(&__stack_chk_guard, if (builtin.os.tag == .openbsd) "__guard_local" else "__stack_chk_guard");
    symbol(&__strcpy_chk, "__strcpy_chk");
    symbol(&__strncpy_chk, "__strncpy_chk");
    symbol(&__strcat_chk, "__strcat_chk");
    symbol(&__strncat_chk, "__strncat_chk");
    symbol(&__memcpy_chk, "__memcpy_chk");
    symbol(&__memmove_chk, "__memmove_chk");
    symbol(&__memset_chk, "__memset_chk");
}

fn __stack_chk_fail() callconv(.c) noreturn {
    @panic("stack smashing detected");
}

fn __chk_fail() callconv(.c) noreturn {
    @panic("buffer overflow detected");
}

// TODO: Initialize the canary with random data
var __stack_chk_guard: usize = blk: {
    var buf: [@sizeOf(usize)]u8 = @splat(0);
    buf[@sizeOf(usize) - 1] = 255;
    buf[@sizeOf(usize) - 2] = '\n';
    break :blk @bitCast(buf);
};

fn __strcpy_chk(dest: [*:0]u8, src: [*:0]const u8, dest_n: usize) callconv(.c) [*:0]u8 {
    @setRuntimeSafety(false);

    var i: usize = 0;
    while (i < dest_n and src[i] != 0) : (i += 1) {
        dest[i] = src[i];
    }

    if (i == dest_n) __chk_fail();

    dest[i] = 0;

    return dest;
}

fn __strncpy_chk(dest: [*:0]u8, src: [*:0]const u8, n: usize, dest_n: usize) callconv(.c) [*:0]u8 {
    @setRuntimeSafety(false);
    if (dest_n < n) __chk_fail();
    var i: usize = 0;
    while (i < n and src[i] != 0) : (i += 1) {
        dest[i] = src[i];
    }
    while (i < n) : (i += 1) {
        dest[i] = 0;
    }
    return dest;
}

fn __strcat_chk(dest: [*:0]u8, src: [*:0]const u8, dest_n: usize) callconv(.c) [*:0]u8 {
    @setRuntimeSafety(false);

    var avail = dest_n;

    var dest_end: usize = 0;
    while (avail > 0 and dest[dest_end] != 0) : (dest_end += 1) {
        avail -= 1;
    }

    if (avail < 1) __chk_fail();

    var i: usize = 0;
    while (avail > 0 and src[i] != 0) : (i += 1) {
        dest[dest_end + i] = src[i];
        avail -= 1;
    }

    if (avail < 1) __chk_fail();

    dest[dest_end + i] = 0;

    return dest;
}

fn __strncat_chk(dest: [*:0]u8, src: [*:0]const u8, n: usize, dest_n: usize) callconv(.c) [*:0]u8 {
    @setRuntimeSafety(false);

    var avail = dest_n;

    var dest_end: usize = 0;
    while (avail > 0 and dest[dest_end] != 0) : (dest_end += 1) {
        avail -= 1;
    }

    if (avail < 1) __chk_fail();

    var i: usize = 0;
    while (avail > 0 and i < n and src[i] != 0) : (i += 1) {
        dest[dest_end + i] = src[i];
        avail -= 1;
    }

    if (avail < 1) __chk_fail();

    dest[dest_end + i] = 0;

    return dest;
}

fn __memcpy_chk(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize, dest_n: usize) callconv(.c) ?[*]u8 {
    if (dest_n < n) __chk_fail();
    return memcpy(dest, src, n);
}

fn __memmove_chk(dest: ?[*]u8, src: ?[*]const u8, n: usize, dest_n: usize) callconv(.c) ?[*]u8 {
    if (dest_n < n) __chk_fail();
    return memmove(dest, src, n);
}

fn __memset_chk(dest: ?[*]u8, c: c_int, n: usize, dest_n: usize) callconv(.c) ?[*]u8 {
    if (dest_n < n) __chk_fail();
    return memset(dest, c, n);
}