Bladeren bron

Replace OOM checks with light wrappers around allocation functions.

master
Ben Kurtovic 11 jaren geleden
bovenliggende
commit
13b7b29157
16 gewijzigde bestanden met toevoegingen van 108 en 172 verwijderingen
  1. +1
    -4
      src/assembler.c
  2. +6
    -16
      src/assembler/errors.c
  3. +3
    -8
      src/assembler/hash_table.c
  4. +4
    -7
      src/assembler/instructions.c
  5. +4
    -11
      src/assembler/io.c
  6. +2
    -7
      src/assembler/parse_util.c
  7. +8
    -30
      src/assembler/preprocessor.c
  8. +9
    -33
      src/assembler/tokenizer.c
  9. +7
    -21
      src/config.c
  10. +2
    -8
      src/gamegear.c
  11. +13
    -11
      src/logging.h
  12. +3
    -9
      src/mmu.c
  13. +1
    -1
      src/mmu.h
  14. +3
    -6
      src/rom.c
  15. +2
    -0
      src/util.h
  16. +40
    -0
      src/util_alloc.h

+ 1
- 4
src/assembler.c Bestand weergeven

@@ -201,10 +201,7 @@ size_t assemble(const LineBuffer *source, uint8_t **binary_ptr, ErrorInfo **ei_p
if ((error_info = resolve_symbols(&state)))
goto error;

uint8_t *binary = malloc(sizeof(uint8_t) * state.rom_size);
if (!binary)
OUT_OF_MEMORY()

uint8_t *binary = cr_malloc(sizeof(uint8_t) * state.rom_size);
serialize_binary(&state, binary);
*binary_ptr = binary;
retval = state.rom_size;


+ 6
- 16
src/assembler/errors.c Bestand weergeven

@@ -6,7 +6,7 @@
#include "errors.h"
#include "state.h"
#include "../assembler.h"
#include "../logging.h"
#include "../util.h"

/* Error strings */

@@ -82,27 +82,20 @@ struct ErrorInfo {
*/
static ASMErrorLine* create_error_line(const ASMLine *line)
{
ASMErrorLine *el = malloc(sizeof(ASMErrorLine));
if (!el)
OUT_OF_MEMORY()

ASMErrorLine *el = cr_malloc(sizeof(ASMErrorLine));
const char *source = line->original->data;
size_t length = line->original->length;
if (!(el->data = malloc(sizeof(char) * length)))
OUT_OF_MEMORY()

// Ignore spaces at beginning:
while (length > 0 && (*source == ' ' || *source == '\t'))
source++, length--;

el->data = cr_malloc(sizeof(char) * length);
memcpy(el->data, source, length);

el->length = length;
el->lineno = line->original->lineno;

el->filename = strdup(line->filename);
if (!el->filename)
OUT_OF_MEMORY()

el->filename = cr_strdup(line->filename);
el->next = NULL;
return el;
}
@@ -119,10 +112,7 @@ static ASMErrorLine* create_error_line(const ASMLine *line)
ErrorInfo* error_info_create(
const ASMLine *line, ASMErrorType err_type, ASMErrorDesc err_desc)
{
ErrorInfo *einfo = malloc(sizeof(ErrorInfo));
if (!einfo)
OUT_OF_MEMORY()

ErrorInfo *einfo = cr_malloc(sizeof(ErrorInfo));
einfo->type = err_type;
einfo->desc = err_desc;
einfo->line = line ? create_error_line(line) : NULL;


+ 3
- 8
src/assembler/hash_table.c Bestand weergeven

@@ -5,7 +5,7 @@
#include <string.h>

#include "hash_table.h"
#include "../logging.h"
#include "../util.h"

#define INITIAL_BUCKETS 127

@@ -61,13 +61,8 @@ static inline bool keyeq(const char *s1, const char *s2, ssize_t size)
HashTable* hash_table_new(
size_t key_offset, size_t next_offset, HashFreeCallback callback)
{
HashTable *table;
if (!(table = malloc(sizeof(HashTable))))
OUT_OF_MEMORY()

if (!(table->nodes = calloc(INITIAL_BUCKETS, sizeof(HashNode*))))
OUT_OF_MEMORY()

HashTable *table = cr_malloc(sizeof(HashTable));
table->nodes = cr_calloc(INITIAL_BUCKETS, sizeof(HashNode*));
table->buckets = INITIAL_BUCKETS;
table->key_offset = key_offset;
table->next_offset = next_offset;


+ 4
- 7
src/assembler/instructions.c Bestand weergeven

@@ -7,7 +7,7 @@
#include "instructions.h"
#include "inst_args.h"
#include "parse_util.h"
#include "../logging.h"
#include "../util.h"

/* Helper macros for get_inst_parser() */

@@ -26,8 +26,7 @@

#define INST_ALLOC_(len) \
*length = len; \
if (!(*bytes = malloc(sizeof(uint8_t) * (len)))) \
OUT_OF_MEMORY()
*bytes = cr_malloc(sizeof(uint8_t) * (len));

#define INST_SET_(b, val) ((*bytes)[b] = val)
#define INST_SET1_(b1) INST_SET_(0, b1)
@@ -55,7 +54,7 @@ static ASMErrorDesc parse_inst_##mnemonic( \

#define INST_TAKES_NO_ARGS \
if (ap_info.arg) \
INST_ERROR(TOO_MANY_ARGS) \
INST_ERROR(TOO_MANY_ARGS)

#define INST_TAKES_ARGS(lo, hi) \
if (!ap_info.arg) \
@@ -104,9 +103,7 @@ static ASMErrorDesc parse_inst_##mnemonic( \
}

#define INST_RETURN_WITH_SYMBOL(len, label, ...) { \
*symbol = strdup(label); \
if (!(*symbol)) \
OUT_OF_MEMORY() \
*symbol = cr_strdup(label); \
INST_ALLOC_(len) \
INST_FILL_BYTES_(len - 2, __VA_ARGS__) \
return ED_NONE; \


+ 4
- 11
src/assembler/io.c Bestand weergeven

@@ -9,6 +9,7 @@

#include "io.h"
#include "../logging.h"
#include "../util.h"

/*
Deallocate a LineBuffer previously created with read_source_file().
@@ -59,14 +60,9 @@ LineBuffer* read_source_file(const char *path, bool print_errors)
return NULL;
}

LineBuffer *source = malloc(sizeof(LineBuffer));
if (!source)
OUT_OF_MEMORY()

LineBuffer *source = cr_malloc(sizeof(LineBuffer));
source->lines = NULL;
source->filename = strdup(path);
if (!source->filename)
OUT_OF_MEMORY()
source->filename = cr_strdup(path);

Line dummy = {.next = NULL};
Line *line, *prev = &dummy;
@@ -90,10 +86,7 @@ LineBuffer* read_source_file(const char *path, bool print_errors)
return NULL;
}

line = malloc(sizeof(Line));
if (!line)
OUT_OF_MEMORY()

line = cr_malloc(sizeof(Line));
line->data = data;
line->length = feof(fp) ? len : (len - 1);
line->lineno = lineno++;


+ 2
- 7
src/assembler/parse_util.c Bestand weergeven

@@ -7,7 +7,6 @@

#include "parse_util.h"
#include "directives.h"
#include "../logging.h"
#include "../util.h"

#define MAX_REGION_SIZE 32
@@ -183,9 +182,7 @@ bool parse_string(char **result, size_t *length, const char *arg, ssize_t size)
return false;

*length = size - 2;
*result = malloc(sizeof(char) * (*length));
if (!*result)
OUT_OF_MEMORY()
*result = cr_malloc(sizeof(char) * (*length));
memcpy(*result, arg + 1, *length);
return true;
}
@@ -217,9 +214,7 @@ bool parse_bytes(uint8_t **result, size_t *length, const char *arg, ssize_t size
}

nbytes++;
bytes = realloc(bytes, sizeof(uint8_t) * nbytes);
if (!bytes)
OUT_OF_MEMORY()
bytes = cr_realloc(bytes, sizeof(uint8_t) * nbytes);
bytes[nbytes - 1] = temp;

if (arg < end - 1 && *arg == ',' && *(arg + 1) == ' ')


+ 8
- 30
src/assembler/preprocessor.c Bestand weergeven

@@ -121,14 +121,8 @@ static size_t read_labels(
return 0;
}

ASMLine *line = malloc(sizeof(ASMLine));
if (!line)
OUT_OF_MEMORY()

line->data = malloc(sizeof(char) * (i - start + 1));
if (!line->data)
OUT_OF_MEMORY()

ASMLine *line = cr_malloc(sizeof(ASMLine));
line->data = cr_malloc(sizeof(char) * (i - start + 1));
memcpy_lc(line->data, source + start, i - start + 1);
line->length = i - start + 1;
line->is_label = true;
@@ -160,10 +154,7 @@ static ASMLine* normalize_line(const char *source, size_t length)
source += offset;
length -= offset;

char *data = malloc(sizeof(char) * length);
if (!data)
OUT_OF_MEMORY()

char *data = cr_malloc(sizeof(char) * length);
size_t si, di, slashes = 0;
bool has_content = false, space_pending = false, in_string = false;
for (si = di = 0; si < length; si++) {
@@ -206,14 +197,8 @@ static ASMLine* normalize_line(const char *source, size_t length)
return head;
}

ASMLine *line = malloc(sizeof(ASMLine));
if (!line)
OUT_OF_MEMORY()

data = realloc(data, sizeof(char) * di);
if (!data)
OUT_OF_MEMORY()

ASMLine *line = cr_malloc(sizeof(ASMLine));
data = cr_realloc(data, sizeof(char) * di);
line->data = data;
line->length = di;
line->is_label = false;
@@ -239,10 +224,7 @@ static char* read_include_path(const ASMLine *line)
if (maxlen >= INT_MAX) // Allows us to safely downcast to int later
return NULL;

char *path = malloc(sizeof(char) * maxlen), *base, *dup;
if (!path)
OUT_OF_MEMORY()

char *path = cr_malloc(sizeof(char) * maxlen), *base, *dup;
if (!(i = DIRECTIVE_OFFSET(line, DIR_INCLUDE)))
goto error;
if (line->length - i <= 3) // Not long enough to hold a non-zero argument
@@ -252,8 +234,7 @@ static char* read_include_path(const ASMLine *line)
if (!parse_string(&base, &baselen, line->data + i, line->length - i))
goto error;

if (!(dup = strdup(line->filename)))
OUT_OF_MEMORY()
dup = cr_strdup(line->filename);

// TODO: should normalize filenames in some way to prevent accidental dupes
snprintf(path, maxlen, "%s/%.*s", dirname(dup), (int) baselen, base);
@@ -330,10 +311,7 @@ static ErrorInfo* build_asm_lines(
goto error;
}

ASMInclude *include = malloc(sizeof(ASMInclude));
if (!include)
OUT_OF_MEMORY()

ASMInclude *include = cr_malloc(sizeof(ASMInclude));
include->lines = incbuffer;
include->next = *includes;
*includes = include;


+ 9
- 33
src/assembler/tokenizer.c Bestand weergeven

@@ -9,7 +9,6 @@
#include "instructions.h"
#include "inst_args.h"
#include "parse_util.h"
#include "../logging.h"
#include "../mmu.h"
#include "../rom.h"
#include "../util.h"
@@ -63,12 +62,8 @@ static void init_layout_info(ASMLayoutInfo *li, AssemblerState *state)
li->origin = NULL;
li->bank = 0;
li->cross_blocks = state->cross_blocks;

if (!(li->overlap_table = calloc(li->size, sizeof(const ASMLine*))))
OUT_OF_MEMORY()

if (!(li->overlap_origins = calloc(li->size, sizeof(const ASMLine*))))
OUT_OF_MEMORY()
li->overlap_table = cr_calloc(li->size, sizeof(const ASMLine*));
li->overlap_origins = cr_calloc(li->size, sizeof(const ASMLine*));

for (size_t i = 0; i < HEADER_SIZE; i++)
li->overlap_table[state->header.offset + i] = &header_sentinel;
@@ -104,10 +99,7 @@ static ErrorInfo* add_label_to_table(
if (argparse_condition(&cond, info))
return error_info_create(line, ET_SYMBOL, ED_SYM_IS_CONDITION);

char *symbol = strndup(line->data, line->length - 1);
if (!symbol)
OUT_OF_MEMORY()

char *symbol = cr_strndup(line->data, line->length - 1);
const ASMSymbol *current = asm_symtable_find(symtable, symbol);
if (current) {
ErrorInfo *ei = error_info_create(line, ET_SYMBOL, ED_SYM_DUPE_LABELS);
@@ -116,10 +108,7 @@ static ErrorInfo* add_label_to_table(
return ei;
}

ASMSymbol *label = malloc(sizeof(ASMSymbol));
if (!label)
OUT_OF_MEMORY()

ASMSymbol *label = cr_malloc(sizeof(ASMSymbol));
label->offset = map_into_slot(offset,
(slot >= 0) ? slot : default_bank_slot(offset / MMU_ROM_BANK_SIZE));
label->symbol = symbol;
@@ -169,13 +158,8 @@ static ErrorInfo* handle_define_directive(
if (!argparse_immediate(&imm, info))
return error_info_create(line, ET_PREPROC, ED_PP_BAD_ARG);

ASMDefine *define = malloc(sizeof(ASMDefine));
if (!define)
OUT_OF_MEMORY()

if (!(define->name = strndup(key, keylen)))
OUT_OF_MEMORY()

ASMDefine *define = cr_malloc(sizeof(ASMDefine));
define->name = cr_strndup(key, keylen);
define->value = imm;
define->line = line;
asm_deftable_insert(deftab, define);
@@ -285,9 +269,7 @@ static bool parse_space(
}

*length = bytes[0];
if (!(*result = malloc(sizeof(uint8_t) * (*length))))
OUT_OF_MEMORY()

*result = cr_malloc(sizeof(uint8_t) * (*length));
memset(*result, nbytes == 2 ? bytes[1] : 0, *length);
free(bytes);
return true;
@@ -328,10 +310,7 @@ static ErrorInfo* parse_data(
const char *arg = line->data + dir_offset;
size_t arglen = line->length - dir_offset;

ASMData *data = malloc(sizeof(ASMData));
if (!data)
OUT_OF_MEMORY()

ASMData *data = cr_malloc(sizeof(ASMData));
data->loc.offset = offset;
data->next = NULL;

@@ -386,10 +365,7 @@ static ErrorInfo* parse_instruction(
if (edesc != ED_NONE)
return error_info_create(line, ET_PARSER, edesc);

ASMInstruction *inst = malloc(sizeof(ASMInstruction));
if (!inst)
OUT_OF_MEMORY()

ASMInstruction *inst = cr_malloc(sizeof(ASMInstruction));
inst->loc.offset = offset;
inst->loc.length = length;
inst->bytes = bytes;


+ 7
- 21
src/config.c Bestand weergeven

@@ -10,6 +10,7 @@

#include "config.h"
#include "logging.h"
#include "util.h"
#include "version.h"

/*
@@ -73,21 +74,15 @@ static int get_rom_paths(char ***path_ptr)

dirp = opendir(ROMS_DIR);
if (dirp) {
paths = malloc(sizeof(char*) * psize);
if (!paths)
OUT_OF_MEMORY()
paths = cr_malloc(sizeof(char*) * psize);
while ((entry = readdir(dirp))) {
path = entry->d_name;
if (ends_with(path, ".gg") || ends_with(path, ".bin")) {
if (npaths >= psize) {
paths = realloc(paths, sizeof(char*) * (psize *= 2));
if (!paths)
OUT_OF_MEMORY()
paths = cr_realloc(paths, sizeof(char*) * (psize *= 2));
}
paths[npaths] = malloc(sizeof(char*) *
paths[npaths] = cr_malloc(sizeof(char*) *
(strlen(path) + strlen(ROMS_DIR) + 1));
if (!paths[npaths])
OUT_OF_MEMORY()
strcpy(paths[npaths], ROMS_DIR "/");
strcat(paths[npaths], path);
npaths++;
@@ -159,9 +154,7 @@ static int parse_args(Config *config, int argc, char *argv[])
return CONFIG_EXIT_FAILURE;
}

path = malloc(sizeof(char) * (strlen(arg) + 1));
if (!path)
OUT_OF_MEMORY()
path = cr_malloc(sizeof(char) * (strlen(arg) + 1));
strcpy(path, arg);

if (paths_read == 1) {
@@ -264,9 +257,7 @@ static void guess_assembler_output_file(Config* config)
}
} while (ptr-- >= src);

config->dst_path = malloc(sizeof(char) * (until_ext + 5));
if (!config->dst_path)
OUT_OF_MEMORY()
config->dst_path = cr_malloc(sizeof(char) * (until_ext + 5));
strcpy(stpncpy(config->dst_path, src, until_ext), ext);
}

@@ -315,14 +306,9 @@ static bool sanity_check(Config* config)
*/
int config_create(Config** config_ptr, int argc, char* argv[])
{
Config *config;
Config *config = cr_malloc(sizeof(Config));
int retval;

if (!(config = malloc(sizeof(Config)))) {
OUT_OF_MEMORY()
return CONFIG_EXIT_FAILURE;
}

config->debug = false;
config->assemble = false;
config->disassemble = false;


+ 2
- 8
src/gamegear.c Bestand weergeven

@@ -12,17 +12,11 @@

/*
Create and return a pointer to a new GameGear object.

If memory could not be allocated, OUT_OF_MEMORY() is triggered.
*/
GameGear* gamegear_create()
{
GameGear *gg = malloc(sizeof(GameGear));
if (!gg)
OUT_OF_MEMORY()

if (!mmu_init(&gg->mmu))
OUT_OF_MEMORY()
GameGear *gg = cr_malloc(sizeof(GameGear));
mmu_init(&gg->mmu);
z80_init(&gg->cpu, &gg->mmu);
gg->powered = false;
gg->exc_buffer[0] = '\0';


+ 13
- 11
src/logging.h Bestand weergeven

@@ -10,27 +10,29 @@

/* Internal usage only */

#define LOG_MSG(dest, level, extra, after, ...) { \
#define LOG_MSG_(dest, level, extra, after, ...) { \
fprintf(dest, level ": " __VA_ARGS__); \
extra; \
fprintf(dest, "\n"); \
after; \
}
#define PRINT_ERRNO() fprintf(stderr, ": %s", strerror(errno))

#define LOG_ERR_(...) LOG_MSG_(stderr, __VA_ARGS__)
#define LOG_OUT_(...) LOG_MSG_(stdout, __VA_ARGS__)

#define PRINT_ERRNO_() fprintf(stderr, ": %s", strerror(errno))

/* Public logging macros */

#define FATAL(...) LOG_MSG(stderr, "fatal", {}, exit(EXIT_FAILURE), __VA_ARGS__)
#define FATAL_ERRNO(...) LOG_MSG(stderr, "fatal", PRINT_ERRNO(), exit(EXIT_FAILURE), __VA_ARGS__)
#define ERROR(...) LOG_MSG(stderr, "error", {}, {}, __VA_ARGS__)
#define ERROR_ERRNO(...) LOG_MSG(stderr, "error", PRINT_ERRNO(), {}, __VA_ARGS__)
#define WARN(...) LOG_MSG(stderr, "warning", {}, {}, __VA_ARGS__)
#define WARN_ERRNO(...) LOG_MSG(stderr, "warning", PRINT_ERRNO(), {}, __VA_ARGS__)
#define FATAL(...) LOG_ERR_("fatal", {}, exit(EXIT_FAILURE), __VA_ARGS__)
#define FATAL_ERRNO(...) LOG_ERR_("fatal", PRINT_ERRNO_(), exit(EXIT_FAILURE), __VA_ARGS__)
#define ERROR(...) LOG_ERR_("error", {}, {}, __VA_ARGS__)
#define ERROR_ERRNO(...) LOG_ERR_("error", PRINT_ERRNO_(), {}, __VA_ARGS__)
#define WARN(...) LOG_ERR_("warning", {}, {}, __VA_ARGS__)
#define WARN_ERRNO(...) LOG_ERR_("warning", PRINT_ERRNO_(), {}, __VA_ARGS__)

#ifdef DEBUG_MODE
#define DEBUG(...) LOG_MSG(stdout, "[DEBUG]", {}, {}, __VA_ARGS__)
#define DEBUG(...) LOG_OUT_("[DEBUG]", {}, {}, __VA_ARGS__)
#else
#define DEBUG(...) {}
#endif

#define OUT_OF_MEMORY() FATAL("couldn't allocate enough memory")

+ 3
- 9
src/mmu.c Bestand weergeven

@@ -5,27 +5,21 @@
#include <string.h>

#include "logging.h"
#include "util.h"
#include "z80.h"

/*
Initialize a MMU object. This must be called before using the MMU.

Return true if initialization was successful, or false if the required
amount of memory could not be allocated.
*/
bool mmu_init(MMU *mmu)
void mmu_init(MMU *mmu)
{
mmu->system_ram = malloc(sizeof(uint8_t) * MMU_SYSTEM_RAM_SIZE);
if (!mmu->system_ram)
return false;
mmu->system_ram = cr_malloc(sizeof(uint8_t) * MMU_SYSTEM_RAM_SIZE);

for (size_t slot = 0; slot < MMU_NUM_SLOTS; slot++)
mmu->map_slots[slot] = NULL;

for (size_t bank = 0; bank < MMU_NUM_ROM_BANKS; bank++)
mmu->rom_banks[bank] = NULL;

return true;
}

/*


+ 1
- 1
src/mmu.h Bestand weergeven

@@ -22,7 +22,7 @@ typedef struct {

/* Functions */

bool mmu_init(MMU*);
void mmu_init(MMU*);
void mmu_free(MMU*);
void mmu_load_rom(MMU*, const uint8_t*, size_t);
void mmu_power(MMU*);


+ 3
- 6
src/rom.c Bestand weergeven

@@ -169,8 +169,7 @@ const char* rom_open(ROM **rom_ptr, const char *path)
return (st.st_mode & S_IFDIR) ? rom_err_isdir : rom_err_notfile;
}

if (!(rom = malloc(sizeof(ROM))))
OUT_OF_MEMORY()
rom = cr_malloc(sizeof(ROM));

// Set defaults:
rom->name = NULL;
@@ -183,8 +182,7 @@ const char* rom_open(ROM **rom_ptr, const char *path)
rom->region_code = 0;

// Set rom->name:
if (!(rom->name = malloc(sizeof(char) * (strlen(path) + 1))))
OUT_OF_MEMORY()
rom->name = cr_malloc(sizeof(char) * (strlen(path) + 1));
strcpy(rom->name, path);
DEBUG("Loading ROM %s:", rom->name)

@@ -198,8 +196,7 @@ const char* rom_open(ROM **rom_ptr, const char *path)
rom->size = st.st_size;

// Set rom->data:
if (!(rom->data = malloc(sizeof(uint8_t) * st.st_size)))
OUT_OF_MEMORY()
rom->data = cr_malloc(sizeof(uint8_t) * st.st_size);
if (!(fread(rom->data, st.st_size, 1, fp))) {
rom_close(rom);
fclose(fp);


+ 2
- 0
src/util.h Bestand weergeven

@@ -6,6 +6,8 @@
#include <stdbool.h>
#include <stdint.h>

#include "util_alloc.h"

#define INVALID_SIZE_CODE 0x8

/* Functions */


+ 40
- 0
src/util_alloc.h Bestand weergeven

@@ -0,0 +1,40 @@
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */

#pragma once

#include <stddef.h>
#include <stdlib.h>
#include <string.h>

#include "logging.h"

#define OUT_OF_MEMORY() FATAL("couldn't allocate enough memory")

#define OOM_GUARD_(type, call) \
type ptr = call; \
if (!ptr) \
OUT_OF_MEMORY() \
return ptr;

#define OOM_GUARD_FUNC_1_(ret_type, func, arg_type) \
static inline ret_type cr_##func(arg_type arg1) { \
OOM_GUARD_(ret_type, func(arg1)) \
}

#define OOM_GUARD_FUNC_2_(ret_type, func, arg1_type, arg2_type) \
static inline ret_type cr_##func(arg1_type arg1, arg2_type arg2) { \
OOM_GUARD_(ret_type, func(arg1, arg2)) \
}

/* Functions */

OOM_GUARD_FUNC_1_(void*, malloc, size_t) // cr_malloc
OOM_GUARD_FUNC_2_(void*, calloc, size_t, size_t) // cr_calloc
OOM_GUARD_FUNC_2_(void*, realloc, void*, size_t) // cr_realloc
OOM_GUARD_FUNC_1_(char*, strdup, const char*) // cr_strdup
OOM_GUARD_FUNC_2_(char*, strndup, const char*, size_t) // cr_strndup

#undef OOM_GUARD_FUNC2_
#undef OOM_GUARD_FUNC1_
#undef OOM_GUARD_

Laden…
Annuleren
Opslaan