Skip to content

Cygwin: system sqlite3 modifies DLL search order #30157

@embray

Description

@embray

Under normal operation Windows searches for DLLs in the following order:

  1. In the same directory as the main executable.
  2. In various standard system directories.
  3. Search $PATH.

On Cygwin, most DLLs are stored under /usr/bin, which is inserted early on the $PATH, but when in the Sage environment $SAGE_LOCAL/bin supersedes it.

However, I discovered that the Cygwin port of sqlite3 contains the following nasty patch, for reasons I can't be sure of:

@@ -47710,13 +48357,52 @@ SQLITE_API int sqlite3_os_init(void){
   assert( winSysInfo.dwAllocationGranularity>0 );
   assert( winSysInfo.dwPageSize>0 );

+#ifdef _WIN32
+  module = osGetModuleHandleW(L"CYGWIN1.DLL");
+  if( !module ){
+    module = osGetModuleHandleW(L"MSYS-2.0.DLL");
+  }
+  if( !module ){
+    module = osGetModuleHandleW(L"MSYS-1.0.DLL");
+  }
+  if( module ){
+    for( i=81; i<ArraySize(aSyscall); ++i ){
+        aSyscall[i].pCurrent = (SYSCALL) osGetProcAddressA(module,
+            aSyscall[i].zName);
+    }
+  }
+#endif
+
+#if SQLITE_OS_UNIX
+  sqlite3_os_unix_init();
+#endif
+
   sqlite3_vfs_register(&winVfs, 1);

+#if !defined(SQLITE_OMIT_LOAD_EXTENSION)
+  if( cygwin_conv_path ){
+    WCHAR buf[MAX_PATH];
+    cygwin_conv_path(CCP_POSIX_TO_WIN_W, "/usr/bin",
+        buf, MAX_PATH*sizeof(WCHAR));
+    osSetDllDirectoryW(buf);
+#ifdef _WIN32
+  }else if( cygwin_conv_to_full_win32_path ){
+    WCHAR buf[MAX_PATH];
+    char *buf1 = (char *)buf;
+    int i = MAX_PATH;
+    cygwin_conv_to_full_win32_path("/usr/bin", buf1);
+    while(--i>=0) buf[i] = buf1[i];
+    osSetDllDirectoryW(buf);
+#endif
+  }
+#endif
+
 #if defined(SQLITE_WIN32_HAS_WIDE)
   sqlite3_vfs_register(&winLongPathVfs, 0);
 #endif

The function SetDllDirectoryW is a system function which works a little like LD_LIBRARY_PATH or LD_PRELOAD allowing an application to insert a non-standard directory into the DLL search path.

Why sqlite3 is doing this I don't know. It has something to do with loading extensions apparently, but there's no reason it should assume I always want to load extensions from /usr/bin (e.g. what if I'm using a custom build of sqlite3 installed in /usr/local/bin.

It does this also when the library is first initialized, as opposed to just doing it before loading an extension and then unsetting it. Thus this change to DLL loading behavior affects the rest of the application for the lifetime of the application. It does get undone if sqlite3_shutdown() is called but this never happens normally.

How does this affect Sage? It's not even obvious that Sage uses sqlite3, but in fact IPython does to store its history, so a sqlite3 database is connected to when starting up the Sage/IPython REPL. This in turn impacts DLL search order for all libraries that haven't been loaded yet, and can cause Cygwin's system versions of those libraries to be privileged over any copies in Sage.

I think this might actually explain some related bugs I've seen in the past, but I'm not sure.

Component: porting: Cygwin

Author: Erik Bray

Branch: 628e7d0

Reviewer: Matthias Koeppe

Issue created by migration from https://trac.sagemath.org/ticket/30157

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions