ERR: Add new building blocks for reporting errors
authorRichard Levitte <levitte@openssl.org>
Wed, 24 Jul 2019 11:03:32 +0000 (13:03 +0200)
committerRichard Levitte <levitte@openssl.org>
Wed, 31 Jul 2019 04:42:45 +0000 (06:42 +0200)
The new building block are ERR_new(), ERR_set_debug(),
ERR_set_error(), ERR_vset_error(), which allocate a new error record
and set the diverse data in them.  They are designed in such a way
that it's reasonably easy to create macros that use all of them but
then rely completely on the function signature of ERR_set_error() or
ERR_vset_error().

Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/9452)

crypto/err/build.info
crypto/err/err_blocks.c [new file with mode: 0644]
doc/man3/ERR_new.pod [new file with mode: 0644]
include/openssl/err.h
util/libcrypto.num

index 6163d95..c010ea4 100644 (file)
@@ -1,3 +1,3 @@
 LIBS=../../libcrypto
 SOURCE[../../libcrypto]=\
-        err.c err_all.c err_prn.c
+        err_blocks.c err.c err_all.c err_prn.c
diff --git a/crypto/err/err_blocks.c b/crypto/err/err_blocks.c
new file mode 100644 (file)
index 0000000..49086bd
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <string.h>
+#include <openssl/err.h>
+#include "err_locl.h"
+
+void ERR_new(void)
+{
+    ERR_STATE *es;
+
+    es = ERR_get_state();
+    if (es == NULL)
+        return;
+
+    /* Allocate a slot */
+    err_get_slot(es);
+    err_clear(es, es->top, 0);
+}
+
+void ERR_set_debug(const char *file, int line, const char *func)
+{
+    ERR_STATE *es;
+
+    es = ERR_get_state();
+    if (es == NULL)
+        return;
+
+    err_set_debug(es, es->top, file, line, func);
+}
+
+void ERR_set_error(int lib, int reason, const char *fmt, ...)
+{
+    va_list args;
+
+    va_start(args, fmt);
+    ERR_vset_error(lib, reason, fmt, args);
+    va_end(args);
+}
+
+void ERR_vset_error(int lib, int reason, const char *fmt, va_list args)
+{
+    ERR_STATE *es;
+    char *buf = NULL;
+    size_t buf_size = 0;
+    unsigned long flags = 0;
+    size_t i;
+
+    es = ERR_get_state();
+    if (es == NULL)
+        return;
+    i = es->top;
+
+    if (fmt != NULL) {
+        int printed_len = 0;
+        char *rbuf = NULL;
+
+        buf = es->err_data[i];
+        buf_size = es->err_data_size[i];
+
+        /*
+         * To protect the string we just grabbed from tampering by other
+         * functions we may call, or to protect them from freeing a pointer
+         * that may no longer be valid at that point, we clear away the
+         * data pointer and the flags.  We will set them again at the end
+         * of this function.
+         */
+        es->err_data[i] = NULL;
+        es->err_data_flags[i] = 0;
+
+        /*
+         * Try to maximize the space available.  If that fails, we use what
+         * we have.
+         */
+        if (buf_size < ERR_MAX_DATA_SIZE
+            && (rbuf = OPENSSL_realloc(buf, ERR_MAX_DATA_SIZE)) != NULL) {
+            buf = rbuf;
+            buf_size = ERR_MAX_DATA_SIZE;
+        }
+
+        if (buf != NULL) {
+            printed_len = BIO_vsnprintf(buf, ERR_MAX_DATA_SIZE, fmt, args);
+        }
+        if (printed_len < 0)
+            printed_len = 0;
+        buf[printed_len] = '\0';
+
+        /*
+         * Try to reduce the size, but only if we maximized above.  If that
+         * fails, we keep what we have.
+         * (According to documentation, realloc leaves the old buffer untouched
+         * if it fails)
+         */
+        if ((rbuf = OPENSSL_realloc(buf, printed_len + 1)) != NULL) {
+            buf = rbuf;
+            buf_size = printed_len + 1;
+        }
+
+        if (buf != NULL)
+            flags = ERR_TXT_MALLOCED | ERR_TXT_STRING;
+    }
+
+    err_clear_data(es, es->top, 0);
+    err_set_error(es, es->top, lib, reason);
+    if (fmt != NULL)
+        err_set_data(es, es->top, buf, buf_size, flags);
+}
diff --git a/doc/man3/ERR_new.pod b/doc/man3/ERR_new.pod
new file mode 100644 (file)
index 0000000..80419da
--- /dev/null
@@ -0,0 +1,78 @@
+=pod
+
+=head1 NAME
+
+ERR_new, ERR_set_debug, ERR_set_error, ERR_vset_error
+- Error recording building blocks
+
+=head1 SYNOPSIS
+
+ #include <openssl/err.h>
+
+ void ERR_new(void);
+ void ERR_set_debug(const char *file, int line, const char *func);
+ void ERR_set_error(int lib, int reason, const char *fmt, ...);
+ void ERR_vset_error(int lib, int reason, const char *fmt, va_list args);
+
+=head1 DESCRIPTION
+
+The functions described here are generally not used directly, but
+rather through macros such as L<ERR_raise(3)>.
+They can still be useful for anyone that wants to make their own
+macros.
+
+ERR_new() allocates a new slot in the thread's error queue.
+
+ERR_set_debug() sets the debug information related to the current
+error in the thread's error queue.
+The values that can be given are the file name I<file>, line in the
+file I<line> and the name of the function I<func> where the error
+occured.
+The names must be constant, this function will only save away the
+pointers, not copy the strings.
+
+ERR_set_error() sets the error information, which are the library
+number I<lib> and the reason code I<reason>, and additional data as a
+format string I<fmt> and an arbitrary number of arguments.
+The additional data is processed with L<BIO_snprintf(3)> to form the
+additional data string, which is allocated and store in the error
+record.
+
+ERR_vset_error() works like ERR_set_error(), but takes a B<va_list>
+argument instead of a variable number of arguments.
+
+=head1 RETURN VALUES
+
+ERR_new, ERR_set_debug, ERR_set_error and ERR_vset_error
+do not return any values.
+
+=head1 NOTES
+
+The library number is unique to each unit that records errors.
+OpenSSL has a number of pre-allocated ones for its own uses, but
+others may allocate their own library number dynamically with
+L<ERR_get_next_error_library(3)>.
+
+Reason codes are unique within each library, and may have an
+associated set of strings as a short description of the reason.
+For dynamically allocated library numbers, reason strings are recorded
+with L<ERR_load_strings(3)>.
+
+Provider authors are supplied with core versions of these functions,
+see L<provider-base(7)>.
+
+=head1 SEE ALSO
+
+L<ERR_raise(3)>, L<ERR_get_next_error_library(3)>,
+L<ERR_load_strings(3)>, L<BIO_snprintf(3)>, L<provider-base(7)>
+
+=head1 COPYRIGHT
+
+Copyright 2000-2019 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License").  You may not use
+this file except in compliance with the License.  You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
index acecca4..90e1467 100644 (file)
@@ -236,6 +236,15 @@ typedef struct ERR_string_data_st {
 
 DEFINE_LHASH_OF(ERR_STRING_DATA);
 
+/* 12 lines and some on an 80 column terminal */
+#define ERR_MAX_DATA_SIZE       1024
+
+/* Building blocks */
+void ERR_new(void);
+void ERR_set_debug(const char *file, int line, const char *func);
+void ERR_set_error(int lib, int reason, const char *fmt, ...);
+void ERR_vset_error(int lib, int reason, const char *fmt, va_list args);
+
 void ERR_put_error(int lib, int func, int reason, const char *file, int line);
 void ERR_put_func_error(int lib, const char *func, int reason,
                         const char *file, int line);
index 8146248..da7395c 100644 (file)
@@ -4700,3 +4700,7 @@ EVP_CIPHER_do_all_ex                    4805      3_0_0   EXIST::FUNCTION:
 EVP_MD_do_all_ex                        4806   3_0_0   EXIST::FUNCTION:
 EVP_KEYEXCH_provider                    4807   3_0_0   EXIST::FUNCTION:
 OSSL_PROVIDER_available                 4808   3_0_0   EXIST::FUNCTION:
+ERR_new                                 4809   3_0_0   EXIST::FUNCTION:
+ERR_set_debug                           4810   3_0_0   EXIST::FUNCTION:
+ERR_set_error                           4811   3_0_0   EXIST::FUNCTION:
+ERR_vset_error                          4812   3_0_0   EXIST::FUNCTION: