From efca41606d4083eade90047d57cb963eb3b7e731 Mon Sep 17 00:00:00 2001
From: Kirill Isakov <bootctl@gmail.com>
Date: Wed, 20 Apr 2022 16:29:23 +0600
Subject: [PATCH] CI: add libgcrypt to sanitizer run

Also disable check for unsigned integer overflow.

I couldn't find a way to reliably disable it for a single function:

	https://github.com/google/sanitizers/issues/765

and warnings it produces do not seem to be of enough importance to
introduce ugly hacks like resetting the most significant byte here:

	size_t result = 0;
	// ...

	for(; len; --len) {
		result = (size_t)(result << 8);
		//                      ^^^^
---
 .ci/sanitizers/run.sh       | 3 ++-
 .ci/sanitizers/suppress.txt | 4 ++++
 .github/workflows/test.yml  | 5 +++++
 src/gcrypt/pem.c            | 4 ++--
 src/gcrypt/rsa.c            | 2 +-
 5 files changed, 14 insertions(+), 4 deletions(-)
 create mode 100644 .ci/sanitizers/suppress.txt

diff --git a/.ci/sanitizers/run.sh b/.ci/sanitizers/run.sh
index b615d9db..3144275a 100755
--- a/.ci/sanitizers/run.sh
+++ b/.ci/sanitizers/run.sh
@@ -8,13 +8,14 @@ logs="$GITHUB_WORKSPACE/sanitizer"
 
 case "$SANITIZER" in
 undefined)
-  flags='-fsanitize=integer -fsanitize=nullability'
+  flags='-fsanitize=integer -fsanitize=nullability -fno-sanitize=unsigned-integer-overflow'
   export UBSAN_OPTIONS="log_path=$logs/ubsan:print_stacktrace=1"
   ;;
 
 address)
   flags='-fsanitize-address-use-after-scope -fsanitize=pointer-compare -fsanitize=pointer-subtract'
   export ASAN_OPTIONS="log_path=$logs/asan:detect_invalid_pointer_pairs=2:strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1"
+  export LSAN_OPTIONS="suppressions=$dir/suppress.txt:print_suppressions=0"
   ;;
 
 thread)
diff --git a/.ci/sanitizers/suppress.txt b/.ci/sanitizers/suppress.txt
new file mode 100644
index 00000000..f151d610
--- /dev/null
+++ b/.ci/sanitizers/suppress.txt
@@ -0,0 +1,4 @@
+# known leak from one-time allocation
+# upstream refuses to fix such things: https://dev.gnupg.org/T4499
+leak:libgcrypt.so
+
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index cb72c663..ec70fa50 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -121,6 +121,7 @@ jobs:
 
       - name: Run tests with OpenSSL 3
         run: bash .ci/sanitizers/run.sh openssl3
+        if: always()
 
       - name: Sanitize tests with default settings
         run: bash .ci/sanitizers/run.sh default
@@ -130,6 +131,10 @@ jobs:
         run: bash .ci/sanitizers/run.sh nolegacy
         if: always()
 
+      - name: Run tests with libgcrypt
+        run: bash .ci/sanitizers/run.sh gcrypt
+        if: always()
+
       - name: Upload test results
         uses: actions/upload-artifact@v2
         with:
diff --git a/src/gcrypt/pem.c b/src/gcrypt/pem.c
index b2eca3d4..0f7763c5 100644
--- a/src/gcrypt/pem.c
+++ b/src/gcrypt/pem.c
@@ -96,8 +96,8 @@ bool pem_encode(FILE *fp, const char *header, uint8_t *buf, size_t size) {
 	char b64[B64_SIZE(size)];
 	const size_t b64len = b64encode(b64, buf, size);
 
-	for(char *p = b64; p < b64 + b64len; p += 64) {
-		if(fprintf(fp, "%.64s\n", p) <= 0) {
+	for(size_t i = 0; i < b64len; i += 64) {
+		if(fprintf(fp, "%.64s\n", &b64[i]) <= 0) {
 			return false;
 		}
 	}
diff --git a/src/gcrypt/rsa.c b/src/gcrypt/rsa.c
index 1b151648..1162ddf6 100644
--- a/src/gcrypt/rsa.c
+++ b/src/gcrypt/rsa.c
@@ -71,7 +71,7 @@ static size_t ber_read_len(unsigned char **p, size_t *buflen) {
 			return 0;
 		}
 
-		while(len--) {
+		for(; len; --len) {
 			result = (size_t)(result << 8);
 			result |= *(*p)++;
 			(*buflen)--;
-- 
2.39.5