Milan Stephan
Fotografie & IT

Zurück zur SP1 Übersicht

halde-test-nudelsalat.c

/* * * * * * * * * * * * * * * *
 *   nudelsalat's halde Test   *
 *    milan.stephan@fau.de     *
 * https://sp.milanstephan.de  *
 * * * * * * * * * * * * * * * */
/*

Version: SS 2020

Anleitung:
- In eine neue Datei halde-test-nudelsalat.c kopieren; im gleichen Verzeichnis, wie die halde.c
- Makefile ergänzen:

halde-test-nudelsalat.o: halde-test-nudelsalat.c halde.h
	gcc -std=c11 -D_XOPEN_SOURCE=700 -Werror -Wall -pedantic -g -c $<

halde-test-nudelsalat: halde-test-nudelsalat.o halde.o
	gcc -o $@ $^

- Makefile: all-Target anpassen und halde-test-nudelsalat hinzufügen
- Makefile: clean-Target anpassen und die Dateien halde-test-nudelsalat und halde-test-nudelsalat.o entfernen

- Mit make kompilieren
- ./halde-test-nudelsalat ausführen

- Vor der Abgabe Änderungen im Makefile rückgängig machen - oder auch nicht^^

*/


// Speichergroesse (Bytes)
#define SIZE (1024*1024)

// Speicher eines mblocks (Bytes)
#define MBLOCKSIZE 16

// Segfault-Tests ausführen
#define DO_SEGFAULT_TESTS 1

// So, jetzt aber Finger weg! ;)

#include "halde.h"
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sys/types.h>
#include <stdint.h>

// Puffer und Flag zur Anzeige der Belegung
#define DEV 0
#define BUFFER_SIZE 4096

// Zahl der Forks (wie viele Pipes brauchen wir?)
#define FORKS 26

// Geheimer errno-Wert
#define MAGICERRNO 242

/* * * * Makros zur Aufuehrung in den Forks * * * */

// Unnoetige Pipe schliessen, '!' in Pipe schreiben, errno auf geheimen Wert setzen
#define INIT {\
		close(fork_pipes[fork_id][0]);\
		write(fork_pipes[fork_id][1], "!", 1);\
		errno = MAGICERRNO;\
}

// Pipe schliessen und Fork beenden
#define EXITFORK {\
		close(fork_pipes[fork_id][1]);\
		exit(0);\
}

// Erfolgreiche Programmausfuehrung vormerken, bei Terminierung => Erfolg (fuer mindestens einen Test benoetigt)
#define SETSUCCESS {\
		write(fork_pipes[fork_id][1], " ", 1);\
}

// Erfolgreiche Ausfuehrung des Forks, ^ aufrufen und beenden
#define SUCCESS {\
		SETSUCCESS;\
		EXITFORK;\
}

// Fehlercode in Pipe schreiben, Fork mit EXITFORK beenden
#define FAIL(code) {\
		write_code_to_pipe(fork_pipes[fork_id][1], code);\
		EXITFORK;\
}
static void write_code_to_pipe(int pipe, char code) {
		write(pipe, &code, 1);
}

/* * * * Ende: Makros zur Aufuehrung in den Forks * * * */

// Ausgabe soll auf jeden Fall funktionieren,
// deswegen nicht auf printf -> malloc verlassen.

// String an Puffer anhaengen
static void buffer_add(char *buffer, int *buffer_position, char *new) {
		for (int i = 0; new[i] != '\0' && *buffer_position < BUFFER_SIZE; i++) {
				buffer[*buffer_position] = new[i];
				(*buffer_position)++;
		}
}

// char an Puffer angaengen
static void buffer_add_char(char *buffer, int *buffer_position, char new) {
		buffer[*buffer_position] = new;
		(*buffer_position)++;
}

#if DEV == 1
// <=32 bit unsigned integer in Dezimaldarstellung umwandeln -> String
static char *int_to_string(int a, char *out) {
		int pos = 0;
		int stringpos = 0;
		char zfill = 0;
		for (int div = 1000000000; div > 0; div /= 10) {
				if (a / div > 0 || zfill == 1 || div == 1) {
						zfill = 1;
						out[stringpos] = a / div + 48;
						stringpos++;
				}
				a -= (a / div) * div;
				pos++;
		}
		out[stringpos] = '\0';
		return out;
}
#endif

// Wegen Signal Handler ausserhalb main()
static int fork_id = 0;
static int fork_pipes[FORKS][2];

static void signal_handler(int signal) {
		INIT;
		// printList(); im abort Fall pruefen, wie Freispeicherliste aufgebaut ist, um z.B. das free im realloc genauer untersuchen zu koennen
		SUCCESS;
}

int main(void) {

		// Returns der Forks egal -> sofort beenden
		signal(SIGCHLD, SIG_IGN);

		pid_t pid;

		// Pipes initialisieren
		for (int i = 0; i < FORKS; i++) {
				pipe(fork_pipes[i]);
		}

		// Test 0: malloc(SIZE) == NULL, errno == ENOMEM
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				void *ptr = malloc(SIZE);
				if (errno != ENOMEM)
						FAIL('1');
				if (ptr != NULL)
						FAIL('2');

				SUCCESS;
		}
		fork_id++;

		// Test 1: Maximal grossen Block reservieren
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				void *ptr = malloc(SIZE - MBLOCKSIZE);
				if (errno != MAGICERRNO)
						FAIL('1');
				if (ptr == NULL)
						FAIL('2');

				SUCCESS;
		}
		fork_id++;

		// Test 2: Pruefen, ob nach maximalem Block voll ist
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				void *ptr = malloc(SIZE - MBLOCKSIZE);
				if (errno != MAGICERRNO)
						FAIL('1');
				if (ptr == NULL)
						FAIL('2');

				void *ptr2 = malloc(10);
				if (ptr2 != NULL)
						FAIL('4');
				if (errno != ENOMEM)
						FAIL('3');

				SUCCESS;
		}
		fork_id++;

		// Test 3: Mehrere Bloecke hintereinander reservieren
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				char *ptr1 = malloc(32);
				if (errno != MAGICERRNO)
						FAIL('1');
				if (ptr1 == NULL)
						FAIL('2');

				char *ptr2 = malloc(24);
				if (errno != MAGICERRNO)
						FAIL('3');
				if (ptr2 == NULL)
						FAIL('4');

				char *ptr3 = malloc(32);
				if (errno != MAGICERRNO)
						FAIL('5');
				if (ptr3 == NULL)
						FAIL('6');

				char *ptr4 = malloc(24);
				if (errno != MAGICERRNO)
						FAIL('7');
				if (ptr4 == NULL)
						FAIL('8');

				if (ptr2 - ptr1 != 32 + MBLOCKSIZE || ptr3 - ptr2 != 24 + MBLOCKSIZE
								|| ptr4 - ptr3 != 32 + MBLOCKSIZE)
						FAIL('9');

				SUCCESS;
		}
		fork_id++;

		// Test 4: Speicher in 4 gleich grosse Bereiche teilen, pruefen ob voll
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				void *ptr1 = malloc(SIZE / 4 - MBLOCKSIZE);
				if (errno != MAGICERRNO)
						FAIL('1');
				if (ptr1 == NULL)
						FAIL('2');

				void *ptr2 = malloc(SIZE / 4 - MBLOCKSIZE);
				if (errno != MAGICERRNO)
						FAIL('3');
				if (ptr2 == NULL)
						FAIL('4');

				void *ptr3 = malloc(SIZE / 4 - MBLOCKSIZE);
				if (errno != MAGICERRNO)
						FAIL('5');
				if (ptr3 == NULL)
						FAIL('6');

				void *ptr4 = malloc(SIZE / 4 - MBLOCKSIZE);
				if (errno != MAGICERRNO)
						FAIL('7');
				if (ptr4 == NULL)
						FAIL('8');

				void *ptr5 = malloc(1);
				if (errno != ENOMEM)
						FAIL('9');
				if (ptr5 != NULL)
						FAIL('A');

				SUCCESS;
		}
		fork_id++;

		// Test 5: malloc(0) == NULL, keine errno gesetzt
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				void *ptr = malloc(0);
				if (errno != MAGICERRNO)
						FAIL('1');
				if (ptr != NULL)
						FAIL('2');

				SUCCESS;
		}
		fork_id++;

		// Test 6: malloc(-1) == NULL, errno == ENOMEM
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				void *ptr = malloc(SSIZE_MAX);
				if (ptr != NULL)
						FAIL('2');
				if (errno != ENOMEM)
						FAIL('1');

				SUCCESS;
		}
		fork_id++;

		// Test 7: malloc(x), free(NULL) geht nicht kaputt
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				void *ptr1 = malloc(12);
				if (errno != MAGICERRNO)
						FAIL('1');
				if (ptr1 == NULL)
						FAIL('2');

				free(NULL);
				if (errno != MAGICERRNO)
						FAIL('3');

				SUCCESS;
		}
		fork_id++;

		// Test 8: malloc(x), free(RANDOM ADDRESSES) geht kaputt
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
#if DO_SEGFAULT_TESTS == 0
				FAIL('S');
#endif
				INIT;
				SETSUCCESS;

				void *ptr1 = malloc(16);
				if (errno != MAGICERRNO)
						FAIL('1');
				if (ptr1 == NULL)
						FAIL('2');

				free((void *) 4096);
				free((void *) 1048576);
				free((void *) 2097152);
				free((void *) 4194304);

				FAIL('3');
		}
		fork_id++;

		// Test 9: abort() nach free() auf nicht gemalloc'tem Pointer
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				char *ptr1 = malloc(128);
				if (errno != MAGICERRNO)
						FAIL('1');
				if (ptr1 == NULL)
						FAIL('2');

				signal(SIGABRT, signal_handler);
				free(ptr1 + 1);

				FAIL('3');
		}
		fork_id++;

		// Test 10: malloc(x) nach gefree'tem malloc(x) wieder auf gleicher Adresse
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				void *ptr1 = malloc(32);
				if (errno != MAGICERRNO)
						FAIL('1');
				if (ptr1 == NULL)
						FAIL('2');
				free(ptr1);
				if (errno != MAGICERRNO)
						FAIL('3');

				void *ptr2 = malloc(32);
				if (errno != MAGICERRNO)
						FAIL('4');
				if (ptr2 == NULL)
						FAIL('5');

				if (ptr1 != ptr2)
						FAIL('6');

				SUCCESS;
		}
		fork_id++;

		// Test 11: Speicher in 4 gleich grosse Bereiche teilen, freigeben und versuchen, groesseres Objekt reinzulegen
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				void *ptr1 = malloc(SIZE / 4 - MBLOCKSIZE);
				if (errno != MAGICERRNO)
						FAIL('1');
				if (ptr1 == NULL)
						FAIL('2');

				void *ptr2 = malloc(SIZE / 4 - MBLOCKSIZE);
				if (errno != MAGICERRNO)
						FAIL('3');
				if (ptr2 == NULL)
						FAIL('4');

				void *ptr3 = malloc(SIZE / 4 - MBLOCKSIZE);
				if (errno != MAGICERRNO)
						FAIL('5');
				if (ptr3 == NULL)
						FAIL('6');

				void *ptr4 = malloc(SIZE / 4 - MBLOCKSIZE);
				if (errno != MAGICERRNO)
						FAIL('7');
				if (ptr4 == NULL)
						FAIL('8');

				free(ptr1);
				if (errno != MAGICERRNO)
						FAIL('9');

				free(ptr2);
				if (errno != MAGICERRNO)
						FAIL('A');

				free(ptr3);
				if (errno != MAGICERRNO)
						FAIL('B');

				free(ptr4);
				if (errno != MAGICERRNO)
						FAIL('C');

				void *ptr5 = malloc(SIZE / 2 - MBLOCKSIZE);
				if (errno != ENOMEM)
						FAIL('D');
				if (ptr5 != NULL)
						FAIL('E');

				SUCCESS;
		}
		fork_id++;

		// Test 12: Keine unnoetige Fragmentierung durch Verwaltungsbloecke mit size=0
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				void *ptr1 = malloc(128);
				if (errno != MAGICERRNO)
						FAIL('1');
				if (ptr1 == NULL)
						FAIL('1');

				free(ptr1);
				if (errno != MAGICERRNO)
						FAIL('3');

				void *ptr2 = malloc(128 - MBLOCKSIZE);
				if (errno != MAGICERRNO)
						FAIL('4');
				if (ptr2 == NULL)
						FAIL('5');

				free(ptr2);
				if (errno != MAGICERRNO)
						FAIL('6');

				void *ptr3 = malloc(128);
				if (errno != MAGICERRNO)
						FAIL('7');
				if (ptr3 == NULL)
						FAIL('8');

				if (ptr3 != ptr1 && (uintptr_t)ptr3 - (uintptr_t)ptr1 != 128 + MBLOCKSIZE)
						FAIL('9');

				SUCCESS;
		}
		fork_id++;

		// Test 13: realloc(NULL, x) != NULL
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				void *ptr1 = realloc(NULL, 128);
				if (errno != MAGICERRNO)
						FAIL('1');
				if (ptr1 == NULL)
						FAIL('2');

				SUCCESS;
		}
		fork_id++;

		// Test 14 realloc(x, 0) == free(x)
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				void *ptr1 = malloc(128);
				if (errno != MAGICERRNO)
						FAIL('1');
				if (ptr1 == NULL)
						FAIL('2');

				void *ptr2 = realloc(ptr1, 0);
				if (errno != MAGICERRNO)
						FAIL('3');
				if (ptr2 != NULL)
						FAIL('4');

				void *ptr3 = malloc(128);
				if (errno != MAGICERRNO)
						FAIL('5');
				if (ptr3 == NULL)
						FAIL('6');

				if (ptr3 != ptr1)
						FAIL('7');

				SUCCESS;
		}
		fork_id++;

		// Test 15: realloc(NULL, 0) == NULL (malloc(0))
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				void *ptr1 = realloc(NULL, 0);
				if (errno != MAGICERRNO)
						FAIL('1');
				if (ptr1 != NULL)
						FAIL('2');

				SUCCESS;
		}
		fork_id++;

		// Test 16: realloc, neuen Speicherbereich hinten anhaengen
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				int *ptr1 = malloc(sizeof(int));
				if (errno != MAGICERRNO)
						FAIL('1');
				if (ptr1 == NULL)
						FAIL('2');
				*ptr1 = 1337;

				int *ptr2 = realloc(ptr1, 128);
				if (errno != MAGICERRNO)
						FAIL('3');
				if (ptr2 == NULL)
						FAIL('4');
				if (*ptr2 != 1337)
						FAIL('5');
				if ((char *) ptr1 + sizeof(int) + MBLOCKSIZE != (char *) ptr2)
						FAIL('6');

				SUCCESS;
		}
		fork_id++;

		// Test 17: realloc, neuen Speicherbereich in Luecke einbauen
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				char *ptr1 = malloc(64);
				if (errno != MAGICERRNO)
						FAIL('1');
				if (ptr1 == NULL)
						FAIL('2');

				char *ptr2 = malloc(128);
				if (errno != MAGICERRNO)
						FAIL('3');
				if (ptr2 == NULL)
						FAIL('4');

				char *ptr3 = malloc(256);
				if (errno != MAGICERRNO)
						FAIL('5');
				if (ptr3 == NULL)
						FAIL('6');

				strcpy(ptr1, "nudelsalat");

				free(ptr2);
				if (errno != MAGICERRNO)
						FAIL('7');

				char *ptr4 = realloc(ptr1, 128);
				if (errno != MAGICERRNO)
						FAIL('8');
				if (ptr4 == NULL)
						FAIL('9');

				if (strcmp(ptr4, "nudelsalat") != 0)
						FAIL('A');
				if (ptr4 != ptr2)
						FAIL('B');

				SUCCESS;
		}
		fork_id++;

		// Test 18: realloc Limit Test 1, neue Groesse > alte Groesse
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				char *ptr1 = malloc(32);
				if (errno != MAGICERRNO)
						FAIL('1');
				if (ptr1 == NULL)
						FAIL('2');

				char *ptr2 = malloc(100);
				if (errno != MAGICERRNO)
						FAIL('3');
				if (ptr2 == NULL)
						FAIL('4');

				for (int i = 0; i < 32; i++) {
						ptr1[i] = '*';
				}

				free(ptr2);
				if (errno != MAGICERRNO)
						FAIL('5');

				char *ptr5 = realloc(ptr1, 100);
				if (errno != MAGICERRNO)
						FAIL('6');
				if (ptr5 == NULL)
						FAIL('7');

				for (int i = 0; i < 32; i++) {
						if (ptr5[i] != '*')
								FAIL('8');
				}
				char different = 0;
				for (int i = 32; i < 32 + MBLOCKSIZE; i++) {
						if (ptr5[i] != ptr1[i])
								different = 1;
				}
				if (different == 0)
						FAIL('9');

				if (ptr5 != ptr2)
						FAIL('A');

				SUCCESS;
		}
		fork_id++;

		// Test 19: realloc Limit Test 2, neue Groesse < alte Groesse
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				char *ptr1 = malloc(32);
				if (errno != MAGICERRNO)
						FAIL('1');
				if (ptr1 == NULL)
						FAIL('2');

				char *ptr2 = malloc(10);
				if (errno != MAGICERRNO)
						FAIL('3');
				if (ptr2 == NULL)
						FAIL('4');

				for (int i = 0; i < 32; i++) {
						ptr1[i] = '*';
				}

				free(ptr2);
				if (errno != MAGICERRNO)
						FAIL('5');

				char *ptr5 = realloc(ptr1, 10);
				if (errno != MAGICERRNO)
						FAIL('6');
				if (ptr2 == NULL)
						FAIL('7');

				for (int i = 0; i < 10; i++) {
						if (ptr5[i] != '*')
								FAIL('8');
				}

				for (int i = 10; i < 32; i++) {
						if (ptr5[i] == '*')
								FAIL('9');
				}

				if (ptr5 != ptr2)
						FAIL('A');

				SUCCESS;
		}
		fork_id++;

		// Test 20: calloc Test, 16*4 Byte
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				char *ptr1 = calloc(16, 4);
				if (errno != MAGICERRNO)
						FAIL('1');
				if (ptr1 == NULL)
						FAIL('2');

				char *ptr2 = malloc(1);
				if (errno != MAGICERRNO)
						FAIL('3');
				if (ptr2 == NULL)
						FAIL('4');

				if (ptr2 != ptr1 + 64 + MBLOCKSIZE)
						FAIL('5');

				for (int i = 0; i < 64; i++) {
						if (ptr1[i] != '\0')
								FAIL('6');
				}

				SUCCESS;
		}
		fork_id++;

		// Test 21: realloc mit nicht gemalloc'tem Pointer -> abort
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				signal(SIGABRT, signal_handler);

				char *ptr1 = malloc(32);
				if (errno != MAGICERRNO)
						FAIL('1');
				if (ptr1 == NULL)
						FAIL('2');

				char *ptr2 = realloc((char *) ptr1 + 42, 64);
				if (errno != MAGICERRNO)
						FAIL('3');
				if (ptr2 == NULL)
						FAIL('4');

				FAIL('5');
		}
		fork_id++;

		// Test 22: realloc mit fehlgeschlagenem malloc
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				char *ptr1 = malloc(32);
				if (errno != MAGICERRNO)
						FAIL('1');
				if (ptr1 == NULL)
						FAIL('2');

				char *ptr2 = realloc(ptr1, SIZE);
				if (errno != ENOMEM)
						FAIL('3');
				if (ptr2 != NULL)
						FAIL('4');

				SUCCESS;
		}
		fork_id++;

		// Test 23: calloc mit fehlgeschlagenem malloc
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				char *ptr1 = calloc(SIZE, SIZE);
				if (errno != ENOMEM)
						FAIL('1');
				if (ptr1 != NULL)
						FAIL('2');

				SUCCESS;
		}
		fork_id++;

		// Test 24: Schleppzeiger richtig verwendet / es gehen keine Listenelemente verloren I
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				char *p1 = malloc(1024);
				char *p2 = malloc(2048);
				char *p3 = malloc(SIZE - 3 * MBLOCKSIZE - 1024 - 2048);
				if(!p1 || !p2 || !p3) FAIL('1');

				free(p3);
				free(p2);
				free(p1);

				// Wenn freie Bloecke an den Anfang der Liste gehaengt werden: [BLOCK]...1024...[BLOCK]...2048...[BLOCK]...REST...
				p1 = malloc(2048);
				p2 = malloc(1024);
				p3 = malloc(SIZE - 3 * MBLOCKSIZE - 1024 - 2048);
				if(!p1 || !p2 || !p3) FAIL('2');

				SUCCESS;
		}
		fork_id++;

		// Test 25: Schleppzeiger richtig verwendet / es gehen keine Listenelemente verloren II
		pid = fork();
		if (pid < 0)
				return -1;
		if (pid == 0) {
				INIT;

				char *p1 = malloc(1024);
				if(!p1) FAIL('1');
				free(p1);
				char *p2 = malloc(SIZE);
				if(p2) FAIL('2');

				SUCCESS;
		}
		fork_id++;


		printf("\x1B[1;37mhalde-Test von nudelsalat | milan.stephan@fau.de | https://sp.milanstephan.de\x1B[0m\n");

		// Pipes auslesen und Ausgabe der Ergebnisse
		int status = EXIT_SUCCESS;
		int buffer_position = 0;
		char buffer[BUFFER_SIZE];
		for (int i = 0; i < fork_id; i++) {
				close(fork_pipes[i][1]);
				char pipe_buffer;
				char fork_status = 0;

				while (read(fork_pipes[i][0], &pipe_buffer, 1) > 0) {
						fork_status = pipe_buffer;
				}

				close(fork_pipes[i][0]);

				// Abschnitte in Testcase-Ausgabe
				switch (i) {
						case 0:
								buffer_add(buffer, &buffer_position,
												"\x1B[32m[+]\x1B[0m = OK, \x1B[31m[x]\x1B[0m = Fehler an Marke x, \x1B[31m[\x1B[1;31m!\x1B[0;31m]\x1B[0m = Programmabbruch\n");
								buffer_add(buffer, &buffer_position, "Basisfunktionen: malloc\n");
								break;
						case 7:
								buffer_add(buffer, &buffer_position, "Basisfunktionen: free\n");
								break;
						case 10:
								buffer_add(buffer, &buffer_position,
												"Kombinierte Tests: malloc + free\n");
								break;
						case 13:
								buffer_add(buffer, &buffer_position, "Abgeleitete Funktionen\n");
								break;
						case 24:
								buffer_add(buffer, &buffer_position, "2015er Tests\n");
								break;
						default:
								break;
				}

				// Fehlerrueckgabe, falls nicht alle Tests erfolgreich waren
				if (fork_status != ' ')
						status = EXIT_FAILURE;

				// Fehler"icons"
				if (fork_status == '!')
						buffer_add(buffer, &buffer_position,
										"\x1B[31m[\x1B[1;31m!\x1B[0;31m]\x1B[0m - ");
				else if (fork_status == ' ')
						buffer_add(buffer, &buffer_position, "\x1B[32m[+]\x1B[0m - ");
				else {
						buffer_add(buffer, &buffer_position, "\x1B[31m[");
						buffer_add_char(buffer, &buffer_position, fork_status);
						buffer_add(buffer, &buffer_position, "]\x1B[0m - ");
				}

				// Statusausgabe
				switch (i) {
						case 0:
								buffer_add(buffer, &buffer_position,
												"malloc(SIZE) == NULL, errno == ENOMEM");
								break;
						case 1:
								buffer_add(buffer, &buffer_position,
												"Maximal grossen Block reservieren");
								break;
						case 2:
								buffer_add(buffer, &buffer_position,
												"Pruefen, ob nach maximalem Block voll ist");
								break;
						case 3:
								buffer_add(buffer, &buffer_position,
												"Mehrere Bloecke hintereinander reservieren");
								break;
						case 4:
								buffer_add(buffer, &buffer_position,
												"Speicher in 4 gleich grosse Bereiche teilen, pruefen ob voll");
								break;
						case 5:
								buffer_add(buffer, &buffer_position,
												"malloc(0) == NULL, keine errno gesetzt");
								break;
						case 6:
								buffer_add(buffer, &buffer_position,
												"malloc(-1) == NULL, errno == ENOMEM");
								break;

						case 7:
								buffer_add(buffer, &buffer_position,
												"free(NULL) geht nicht kaputt");
								break;
						case 8:
								buffer_add(buffer, &buffer_position,
												"free(RANDOM ADDRESSES) geht kaputt, S = Test uebersprungen!");
								break;
						case 9:
								buffer_add(buffer, &buffer_position,
												"abort() nach free() auf nicht gemalloc'tem Pointer");
								break;

						case 10:
								buffer_add(buffer, &buffer_position,
												"malloc(x) nach gefree'tem malloc(x) wieder auf gleicher Adresse");
								break;
						case 11:
								buffer_add(buffer, &buffer_position,
												"Speicher in 4 gleich grosse Bereiche teilen, freigeben und versuchen, groesseres Objekt reinzulegen");
								break;
						case 12:
								buffer_add(buffer, &buffer_position,
												"Keine unnoetige Fragmentierung durch Verwaltungsbloecke mit size=0");
								break;

						case 13:
								buffer_add(buffer, &buffer_position, "realloc(NULL, x) != NULL");
								break;
						case 14:
								buffer_add(buffer, &buffer_position, "realloc(x, 0) == free(x)");
								break;
						case 15:
								buffer_add(buffer, &buffer_position,
												"realloc(NULL, 0) == NULL (malloc(0))");
								break;
						case 16:
								buffer_add(buffer, &buffer_position,
												"realloc, neuen Speicherbereich hinten anhaengen");
								break;
						case 17:
								buffer_add(buffer, &buffer_position,
												"realloc, neuen Speicherbereich in Luecke einbauen");
								break;
						case 18:
								buffer_add(buffer, &buffer_position,
												"realloc Limit Test 1, neue Groesse > alte Groesse");
								break;
						case 19:
								buffer_add(buffer, &buffer_position,
												"realloc Limit Test 2, neue Groesse < alte Groesse");
								break;
						case 20:
								buffer_add(buffer, &buffer_position, "calloc Test, 16*4 Byte");
								break;
						case 21:
								buffer_add(buffer, &buffer_position,
												"realloc mit nicht gemalloc'tem Pointer -> abort (weil free())");
								break;
						case 22:
								buffer_add(buffer, &buffer_position,
												"realloc mit fehlgeschlagenem malloc");
								break;
						case 23:
								buffer_add(buffer, &buffer_position,
												"calloc mit fehlgeschlagenem malloc");
								break;

// 2015er Tests
						case 24:
								buffer_add(buffer, &buffer_position,
												"Schleppzeiger richtig verwendet / es gehen keine Listenelemente verloren I");
								break;
						case 25:
								buffer_add(buffer, &buffer_position,
												"Schleppzeiger richtig verwendet / es gehen keine Listenelemente verloren II");
								break;

						default:
								buffer_add(buffer, &buffer_position, "<Keine Beschreibung>");
								break;
				}
				buffer_add(buffer, &buffer_position, "\n");
		}

#if DEV == 1
		char intbuffer[11];
		int_to_string(buffer_position, intbuffer);
		buffer_add(buffer, &buffer_position, "Puffer (vor dieser Zeile): ");
		buffer_add(buffer, &buffer_position, intbuffer);
		buffer_add(buffer, &buffer_position, " Bytes\n");
#endif

		write(STDOUT_FILENO, buffer, buffer_position);

		return status;
}