]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-127257: Add hex code to ssl "unknown error" message (GH-127360)
authorPetr Viktorin <encukou@gmail.com>
Fri, 10 Jan 2025 12:59:51 +0000 (13:59 +0100)
committerGitHub <noreply@github.com>
Fri, 10 Jan 2025 12:59:51 +0000 (13:59 +0100)
* ssl: Add hex error code to "unknown error" messages

To make it easier to vary the individual parts of the message,
replace the if-ladder with constant format strings by building
the string piece-wise with PyUnicodeWriter.

Use "unknown error (0x%x)" rather than just "unknown error" if we
can't get a better error message. (Hex makes sense as the error
includes two packed parts.)

Misc/NEWS.d/next/Library/2024-11-28-14-24-12.gh-issue-127360.HVKt-c.rst [new file with mode: 0644]
Modules/_ssl.c

diff --git a/Misc/NEWS.d/next/Library/2024-11-28-14-24-12.gh-issue-127360.HVKt-c.rst b/Misc/NEWS.d/next/Library/2024-11-28-14-24-12.gh-issue-127360.HVKt-c.rst
new file mode 100644 (file)
index 0000000..4772aef
--- /dev/null
@@ -0,0 +1,4 @@
+When a descriptive error message cannot be provided for an
+:exc:`ssl.SSLError`, the "unknown error" message now shows the internal
+error code (as retrieved by ``ERR_get_error`` and similar OpenSSL
+functions).
index 87739832fbf784e66854b9b9e53e1f4311e6b8ae..a7d0f509aed3d1be355e3fb073ebce9e8a8490d6 100644 (file)
@@ -473,6 +473,7 @@ fill_and_set_sslerror(_sslmodulestate *state,
     PyObject *err_value = NULL, *reason_obj = NULL, *lib_obj = NULL;
     PyObject *verify_obj = NULL, *verify_code_obj = NULL;
     PyObject *init_value, *msg, *key;
+    PyUnicodeWriter *writer = NULL;
 
     if (errcode != 0) {
         int lib, reason;
@@ -495,11 +496,10 @@ fill_and_set_sslerror(_sslmodulestate *state,
         if (lib_obj == NULL && PyErr_Occurred()) {
             goto fail;
         }
-        if (errstr == NULL)
+        if (errstr == NULL) {
             errstr = ERR_reason_error_string(errcode);
+        }
     }
-    if (errstr == NULL)
-        errstr = "unknown error";
 
     /* verify code for cert validation error */
     if ((sslsock != NULL) && (type == state->PySSLCertVerificationErrorObject)) {
@@ -539,20 +539,50 @@ fill_and_set_sslerror(_sslmodulestate *state,
         }
     }
 
-    if (verify_obj && reason_obj && lib_obj)
-        msg = PyUnicode_FromFormat("[%S: %S] %s: %S (_ssl.c:%d)",
-                                   lib_obj, reason_obj, errstr, verify_obj,
-                                   lineno);
-    else if (reason_obj && lib_obj)
-        msg = PyUnicode_FromFormat("[%S: %S] %s (_ssl.c:%d)",
-                                   lib_obj, reason_obj, errstr, lineno);
-    else if (lib_obj)
-        msg = PyUnicode_FromFormat("[%S] %s (_ssl.c:%d)",
-                                   lib_obj, errstr, lineno);
-    else
-        msg = PyUnicode_FromFormat("%s (_ssl.c:%d)", errstr, lineno);
-    if (msg == NULL)
+    // Format message roughly as:
+    // [lib_obj: reason_obj] errstr: verify_obj (_ssl.c:lineno)
+    // with parts missing/replaced if unavailable
+    writer = PyUnicodeWriter_Create(64);
+    if (!writer) {
+        goto fail;
+    }
+    if (lib_obj) {
+        if (PyUnicodeWriter_Format(writer, "[%S", lib_obj) < 0) {
+            goto fail;
+        }
+        if (reason_obj) {
+            if (PyUnicodeWriter_Format(writer, ": %S", reason_obj) < 0) {
+                goto fail;
+            }
+        }
+        if (PyUnicodeWriter_WriteUTF8(writer, "] ", 2) < 0) {
+            goto fail;
+        }
+    }
+    if (errstr) {
+        if (PyUnicodeWriter_Format(writer, "%s", errstr) < 0) {
+            goto fail;
+        }
+    }
+    else {
+        if (PyUnicodeWriter_Format(
+                writer, "unknown error (0x%x)", errcode) < 0) {
+            goto fail;
+        }
+    }
+    if (verify_obj) {
+        if (PyUnicodeWriter_Format(writer, ": %S", verify_obj) < 0) {
+            goto fail;
+        }
+    }
+    if (PyUnicodeWriter_Format(writer, " (_ssl.c:%d)", lineno) < 0) {
         goto fail;
+    }
+    msg = PyUnicodeWriter_Finish(writer);
+    writer = NULL;
+    if (!msg) {
+        goto fail;
+    }
 
     init_value = Py_BuildValue("iN", ERR_GET_REASON(ssl_errno), msg);
     if (init_value == NULL)
@@ -587,6 +617,7 @@ fail:
     Py_XDECREF(err_value);
     Py_XDECREF(verify_code_obj);
     Py_XDECREF(verify_obj);
+    PyUnicodeWriter_Discard(writer);
 }
 
 static int