Improve memory safety

This commit makes numerous refinements to cosmopolitan memory handling.

The default stack size has been reduced from 2mb to 128kb. A new macro
is now provided so you can easily reconfigure the stack size to be any
value you want. Work around the breaking change by adding to your main:

    STATIC_STACK_SIZE(0x00200000);  // 2mb stack

If you're not sure how much stack you need, then you can use:

    STATIC_YOINK("stack_usage_logging");

After which you can `sort -nr o/$MODE/stack.log`. Based on the unit test
suite, nothing in the Cosmopolitan repository (except for Python) needs
a stack size greater than 30kb. There are also new macros for detecting
the size and address of the stack at runtime, e.g. GetStackAddr(). We
also now support sigaltstack() so if you want to see nice looking crash
reports whenever a stack overflow happens, you can put this in main():

    ShowCrashReports();

Under `make MODE=dbg` and `make MODE=asan` the unit testing framework
will now automatically print backtraces of memory allocations when
things like memory leaks happen. Bugs are now fixed in ASAN global
variable overrun detection. The memtrack and asan runtimes also handle
edge cases now. The new tools helped to identify a few memory leaks,
which are fixed by this change.

This change should fix an issue reported in #288 with ARG_MAX limits.
Fixing this doubled the performance of MKDEPS.COM and AR.COM yet again.
This commit is contained in:
Justine Tunney 2021-10-13 17:27:13 -07:00
parent a0b39f886c
commit 226aaf3547
317 changed files with 6474 additions and 3993 deletions

View file

@ -1,7 +1,7 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
@ -16,18 +16,23 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/errno.h"
#include "libc/macros.internal.h"
.source __FILE__
#include "libc/mem/mem.h"
.initbss 202,_init_posix_memalign
hook_posix_memalign:
.quad 0
.endobj hook_posix_memalign,globl,hidden
.previous
.init.start 202,_init_posix_memalign
.hidden dlposix_memalign
ezlea dlposix_memalign,ax
stosq
yoink free
.init.end 202,_init_posix_memalign
/**
* Same as memalign(a, n) but requires IS2POW(a).
*
* @param n number of bytes needed
* @return memory address, or NULL w/ errno
* @throw EINVAL if !IS2POW(a)
* @see pvalloc()
*/
void *aligned_alloc(size_t a, size_t n) {
if (IS2POW(a)) {
return memalign(a, n);
} else {
errno = EINVAL;
return 0;
}
}

View file

@ -22,37 +22,39 @@
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/limits.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/mem/arena.h"
#include "libc/mem/hook/hook.internal.h"
#include "libc/nexgen32e/bsf.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/errfuns.h"
#define BASE ((char *)0x30000000)
#define LIMIT ((char *)0x50000000)
#define BASE 0x50000000
#define SIZE 0x2ffe0000
#define P(i) ((void *)(intptr_t)(i))
#define EXCHANGE(HOOK, SLOT) \
__arena_hook((intptr_t *)weaken(HOOK), (intptr_t *)(&(SLOT)))
static struct Arena {
bool once;
uint8_t depth;
unsigned size;
unsigned offset[16];
size_t size;
size_t depth;
size_t offset[16];
void (*free)(void *);
void *(*malloc)(size_t);
void *(*calloc)(size_t, size_t);
void *(*memalign)(size_t, size_t);
void *(*realloc)(void *, size_t);
void *(*realloc_in_place)(void *, size_t);
void *(*valloc)(size_t);
void *(*pvalloc)(size_t);
int (*malloc_trim)(size_t);
size_t (*malloc_usable_size)(const void *);
size_t (*bulk_free)(void *[], size_t);
int (*malloc_trim)(size_t);
} __arena;
static wontreturn void __arena_die(void) {
@ -61,103 +63,202 @@ static wontreturn void __arena_die(void) {
}
static wontreturn void __arena_not_implemented(void) {
__printf("not implemented");
assert(!"not implemented");
__arena_die();
}
static void __arena_free(void *p) {
if (!p) return;
forceinline void __arena_check(void) {
assert(__arena.depth);
assert((intptr_t)BASE + __arena.offset[__arena.depth - 1] <= (intptr_t)p &&
(intptr_t)p < (intptr_t)BASE + __arena.offset[__arena.depth]);
}
forceinline void __arena_check_pointer(void *p) {
assert(BASE + __arena.offset[__arena.depth - 1] <= (uintptr_t)p &&
(uintptr_t)p < BASE + __arena.offset[__arena.depth]);
}
forceinline bool __arena_is_arena_pointer(void *p) {
return BASE <= (uintptr_t)p && (uintptr_t)p < BASE + SIZE;
}
forceinline size_t __arena_get_size(void *p) {
return *(const size_t *)((const char *)p - sizeof(size_t));
}
static void __arena_free(void *p) {
__arena_check();
if (p) {
__arena_check_pointer(p);
if (!(BASE <= (uintptr_t)p && (uintptr_t)p < BASE + SIZE)) {
__arena.free(p);
}
}
}
static size_t __arena_bulk_free(void *p[], size_t n) {
size_t i;
for (i = 0; i < n; ++i) {
if (p[i]) __arena_free(p[i]);
__arena_free(p[i]);
p[i] = 0;
}
bzero(p, n * sizeof(void *));
return 0;
}
static noinline bool __arena_grow(size_t offset, size_t request) {
size_t greed;
greed = __arena.size + 1;
do {
greed += greed >> 1;
greed = ROUNDUP(greed, FRAMESIZE);
} while (greed < offset + request);
if (greed <= SIZE) {
if (mmap(P(BASE + __arena.size), greed - __arena.size,
PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED,
-1, 0) != MAP_FAILED) {
__arena.size = greed;
return true;
}
} else {
enomem();
}
if (weaken(__oom_hook)) {
weaken(__oom_hook)(request);
}
return false;
}
static void *__arena_alloc(size_t a, size_t n) {
size_t o;
if (!n) n = 1;
o = ROUNDUP(__arena.offset[__arena.depth] + sizeof(size_t), a);
if (o + n >= n) {
if (n <= sizeof(size_t)) {
n = sizeof(size_t);
} else {
n = ROUNDUP(n, sizeof(size_t));
}
if (o + n <= SIZE) {
if (UNLIKELY(o + n > __arena.size)) {
if (!__arena_grow(o, n)) return 0;
}
__arena.offset[__arena.depth] = o + n;
*(size_t *)(BASE + o - sizeof(size_t)) = n;
return (void *)(BASE + o);
}
}
enomem();
return 0;
}
static void *__arena_malloc(size_t n) {
char *ptr;
size_t need, greed;
assert(__arena.depth);
if (!n) n = 1;
if (n < LIMIT - BASE) {
need = __arena.offset[__arena.depth] + n;
need = ROUNDUP(need, __BIGGEST_ALIGNMENT__);
if (UNLIKELY(need > __arena.size)) {
greed = __arena.size + 1;
do {
greed += greed >> 1;
greed = ROUNDUP(greed, FRAMESIZE);
} while (need > greed);
if (greed < LIMIT - BASE &&
mmap(BASE + __arena.size, greed - __arena.size,
PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED,
-1, 0) != MAP_FAILED) {
__arena.size = greed;
__arena_check();
return __arena_alloc(16, n);
}
static void *__arena_calloc(size_t n, size_t z) {
__arena_check();
if (__builtin_mul_overflow(n, z, &n)) n = -1;
return __arena_alloc(16, n);
}
static void *__arena_memalign(size_t a, size_t n) {
__arena_check();
if (a <= sizeof(size_t)) {
return __arena_alloc(8, n);
} else {
return __arena_alloc(2ul << bsrl(a - 1), n);
}
}
static size_t __arena_malloc_usable_size(const void *p) {
__arena_check();
__arena_check_pointer(p);
if (__arena_is_arena_pointer(p)) {
return __arena_get_size(p);
} else {
return __arena.malloc_usable_size(p);
}
}
static void *__arena_realloc(void *p, size_t n) {
char *q;
size_t m, o, z;
__arena_check();
if (p) {
__arena_check_pointer(p);
if (__arena_is_arena_pointer(p)) {
if (n) {
if ((m = __arena_get_size(p)) >= n) {
return p;
} else if (n <= SIZE) {
z = 2ul << bsrl(n - 1);
if (__arena.offset[__arena.depth] - m == (o = (intptr_t)p - BASE)) {
if (UNLIKELY(o + z > __arena.size)) {
if (o + z <= SIZE) {
if (!__arena_grow(o, z)) {
return 0;
}
} else {
enomem();
return 0;
}
}
__arena.offset[__arena.depth] = o + z;
*(size_t *)((char *)p - sizeof(size_t)) = z;
return p;
} else if ((q = __arena_alloc(1ul << bsfl((intptr_t)p), z))) {
memmove(q, p, m);
return q;
} else {
return 0;
}
} else {
enomem();
return 0;
}
} else {
return 0;
}
} else {
return __arena.realloc(p, n);
}
} else {
if (n <= 16) {
n = 16;
} else {
n = 2ul << bsrl(n - 1);
}
return __arena_alloc(16, n);
}
}
static void *__arena_realloc_in_place(void *p, size_t n) {
char *q;
size_t m, z;
__arena_check();
if (p) {
__arena_check_pointer(p);
if (__arena_is_arena_pointer(p)) {
if (n) {
if ((m = __arena_get_size(p)) >= n) {
return p;
} else {
return 0;
}
} else {
return 0;
}
} else {
return __arena.realloc_in_place(p, n);
}
ptr = BASE + __arena.offset[__arena.depth];
__arena.offset[__arena.depth] = need;
return ptr;
} else {
return 0;
}
}
static void *__arena_calloc(size_t n, size_t z) {
if (__builtin_mul_overflow(n, z, &n)) n = -1;
return __arena_malloc(n);
}
static void *__arena_memalign(size_t a, size_t n) {
if (a <= __BIGGEST_ALIGNMENT__) {
return __arena_malloc(n);
} else {
__arena_not_implemented();
}
}
static void *__arena_realloc(void *p, size_t n) {
if (p) {
if (n) {
__arena_not_implemented();
} else {
__arena_free(p);
return 0;
}
} else {
return __arena_malloc(n);
}
}
static int __arena_malloc_trim(size_t n) {
return 0;
}
static void *__arena_realloc_in_place(void *p, size_t n) {
__arena_not_implemented();
}
static void *__arena_valloc(size_t n) {
__arena_not_implemented();
}
static void *__arena_pvalloc(size_t n) {
__arena_not_implemented();
}
static size_t __arena_malloc_usable_size(const void *p) {
__arena_not_implemented();
}
static void __arena_hook(intptr_t *h, intptr_t *f) {
intptr_t t;
if (h) {
@ -169,42 +270,32 @@ static void __arena_hook(intptr_t *h, intptr_t *f) {
static void __arena_install(void) {
EXCHANGE(hook_free, __arena.free);
EXCHANGE(hook_realloc, __arena.realloc);
EXCHANGE(hook_realloc, __arena.realloc);
EXCHANGE(hook_malloc, __arena.malloc);
EXCHANGE(hook_calloc, __arena.calloc);
EXCHANGE(hook_realloc, __arena.realloc);
EXCHANGE(hook_memalign, __arena.memalign);
EXCHANGE(hook_realloc_in_place, __arena.realloc_in_place);
EXCHANGE(hook_valloc, __arena.valloc);
EXCHANGE(hook_pvalloc, __arena.pvalloc);
EXCHANGE(hook_malloc_trim, __arena.malloc_trim);
EXCHANGE(hook_malloc_usable_size, __arena.malloc_usable_size);
EXCHANGE(hook_bulk_free, __arena.bulk_free);
EXCHANGE(hook_malloc_trim, __arena.malloc_trim);
EXCHANGE(hook_realloc_in_place, __arena.realloc_in_place);
EXCHANGE(hook_malloc_usable_size, __arena.malloc_usable_size);
}
static void __arena_destroy(void) {
if (__arena.depth) {
__arena_install();
}
if (__arena.size) {
munmap(BASE, __arena.size);
}
if (__arena.depth) __arena_install();
if (__arena.size) munmap(P(BASE), __arena.size);
bzero(&__arena, sizeof(__arena));
}
static void __arena_init(void) {
__arena.free = __arena_free;
__arena.realloc = __arena_realloc;
__arena.realloc = __arena_realloc;
__arena.malloc = __arena_malloc;
__arena.calloc = __arena_calloc;
__arena.realloc = __arena_realloc;
__arena.memalign = __arena_memalign;
__arena.realloc_in_place = __arena_realloc_in_place;
__arena.valloc = __arena_valloc;
__arena.pvalloc = __arena_pvalloc;
__arena.malloc_trim = __arena_malloc_trim;
__arena.malloc_usable_size = __arena_malloc_usable_size;
__arena.bulk_free = __arena_bulk_free;
__arena.malloc_trim = __arena_malloc_trim;
__arena.realloc_in_place = __arena_realloc_in_place;
__arena.malloc_usable_size = __arena_malloc_usable_size;
atexit(__arena_destroy);
}
@ -215,24 +306,27 @@ void __arena_push(void) {
}
if (!__arena.depth) {
__arena_install();
} else if (__arena.depth == ARRAYLEN(__arena.offset) - 1) {
__printf("too many arenas");
__arena_die();
} else {
assert(__arena.depth < ARRAYLEN(__arena.offset) - 1);
}
__arena.offset[__arena.depth + 1] = __arena.offset[__arena.depth];
++__arena.depth;
}
void __arena_pop(void) {
unsigned greed;
assert(__arena.depth);
bzero(BASE + __arena.offset[__arena.depth - 1],
__arena.offset[__arena.depth] - __arena.offset[__arena.depth - 1]);
size_t a, b, greed;
__arena_check();
if (!--__arena.depth) __arena_install();
greed = __arena.offset[__arena.depth];
a = __arena.offset[__arena.depth];
b = __arena.offset[__arena.depth + 1];
greed = a;
greed += FRAMESIZE;
greed <<= 1;
if (__arena.size > greed) {
munmap(BASE + greed, __arena.size - greed);
munmap(P(BASE + greed), __arena.size - greed);
__arena.size = greed;
b = MIN(b, greed);
a = MIN(b, a);
}
bzero(P(BASE + a), b - a);
}

View file

@ -19,6 +19,8 @@
#include "libc/mem/mem.h"
#include "libc/runtime/buffer.h"
/* TODO(jart): delete */
#define kGuard PAGESIZE
#define kGrain FRAMESIZE

View file

@ -18,11 +18,13 @@
*/
#include "libc/assert.h"
#include "libc/bits/likely.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/gc.internal.h"
#include "libc/runtime/gc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
forceinline bool PointerNotOwnedByParentStackFrame(struct StackFrame *frame,
struct StackFrame *parent,
@ -31,14 +33,28 @@ forceinline bool PointerNotOwnedByParentStackFrame(struct StackFrame *frame,
((intptr_t)ptr < (intptr_t)parent));
}
static void __garbage_destroy(void) {
if (weaken(free)) {
weaken(free)(__garbage.p);
}
bzero(&__garbage, sizeof(__garbage));
}
void __deferer(struct StackFrame *frame, void *fn, void *arg) {
size_t n2;
struct Garbage *p2;
if (UNLIKELY(__garbage.i == __garbage.n)) {
p2 = __garbage.p;
n2 = __garbage.n + (__garbage.n >> 1);
p2 = malloc(n2 * sizeof(*__garbage.p));
memcpy(p2, __garbage.p, __garbage.n * sizeof(*__garbage.p));
if (__garbage.p != __garbage.initmem) free(__garbage.p);
if (__garbage.p != __garbage.initmem) {
if (!weaken(realloc)) return;
if (!(p2 = weaken(realloc)(p2, n2 * sizeof(*p2)))) return;
} else {
if (!weaken(malloc)) return;
if (!(p2 = weaken(malloc)(n2 * sizeof(*p2)))) return;
memcpy(p2, __garbage.p, __garbage.n * sizeof(*p2));
atexit(__garbage_destroy);
}
__garbage.p = p2;
__garbage.n = n2;
}
@ -59,11 +75,11 @@ void __deferer(struct StackFrame *frame, void *fn, void *arg) {
* @return arg
*/
void __defer(struct StackFrame *frame, void *fn, void *arg) {
struct StackFrame *f2;
struct StackFrame *f;
if (!arg) return;
f2 = __builtin_frame_address(0);
f = __builtin_frame_address(0);
assert(__garbage.n);
assert(f2->next == frame);
assert(PointerNotOwnedByParentStackFrame(f2, frame, arg));
assert(f->next == frame);
assert(PointerNotOwnedByParentStackFrame(f, frame, arg));
__deferer(frame, fn, arg);
}

View file

@ -9,8 +9,6 @@ extern void *(*hook_calloc)(size_t, size_t);
extern void *(*hook_memalign)(size_t, size_t);
extern void *(*hook_realloc)(void *, size_t);
extern void *(*hook_realloc_in_place)(void *, size_t);
extern void *(*hook_valloc)(size_t);
extern void *(*hook_pvalloc)(size_t);
extern int (*hook_malloc_trim)(size_t);
extern size_t (*hook_malloc_usable_size)(const void *);
extern size_t (*hook_bulk_free)(void *[], size_t);

View file

@ -4,6 +4,7 @@
COSMOPOLITAN_C_START_
int PutEnvImpl(char *, bool) hidden;
void __freeenv(void *) hidden;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -17,7 +17,6 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.source __FILE__
// Allocates uninitialized memory.
//
@ -32,9 +31,7 @@
// fail. The maximum supported value of n differs across systems, but is
// in all cases less than the maximum representable value of a size_t.
//
// @param rdi is number of bytes needed
// @param rdi is number of bytes needed, coerced to 1+
// @return new memory, or NULL w/ errno
// @note malloc(0) → malloc(32)
// @see dlmalloc()
malloc: jmp *hook_malloc(%rip)
.endfn malloc,globl

View file

@ -15,15 +15,17 @@ void free(void *) libcesque;
void *malloc(size_t) attributeallocsize((1)) mallocesque;
void *calloc(size_t, size_t) attributeallocsize((1, 2)) mallocesque;
void *memalign(size_t, size_t) attributeallocalign((1))
attributeallocsize((2)) mallocesque;
attributeallocsize((2)) returnspointerwithnoaliases libcesque nodiscard;
void *realloc(void *, size_t) reallocesque;
void *realloc_in_place(void *, size_t);
void *realloc_in_place(void *, size_t) reallocesque;
void *reallocarray(void *, size_t, size_t) nodiscard;
void *valloc(size_t) attributeallocsize((1)) vallocesque;
void *pvalloc(size_t) attributeallocsize((1)) mallocesque;
void *pvalloc(size_t) vallocesque;
char *strdup(const char *) paramsnonnull() mallocesque;
char *strndup(const char *, size_t) paramsnonnull() mallocesque;
int posix_memalign(void **, size_t, size_t); /* wut */
void *aligned_alloc(size_t, size_t) attributeallocsize((1))
attributeallocsize((2)) returnspointerwithnoaliases libcesque nodiscard;
int posix_memalign(void **, size_t, size_t);
bool __grow(void *, size_t *, size_t, size_t) paramsnonnull((1, 2)) libcesque;
int malloc_trim(size_t);

View file

@ -18,22 +18,18 @@
*/
#include "libc/macros.internal.h"
#include "libc/notice.inc"
.source __FILE__
// Allocates aligned memory.
//
// Returns a pointer to a newly allocated chunk of n bytes, aligned in
// accord with the alignment argument. The alignment argument should be
// a power of two. If the argument is not a power of two, the nearest
// greater power is used. 8-byte alignment is guaranteed by normal
// malloc calls, so don't bother calling memalign with an argument of 8
// or less.
// accord with the alignment argument. The alignment argument shall be
// rounded up to the nearest two power and higher 2 powers may be used
// if the allocator imposes a minimum alignment requirement.
//
// @param rdi is alignment in bytes
// @param rsi (newsize) is number of bytes needed
// @param rdi is alignment in bytes, coerced to 1+ w/ 2-power roundup
// @param rsi is number of bytes needed, coerced to 1+
// @return rax is memory address, or NULL w/ errno
// @note overreliance on memalign is a sure way to fragment space
// @see dlmemalign()
// @see valloc(), pvalloc()
memalign:
jmp *hook_memalign(%rip)
.endfn memalign,globl

View file

@ -1,7 +1,7 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
@ -16,21 +16,43 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/errno.h"
#include "libc/macros.internal.h"
.source __FILE__
#include "libc/mem/mem.h"
// Allocates aligned memory the POSIX way.
//
// Allocates a chunk of n bytes, aligned in accord with the alignment
// argument. Differs from memalign only in that it (1) assigns the
// allocated memory to *pp rather than returning it, (2) fails and
// returns EINVAL if the alignment is not a power of two (3) fails and
// returns ENOMEM if memory cannot be allocated.
//
// @param rdi is void **pp
// @param rsi is size_t align
// @param rdx is size_t size
// @return eax
posix_memalign:
jmp *hook_posix_memalign(%rip)
.endfn posix_memalign,globl
/**
* Allocates aligned memory, the POSIX way.
*
* Allocates a chunk of n bytes, aligned in accord with the alignment
* argument. Differs from memalign() only in that it:
*
* 1. Assigns the allocated memory to *pp rather than returning it
* 2. Fails and returns EINVAL if the alignment is not a power of two
* 3. Fails and returns ENOMEM if memory cannot be allocated
*
* @param pp receives pointer, only on success
* @param alignment must be 2-power multiple of sizeof(void *)
* @param bytes is number of bytes to allocate
* @return return 0 or EINVAL or ENOMEM w/o setting errno
* @see memalign()
*/
int posix_memalign(void **pp, size_t alignment, size_t bytes) {
int e;
void *m;
size_t q, r;
q = alignment / sizeof(void *);
r = alignment % sizeof(void *);
if (!r && q && IS2POW(q)) {
e = errno;
m = memalign(alignment, bytes);
errno = e;
if (m) {
*pp = m;
return 0;
} else {
return ENOMEM;
}
} else {
return EINVAL;
}
}

View file

@ -43,6 +43,12 @@ static void PutEnvInit(void) {
atexit(PutEnvDestroy);
}
void __freeenv(void *p) {
if (once) {
free(p);
}
}
int PutEnvImpl(char *s, bool overwrite) {
char *p;
unsigned i, namelen;
@ -62,7 +68,10 @@ int PutEnvImpl(char *s, bool overwrite) {
goto replace;
}
}
if (i + 1 >= MAX_VARS) goto fail;
if (i + 1 >= MAX_VARS) {
free(s);
return enomem();
}
environ[i + 1] = NULL;
replace:
free(environ[i]);

View file

@ -1,30 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#include "libc/notice.inc"
.source __FILE__
// Equivalent to valloc(minimum-page-that-holds(n)), that is,
// round up n to nearest pagesize.
//
// @param rdi is number of bytes needed
// @return rax is memory address, or NULL w/ errno
// @see dlpvalloc()
pvalloc:jmp *hook_pvalloc(%rip)
.endfn pvalloc,globl

View file

@ -1,7 +1,7 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
@ -17,17 +17,15 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.source __FILE__
#include "libc/mem/mem.h"
.initbss 202,_init_pvalloc
hook_pvalloc:
.quad 0
.endobj hook_pvalloc,globl,hidden
.previous
.init.start 202,_init_pvalloc
.hidden dlpvalloc
ezlea dlpvalloc,ax
stosq
yoink free
.init.end 202,_init_pvalloc
/**
* Equivalent to memalign(PAGESIZE, ROUNDUP(n, PAGESIZE)).
*
* @param n number of bytes needed
* @return memory address, or NULL w/ errno
* @see valloc()
*/
void *pvalloc(size_t n) {
return memalign(PAGESIZE, ROUNDUP(n, PAGESIZE));
}

View file

@ -23,6 +23,5 @@
nodiscard void *unhexstr(const char *hexdigs) {
assert(strlen(hexdigs) % 2 == 0);
return unhexbuf(memalign(__BIGGEST_ALIGNMENT__, strlen(hexdigs) / 2),
strlen(hexdigs) / 2, hexdigs);
return unhexbuf(malloc(strlen(hexdigs) / 2), strlen(hexdigs) / 2, hexdigs);
}

View file

@ -1,29 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#include "libc/notice.inc"
.source __FILE__
// Equivalent to memalign(4096, n).
//
// @param rdi is number of bytes needed
// @return rax is memory address, or NULL w/ errno
// @see dlvalloc()
valloc: jmp *hook_valloc(%rip)
.endfn valloc,globl

View file

@ -1,7 +1,7 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
@ -16,18 +16,15 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.source __FILE__
#include "libc/mem/mem.h"
.initbss 202,_init_valloc
hook_valloc:
.quad 0
.endobj hook_valloc,globl,hidden
.previous
.init.start 202,_init_valloc
.hidden dlvalloc
ezlea dlvalloc,ax
stosq
yoink free
.init.end 202,_init_valloc
/**
* Equivalent to memalign(PAGESIZE, n).
*
* @param n number of bytes needed
* @return memory address, or NULL w/ errno
* @see pvalloc()
*/
void *valloc(size_t n) {
return memalign(PAGESIZE, n);
}