build: add option for sanitizers and valgrind (#109)

* build: add support for sanitzers over cmake

* refactor: random cleanups

* fix: use-of-uninitialized-value

* chore: add valgrind also to cmake
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4762954..645e8e0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -38,6 +38,49 @@
 option(COSE_C_INCLUDE_SIGN "Include COSE_SIGN" ON)
 option(COSE_C_INCLUDE_SIGN1 "Include COSE_SIGN1" ON)
 option(COSE_C_INCLUDE_COUNTERSIGN "Include COSE_COUNTERSIGN" OFF)
+option(COSE_C_VALGRIND_MEMORY_CHECK "use Valgrind to check memory, \
+  run `ctest -D ExperimentalMemCheck` then after build to run tests with valgrind" OFF)
+
+if(COSE_C_VALGRIND_MEMORY_CHECK)
+  find_program(MEMORYCHECK_COMMAND valgrind)
+  if(NOT MEMORYCHECK_COMMAND)
+    message(FATAL_ERROR "valgrind not found.")
+  endif()
+  set(MEMORYCHECK_COMMAND_OPTIONS "--trace-children=yes --leak-check=full")
+  set(MEMORYCHECK_SUPPRESSIONS_FILE "${PROJECT_SOURCE_DIR}/valgrind_suppress.txt")
+endif()
+
+set(COSE_C_USE_SANITIZER
+    "none"
+    CACHE
+      STRING
+      " \
+    Name of the sanitizer which the user whats to use \
+    This behaviour is the same is turning on one the sanitizer flags below \
+    This option is a convenience option \
+    ")
+set_property(CACHE COSE_C_USE_SANITIZER PROPERTY STRINGS none address memory leak undefined)
+
+set(COSE_C_USE_ADDRESS_SANITIZER OFF)
+set(COSE_C_USE_MEMORY_SANITIZER OFF)
+set(COSE_C_USE_LEAK_SANITIZER OFF)
+set(COSE_C_USE_UNDEFINED_SANITIZER OFF)
+
+if(COSE_C_USE_SANITIZER STREQUAL "address")
+  set(COSE_C_USE_ADDRESS_SANITIZER ON)
+endif()
+
+if(COSE_C_USE_SANITIZER STREQUAL "memory")
+  set(COSE_C_USE_MEMORY_SANITIZER ON)
+endif()
+
+if(COSE_C_USE_SANITIZER STREQUAL "leak")
+  set(COSE_C_USE_LEAK_SANITIZER ON)
+endif()
+
+if(COSE_C_USE_SANITIZER STREQUAL "undefined")
+  set(COSE_C_USE_UNDEFINED_SANITIZER ON)
+endif()
 
 # Set the output of the libraries and executables.
 set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
@@ -127,7 +170,7 @@
 endif()
 
 ###############################################################################
-# DEPENDENCIES
+# STATIC ANALYSIS
 ###############################################################################
 
 if(COSE_C_RUN_CLANG_TIDY)
@@ -140,6 +183,8 @@
   endif()
 endif(COSE_C_RUN_CLANG_TIDY)
 
+include(sanitizers)
+
 ###############################################################################
 # DEPENDENCIES
 ###############################################################################
@@ -271,6 +316,12 @@
 message(STATUS "CMAKE_C_COMPILER:................${CMAKE_C_COMPILER}")
 message(STATUS "CMAKE_CXX_COMPILER:..............${CMAKE_CXX_COMPILER}")
 message(STATUS "CLANG_TIDY_EXE:..................${CLANG_TIDY_EXE}")
+message(STATUS "COSE_C_USE_SANITIZER:............${COSE_C_USE_SANITIZER}")
+message(STATUS "COSE_C_USE_ADDRESS_SANITIZER:....${COSE_C_USE_ADDRESS_SANITIZER}")
+message(STATUS "COSE_C_USE_MEMORY_SANITIZER:.....${COSE_C_USE_MEMORY_SANITIZER}")
+message(STATUS "COSE_C_USE_LEAK_SANITIZER:.......${COSE_C_USE_LEAK_SANITIZER}")
+message(STATUS "COSE_C_USE_UNDEFINED_SANITIZER:..${COSE_C_USE_UNDEFINED_SANITIZER}")
+message(STATUS "COSE_C_VALGRIND_MEMORY_CHECK:....${COSE_C_VALGRIND_MEMORY_CHECK}")
 message(STATUS "project_cn_cbor_SOURCE_DIR:......${project_cn_cbor_SOURCE_DIR}")
 message(STATUS "project_cn_cbor_BINARY_DIR:......${project_cn_cbor_BINARY_DIR}")
 message(STATUS "project_mbedtls_SOURCE_DIR:......${project_mbedtls_SOURCE_DIR}")
diff --git a/cmake/sanitizers.cmake b/cmake/sanitizers.cmake
new file mode 100644
index 0000000..89269fc
--- /dev/null
+++ b/cmake/sanitizers.cmake
@@ -0,0 +1,38 @@
+if(COSE_C_USE_ADDRESS_SANITIZER)
+  set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address  -g")
+  set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address  -g")
+  set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address  ")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
+  set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -fsanitize=address")
+endif(COSE_C_USE_ADDRESS_SANITIZER)
+
+if(COSE_C_USE_LEAK_SANITIZER)
+  set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer  -fsanitize=leak -g")
+  set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer  -fsanitize=leak -g")
+  set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer  -fsanitize=leak")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=leak ")
+  set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -fsanitize=leak ")
+endif(COSE_C_USE_LEAK_SANITIZER)
+
+if(COSE_C_USE_MEMORY_SANITIZER)
+  # NOTE: memory sanitizer can only run on x86_64 linux https://github.com/google/sanitizers/wiki/MemorySanitizer
+  # and only works with clang, no gcc support
+
+  if(NOT CMAKE_C_COMPILER_ID MATCHES "Clang")
+    message(FATAL_ERROR "COSE_C_USE_MEMORY_SANITIZER is ON, but this option is only supported with clang compiler")
+  endif()
+
+  set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=memory  -g")
+  set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=memory  -g")
+  set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=memory  ")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=memory")
+  set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -fsanitize=memory")
+endif(COSE_C_USE_MEMORY_SANITIZER)
+
+if(COSE_C_USE_UNDEFINED_SANITIZER)
+  set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=undefined -g")
+  set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=undefined -g")
+  set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=undefined")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined")
+  set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -fsanitize=undefined ")
+endif(COSE_C_USE_UNDEFINED_SANITIZER)
diff --git a/dumper/dumper.c b/dumper/dumper.c
index fea6500..aa17ad8 100644
--- a/dumper/dumper.c
+++ b/dumper/dumper.c
@@ -235,9 +235,7 @@
 
 void Indent(FILE* fp, int depth)
 {
-	int i;
-
-	for (i = 0; i < depth; i++) {
+	for (int i = 0; i < depth; i++) {
 		WrapPrintF(fp, "  ");
 	}
 }
@@ -250,10 +248,9 @@
 
 void DumpBytes(FILE* fp, const cn_cbor* cbor)
 {
-	int i;
-	int fText = true;
+	bool fText = true;
 
-	for (i = 0; i < cbor->length; i++) {
+	for (int i = 0; i < cbor->length; i++) {
 		if ((cbor->v.bytes[i] < 32) || (cbor->v.bytes[i] > 126) ||
 			(cbor->v.bytes[i] == '\'')) {
 			fText = false;
@@ -262,13 +259,13 @@
 
 	if (fText && (cbor->length > 0)) {
 		WrapPrintF(fp, "'");
-		for (i = 0; i < cbor->length; i++) {
+		for (int i = 0; i < cbor->length; i++) {
 			WrapPrintF(fp, "%c", cbor->v.bytes[i]);
 		}
 		WrapPrintF(fp, "'");
 	} else {
 		WrapPrintF(fp, "h'");
-		for (i = 0; i < cbor->length; i++) {
+		for (int i = 0; i < cbor->length; i++) {
 			WrapPrintF(fp, "%02x", cbor->v.bytes[i]);
 		}
 		WrapPrintF(fp, "'");
@@ -511,7 +508,6 @@
 
 int main(int argc, char** argv)
 {
-	int i;
 	FILE* in = NULL;
 	FILE* out = NULL;
 	byte* pb = NULL;
@@ -521,7 +517,7 @@
 	int forXML = false;
 	FOO* root = NULL;
 
-	for (i = 1; i < argc; i++) {
+	for (int i = 1; i < argc; i++) {
 		if ((argv[i][0] == '-') || (argv[i][0] == '/')) {
 			if (strcmp(&argv[i][1], "someoption") == 0) {
 			} else if (strcmp(&argv[i][1], "xml=yes") == 0) {
diff --git a/src/openssl.c b/src/openssl.c
index a050b6a..a377f9c 100644
--- a/src/openssl.c
+++ b/src/openssl.c
@@ -1012,9 +1012,8 @@
 	HMAC_CTX *ctx = NULL;
 	const EVP_MD *pmd = NULL;
 	byte *rgbOut = NULL;
-	unsigned int cbOut;
+	unsigned int cbOut = 0 ;
 	bool f = false;
-	unsigned int i;
 #ifdef USE_CBOR_CONTEXT
 	cn_cbor_context *context = &pcose->m_message.m_allocContext;
 #endif
@@ -1052,7 +1051,7 @@
 	if (cn->length > (int)cbOut) {
 		return false;
 	}
-	for (i = 0; i < (unsigned int)TSize / 8; i++) {
+	for (unsigned int i = 0; i < (unsigned int)TSize / 8; i++) {
 		f |= (cn->v.bytes[i] != rgbOut[i]);
 	}
 
diff --git a/test/json.c b/test/json.c
index 0eb426d..80dda58 100644
--- a/test/json.c
+++ b/test/json.c
@@ -21,12 +21,11 @@
 {
 	char ch;
 	int ib2;
-	cn_cbor *node = NULL;
 	cn_cbor *parent = NULL;
 	cn_cbor *root = NULL;
 
 	for (; ib < cch; ib++) {
-		node = NULL;
+		cn_cbor *node = NULL;
 		ch = rgch[ib];
 		switch (ch) {
 			case '{':
diff --git a/test/test.c b/test/test.c
index ce712fa..bedc63e 100644
--- a/test/test.c
+++ b/test/test.c
@@ -872,7 +872,7 @@
 #endif
 }
 
-void RunMemoryTest(const char* szFileName)
+static void RunMemoryTest(const char* szFileName)
 {
 #ifdef USE_CBOR_CONTEXT
 	unsigned int iFail;
@@ -1218,11 +1218,9 @@
 	return true;
 }
 
-void RunFileTest(const char* szFileName)
+static void RunFileTest(const char* szFileName)
 {
-	const cn_cbor* pControl = NULL;
-
-	pControl = ParseJson(szFileName);
+	const cn_cbor*  pControl = ParseJson(szFileName);
 
 	//
 	//  If we are given a file name, then process the file name