diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index f5227898afcfdf0bc0f4ca722ad11875fd60ef5b..fd23279ae89ed805738527a17b1e411d55eaf6a9 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -51,6 +51,7 @@ clang-tidy:
     - clang-tidy-html clang-tidy-output.log
     - mv clang.html clang-tidy-html-report
   artifacts:
+    when: always
     paths:
       - ./clang-tidy-html-report
 
@@ -85,9 +86,8 @@ ikos:
   script:
     - cd $CI_PROJECT_DIR
     - ikos-scan cmake .
-    - ikos-scan make
+    - ikos-scan make tests
     - ikos tests.bc
-    - ikos ecss_services.bc
     - ikos-report -o=ikos-report.txt output.db
   after_script:
     - mv ikos-report.txt ikos-report
diff --git a/inc/Platform/x86/Helpers/EnumMagic.hpp b/inc/Platform/x86/Helpers/EnumMagic.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..6e5582406bb1e09b75e5121ff75ea3c8c6158217
--- /dev/null
+++ b/inc/Platform/x86/Helpers/EnumMagic.hpp
@@ -0,0 +1,114 @@
+#pragma once
+
+#include <string>
+#include <utility>
+
+#if !defined(__GNUC__) && !defined(__clang__)
+#define __PRETTY_FUNCTION__ "E V = Sorry, feature not supported!"
+#endif
+
+/**
+ * A simplified version of https://github.com/Neargye/magic_enum, this file uses some gcc compiler options to provide an @ref enumName function.
+ * This function converts an enum value to a string. It's used for debugging purposes only, to improve the readability of values that are hidden
+ * behind enums.
+ *
+ * Use with care. NOT intended for a microcontroller.
+ *
+ * @note This functionality is designed for simple, sequence-like enums. Their values should start from 0 and increase 1-by-1 until the end. It will probably
+ * result in slow compilation or incorrect results if used for other, "weirder" enums.
+ *
+ * This hack aims to be safe from errors by using `constexpr` lavishly. Enum values which are out of bounds (e.g. not defined or beyond
+ * EnumMagic_::MaximumValues) will not throw errors or cause unexpected events, but will probably display some kind of string.
+ *
+ * @license MIT, Daniil Goncharov
+ */
+namespace EnumMagic_ {
+	/**
+	 * The highest enum value that can be handled.
+	 *
+	 * Values higher than this will just result in a number or malformed text, but _not_ a compilation or runtime error.
+	 */
+	constexpr auto MaximumValues = 256;
+
+	/**
+	 * Returns the identifier of an enum value.
+	 *
+	 * For example, if you define an enum:
+	 * @code
+	 * enum Something {
+	 *     First = 0,
+	 *     Second = 1
+	 * }
+	 * @endcode
+	 * then calling this function with `Something::First` will return the string `"Something::First"`.
+	 *
+	 * Internally, this function uses the [`__PRETTY_FUNCTION__`](https://gcc.gnu.org/onlinedocs/gcc/Function-Names.html)
+	 * magic constant defined by GCC. The constant contains the template arguments of the function in a string,
+	 * which themselves contain the identifier of the enum value.
+	 *
+	 * @note Tested with GCC version 11 only, other versions or compilers might return incorrect values
+	 *
+	 * @tparam E Enum type
+	 * @tparam V Enum value (of type E)
+	 * @return The identifier of the enum value
+	 */
+	template <typename E, E V>
+	constexpr std::basic_string_view<char> enumHack() {
+		static_assert(std::is_enum_v<E>, "enumHack() requires enum type.");
+
+		std::string_view function = __PRETTY_FUNCTION__;
+		auto pos = function.find("E V = ");
+		std::string_view output = function.substr(pos + 6);
+		output.remove_suffix(1);
+		return output;
+	}
+
+	/**
+	 * Shortcut definition of enumHack for easier access
+	 */
+	template <typename Enum, Enum Value>
+	inline constexpr auto enumNameV = enumHack<Enum, Value>();
+
+	/**
+	 * Given an enum type and a sequence of values, this function returns a list
+	 *
+	 * @tparam Indexes A list of potential enum values in numerical format
+	 * @return An std::array of names for every enum value in the indexes
+	 */
+	template <typename Enum, std::size_t... Indexes>
+	constexpr auto names(std::index_sequence<Indexes...>) noexcept {
+		static_assert(std::is_enum_v<Enum>, "names() requires enum type.");
+
+		return std::array<std::string_view, sizeof...(Indexes)>{{enumNameV<Enum, static_cast<Enum>(Indexes)>...}};
+	}
+
+	/**
+	 * For the specified Enum enumeration, this variable will contain a list of the names of all its values
+	 */
+	template <typename Enum>
+	inline constexpr std::array namesV = names<Enum>(std::make_index_sequence<MaximumValues>{});
+
+	/**
+	 * Given a nested name (e.g. `Services::Parameter::value`), this function returns the innermost name (e.g. `value`)
+	 */
+	constexpr std::string_view removeNamespace(std::string_view in) {
+		auto pos = in.find_last_of("::");
+		return in.substr(pos + 1);
+	}
+} // namespace EnumMagic_
+
+/**
+ * Get the name of an enum value, as defined in the source code.
+ */
+template <typename Enum>
+std::string enumName(Enum value) {
+	using namespace EnumMagic_;
+
+	auto index = static_cast<size_t>(value);
+
+	if (index >= namesV<Enum>.size()) {
+		return "(Unknown)";
+	}
+
+	return std::string(removeNamespace(namesV<Enum>[index]));
+}
diff --git a/src/Platform/x86/ErrorHandler.cpp b/src/Platform/x86/ErrorHandler.cpp
index 06ad3859f622b51b0cbddde81d411ef46abdd7a3..572d34246c301c3aa4f30c57ae48540fe4ac737f 100644
--- a/src/Platform/x86/ErrorHandler.cpp
+++ b/src/Platform/x86/ErrorHandler.cpp
@@ -9,6 +9,7 @@
 #include <Message.hpp>
 #include <Logger.hpp>
 #include <type_traits>
+#include "Helpers/EnumMagic.hpp"
 
 // TODO: Find a way to reduce the number of copies of this chunk
 template void ErrorHandler::logError(const Message&, ErrorHandler::AcceptanceErrorType);
@@ -27,7 +28,7 @@ void ErrorHandler::logError(const Message& message, ErrorType errorType) {
 	     */
 	    << abi::__cxa_demangle(typeid(ErrorType).name(), nullptr, nullptr, nullptr) << " Error "
 	    << "[" << static_cast<uint16_t>(message.serviceType) << "," << static_cast<uint16_t>(message.messageType)
-	    << "]: " << std::underlying_type_t<ErrorType>(errorType);
+	    << "]: " << enumName(errorType) << " (" << static_cast<std::underlying_type_t<ErrorType>>(errorType) << ")";
 }
 
 template <typename ErrorType>
@@ -39,5 +40,5 @@ void ErrorHandler::logError(ErrorType errorType) {
 	     */
 	    << abi::__cxa_demangle(typeid(ErrorType).name(), nullptr, nullptr, nullptr)
 	    << " Error: "
-	    << std::underlying_type_t<ErrorType>(errorType);
+	    << enumName(errorType) << " (" << static_cast<std::underlying_type_t<ErrorType>>(errorType) << ")";
 }
diff --git a/src/Platform/x86/main.cpp b/src/Platform/x86/main.cpp
index d8be71a147455f01d1cd29f37d01ca2fc8dcfa52..4928e91da4a14bb2dcbbc6af05dc6751e74c9063 100644
--- a/src/Platform/x86/main.cpp
+++ b/src/Platform/x86/main.cpp
@@ -363,6 +363,8 @@ int main() {
 
 	LOG_NOTICE << "ECSS Services test complete";
 
+	ErrorHandler::reportInternalError(static_cast<ErrorHandler::InternalErrorType>(254));
+
 	std::cout << UTCTimestamp() << std::endl;
 	return 0;
-}
\ No newline at end of file
+}
diff --git a/test/Services/DummyService.cpp b/test/Services/DummyService.cpp
index 188d1899c5d0877a4fac14d62f1ab77206b75226..ff3549355b8386514e84f8cedafd7bbc937ecccf 100644
--- a/test/Services/DummyService.cpp
+++ b/test/Services/DummyService.cpp
@@ -13,5 +13,5 @@ TEST_CASE("Log string as message TM[128, 128]", "[service][st128]") {
 	CHECK(report.messageType == DummyService::MessageType::LogString);
 	char logOutput[39];
 	report.readString(logOutput, 39);
-	CHECK(strcmp(logOutput, "An amazing log that is very informative") == 0);
+	CHECK(memcmp(logOutput, "An amazing log that is very informative", 39) == 0);
 }
diff --git a/test/Services/MemoryManagementServiceTests.cpp b/test/Services/MemoryManagementServiceTests.cpp
index d37ac4c4a9f7c508c264cb94ebb01c15979d3228..2ad8097ee385bcc0a64ae88ad54da3ad60993571 100644
--- a/test/Services/MemoryManagementServiceTests.cpp
+++ b/test/Services/MemoryManagementServiceTests.cpp
@@ -28,6 +28,8 @@ TEST_CASE("TC[6,2]", "[service][st06]") {
 	CHECK(pStr[0] == 'h');
 	CHECK(pStr[1] == 'R');
 	CHECK(pStr[2] == 'h');
+
+	free(pStr);
 }
 
 TEST_CASE("TC[6,5]", "[service][st06]") {