Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
Trac #30157: Undo sqlite3's munging of DLL search paths
Browse files Browse the repository at this point in the history
Includes a Cython function specifically targeted to fixing the sqlite3
issue, and adds a monkey-patching at sage import time which wraps
sqlite3.connect (the first place where the issue that causes this
is invoked) to call the workaround function.
  • Loading branch information
embray committed Jul 16, 2020
1 parent 467fbc7 commit 628e7d0
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 2 deletions.
7 changes: 5 additions & 2 deletions src/module_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,9 @@
################################

Extension('*', ['sage/misc/*.pyx']),
Extension('sage.misc.sage_ostools',
sources = ['sage/misc/sage_ostools.pyx'],
libraries = ['sqlite3']),

################################
##
Expand Down Expand Up @@ -1120,10 +1123,10 @@

Extension('sage.rings.polynomial.ore_polynomial_element',
sources = ['sage/rings/polynomial/ore_polynomial_element.pyx']),

Extension('sage.rings.polynomial.skew_polynomial_element',
sources = ['sage/rings/polynomial/skew_polynomial_element.pyx']),

Extension('sage.rings.polynomial.skew_polynomial_finite_order',
sources = ['sage/rings/polynomial/skew_polynomial_finite_order.pyx']),

Expand Down
38 changes: 38 additions & 0 deletions src/sage/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# to many other Python packages.
from sage.version import version as __version__

import sys
# Make sure that the correct zlib library is loaded. This is needed
# to prevent the system zlib to be loaded instead of the Sage one.
# See https://trac.sagemath.org/ticket/23122
Expand Down Expand Up @@ -66,3 +67,40 @@ def isfunction(obj):
pass # Python 2
else:
del ExtensionFileLoader.get_source


# Work around a Cygwin-specific bug caused by sqlite3; see
# https://trac.sagemath.org/ticket/30157 and the docstring for
# fix_for_ticket_30157
# Here we monkey-patch the sqlite3 module to ensure the fix is
# applied the very first time a connection is made to a sqlite3
# database
if sys.platform == 'cygwin':
def patch_sqlite3():
try:
from sage.misc.sage_ostools import fix_for_ticket_30157
except ImportError:
# The module might not have been re-built yet; don't worry about it
# then
return

import sqlite3, functools
orig_sqlite3_connect = sqlite3.connect

@functools.wraps(orig_sqlite3_connect)
def connect(*args, **kwargs):
if fix_for_ticket_30157():
raise RuntimeError(
'patch for Trac ticket #30157 failed; please report this '
'bug to https://trac.sagemath.org')

# Undo the monkey-patch
try:
return orig_sqlite3_connect(*args, **kwargs)
finally:
sqlite3.connect = orig_sqlite3_connect

sqlite3.connect = connect

patch_sqlite3()
del patch_sqlite3
41 changes: 41 additions & 0 deletions src/sage/misc/sage_ostools.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ from cpython.exc cimport PyErr_SetFromErrno
import os
import contextlib


def have_program(program, path=None):
"""
Return ``True`` if a ``program`` executable is found in the path
Expand Down Expand Up @@ -302,3 +303,43 @@ cdef class redirection:
if self.close_dest:
self.dest_file.close()
self.dest_fd = -1


IF PY_PLATFORM == 'cygwin':
from libc.stddef cimport wchar_t

cdef extern from "Windows.h":
int SetDllDirectoryW(wchar_t* lpPathName)

cdef extern from "sqlite3.h":
int sqlite3_initialize()

def fix_for_ticket_30157():
"""
Cygwin-only workaround for an issue caused by the sqlite3 library. See
trac:`30157`.
The issue here is that when the sqlite3 library is first initialized
it modifies Windows' default DLL search path order, which can possibly
break the correct search path for subsequent DLL loads.
This workaround ensures that the sqlite3 library is initialized very
early on (this does not add any significant overhead) and then
immediately undoes its deleterious effects. In particular, calling
SetDllDirectoryW(NULL) restores the default DLL search path.
To be clear, there's no reason sqlite3 needs this to function
correctly; it's just a poorly-considered hack that attempted to work
around a problem that doesn't affect us.
Returns 0 if it succeeeds or a non-zero value if not.
"""

ret = sqlite3_initialize()

if ret != 0:
# Library initialization failed for some reason
return ret

# SetDllDirectory returns 1 if it succeeds.
return not SetDllDirectoryW(NULL)
1 change: 1 addition & 0 deletions src/sage_setup/command/sage_build_cython.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ def finalize_options(self):
self.compile_time_env = dict(
PY_VERSION_HEX=sys.hexversion,
PY_MAJOR_VERSION=sys.version_info[0],
PY_PLATFORM=sys.platform
)

# We check the Cython version and some relevant configuration
Expand Down

0 comments on commit 628e7d0

Please sign in to comment.