We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Encode package version as a shared object symbol
One of the more common issues we see with users is an `AttributeError` where one of our `Cryptograpy_HAS_*` can't be found. This is pretty much always an issue where Python has loaded a newer version of cryptography's Python code, but for some reason loads an older shared object (which does not have the symbol the Python code is looking for).

This is a bad error message for a serious environment problem, and it doesn't always happen immediately. We should encode the version of cryptography in the shared object we build and then raise an `ImportError` on import if the shared object version and cryptography's version do not match.

refs https://github.com/certbot/certbot/issues/5651

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/cryptography/hazmat/bindings/openssl/binding.py`
Content:
```
1 # This file is dual licensed under the terms of the Apache License, Version
2 # 2.0, and the BSD License. See the LICENSE file in the root of this repository
3 # for complete details.
4 
5 from __future__ import absolute_import, division, print_function
6 
7 import collections
8 import threading
9 import types
10 import warnings
11 
12 from cryptography import utils
13 from cryptography.exceptions import InternalError
14 from cryptography.hazmat.bindings._openssl import ffi, lib
15 from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES
16 
17 _OpenSSLErrorWithText = collections.namedtuple(
18     "_OpenSSLErrorWithText", ["code", "lib", "func", "reason", "reason_text"]
19 )
20 
21 
22 class _OpenSSLError(object):
23     def __init__(self, code, lib, func, reason):
24         self._code = code
25         self._lib = lib
26         self._func = func
27         self._reason = reason
28 
29     def _lib_reason_match(self, lib, reason):
30         return lib == self.lib and reason == self.reason
31 
32     code = utils.read_only_property("_code")
33     lib = utils.read_only_property("_lib")
34     func = utils.read_only_property("_func")
35     reason = utils.read_only_property("_reason")
36 
37 
38 def _consume_errors(lib):
39     errors = []
40     while True:
41         code = lib.ERR_get_error()
42         if code == 0:
43             break
44 
45         err_lib = lib.ERR_GET_LIB(code)
46         err_func = lib.ERR_GET_FUNC(code)
47         err_reason = lib.ERR_GET_REASON(code)
48 
49         errors.append(_OpenSSLError(code, err_lib, err_func, err_reason))
50 
51     return errors
52 
53 
54 def _openssl_assert(lib, ok):
55     if not ok:
56         errors = _consume_errors(lib)
57         errors_with_text = []
58         for err in errors:
59             buf = ffi.new("char[]", 256)
60             lib.ERR_error_string_n(err.code, buf, len(buf))
61             err_text_reason = ffi.string(buf)
62 
63             errors_with_text.append(
64                 _OpenSSLErrorWithText(
65                     err.code, err.lib, err.func, err.reason, err_text_reason
66                 )
67             )
68 
69         raise InternalError(
70             "Unknown OpenSSL error. This error is commonly encountered when "
71             "another library is not cleaning up the OpenSSL error stack. If "
72             "you are using cryptography with another library that uses "
73             "OpenSSL try disabling it before reporting a bug. Otherwise "
74             "please file an issue at https://github.com/pyca/cryptography/"
75             "issues with information on how to reproduce "
76             "this. ({0!r})".format(errors_with_text),
77             errors_with_text
78         )
79 
80 
81 def build_conditional_library(lib, conditional_names):
82     conditional_lib = types.ModuleType("lib")
83     conditional_lib._original_lib = lib
84     excluded_names = set()
85     for condition, names_cb in conditional_names.items():
86         if not getattr(lib, condition):
87             excluded_names.update(names_cb())
88 
89     for attr in dir(lib):
90         if attr not in excluded_names:
91             setattr(conditional_lib, attr, getattr(lib, attr))
92 
93     return conditional_lib
94 
95 
96 class Binding(object):
97     """
98     OpenSSL API wrapper.
99     """
100     lib = None
101     ffi = ffi
102     _lib_loaded = False
103     _init_lock = threading.Lock()
104     _lock_init_lock = threading.Lock()
105 
106     def __init__(self):
107         self._ensure_ffi_initialized()
108 
109     @classmethod
110     def _register_osrandom_engine(cls):
111         # Clear any errors extant in the queue before we start. In many
112         # scenarios other things may be interacting with OpenSSL in the same
113         # process space and it has proven untenable to assume that they will
114         # reliably clear the error queue. Once we clear it here we will
115         # error on any subsequent unexpected item in the stack.
116         cls.lib.ERR_clear_error()
117         cls._osrandom_engine_id = cls.lib.Cryptography_osrandom_engine_id
118         cls._osrandom_engine_name = cls.lib.Cryptography_osrandom_engine_name
119         result = cls.lib.Cryptography_add_osrandom_engine()
120         _openssl_assert(cls.lib, result in (1, 2))
121 
122     @classmethod
123     def _ensure_ffi_initialized(cls):
124         with cls._init_lock:
125             if not cls._lib_loaded:
126                 cls.lib = build_conditional_library(lib, CONDITIONAL_NAMES)
127                 cls._lib_loaded = True
128                 # initialize the SSL library
129                 cls.lib.SSL_library_init()
130                 # adds all ciphers/digests for EVP
131                 cls.lib.OpenSSL_add_all_algorithms()
132                 # loads error strings for libcrypto and libssl functions
133                 cls.lib.SSL_load_error_strings()
134                 cls._register_osrandom_engine()
135 
136     @classmethod
137     def init_static_locks(cls):
138         with cls._lock_init_lock:
139             cls._ensure_ffi_initialized()
140             # Use Python's implementation if available, importing _ssl triggers
141             # the setup for this.
142             __import__("_ssl")
143 
144             if (not cls.lib.Cryptography_HAS_LOCKING_CALLBACKS or
145                     cls.lib.CRYPTO_get_locking_callback() != cls.ffi.NULL):
146                 return
147 
148             # If nothing else has setup a locking callback already, we set up
149             # our own
150             res = lib.Cryptography_setup_ssl_threads()
151             _openssl_assert(cls.lib, res == 1)
152 
153 
154 def _verify_openssl_version(lib):
155     if (
156         lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 and
157         not lib.CRYPTOGRAPHY_IS_LIBRESSL
158     ):
159         warnings.warn(
160             "OpenSSL version 1.0.1 is no longer supported by the OpenSSL "
161             "project, please upgrade. A future version of cryptography will "
162             "drop support for it.",
163             utils.CryptographyDeprecationWarning
164         )
165 
166 
167 # OpenSSL is not thread safe until the locks are initialized. We call this
168 # method in module scope so that it executes with the import lock. On
169 # Pythons < 3.4 this import lock is a global lock, which can prevent a race
170 # condition registering the OpenSSL locks. On Python 3.4+ the import lock
171 # is per module so this approach will not work.
172 Binding.init_static_locks()
173 
174 _verify_openssl_version(Binding.lib)
175
```

Path: `src/_cffi_src/utils.py`
Content:
```
1 # This file is dual licensed under the terms of the Apache License, Version
2 # 2.0, and the BSD License. See the LICENSE file in the root of this repository
3 # for complete details.
4 
5 from __future__ import absolute_import, division, print_function
6 
7 import sys
8 from distutils.ccompiler import new_compiler
9 from distutils.dist import Distribution
10 
11 from cffi import FFI
12 
13 
14 def build_ffi_for_binding(module_name, module_prefix, modules, libraries=[],
15                           extra_compile_args=[], extra_link_args=[]):
16     """
17     Modules listed in ``modules`` should have the following attributes:
18 
19     * ``INCLUDES``: A string containing C includes.
20     * ``TYPES``: A string containing C declarations for types.
21     * ``FUNCTIONS``: A string containing C declarations for functions & macros.
22     * ``CUSTOMIZATIONS``: A string containing arbitrary top-level C code, this
23         can be used to do things like test for a define and provide an
24         alternate implementation based on that.
25     """
26     types = []
27     includes = []
28     functions = []
29     customizations = []
30     for name in modules:
31         __import__(module_prefix + name)
32         module = sys.modules[module_prefix + name]
33 
34         types.append(module.TYPES)
35         functions.append(module.FUNCTIONS)
36         includes.append(module.INCLUDES)
37         customizations.append(module.CUSTOMIZATIONS)
38 
39     verify_source = "\n".join(
40         includes +
41         customizations
42     )
43     ffi = build_ffi(
44         module_name,
45         cdef_source="\n".join(types + functions),
46         verify_source=verify_source,
47         libraries=libraries,
48         extra_compile_args=extra_compile_args,
49         extra_link_args=extra_link_args,
50     )
51 
52     return ffi
53 
54 
55 def build_ffi(module_name, cdef_source, verify_source, libraries=[],
56               extra_compile_args=[], extra_link_args=[]):
57     ffi = FFI()
58     ffi.cdef(cdef_source)
59     ffi.set_source(
60         module_name,
61         verify_source,
62         libraries=libraries,
63         extra_compile_args=extra_compile_args,
64         extra_link_args=extra_link_args,
65     )
66     return ffi
67 
68 
69 def extra_link_args(compiler_type):
70     if compiler_type == 'msvc':
71         # Enable NX and ASLR for Windows builds on MSVC. These are enabled by
72         # default on Python 3.3+ but not on 2.x.
73         return ['/NXCOMPAT', '/DYNAMICBASE']
74     else:
75         return []
76 
77 
78 def compiler_type():
79     """
80     Gets the compiler type from distutils. On Windows with MSVC it will be
81     "msvc". On macOS and linux it is "unix".
82     """
83     dist = Distribution()
84     dist.parse_config_files()
85     cmd = dist.get_command_obj('build')
86     cmd.ensure_finalized()
87     compiler = new_compiler(compiler=cmd.compiler)
88     return compiler.compiler_type
89
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/_cffi_src/utils.py b/src/_cffi_src/utils.py
--- a/src/_cffi_src/utils.py
+++ b/src/_cffi_src/utils.py
@@ -4,6 +4,7 @@
 
 from __future__ import absolute_import, division, print_function
 
+import os
 import sys
 from distutils.ccompiler import new_compiler
 from distutils.dist import Distribution
@@ -11,6 +12,13 @@
 from cffi import FFI
 
 
+# Load the cryptography __about__ to get the current package version
+base_src = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+about = {}
+with open(os.path.join(base_src, "cryptography", "__about__.py")) as f:
+    exec(f.read(), about)
+
+
 def build_ffi_for_binding(module_name, module_prefix, modules, libraries=[],
                           extra_compile_args=[], extra_link_args=[]):
     """
@@ -55,6 +63,11 @@
 def build_ffi(module_name, cdef_source, verify_source, libraries=[],
               extra_compile_args=[], extra_link_args=[]):
     ffi = FFI()
+    # Always add the CRYPTOGRAPHY_PACKAGE_VERSION to the shared object
+    cdef_source += "\nstatic const char *const CRYPTOGRAPHY_PACKAGE_VERSION;"
+    verify_source += '\n#define CRYPTOGRAPHY_PACKAGE_VERSION "{}"'.format(
+        about["__version__"]
+    )
     ffi.cdef(cdef_source)
     ffi.set_source(
         module_name,
diff --git a/src/cryptography/hazmat/bindings/openssl/binding.py b/src/cryptography/hazmat/bindings/openssl/binding.py
--- a/src/cryptography/hazmat/bindings/openssl/binding.py
+++ b/src/cryptography/hazmat/bindings/openssl/binding.py
@@ -9,6 +9,7 @@
 import types
 import warnings
 
+import cryptography
 from cryptography import utils
 from cryptography.exceptions import InternalError
 from cryptography.hazmat.bindings._openssl import ffi, lib
@@ -164,6 +165,29 @@
         )
 
 
+def _verify_package_version(version):
+    # Occasionally we run into situations where the version of the Python
+    # package does not match the version of the shared object that is loaded.
+    # This may occur in environments where multiple versions of cryptography
+    # are installed and available in the python path. To avoid errors cropping
+    # up later this code checks that the currently imported package and the
+    # shared object that were loaded have the same version and raise an
+    # ImportError if they do not
+    so_package_version = ffi.string(lib.CRYPTOGRAPHY_PACKAGE_VERSION)
+    if version.encode("ascii") != so_package_version:
+        raise ImportError(
+            "The version of cryptography does not match the loaded "
+            "shared object. This can happen if you have multiple copies of "
+            "cryptography installed in your Python path. Please try creating "
+            "a new virtual environment to resolve this issue. "
+            "Loaded python version: {}, shared object version: {}".format(
+                version, so_package_version
+            )
+        )
+
+
+_verify_package_version(cryptography.__version__)
+
 # OpenSSL is not thread safe until the locks are initialized. We call this
 # method in module scope so that it executes with the import lock. On
 # Pythons < 3.4 this import lock is a global lock, which can prevent a race

{"golden_diff": "diff --git a/src/_cffi_src/utils.py b/src/_cffi_src/utils.py\n--- a/src/_cffi_src/utils.py\n+++ b/src/_cffi_src/utils.py\n@@ -4,6 +4,7 @@\n \n from __future__ import absolute_import, division, print_function\n \n+import os\n import sys\n from distutils.ccompiler import new_compiler\n from distutils.dist import Distribution\n@@ -11,6 +12,13 @@\n from cffi import FFI\n \n \n+# Load the cryptography __about__ to get the current package version\n+base_src = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\n+about = {}\n+with open(os.path.join(base_src, \"cryptography\", \"__about__.py\")) as f:\n+    exec(f.read(), about)\n+\n+\n def build_ffi_for_binding(module_name, module_prefix, modules, libraries=[],\n                           extra_compile_args=[], extra_link_args=[]):\n     \"\"\"\n@@ -55,6 +63,11 @@\n def build_ffi(module_name, cdef_source, verify_source, libraries=[],\n               extra_compile_args=[], extra_link_args=[]):\n     ffi = FFI()\n+    # Always add the CRYPTOGRAPHY_PACKAGE_VERSION to the shared object\n+    cdef_source += \"\\nstatic const char *const CRYPTOGRAPHY_PACKAGE_VERSION;\"\n+    verify_source += '\\n#define CRYPTOGRAPHY_PACKAGE_VERSION \"{}\"'.format(\n+        about[\"__version__\"]\n+    )\n     ffi.cdef(cdef_source)\n     ffi.set_source(\n         module_name,\ndiff --git a/src/cryptography/hazmat/bindings/openssl/binding.py b/src/cryptography/hazmat/bindings/openssl/binding.py\n--- a/src/cryptography/hazmat/bindings/openssl/binding.py\n+++ b/src/cryptography/hazmat/bindings/openssl/binding.py\n@@ -9,6 +9,7 @@\n import types\n import warnings\n \n+import cryptography\n from cryptography import utils\n from cryptography.exceptions import InternalError\n from cryptography.hazmat.bindings._openssl import ffi, lib\n@@ -164,6 +165,29 @@\n         )\n \n \n+def _verify_package_version(version):\n+    # Occasionally we run into situations where the version of the Python\n+    # package does not match the version of the shared object that is loaded.\n+    # This may occur in environments where multiple versions of cryptography\n+    # are installed and available in the python path. To avoid errors cropping\n+    # up later this code checks that the currently imported package and the\n+    # shared object that were loaded have the same version and raise an\n+    # ImportError if they do not\n+    so_package_version = ffi.string(lib.CRYPTOGRAPHY_PACKAGE_VERSION)\n+    if version.encode(\"ascii\") != so_package_version:\n+        raise ImportError(\n+            \"The version of cryptography does not match the loaded \"\n+            \"shared object. This can happen if you have multiple copies of \"\n+            \"cryptography installed in your Python path. Please try creating \"\n+            \"a new virtual environment to resolve this issue. \"\n+            \"Loaded python version: {}, shared object version: {}\".format(\n+                version, so_package_version\n+            )\n+        )\n+\n+\n+_verify_package_version(cryptography.__version__)\n+\n # OpenSSL is not thread safe until the locks are initialized. We call this\n # method in module scope so that it executes with the import lock. On\n # Pythons < 3.4 this import lock is a global lock, which can prevent a race\n", "issue": "Encode package version as a shared object symbol\nOne of the more common issues we see with users is an `AttributeError` where one of our `Cryptograpy_HAS_*` can't be found. This is pretty much always an issue where Python has loaded a newer version of cryptography's Python code, but for some reason loads an older shared object (which does not have the symbol the Python code is looking for).\r\n\r\nThis is a bad error message for a serious environment problem, and it doesn't always happen immediately. We should encode the version of cryptography in the shared object we build and then raise an `ImportError` on import if the shared object version and cryptography's version do not match.\r\n\r\nrefs https://github.com/certbot/certbot/issues/5651\n", "before_files": [{"content": "# This file is dual licensed under the terms of the Apache License, Version\n# 2.0, and the BSD License. See the LICENSE file in the root of this repository\n# for complete details.\n\nfrom __future__ import absolute_import, division, print_function\n\nimport collections\nimport threading\nimport types\nimport warnings\n\nfrom cryptography import utils\nfrom cryptography.exceptions import InternalError\nfrom cryptography.hazmat.bindings._openssl import ffi, lib\nfrom cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES\n\n_OpenSSLErrorWithText = collections.namedtuple(\n    \"_OpenSSLErrorWithText\", [\"code\", \"lib\", \"func\", \"reason\", \"reason_text\"]\n)\n\n\nclass _OpenSSLError(object):\n    def __init__(self, code, lib, func, reason):\n        self._code = code\n        self._lib = lib\n        self._func = func\n        self._reason = reason\n\n    def _lib_reason_match(self, lib, reason):\n        return lib == self.lib and reason == self.reason\n\n    code = utils.read_only_property(\"_code\")\n    lib = utils.read_only_property(\"_lib\")\n    func = utils.read_only_property(\"_func\")\n    reason = utils.read_only_property(\"_reason\")\n\n\ndef _consume_errors(lib):\n    errors = []\n    while True:\n        code = lib.ERR_get_error()\n        if code == 0:\n            break\n\n        err_lib = lib.ERR_GET_LIB(code)\n        err_func = lib.ERR_GET_FUNC(code)\n        err_reason = lib.ERR_GET_REASON(code)\n\n        errors.append(_OpenSSLError(code, err_lib, err_func, err_reason))\n\n    return errors\n\n\ndef _openssl_assert(lib, ok):\n    if not ok:\n        errors = _consume_errors(lib)\n        errors_with_text = []\n        for err in errors:\n            buf = ffi.new(\"char[]\", 256)\n            lib.ERR_error_string_n(err.code, buf, len(buf))\n            err_text_reason = ffi.string(buf)\n\n            errors_with_text.append(\n                _OpenSSLErrorWithText(\n                    err.code, err.lib, err.func, err.reason, err_text_reason\n                )\n            )\n\n        raise InternalError(\n            \"Unknown OpenSSL error. This error is commonly encountered when \"\n            \"another library is not cleaning up the OpenSSL error stack. If \"\n            \"you are using cryptography with another library that uses \"\n            \"OpenSSL try disabling it before reporting a bug. Otherwise \"\n            \"please file an issue at https://github.com/pyca/cryptography/\"\n            \"issues with information on how to reproduce \"\n            \"this. ({0!r})\".format(errors_with_text),\n            errors_with_text\n        )\n\n\ndef build_conditional_library(lib, conditional_names):\n    conditional_lib = types.ModuleType(\"lib\")\n    conditional_lib._original_lib = lib\n    excluded_names = set()\n    for condition, names_cb in conditional_names.items():\n        if not getattr(lib, condition):\n            excluded_names.update(names_cb())\n\n    for attr in dir(lib):\n        if attr not in excluded_names:\n            setattr(conditional_lib, attr, getattr(lib, attr))\n\n    return conditional_lib\n\n\nclass Binding(object):\n    \"\"\"\n    OpenSSL API wrapper.\n    \"\"\"\n    lib = None\n    ffi = ffi\n    _lib_loaded = False\n    _init_lock = threading.Lock()\n    _lock_init_lock = threading.Lock()\n\n    def __init__(self):\n        self._ensure_ffi_initialized()\n\n    @classmethod\n    def _register_osrandom_engine(cls):\n        # Clear any errors extant in the queue before we start. In many\n        # scenarios other things may be interacting with OpenSSL in the same\n        # process space and it has proven untenable to assume that they will\n        # reliably clear the error queue. Once we clear it here we will\n        # error on any subsequent unexpected item in the stack.\n        cls.lib.ERR_clear_error()\n        cls._osrandom_engine_id = cls.lib.Cryptography_osrandom_engine_id\n        cls._osrandom_engine_name = cls.lib.Cryptography_osrandom_engine_name\n        result = cls.lib.Cryptography_add_osrandom_engine()\n        _openssl_assert(cls.lib, result in (1, 2))\n\n    @classmethod\n    def _ensure_ffi_initialized(cls):\n        with cls._init_lock:\n            if not cls._lib_loaded:\n                cls.lib = build_conditional_library(lib, CONDITIONAL_NAMES)\n                cls._lib_loaded = True\n                # initialize the SSL library\n                cls.lib.SSL_library_init()\n                # adds all ciphers/digests for EVP\n                cls.lib.OpenSSL_add_all_algorithms()\n                # loads error strings for libcrypto and libssl functions\n                cls.lib.SSL_load_error_strings()\n                cls._register_osrandom_engine()\n\n    @classmethod\n    def init_static_locks(cls):\n        with cls._lock_init_lock:\n            cls._ensure_ffi_initialized()\n            # Use Python's implementation if available, importing _ssl triggers\n            # the setup for this.\n            __import__(\"_ssl\")\n\n            if (not cls.lib.Cryptography_HAS_LOCKING_CALLBACKS or\n                    cls.lib.CRYPTO_get_locking_callback() != cls.ffi.NULL):\n                return\n\n            # If nothing else has setup a locking callback already, we set up\n            # our own\n            res = lib.Cryptography_setup_ssl_threads()\n            _openssl_assert(cls.lib, res == 1)\n\n\ndef _verify_openssl_version(lib):\n    if (\n        lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 and\n        not lib.CRYPTOGRAPHY_IS_LIBRESSL\n    ):\n        warnings.warn(\n            \"OpenSSL version 1.0.1 is no longer supported by the OpenSSL \"\n            \"project, please upgrade. A future version of cryptography will \"\n            \"drop support for it.\",\n            utils.CryptographyDeprecationWarning\n        )\n\n\n# OpenSSL is not thread safe until the locks are initialized. We call this\n# method in module scope so that it executes with the import lock. On\n# Pythons < 3.4 this import lock is a global lock, which can prevent a race\n# condition registering the OpenSSL locks. On Python 3.4+ the import lock\n# is per module so this approach will not work.\nBinding.init_static_locks()\n\n_verify_openssl_version(Binding.lib)\n", "path": "src/cryptography/hazmat/bindings/openssl/binding.py"}, {"content": "# This file is dual licensed under the terms of the Apache License, Version\n# 2.0, and the BSD License. See the LICENSE file in the root of this repository\n# for complete details.\n\nfrom __future__ import absolute_import, division, print_function\n\nimport sys\nfrom distutils.ccompiler import new_compiler\nfrom distutils.dist import Distribution\n\nfrom cffi import FFI\n\n\ndef build_ffi_for_binding(module_name, module_prefix, modules, libraries=[],\n                          extra_compile_args=[], extra_link_args=[]):\n    \"\"\"\n    Modules listed in ``modules`` should have the following attributes:\n\n    * ``INCLUDES``: A string containing C includes.\n    * ``TYPES``: A string containing C declarations for types.\n    * ``FUNCTIONS``: A string containing C declarations for functions & macros.\n    * ``CUSTOMIZATIONS``: A string containing arbitrary top-level C code, this\n        can be used to do things like test for a define and provide an\n        alternate implementation based on that.\n    \"\"\"\n    types = []\n    includes = []\n    functions = []\n    customizations = []\n    for name in modules:\n        __import__(module_prefix + name)\n        module = sys.modules[module_prefix + name]\n\n        types.append(module.TYPES)\n        functions.append(module.FUNCTIONS)\n        includes.append(module.INCLUDES)\n        customizations.append(module.CUSTOMIZATIONS)\n\n    verify_source = \"\\n\".join(\n        includes +\n        customizations\n    )\n    ffi = build_ffi(\n        module_name,\n        cdef_source=\"\\n\".join(types + functions),\n        verify_source=verify_source,\n        libraries=libraries,\n        extra_compile_args=extra_compile_args,\n        extra_link_args=extra_link_args,\n    )\n\n    return ffi\n\n\ndef build_ffi(module_name, cdef_source, verify_source, libraries=[],\n              extra_compile_args=[], extra_link_args=[]):\n    ffi = FFI()\n    ffi.cdef(cdef_source)\n    ffi.set_source(\n        module_name,\n        verify_source,\n        libraries=libraries,\n        extra_compile_args=extra_compile_args,\n        extra_link_args=extra_link_args,\n    )\n    return ffi\n\n\ndef extra_link_args(compiler_type):\n    if compiler_type == 'msvc':\n        # Enable NX and ASLR for Windows builds on MSVC. These are enabled by\n        # default on Python 3.3+ but not on 2.x.\n        return ['/NXCOMPAT', '/DYNAMICBASE']\n    else:\n        return []\n\n\ndef compiler_type():\n    \"\"\"\n    Gets the compiler type from distutils. On Windows with MSVC it will be\n    \"msvc\". On macOS and linux it is \"unix\".\n    \"\"\"\n    dist = Distribution()\n    dist.parse_config_files()\n    cmd = dist.get_command_obj('build')\n    cmd.ensure_finalized()\n    compiler = new_compiler(compiler=cmd.compiler)\n    return compiler.compiler_type\n", "path": "src/_cffi_src/utils.py"}], "after_files": [{"content": "# This file is dual licensed under the terms of the Apache License, Version\n# 2.0, and the BSD License. See the LICENSE file in the root of this repository\n# for complete details.\n\nfrom __future__ import absolute_import, division, print_function\n\nimport collections\nimport threading\nimport types\nimport warnings\n\nimport cryptography\nfrom cryptography import utils\nfrom cryptography.exceptions import InternalError\nfrom cryptography.hazmat.bindings._openssl import ffi, lib\nfrom cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES\n\n_OpenSSLErrorWithText = collections.namedtuple(\n    \"_OpenSSLErrorWithText\", [\"code\", \"lib\", \"func\", \"reason\", \"reason_text\"]\n)\n\n\nclass _OpenSSLError(object):\n    def __init__(self, code, lib, func, reason):\n        self._code = code\n        self._lib = lib\n        self._func = func\n        self._reason = reason\n\n    def _lib_reason_match(self, lib, reason):\n        return lib == self.lib and reason == self.reason\n\n    code = utils.read_only_property(\"_code\")\n    lib = utils.read_only_property(\"_lib\")\n    func = utils.read_only_property(\"_func\")\n    reason = utils.read_only_property(\"_reason\")\n\n\ndef _consume_errors(lib):\n    errors = []\n    while True:\n        code = lib.ERR_get_error()\n        if code == 0:\n            break\n\n        err_lib = lib.ERR_GET_LIB(code)\n        err_func = lib.ERR_GET_FUNC(code)\n        err_reason = lib.ERR_GET_REASON(code)\n\n        errors.append(_OpenSSLError(code, err_lib, err_func, err_reason))\n\n    return errors\n\n\ndef _openssl_assert(lib, ok):\n    if not ok:\n        errors = _consume_errors(lib)\n        errors_with_text = []\n        for err in errors:\n            buf = ffi.new(\"char[]\", 256)\n            lib.ERR_error_string_n(err.code, buf, len(buf))\n            err_text_reason = ffi.string(buf)\n\n            errors_with_text.append(\n                _OpenSSLErrorWithText(\n                    err.code, err.lib, err.func, err.reason, err_text_reason\n                )\n            )\n\n        raise InternalError(\n            \"Unknown OpenSSL error. This error is commonly encountered when \"\n            \"another library is not cleaning up the OpenSSL error stack. If \"\n            \"you are using cryptography with another library that uses \"\n            \"OpenSSL try disabling it before reporting a bug. Otherwise \"\n            \"please file an issue at https://github.com/pyca/cryptography/\"\n            \"issues with information on how to reproduce \"\n            \"this. ({0!r})\".format(errors_with_text),\n            errors_with_text\n        )\n\n\ndef build_conditional_library(lib, conditional_names):\n    conditional_lib = types.ModuleType(\"lib\")\n    conditional_lib._original_lib = lib\n    excluded_names = set()\n    for condition, names_cb in conditional_names.items():\n        if not getattr(lib, condition):\n            excluded_names.update(names_cb())\n\n    for attr in dir(lib):\n        if attr not in excluded_names:\n            setattr(conditional_lib, attr, getattr(lib, attr))\n\n    return conditional_lib\n\n\nclass Binding(object):\n    \"\"\"\n    OpenSSL API wrapper.\n    \"\"\"\n    lib = None\n    ffi = ffi\n    _lib_loaded = False\n    _init_lock = threading.Lock()\n    _lock_init_lock = threading.Lock()\n\n    def __init__(self):\n        self._ensure_ffi_initialized()\n\n    @classmethod\n    def _register_osrandom_engine(cls):\n        # Clear any errors extant in the queue before we start. In many\n        # scenarios other things may be interacting with OpenSSL in the same\n        # process space and it has proven untenable to assume that they will\n        # reliably clear the error queue. Once we clear it here we will\n        # error on any subsequent unexpected item in the stack.\n        cls.lib.ERR_clear_error()\n        cls._osrandom_engine_id = cls.lib.Cryptography_osrandom_engine_id\n        cls._osrandom_engine_name = cls.lib.Cryptography_osrandom_engine_name\n        result = cls.lib.Cryptography_add_osrandom_engine()\n        _openssl_assert(cls.lib, result in (1, 2))\n\n    @classmethod\n    def _ensure_ffi_initialized(cls):\n        with cls._init_lock:\n            if not cls._lib_loaded:\n                cls.lib = build_conditional_library(lib, CONDITIONAL_NAMES)\n                cls._lib_loaded = True\n                # initialize the SSL library\n                cls.lib.SSL_library_init()\n                # adds all ciphers/digests for EVP\n                cls.lib.OpenSSL_add_all_algorithms()\n                # loads error strings for libcrypto and libssl functions\n                cls.lib.SSL_load_error_strings()\n                cls._register_osrandom_engine()\n\n    @classmethod\n    def init_static_locks(cls):\n        with cls._lock_init_lock:\n            cls._ensure_ffi_initialized()\n            # Use Python's implementation if available, importing _ssl triggers\n            # the setup for this.\n            __import__(\"_ssl\")\n\n            if (not cls.lib.Cryptography_HAS_LOCKING_CALLBACKS or\n                    cls.lib.CRYPTO_get_locking_callback() != cls.ffi.NULL):\n                return\n\n            # If nothing else has setup a locking callback already, we set up\n            # our own\n            res = lib.Cryptography_setup_ssl_threads()\n            _openssl_assert(cls.lib, res == 1)\n\n\ndef _verify_openssl_version(lib):\n    if (\n        lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 and\n        not lib.CRYPTOGRAPHY_IS_LIBRESSL\n    ):\n        warnings.warn(\n            \"OpenSSL version 1.0.1 is no longer supported by the OpenSSL \"\n            \"project, please upgrade. A future version of cryptography will \"\n            \"drop support for it.\",\n            utils.CryptographyDeprecationWarning\n        )\n\n\ndef _verify_package_version(version):\n    # Occasionally we run into situations where the version of the Python\n    # package does not match the version of the shared object that is loaded.\n    # This may occur in environments where multiple versions of cryptography\n    # are installed and available in the python path. To avoid errors cropping\n    # up later this code checks that the currently imported package and the\n    # shared object that were loaded have the same version and raise an\n    # ImportError if they do not\n    so_package_version = ffi.string(lib.CRYPTOGRAPHY_PACKAGE_VERSION)\n    if version.encode(\"ascii\") != so_package_version:\n        raise ImportError(\n            \"The version of cryptography does not match the loaded \"\n            \"shared object. This can happen if you have multiple copies of \"\n            \"cryptography installed in your Python path. Please try creating \"\n            \"a new virtual environment to resolve this issue. \"\n            \"Loaded python version: {}, shared object version: {}\".format(\n                version, so_package_version\n            )\n        )\n\n\n_verify_package_version(cryptography.__version__)\n\n# OpenSSL is not thread safe until the locks are initialized. We call this\n# method in module scope so that it executes with the import lock. On\n# Pythons < 3.4 this import lock is a global lock, which can prevent a race\n# condition registering the OpenSSL locks. On Python 3.4+ the import lock\n# is per module so this approach will not work.\nBinding.init_static_locks()\n\n_verify_openssl_version(Binding.lib)\n", "path": "src/cryptography/hazmat/bindings/openssl/binding.py"}, {"content": "# This file is dual licensed under the terms of the Apache License, Version\n# 2.0, and the BSD License. See the LICENSE file in the root of this repository\n# for complete details.\n\nfrom __future__ import absolute_import, division, print_function\n\nimport os\nimport sys\nfrom distutils.ccompiler import new_compiler\nfrom distutils.dist import Distribution\n\nfrom cffi import FFI\n\n\n# Load the cryptography __about__ to get the current package version\nbase_src = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\nabout = {}\nwith open(os.path.join(base_src, \"cryptography\", \"__about__.py\")) as f:\n    exec(f.read(), about)\n\n\ndef build_ffi_for_binding(module_name, module_prefix, modules, libraries=[],\n                          extra_compile_args=[], extra_link_args=[]):\n    \"\"\"\n    Modules listed in ``modules`` should have the following attributes:\n\n    * ``INCLUDES``: A string containing C includes.\n    * ``TYPES``: A string containing C declarations for types.\n    * ``FUNCTIONS``: A string containing C declarations for functions & macros.\n    * ``CUSTOMIZATIONS``: A string containing arbitrary top-level C code, this\n        can be used to do things like test for a define and provide an\n        alternate implementation based on that.\n    \"\"\"\n    types = []\n    includes = []\n    functions = []\n    customizations = []\n    for name in modules:\n        __import__(module_prefix + name)\n        module = sys.modules[module_prefix + name]\n\n        types.append(module.TYPES)\n        functions.append(module.FUNCTIONS)\n        includes.append(module.INCLUDES)\n        customizations.append(module.CUSTOMIZATIONS)\n\n    verify_source = \"\\n\".join(\n        includes +\n        customizations\n    )\n    ffi = build_ffi(\n        module_name,\n        cdef_source=\"\\n\".join(types + functions),\n        verify_source=verify_source,\n        libraries=libraries,\n        extra_compile_args=extra_compile_args,\n        extra_link_args=extra_link_args,\n    )\n\n    return ffi\n\n\ndef build_ffi(module_name, cdef_source, verify_source, libraries=[],\n              extra_compile_args=[], extra_link_args=[]):\n    ffi = FFI()\n    # Always add the CRYPTOGRAPHY_PACKAGE_VERSION to the shared object\n    cdef_source += \"\\nstatic const char *const CRYPTOGRAPHY_PACKAGE_VERSION;\"\n    verify_source += '\\n#define CRYPTOGRAPHY_PACKAGE_VERSION \"{}\"'.format(\n        about[\"__version__\"]\n    )\n    ffi.cdef(cdef_source)\n    ffi.set_source(\n        module_name,\n        verify_source,\n        libraries=libraries,\n        extra_compile_args=extra_compile_args,\n        extra_link_args=extra_link_args,\n    )\n    return ffi\n\n\ndef extra_link_args(compiler_type):\n    if compiler_type == 'msvc':\n        # Enable NX and ASLR for Windows builds on MSVC. These are enabled by\n        # default on Python 3.3+ but not on 2.x.\n        return ['/NXCOMPAT', '/DYNAMICBASE']\n    else:\n        return []\n\n\ndef compiler_type():\n    \"\"\"\n    Gets the compiler type from distutils. On Windows with MSVC it will be\n    \"msvc\". On macOS and linux it is \"unix\".\n    \"\"\"\n    dist = Distribution()\n    dist.parse_config_files()\n    cmd = dist.get_command_obj('build')\n    cmd.ensure_finalized()\n    compiler = new_compiler(compiler=cmd.compiler)\n    return compiler.compiler_type\n", "path": "src/_cffi_src/utils.py"}]}