From 5f6067c3e166cd6fa706d75619e2355332848186 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Wed, 7 Aug 2024 12:17:12 -0500 Subject: [PATCH 1/6] add --enable-debug-trace-errcodes=backtrace. * uses libbacktrace to enhance existing "ERR TRACE" messages with backtraces, rendered in same format as the sanitizers. * adds wc_backtrace_render() and some related callbacks to wolfcrypt/src/logging.c. * adds an overrideable WOLFSSL_DEBUG_BACKTRACE_RENDER_CLAUSE to the WC_ERR_TRACE() mechanism in wolfssl/wolfcrypt/error-crypt.h. --- configure.ac | 10 ++- wolfcrypt/src/logging.c | 127 ++++++++++++++++++++++++++++++++ wolfssl/wolfcrypt/error-crypt.h | 22 +++++- 3 files changed, 153 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index 970cc50810..72cbde7899 100644 --- a/configure.ac +++ b/configure.ac @@ -217,11 +217,17 @@ AC_ARG_ENABLE([debug-trace-errcodes], [ ENABLED_DEBUG_TRACE_ERRCODES=no ] ) -if test "$ENABLED_DEBUG_TRACE_ERRCODES" = "yes" +if test "$ENABLED_DEBUG_TRACE_ERRCODES" != "no" then AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DEBUG_TRACE_ERROR_CODES" fi +if test "$ENABLED_DEBUG_TRACE_ERRCODES" = "backtrace" +then + AM_CFLAGS="$AM_CFLAGS -g -funwind-tables -DWOLFSSL_DEBUG_BACKTRACE_ERROR_CODES" + AM_LDFLAGS="$AM_LDFLAGS -lbacktrace" +fi + # Start without certificates enabled and enable if a certificate algorithm is # enabled ENABLED_CERTS="no" @@ -9981,7 +9987,7 @@ echo "" >> $OPTION_FILE echo "#endif /* WOLFSSL_OPTIONS_H */" >> $OPTION_FILE echo "" >> $OPTION_FILE -if test "$ENABLED_DEBUG_TRACE_ERRCODES" = "yes" +if test "$ENABLED_DEBUG_TRACE_ERRCODES" != "no" then support/gen-debug-trace-error-codes.sh || AC_MSG_ERROR([Header generation for debug-trace-errcodes failed.]) fi diff --git a/wolfcrypt/src/logging.c b/wolfcrypt/src/logging.c index f28a71ef7b..7d7571ed82 100644 --- a/wolfcrypt/src/logging.c +++ b/wolfcrypt/src/logging.c @@ -1674,3 +1674,130 @@ void WOLFSSL_ERROR_MSG(const char* msg) } #endif /* DEBUG_WOLFSSL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */ + +#ifdef WOLFSSL_DEBUG_BACKTRACE_ERROR_CODES + +#include + +#if BACKTRACE_SUPPORTED != 1 + #error WOLFSSL_DEBUG_BACKTRACE_ERROR_CODES is defined but BACKTRACE_SUPPORTED is 0. +#endif + +#if !defined(WOLFSSL_MUTEX_INITIALIZER) && defined(WOLFSSL_NO_ATOMICS) + #error WOLFSSL_DEBUG_BACKTRACE_ERROR_CODES requires WOLFSSL_MUTEX_INITIALIZER or wolfSSL_Atomic_Ints. +#endif + +#include + +static int backtrace_callback(void *data, uintptr_t pc, const char *filename, + int lineno, const char *function) +{ + if (function == NULL) + return 0; + /* the first callback is for the call to wc_print_backtrace() -- skip it. */ + if (*(int *)data == 0) { + *(int *)data = 1; + return 0; + } +#ifdef NO_STDIO_FILESYSTEM + printf(" #%d %p in %s %s:%d\n", (*(int *)data)++, (void *)pc, + function, filename, lineno); +#else + fprintf(stderr, " #%d %p in %s %s:%d\n", (*(int *)data)++, (void *)pc, + function, filename, lineno); +#endif + return 0; +} + +static void backtrace_error(void *data, const char *msg, int errnum) { + (void)data; +#ifdef NO_STDIO_FILESYSTEM + printf("ERR TRACE: error %d while backtracing: %s", errnum, msg); +#else + fprintf(stderr, "ERR TRACE: error %d while backtracing: %s", errnum, msg); +#endif +} + +static void backtrace_creation_error(void *data, const char *msg, int errnum) { + (void)data; +#ifdef NO_STDIO_FILESYSTEM + printf("ERR TRACE: internal error %d " + "while initializing backtrace facility: %s", errnum, msg); + printf("ERR TRACE: internal error " + "while initializing backtrace facility"); +#else + fprintf(stderr, "ERR TRACE: internal error %d " + "while initializing backtrace facility: %s", errnum, msg); +#endif +} + +static int backtrace_init(struct backtrace_state **backtrace_state) { +#ifdef WOLFSSL_MUTEX_INITIALIZER + static wolfSSL_Mutex backtrace_create_state_mutex = + WOLFSSL_MUTEX_INITIALIZER(backtrace_create_state_mutex); + if (wc_LockMutex(&backtrace_create_state_mutex) != 0) + return -1; +#elif defined(WOLFSSL_ATOMIC_OPS) + static wolfSSL_Atomic_Int init_count = 0; + if (wolfSSL_Atomic_Int_FetchAdd(&init_count, 1) != 1) + return -1; +#endif + if (*backtrace_state == NULL) { + /* passing a NULL filename to backtrace_create_state() tells + * libbacktrace to use a target-specific strategy to determine the + * executable. "libbacktrace supports ELF, PE/COFF, Mach-O, and XCOFF + * executables with DWARF debugging information. In other words, it + * supports GNU/Linux, *BSD, macOS, Windows, and AIX." + */ + *backtrace_state = backtrace_create_state( + NULL, 0, backtrace_creation_error, NULL); + } +#ifdef WOLFSSL_MUTEX_INITIALIZER + wc_UnLockMutex(&backtrace_create_state_mutex); +#endif + if (*backtrace_state == NULL) + return -1; + return 0; +} + +void wc_backtrace_render(void) { + static wolfSSL_Mutex backtrace_mutex WOLFSSL_MUTEX_INITIALIZER_CLAUSE(backtrace_mutex); + static struct backtrace_state *backtrace_state = NULL; + int depth = 0; + +#ifndef WOLFSSL_MUTEX_INITIALIZER + static wolfSSL_Atomic_Int init_count = 0; + if (init_count != 1) { + if (wolfSSL_Atomic_Int_FetchSub(&init_count, 1) != -1) + return; + if (wc_InitMutex(&backtrace_mutex) != 0) + return; + init_count = 1; + } +#endif + + /* backtrace_state can't be shared between threads even when + * BACKTRACE_SUPPORTS_THREADS == 1, so we serialize the render op. this + * helpfully mutexes the initialization too. + */ + if (wc_LockMutex(&backtrace_mutex) != 0) + return; + + if (backtrace_state == NULL) { + if (backtrace_init(&backtrace_state) < 0) { + wc_UnLockMutex(&backtrace_mutex); + return; + } + } + + /* note that the optimizer can produce misleading backtraces, even with + * -funwind-tables. in contrast, the macro-generated "ERR TRACE" message + * from WC_ERR_TRACE() always accurately identifies the error code point. + */ + backtrace_full(backtrace_state, 0, backtrace_callback, backtrace_error, + (void *)&depth); + + wc_UnLockMutex(&backtrace_mutex); +} + +#endif /* WOLFSSL_DEBUG_BACKTRACE_ERROR_CODES */ diff --git a/wolfssl/wolfcrypt/error-crypt.h b/wolfssl/wolfcrypt/error-crypt.h index 8fb71b3c6a..413868ebbc 100644 --- a/wolfssl/wolfcrypt/error-crypt.h +++ b/wolfssl/wolfcrypt/error-crypt.h @@ -298,17 +298,31 @@ WOLFSSL_ABI WOLFSSL_API const char* wc_GetErrorString(int error); #undef WOLFSSL_DEBUG_TRACE_ERROR_CODES #endif #ifdef WOLFSSL_DEBUG_TRACE_ERROR_CODES + extern void wc_backtrace_render(void); #define WC_NO_ERR_TRACE(label) (CONST_NUM_ERR_ ## label) + #ifndef WOLFSSL_DEBUG_BACKTRACE_RENDER_CLAUSE + #ifdef WOLFSSL_DEBUG_BACKTRACE_ERROR_CODES + #define WOLFSSL_DEBUG_BACKTRACE_RENDER_CLAUSE wc_backtrace_render() + #else + #define WOLFSSL_DEBUG_BACKTRACE_RENDER_CLAUSE (void)0 + #endif + #endif #ifndef WC_ERR_TRACE #ifdef NO_STDIO_FILESYSTEM #define WC_ERR_TRACE(label) \ - ( printf("ERR TRACE: %s L %d " #label " (%d)\n", \ - __FILE__, __LINE__, label), label) + ( printf("ERR TRACE: %s L %d %s (%d)\n", \ + __FILE__, __LINE__, #label, label), \ + WOLFSSL_DEBUG_BACKTRACE_RENDER_CLAUSE, \ + label \ + ) #else #define WC_ERR_TRACE(label) \ ( fprintf(stderr, \ - "ERR TRACE: %s L %d " #label " (%d)\n", \ - __FILE__, __LINE__, label), label) + "ERR TRACE: %s L %d %s (%d)\n", \ + __FILE__, __LINE__, #label, label), \ + WOLFSSL_DEBUG_BACKTRACE_RENDER_CLAUSE, \ + label \ + ) #endif #endif #include From 763ced668e4db6eb41540c5fee9d55e45ccccf8d Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Wed, 7 Aug 2024 13:13:43 -0500 Subject: [PATCH 2/6] fixes for defects identified by cppcheck and clang-tidy on --enable-debug builds: null deref in tests/api.c:load_pem_key_file_as_der(), redundant declarations in wolfcrypt/benchmark/benchmark.c, and numerous unchecked XSNPRINTF()s in wolfcrypt/src/logging.c and src/internal.c. --- src/internal.c | 6 +++- tests/api.c | 8 +++-- wolfcrypt/benchmark/benchmark.c | 12 ------- wolfcrypt/src/logging.c | 62 ++++++++++++++++++++++++++------- 4 files changed, 60 insertions(+), 28 deletions(-) diff --git a/src/internal.c b/src/internal.c index 16230dbb78..219465a1db 100644 --- a/src/internal.c +++ b/src/internal.c @@ -20653,7 +20653,11 @@ static void LogAlert(int type) typeStr = AlertTypeToString(type); if (typeStr != NULL) { char buff[60]; - XSNPRINTF(buff, sizeof(buff), "Alert type: %s", typeStr); + if (XSNPRINTF(buff, sizeof(buff), "Alert type: %s", typeStr) + >= (int)sizeof(buff)) + { + buff[sizeof(buff) - 1] = 0; + } WOLFSSL_MSG(buff); } #else diff --git a/tests/api.c b/tests/api.c index 04858591de..bb0877d100 100644 --- a/tests/api.c +++ b/tests/api.c @@ -78089,9 +78089,11 @@ static int load_pem_key_file_as_der(const char* privKeyFile, DerBuffer** pDer, (void)encInfo; /* not used in this test */ #ifdef DEBUG_WOLFSSL - fprintf(stderr, "%s (%d): Loading PEM %s (len %d) to DER (len %d)\n", - (ret == 0) ? "Success" : "Failure", ret, privKeyFile, (int)key_sz, - (*pDer)->length); + if (*pDer != NULL) { + fprintf(stderr, "%s (%d): Loading PEM %s (len %d) to DER (len %d)\n", + (ret == 0) ? "Success" : "Failure", ret, privKeyFile, + (int)key_sz, (*pDer)->length); + } #endif return ret; diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index 0bb5322370..9078c0bf6c 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -1663,18 +1663,6 @@ static const char* bench_result_words3[][5] = { const char *desc_extra); #endif -#if defined(DEBUG_WOLFSSL) && !defined(HAVE_VALGRIND) && \ - !defined(HAVE_STACK_SIZE) -#ifdef __cplusplus - extern "C" { -#endif - WOLFSSL_API int wolfSSL_Debugging_ON(void); - WOLFSSL_API void wolfSSL_Debugging_OFF(void); -#ifdef __cplusplus - } /* extern "C" */ -#endif -#endif - #if !defined(WC_NO_RNG) && \ ((!defined(NO_RSA) && !defined(WOLFSSL_RSA_VERIFY_ONLY)) \ || !defined(NO_DH) || defined(WOLFSSL_KEY_GEN) || defined(HAVE_ECC) \ diff --git a/wolfcrypt/src/logging.c b/wolfcrypt/src/logging.c index 7d7571ed82..710b68bfdf 100644 --- a/wolfcrypt/src/logging.c +++ b/wolfcrypt/src/logging.c @@ -471,26 +471,48 @@ void WOLFSSL_BUFFER(const byte* buffer, word32 length) while (buflen > 0) { int bufidx = 0; - XSNPRINTF(&line[bufidx], sizeof(line)-bufidx, "\t"); + if (XSNPRINTF(&line[bufidx], sizeof(line)-bufidx, "\t") + >= (int)sizeof(line) - bufidx) + { + return; + } bufidx++; for (i = 0; i < LINE_LEN; i++) { if (i < buflen) { - XSNPRINTF(&line[bufidx], sizeof(line)-bufidx, "%02x ", buffer[i]); + if (XSNPRINTF(&line[bufidx], sizeof(line)-bufidx, "%02x ", + buffer[i]) >= (int)sizeof(line) - bufidx) + { + return; + } } else { - XSNPRINTF(&line[bufidx], sizeof(line)-bufidx, " "); + if (XSNPRINTF(&line[bufidx], sizeof(line)-bufidx, " ") + >= (int)sizeof(line) - bufidx) + { + return; + } } bufidx += 3; } - XSNPRINTF(&line[bufidx], sizeof(line)-bufidx, "| "); + if (XSNPRINTF(&line[bufidx], sizeof(line)-bufidx, "| ") + >= (int)sizeof(line) - bufidx) + { + return; + } bufidx++; for (i = 0; i < LINE_LEN; i++) { if (i < buflen) { - XSNPRINTF(&line[bufidx], sizeof(line)-bufidx, - "%c", 31 < buffer[i] && buffer[i] < 127 ? buffer[i] : '.'); + if (XSNPRINTF(&line[bufidx], sizeof(line)-bufidx, + "%c", 31 < buffer[i] && buffer[i] < 127 + ? buffer[i] + : '.') + >= (int)sizeof(line) - bufidx) + { + return; + } bufidx++; } } @@ -506,7 +528,11 @@ void WOLFSSL_ENTER(const char* msg) { if (loggingEnabled) { char buffer[WOLFSSL_MAX_ERROR_SZ]; - XSNPRINTF(buffer, sizeof(buffer), "wolfSSL Entering %s", msg); + if (XSNPRINTF(buffer, sizeof(buffer), "wolfSSL Entering %s", msg) + >= (int)sizeof(buffer)) + { + buffer[sizeof(buffer) - 1] = 0; + } wolfssl_log(ENTER_LOG, NULL, 0, buffer); } } @@ -516,7 +542,11 @@ void WOLFSSL_ENTER2(const char *file, int line, const char* msg) { if (loggingEnabled) { char buffer[WOLFSSL_MAX_ERROR_SZ]; - XSNPRINTF(buffer, sizeof(buffer), "wolfSSL Entering %s", msg); + if (XSNPRINTF(buffer, sizeof(buffer), "wolfSSL Entering %s", msg) + >= (int)sizeof(buffer)) + { + buffer[sizeof(buffer) - 1] = 0; + } wolfssl_log(ENTER_LOG, file, line, buffer); } } @@ -527,8 +557,12 @@ void WOLFSSL_LEAVE(const char* msg, int ret) { if (loggingEnabled) { char buffer[WOLFSSL_MAX_ERROR_SZ]; - XSNPRINTF(buffer, sizeof(buffer), "wolfSSL Leaving %s, return %d", - msg, ret); + if (XSNPRINTF(buffer, sizeof(buffer), "wolfSSL Leaving %s, return %d", + msg, ret) + >= (int)sizeof(buffer)) + { + buffer[sizeof(buffer) - 1] = 0; + } wolfssl_log(LEAVE_LOG, NULL, 0, buffer); } } @@ -538,8 +572,12 @@ void WOLFSSL_LEAVE2(const char *file, int line, const char* msg, int ret) { if (loggingEnabled) { char buffer[WOLFSSL_MAX_ERROR_SZ]; - XSNPRINTF(buffer, sizeof(buffer), "wolfSSL Leaving %s, return %d", - msg, ret); + if (XSNPRINTF(buffer, sizeof(buffer), "wolfSSL Leaving %s, return %d", + msg, ret) + >= (int)sizeof(buffer)) + { + buffer[sizeof(buffer) - 1] = 0; + } wolfssl_log(LEAVE_LOG, file, line, buffer); } } From f5e775fe95e3cf046ecc663217713cf8d7683d26 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Thu, 8 Aug 2024 09:13:56 -0500 Subject: [PATCH 3/6] wolfcrypt/src/wc_kyber.c: fixes for null derefs (nullPointerRedundantCheck) in wc_KyberKey_MakeKeyWithRandom() and wc_KyberKey_Decapsulate() added in d350ba6c41. --- wolfcrypt/src/wc_kyber.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/wolfcrypt/src/wc_kyber.c b/wolfcrypt/src/wc_kyber.c index ffa37d84c1..a32d0916b5 100644 --- a/wolfcrypt/src/wc_kyber.c +++ b/wolfcrypt/src/wc_kyber.c @@ -286,7 +286,9 @@ int wc_KyberKey_MakeKeyWithRandom(KyberKey* key, const unsigned char* rand, } /* Free dynamic memory allocated in function. */ - XFREE(a, key->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (key != NULL) { + XFREE(a, key->heap, DYNAMIC_TYPE_TMP_BUFFER); + } return ret; } @@ -890,7 +892,9 @@ int wc_KyberKey_Decapsulate(KyberKey* key, unsigned char* ss, #ifndef USE_INTEL_SPEEDUP /* Dispose of dynamic memory allocated in function. */ - XFREE(cmp, key->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (key != NULL) { + XFREE(cmp, key->heap, DYNAMIC_TYPE_TMP_BUFFER); + } #endif return ret; From 24e34aa41acc814ea691f19b26e95125219c1169 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Thu, 8 Aug 2024 10:49:05 -0500 Subject: [PATCH 4/6] wolfcrypt/src/logging.c: in WOLFSSL_BUFFER(), on averted overrun, log a buffer error rather than silently failing; in wc_backtrace_render(), fix !WOLFSSL_MUTEX_INITIALIZER race mitigation code. --- wolfcrypt/src/logging.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/wolfcrypt/src/logging.c b/wolfcrypt/src/logging.c index 710b68bfdf..9568f1c6a1 100644 --- a/wolfcrypt/src/logging.c +++ b/wolfcrypt/src/logging.c @@ -474,7 +474,7 @@ void WOLFSSL_BUFFER(const byte* buffer, word32 length) if (XSNPRINTF(&line[bufidx], sizeof(line)-bufidx, "\t") >= (int)sizeof(line) - bufidx) { - return; + goto errout; } bufidx++; @@ -483,14 +483,14 @@ void WOLFSSL_BUFFER(const byte* buffer, word32 length) if (XSNPRINTF(&line[bufidx], sizeof(line)-bufidx, "%02x ", buffer[i]) >= (int)sizeof(line) - bufidx) { - return; + goto errout; } } else { if (XSNPRINTF(&line[bufidx], sizeof(line)-bufidx, " ") >= (int)sizeof(line) - bufidx) { - return; + goto errout; } } bufidx += 3; @@ -499,7 +499,7 @@ void WOLFSSL_BUFFER(const byte* buffer, word32 length) if (XSNPRINTF(&line[bufidx], sizeof(line)-bufidx, "| ") >= (int)sizeof(line) - bufidx) { - return; + goto errout; } bufidx++; @@ -511,7 +511,7 @@ void WOLFSSL_BUFFER(const byte* buffer, word32 length) : '.') >= (int)sizeof(line) - bufidx) { - return; + goto errout; } bufidx++; } @@ -521,6 +521,12 @@ void WOLFSSL_BUFFER(const byte* buffer, word32 length) buffer += LINE_LEN; buflen -= LINE_LEN; } + + return; + +errout: + + wolfssl_log(INFO_LOG, NULL, 0, "\t[Buffer error while rendering]"); } #undef WOLFSSL_ENTER /* undo WOLFSSL_DEBUG_CODEPOINTS wrapper */ @@ -1799,18 +1805,23 @@ static int backtrace_init(struct backtrace_state **backtrace_state) { } void wc_backtrace_render(void) { - static wolfSSL_Mutex backtrace_mutex WOLFSSL_MUTEX_INITIALIZER_CLAUSE(backtrace_mutex); + static wolfSSL_Mutex backtrace_mutex + WOLFSSL_MUTEX_INITIALIZER_CLAUSE(backtrace_mutex); static struct backtrace_state *backtrace_state = NULL; int depth = 0; #ifndef WOLFSSL_MUTEX_INITIALIZER static wolfSSL_Atomic_Int init_count = 0; if (init_count != 1) { - if (wolfSSL_Atomic_Int_FetchSub(&init_count, 1) != -1) + int cur_init_count = wolfSSL_Atomic_Int_FetchSub(&init_count, 1); + if (cur_init_count != 0) { + (void)wolfSSL_Atomic_Int_FetchAdd(&init_count, 1); return; + } if (wc_InitMutex(&backtrace_mutex) != 0) return; - init_count = 1; + /* set init_count to 1, race-free: (-1) - (0-2) = 1 */ + (void)wolfSSL_Atomic_Int_FetchSub(&init_count, cur_init_count - 2); } #endif From a75d520727378b0d3a1c6e15dac5438a0c9f9d68 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Thu, 8 Aug 2024 11:40:57 -0500 Subject: [PATCH 5/6] src/pk.c: fix a null deref (nullPointerRedundantCheck) in wolfSSL_RSA_GenAdd() added in d350ba6c41. --- src/pk.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pk.c b/src/pk.c index 8b8dd97737..34e2727844 100644 --- a/src/pk.c +++ b/src/pk.c @@ -4691,7 +4691,9 @@ int wolfSSL_RSA_GenAdd(WOLFSSL_RSA* rsa) mp_clear(t); #ifdef WOLFSSL_SMALL_STACK - XFREE(tmp, rsa->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (rsa != NULL) { + XFREE(tmp, rsa->heap, DYNAMIC_TYPE_TMP_BUFFER); + } #endif return ret; From c25d86c6c70b50e9d55713ed7a63f61425fa0384 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Thu, 8 Aug 2024 15:57:14 -0500 Subject: [PATCH 6/6] support/gen-debug-trace-error-codes.sh: tweak for compatibility with mawk. --- support/gen-debug-trace-error-codes.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/support/gen-debug-trace-error-codes.sh b/support/gen-debug-trace-error-codes.sh index 1aba489d9e..01f32faa80 100755 --- a/support/gen-debug-trace-error-codes.sh +++ b/support/gen-debug-trace-error-codes.sh @@ -12,7 +12,12 @@ BEGIN { print("#undef WOLFSSL_DEBUG_TRACE_ERROR_CODES_H") >> "wolfssl/debug-untrace-error-codes.h"; } { - if (match($0, "^[[:space:]]+([A-Z][A-Z0-9_]+)[[:space:]]*=[[:space:]]*(-[0-9]+)[,[:space:]]", errcode_a)) { + if (match($0, "^[[:space:]]+([A-Z][A-Z0-9_]+)[[:space:]]*=[[:space:]]*(-[0-9]+)[,[:space:]]")) { + + # for mawkward compatibility -- gawk allows errcode_a as the 3rd arg to match(). + gsub("^[[:space:]]+", "", $0); + split($0, errcode_a, "[[:space:]=,]+"); + if ((errcode_a[1] == "MIN_CODE_E") || (errcode_a[1] == "WC_LAST_E") || (errcode_a[1] == "MAX_CODE_E"))