Path: blob/main/system/lib/mimalloc/src/libc.c
6175 views
/* ----------------------------------------------------------------------------1Copyright (c) 2018-2023, Microsoft Research, Daan Leijen2This is free software; you can redistribute it and/or modify it under the3terms of the MIT license. A copy of the license can be found in the file4"LICENSE" at the root of this distribution.5-----------------------------------------------------------------------------*/67// --------------------------------------------------------8// This module defines various std libc functions to reduce9// the dependency on libc, and also prevent errors caused10// by some libc implementations when called before `main`11// executes (due to malloc redirection)12// --------------------------------------------------------1314#include "mimalloc.h"15#include "mimalloc/internal.h"16#include "mimalloc/prim.h" // mi_prim_getenv1718char _mi_toupper(char c) {19if (c >= 'a' && c <= 'z') return (c - 'a' + 'A');20else return c;21}2223int _mi_strnicmp(const char* s, const char* t, size_t n) {24if (n == 0) return 0;25for (; *s != 0 && *t != 0 && n > 0; s++, t++, n--) {26if (_mi_toupper(*s) != _mi_toupper(*t)) break;27}28return (n == 0 ? 0 : *s - *t);29}3031void _mi_strlcpy(char* dest, const char* src, size_t dest_size) {32if (dest==NULL || src==NULL || dest_size == 0) return;33// copy until end of src, or when dest is (almost) full34while (*src != 0 && dest_size > 1) {35*dest++ = *src++;36dest_size--;37}38// always zero terminate39*dest = 0;40}4142void _mi_strlcat(char* dest, const char* src, size_t dest_size) {43if (dest==NULL || src==NULL || dest_size == 0) return;44// find end of string in the dest buffer45while (*dest != 0 && dest_size > 1) {46dest++;47dest_size--;48}49// and catenate50_mi_strlcpy(dest, src, dest_size);51}5253size_t _mi_strlen(const char* s) {54if (s==NULL) return 0;55size_t len = 0;56while(s[len] != 0) { len++; }57return len;58}5960size_t _mi_strnlen(const char* s, size_t max_len) {61if (s==NULL) return 0;62size_t len = 0;63while(s[len] != 0 && len < max_len) { len++; }64return len;65}6667#ifdef MI_NO_GETENV68bool _mi_getenv(const char* name, char* result, size_t result_size) {69MI_UNUSED(name);70MI_UNUSED(result);71MI_UNUSED(result_size);72return false;73}74#else75bool _mi_getenv(const char* name, char* result, size_t result_size) {76if (name==NULL || result == NULL || result_size < 64) return false;77return _mi_prim_getenv(name,result,result_size);78}79#endif8081// --------------------------------------------------------82// Define our own limited `_mi_vsnprintf` and `_mi_snprintf`83// This is mostly to avoid calling these when libc is not yet84// initialized (and to reduce dependencies)85//86// format: d i, p x u, s87// prec: z l ll L88// width: 1089// align-left: -90// fill: 091// plus: +92// --------------------------------------------------------9394static void mi_outc(char c, char** out, char* end) {95char* p = *out;96if (p >= end) return;97*p = c;98*out = p + 1;99}100101static void mi_outs(const char* s, char** out, char* end) {102if (s == NULL) return;103char* p = *out;104while (*s != 0 && p < end) {105*p++ = *s++;106}107*out = p;108}109110static void mi_out_fill(char fill, size_t len, char** out, char* end) {111char* p = *out;112for (size_t i = 0; i < len && p < end; i++) {113*p++ = fill;114}115*out = p;116}117118static void mi_out_alignright(char fill, char* start, size_t len, size_t extra, char* end) {119if (len == 0 || extra == 0) return;120if (start + len + extra >= end) return;121// move `len` characters to the right (in reverse since it can overlap)122for (size_t i = 1; i <= len; i++) {123start[len + extra - i] = start[len - i];124}125// and fill the start126for (size_t i = 0; i < extra; i++) {127start[i] = fill;128}129}130131132static void mi_out_num(uintptr_t x, size_t base, char prefix, char** out, char* end)133{134if (x == 0 || base == 0 || base > 16) {135if (prefix != 0) { mi_outc(prefix, out, end); }136mi_outc('0',out,end);137}138else {139// output digits in reverse140char* start = *out;141while (x > 0) {142char digit = (char)(x % base);143mi_outc((digit <= 9 ? '0' + digit : 'A' + digit - 10),out,end);144x = x / base;145}146if (prefix != 0) {147mi_outc(prefix, out, end);148}149size_t len = *out - start;150// and reverse in-place151for (size_t i = 0; i < (len / 2); i++) {152char c = start[len - i - 1];153start[len - i - 1] = start[i];154start[i] = c;155}156}157}158159160#define MI_NEXTC() c = *in; if (c==0) break; in++;161162void _mi_vsnprintf(char* buf, size_t bufsize, const char* fmt, va_list args) {163if (buf == NULL || bufsize == 0 || fmt == NULL) return;164buf[bufsize - 1] = 0;165char* const end = buf + (bufsize - 1);166const char* in = fmt;167char* out = buf;168while (true) {169if (out >= end) break;170char c;171MI_NEXTC();172if (c != '%') {173if ((c >= ' ' && c <= '~') || c=='\n' || c=='\r' || c=='\t') { // output visible ascii or standard control only174mi_outc(c, &out, end);175}176}177else {178MI_NEXTC();179char fill = ' ';180size_t width = 0;181char numtype = 'd';182char numplus = 0;183bool alignright = true;184if (c == '+' || c == ' ') { numplus = c; MI_NEXTC(); }185if (c == '-') { alignright = false; MI_NEXTC(); }186if (c == '0') { fill = '0'; MI_NEXTC(); }187if (c >= '1' && c <= '9') {188width = (c - '0'); MI_NEXTC();189while (c >= '0' && c <= '9') {190width = (10 * width) + (c - '0'); MI_NEXTC();191}192if (c == 0) break; // extra check due to while193}194if (c == 'z' || c == 't' || c == 'L') { numtype = c; MI_NEXTC(); }195else if (c == 'l') {196numtype = c; MI_NEXTC();197if (c == 'l') { numtype = 'L'; MI_NEXTC(); }198}199200char* start = out;201if (c == 's') {202// string203const char* s = va_arg(args, const char*);204mi_outs(s, &out, end);205}206else if (c == 'p' || c == 'x' || c == 'u') {207// unsigned208uintptr_t x = 0;209if (c == 'x' || c == 'u') {210if (numtype == 'z') x = va_arg(args, size_t);211else if (numtype == 't') x = va_arg(args, uintptr_t); // unsigned ptrdiff_t212else if (numtype == 'L') x = (uintptr_t)va_arg(args, unsigned long long);213else x = va_arg(args, unsigned long);214}215else if (c == 'p') {216x = va_arg(args, uintptr_t);217mi_outs("0x", &out, end);218start = out;219width = (width >= 2 ? width - 2 : 0);220}221if (width == 0 && (c == 'x' || c == 'p')) {222if (c == 'p') { width = 2 * (x <= UINT32_MAX ? 4 : ((x >> 16) <= UINT32_MAX ? 6 : sizeof(void*))); }223if (width == 0) { width = 2; }224fill = '0';225}226mi_out_num(x, (c == 'x' || c == 'p' ? 16 : 10), numplus, &out, end);227}228else if (c == 'i' || c == 'd') {229// signed230intptr_t x = 0;231if (numtype == 'z') x = va_arg(args, intptr_t );232else if (numtype == 't') x = va_arg(args, ptrdiff_t);233else if (numtype == 'L') x = (intptr_t)va_arg(args, long long);234else x = va_arg(args, long);235char pre = 0;236if (x < 0) {237pre = '-';238if (x > INTPTR_MIN) { x = -x; }239}240else if (numplus != 0) {241pre = numplus;242}243mi_out_num((uintptr_t)x, 10, pre, &out, end);244}245else if (c >= ' ' && c <= '~') {246// unknown format247mi_outc('%', &out, end);248mi_outc(c, &out, end);249}250251// fill & align252mi_assert_internal(out <= end);253mi_assert_internal(out >= start);254const size_t len = out - start;255if (len < width) {256mi_out_fill(fill, width - len, &out, end);257if (alignright && out <= end) {258mi_out_alignright(fill, start, len, width - len, end);259}260}261}262}263mi_assert_internal(out <= end);264*out = 0;265}266267void _mi_snprintf(char* buf, size_t buflen, const char* fmt, ...) {268va_list args;269va_start(args, fmt);270_mi_vsnprintf(buf, buflen, fmt, args);271va_end(args);272}273274275