aboutsummaryrefslogtreecommitdiff
path: root/pseudocode-lib/memory.cc
blob: 5eed4c0240b5d8a71af07821731e54f83a8a6115 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

#include <cstddef>
#include <cstdio>
#include <cstdlib>

extern "C" int __cps_user_line;

namespace {
struct Allocation {
    void *Address;
    Allocation *Next;
};
Allocation *Head = nullptr;

[[noreturn]] void fail(const char *Reason) {
    std::fprintf(stderr, "[Fatal] line %d: %s\n", __cps_user_line, Reason);
    throw 0;
}

// Return the link owning the node so head and interior removals are identical.
Allocation **find(void *Address) {
    for (Allocation **Link = &Head; *Link; Link = &(*Link)->Next)
        if ((*Link)->Address == Address) return Link;
    fail("Invalid memory address (not an active allocation)");
}
}

extern "C" {
void *_memory_impl_malloc(unsigned long long Bytes) {
    std::size_t Size = static_cast<std::size_t>(Bytes);
    if (!Size) return nullptr;
    auto *Node = static_cast<Allocation *>(std::malloc(sizeof(Allocation)));
    if (!Node) fail("Allocation tracking failed");
    void *Address = std::malloc(Size);
    if (!Address) {
        std::free(Node);
        fail("Memory allocation failed");
    }
    Node->Address = Address;
    Node->Next = Head;
    Head = Node;
    return Address;
}

void _memory_impl_validate(void *Address) {
    find(Address);
}

void *_memory_impl_free(void *Address) {
    if (Address) {
        Allocation **Link = find(Address);
        Allocation *Node = *Link;
        *Link = Node->Next;
        std::free(Address);
        std::free(Node);
    }
    return Address;
}

void *_memory_impl_realloc(void *Address, unsigned long long Bytes) {
    std::size_t Size = static_cast<std::size_t>(Bytes);
    if (!Address) return _memory_impl_malloc(Bytes);
    Allocation *Node = *find(Address);
    if (!Size) {
        _memory_impl_free(Address);
        return nullptr;
    }
    void *Resized = std::realloc(Address, Size);
    // Failure preserves both the original allocation and its tracking record.
    if (!Resized) fail("Memory allocation failed");
    Node->Address = Resized;
    return Resized;
}
}