Added memory allocator and tests.
This commit is contained in:
2
Makefile
2
Makefile
@@ -116,7 +116,7 @@ test: $(LIB) $(TESTBINS)
|
|||||||
FAILURE=$$((FAILURE + 1)); \
|
FAILURE=$$((FAILURE + 1)); \
|
||||||
fi; \
|
fi; \
|
||||||
done; \
|
done; \
|
||||||
printf "\nTests completed\n"; \
|
printf "\nTests completed. First two should fail.\n"; \
|
||||||
printf "SUCCESS: %b%d%b\n" "$$GREEN" "$$SUCCESS" "$$NC"; \
|
printf "SUCCESS: %b%d%b\n" "$$GREEN" "$$SUCCESS" "$$NC"; \
|
||||||
printf "FAILURE: %b%d%b\n" "$$RED" "$$FAILURE" "$$NC"; \
|
printf "FAILURE: %b%d%b\n" "$$RED" "$$FAILURE" "$$NC"; \
|
||||||
test $$FAILURE -eq 0
|
test $$FAILURE -eq 0
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
#ifndef CI2_INCLUDED
|
|
||||||
#define CI2_INCLUDED
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
30
include/ci2_mem.h
Normal file
30
include/ci2_mem.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#ifndef CI2_MEM_H
|
||||||
|
#define CI2_MEM_H
|
||||||
|
|
||||||
|
#include "ci2_exception.h" // Exceptions
|
||||||
|
#include <stddef.h> // size_t
|
||||||
|
|
||||||
|
/* General Macros*/
|
||||||
|
#define MEM_KB(x) ((size_t)(x) * 1024ULL)
|
||||||
|
#define MEM_MB(x) ((size_t)(x) * 1024ULL * 1024ULL)
|
||||||
|
#define MEM_GB(x) ((size_t)(x) * 1024ULL * 1024ULL * 1024ULL)
|
||||||
|
#define MEM_SIZE(x) (ptrdiff_t)sizeof(x)
|
||||||
|
#define MEM_COUNT(a) (MEM_SIZE(a) / MEM_SIZE(*(a)))
|
||||||
|
#define MEM_LEN(s) (MEM_COUNT(s) - 1)
|
||||||
|
|
||||||
|
|
||||||
|
extern const Exception oom; // Out of memory
|
||||||
|
|
||||||
|
extern void *mem_alloc (size_t nbytes,const char *file, int line);
|
||||||
|
extern void *mem_calloc(size_t count, size_t nbytes, const char *file, int line);
|
||||||
|
extern void mem_free(void *ptr, const char *file, int line);
|
||||||
|
extern void *mem_resize(void *ptr, size_t nbytes, const char *file, int line);
|
||||||
|
|
||||||
|
#define ALLOC(nbytes) mem_alloc((nbytes), __FILE__, __LINE__)
|
||||||
|
#define CALLOC(count, nbytes) mem_calloc((count), (nbytes), __FILE__, __LINE__)
|
||||||
|
#define NEW(p) ((p) = ALLOC((size_t)sizeof *(p)))
|
||||||
|
#define NEW0(p) ((p) = CALLOC(1, (size_t)sizeof *(p)))
|
||||||
|
#define FREE(ptr) ((void)(mem_free((ptr), __FILE__, __LINE__), (ptr) = 0))
|
||||||
|
#define RESIZE(ptr, nbytes) ((ptr) = mem_resize((ptr), (nbytes), __FILE__, __LINE__))
|
||||||
|
|
||||||
|
#endif // CI2_MEM_H
|
||||||
60
src/ci2_mem.c
Normal file
60
src/ci2_mem.c
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "../include/ci2_exception.h"
|
||||||
|
#include "../include/ci2_mem.h"
|
||||||
|
|
||||||
|
const struct Exception oom = { "Out of memory!" };
|
||||||
|
|
||||||
|
void *mem_alloc(size_t nbytes, const char *file, int line)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
assert(nbytes > 0);
|
||||||
|
ptr = malloc(nbytes);
|
||||||
|
if (ptr == NULL)
|
||||||
|
{
|
||||||
|
if (file == NULL)
|
||||||
|
RAISE(oom);
|
||||||
|
else
|
||||||
|
except_raise(&oom, file, line);
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
void *mem_calloc(size_t count, size_t nbytes, const char *file, int line)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
assert(count > 0);
|
||||||
|
assert(nbytes > 0);
|
||||||
|
ptr = calloc(count, nbytes);
|
||||||
|
if (ptr == NULL)
|
||||||
|
{
|
||||||
|
if (file == NULL)
|
||||||
|
RAISE(oom);
|
||||||
|
else
|
||||||
|
except_raise(&oom, file, line);
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
void mem_free(void *ptr, const char *file, int line)
|
||||||
|
{
|
||||||
|
(void) file;
|
||||||
|
(void) line;
|
||||||
|
|
||||||
|
if (ptr)
|
||||||
|
free(ptr);
|
||||||
|
|
||||||
|
}
|
||||||
|
void *mem_resize(void *ptr, size_t nbytes, const char *file, int line)
|
||||||
|
{
|
||||||
|
assert(ptr); // ?
|
||||||
|
assert(nbytes > 0);// ?
|
||||||
|
void *tmp = realloc(ptr, nbytes);
|
||||||
|
if (tmp == NULL)
|
||||||
|
{
|
||||||
|
if (file == NULL)
|
||||||
|
RAISE(oom);
|
||||||
|
else
|
||||||
|
except_raise(&oom, file, line);
|
||||||
|
}
|
||||||
|
ptr = tmp;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
@@ -3,14 +3,16 @@
|
|||||||
#include "../include/ci2_exception.h"
|
#include "../include/ci2_exception.h"
|
||||||
|
|
||||||
struct Except_Frame *except_stack = NULL;
|
struct Except_Frame *except_stack = NULL;
|
||||||
const struct Exception assertion_failed = { "Assertion failed" };
|
|
||||||
|
|
||||||
|
// Custom Assertion
|
||||||
|
const struct Exception assertion_failed = { "Assertion failed" };
|
||||||
void ci2_assert(int e){
|
void ci2_assert(int e){
|
||||||
if(!e){
|
if(!e){
|
||||||
RAISE(assertion_failed);
|
RAISE(assertion_failed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Raise an exception and add it to the stack.
|
||||||
void except_raise(const struct Exception *e, const char *file,int line){
|
void except_raise(const struct Exception *e, const char *file,int line){
|
||||||
|
|
||||||
struct Except_Frame *p = except_stack;
|
struct Except_Frame *p = except_stack;
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int main(void){
|
int main(void){
|
||||||
printf("\n\n");
|
|
||||||
printf("Assertion sanity test.\n");
|
printf("Assertion sanity test.\n");
|
||||||
ci2_assert(0);
|
ci2_assert(0);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int main(void){
|
int main(void){
|
||||||
printf("\n\n");
|
|
||||||
printf("Uncaught exceptions sanity test.\n");
|
printf("Uncaught exceptions sanity test.\n");
|
||||||
struct Exception uncaught = {NULL};
|
struct Exception uncaught = {NULL};
|
||||||
RAISE(uncaught);
|
RAISE(uncaught);
|
||||||
|
|||||||
33
tests/03_mem_exception.c
Normal file
33
tests/03_mem_exception.c
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#define DEBUG
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../include/ci2_mem.h"
|
||||||
|
|
||||||
|
|
||||||
|
__attribute__((constructor)) static void setup_asan(void) {
|
||||||
|
setenv("ASAN_OPTIONS", "allocator_may_return_null=1", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void){
|
||||||
|
size_t nbytes = MEM_GB(1024);
|
||||||
|
void *buf;
|
||||||
|
TRY {
|
||||||
|
buf = ALLOC(nbytes); /* try 1GB */
|
||||||
|
if (!buf)
|
||||||
|
RAISE(oom);
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
EXCEPT(oom) {
|
||||||
|
/* handle memory failure gracefully */
|
||||||
|
fprintf(stderr, "Caught: %s Exception! Now we can return success.\n", oom.reason);
|
||||||
|
return EXIT_SUCCESS; /* requested behavior */
|
||||||
|
}
|
||||||
|
FINALLY {
|
||||||
|
/* cleanup if needed, runs always */
|
||||||
|
if (buf) free(buf);
|
||||||
|
}
|
||||||
|
END_TRY;
|
||||||
|
|
||||||
|
return EXIT_FAILURE; /* shouldn't reach here for this example */
|
||||||
|
}
|
||||||
31
tests/04_malloc.c
Normal file
31
tests/04_malloc.c
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#define DEBUG
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "../include/ci2_mem.h"
|
||||||
|
int mem_is_zero(const void *ptr, size_t nbytes) {
|
||||||
|
assert(ptr);
|
||||||
|
assert(nbytes > 0);
|
||||||
|
static const unsigned char zero_block[1024] = {0};
|
||||||
|
while (nbytes >= sizeof(zero_block)) {
|
||||||
|
if (memcmp(ptr, zero_block, sizeof(zero_block)) != 0)
|
||||||
|
return 0;
|
||||||
|
ptr = (const unsigned char *)ptr + sizeof(zero_block);
|
||||||
|
nbytes -= sizeof(zero_block);
|
||||||
|
}
|
||||||
|
if (nbytes > 0 && memcmp(ptr, zero_block, nbytes) != 0)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void){
|
||||||
|
size_t nbytes = 4096;
|
||||||
|
|
||||||
|
void *tmp = malloc(nbytes);
|
||||||
|
memset(tmp, 0xAB, nbytes);
|
||||||
|
free(tmp);
|
||||||
|
|
||||||
|
void *ptr = ALLOC(nbytes); // likely gets the same region back
|
||||||
|
assert(!mem_is_zero(ptr, nbytes)); // FAILS — 0xAB still there
|
||||||
|
assert(ptr != NULL);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
27
tests/05_calloc.c
Normal file
27
tests/05_calloc.c
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#define DEBUG
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "../include/ci2_mem.h"
|
||||||
|
|
||||||
|
int mem_is_zero(const void *ptr, size_t nbytes) {
|
||||||
|
assert(ptr);
|
||||||
|
assert(nbytes > 0);
|
||||||
|
static const unsigned char zero_block[1024] = {0};
|
||||||
|
while (nbytes >= sizeof(zero_block)) {
|
||||||
|
if (memcmp(ptr, zero_block, sizeof(zero_block)) != 0)
|
||||||
|
return 0;
|
||||||
|
ptr = (const unsigned char *)ptr + sizeof(zero_block);
|
||||||
|
nbytes -= sizeof(zero_block);
|
||||||
|
}
|
||||||
|
if (nbytes > 0 && memcmp(ptr, zero_block, nbytes) != 0)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void){
|
||||||
|
size_t nbytes = 4096;
|
||||||
|
void *ptr = CALLOC(1,nbytes);
|
||||||
|
assert(ptr != NULL);
|
||||||
|
assert( mem_is_zero(ptr, nbytes));
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user