From 6a63c3bf47aa190138a696a1e524949eeba031c8 Mon Sep 17 00:00:00 2001
From: Alex Peshkoff <alexander.peshkoff@gmail.com>
Date: Fri, 7 Sep 2018 17:05:42 +0300
Subject: [PATCH] Backported CORE-5908: Enhance dynamic libraries loading
 related error messages

---
 src/common/os/darwin/mod_loader.cpp  | 13 +++++--
 src/common/os/mod_loader.h           | 14 +++----
 src/common/os/posix/mod_loader.cpp   | 17 ++++++---
 src/common/os/win32/mod_loader.cpp   |  9 ++++-
 src/common/unicode_util.cpp          |  6 +--
 src/jrd/IntlManager.cpp              |  9 +++--
 src/jrd/flu.cpp                      |  2 +-
 src/jrd/fun.epp                      |  2 +-
 src/plugins/udr_engine/UdrEngine.cpp | 55 +++++++++++++---------------
 src/remote/remote.cpp                |  2 +-
 src/yvalve/PluginManager.cpp         | 11 ++++--
 11 files changed, 79 insertions(+), 61 deletions(-)

diff --git a/src/common/os/darwin/mod_loader.cpp b/src/common/os/darwin/mod_loader.cpp
index b7b6acac09..1556d02cd6 100644
--- a/src/common/os/darwin/mod_loader.cpp
+++ b/src/common/os/darwin/mod_loader.cpp
@@ -87,14 +87,19 @@ void ModuleLoader::doctorModuleExtension(Firebird::PathName& name)
 #define FB_RTLD_MODE RTLD_LAZY
 #endif
 
-ModuleLoader::Module* ModuleLoader::loadModule(const Firebird::PathName& modPath)
+ModuleLoader::Module* ModuleLoader::loadModule(ISC_STATUS* status, const Firebird::PathName& modPath)
 {
 	void* module = dlopen(modPath.c_str(), FB_RTLD_MODE);
 	if (module == NULL)
 	{
-#ifdef DEBUG_LOADER
-		fprintf(stderr, "load error: %s: %s\n", modPath.c_str(), dlerror());
-#endif // DEBUG_LOADER
+		if (status)
+		{
+			status[0] = isc_arg_gds;
+			status[1] = isc_random;
+			status[2] = isc_arg_string;
+			status[3] = (ISC_STATUS) dlerror();
+			status[4] = isc_arg_end;
+		}
 		return 0;
 	}
 
diff --git a/src/common/os/mod_loader.h b/src/common/os/mod_loader.h
index b57af4ac9f..069ab23039 100644
--- a/src/common/os/mod_loader.h
+++ b/src/common/os/mod_loader.h
@@ -90,11 +90,11 @@ class ModuleLoader
 	/** loadModule is given as a string the path to the module to load.  It
 		attempts to load the module.  If successful it returns the ModuleLoader::Module
 		object that represents the loaded module in memory and can be used to
-		perform symbol lookups on the module.  If unsuccessful it returns NULL.
-		It is the callers responsibility to delete the returned module object
-		when it is no longer needed.
+		perform symbol lookups on the module. It is the callers responsibility to delete
+		the returned module object when it is no longer needed.
+		If unsuccessful it returns NULL. OS-specific error is returned in status parameter.
 	**/
-	static Module* loadModule(const Firebird::PathName&);
+	static Module* loadModule(ISC_STATUS* status, const Firebird::PathName&);
 
 	/** doctorModuleExtension modifies the given path name to add the platform
 		specific module extention.  This allows the user to provide the root name
@@ -107,14 +107,14 @@ class ModuleLoader
 	/** Almost like loadModule(), but in case of failure invokes doctorModuleExtension()
 		and retries.
 	**/
-	static Module* fixAndLoadModule(const Firebird::PathName& modName)
+	static Module* fixAndLoadModule(ISC_STATUS* status, const Firebird::PathName& modName)
 	{
-		Module* mod = loadModule(modName);
+		Module* mod = loadModule(NULL, modName);
 		if (!mod)
 		{
 			Firebird::PathName fixed(modName);
 			doctorModuleExtension(fixed);
-			mod = loadModule(fixed);
+			mod = loadModule(status, fixed);
 		}
 		return mod;
 	}
diff --git a/src/common/os/posix/mod_loader.cpp b/src/common/os/posix/mod_loader.cpp
index 2b42c59a5c..9c8ba38ddd 100644
--- a/src/common/os/posix/mod_loader.cpp
+++ b/src/common/os/posix/mod_loader.cpp
@@ -72,7 +72,9 @@ void ModuleLoader::doctorModuleExtension(Firebird::PathName& name)
 	Firebird::PathName::size_type pos = name.rfind("." SHRLIB_EXT);
 	if (pos != name.length() - 3)
 	{
-		name += "." SHRLIB_EXT;
+		pos = name.rfind("." SHRLIB_EXT ".");
+		if (pos == Firebird::PathName::npos)
+			name += "." SHRLIB_EXT;
 	}
 	pos = name.rfind('/');
 	pos = (pos == Firebird::PathName::npos) ? 0 : pos + 1;
@@ -88,14 +90,19 @@ void ModuleLoader::doctorModuleExtension(Firebird::PathName& name)
 #define FB_RTLD_MODE RTLD_LAZY	// save time when loading library
 #endif
 
-ModuleLoader::Module* ModuleLoader::loadModule(const Firebird::PathName& modPath)
+ModuleLoader::Module* ModuleLoader::loadModule(ISC_STATUS* status, const Firebird::PathName& modPath)
 {
 	void* module = dlopen(modPath.nullStr(), FB_RTLD_MODE);
 	if (module == NULL)
 	{
-#ifdef DEV_BUILD
-//		gds__log("loadModule failed loading %s: %s", modPath.c_str(), dlerror());
-#endif
+		if (status)
+		{
+			status[0] = isc_arg_gds;
+			status[1] = isc_random;
+			status[2] = isc_arg_string;
+			status[3] = (ISC_STATUS) dlerror();
+			status[4] = isc_arg_end;
+		}
 		return 0;
 	}
 
diff --git a/src/common/os/win32/mod_loader.cpp b/src/common/os/win32/mod_loader.cpp
index 909de85026..2ffdbdfbeb 100644
--- a/src/common/os/win32/mod_loader.cpp
+++ b/src/common/os/win32/mod_loader.cpp
@@ -191,7 +191,7 @@ void ModuleLoader::doctorModuleExtension(PathName& name)
 	name += ".dll";
 }
 
-ModuleLoader::Module* ModuleLoader::loadModule(const PathName& modPath)
+ModuleLoader::Module* ModuleLoader::loadModule(ISC_STATUS* status, const PathName& modPath)
 {
 	ContextActivator ctx;
 
@@ -214,6 +214,13 @@ ModuleLoader::Module* ModuleLoader::loadModule(const PathName& modPath)
 	if (!module)
 		module = LoadLibraryEx(modPath.c_str(), 0, LOAD_WITH_ALTERED_SEARCH_PATH);
 
+	if (!module && status)
+	{
+		status[0] = isc_arg_win32;
+		status[1] = GetLastError();
+		status[2] = isc_arg_end;
+	}
+
 	// Restore old mode in case we are embedded into user application
 	SetErrorMode(oldErrorMode);
 
diff --git a/src/common/unicode_util.cpp b/src/common/unicode_util.cpp
index 1850ea2e96..a33f495910 100644
--- a/src/common/unicode_util.cpp
+++ b/src/common/unicode_util.cpp
@@ -233,7 +233,7 @@ class ImplementConversionICU : public UnicodeUtil::ConversionICU, BaseICU
 		PathName filename;
 		formatFilename(filename, ucTemplate, aMajorVersion, aMinorVersion);
 
-		module = ModuleLoader::fixAndLoadModule(filename);
+		module = ModuleLoader::fixAndLoadModule(NULL, filename);
 		if (!module)
 			return;
 
@@ -998,7 +998,7 @@ UnicodeUtil::ICU* UnicodeUtil::loadICU(const string& icuVersion, const string& c
 
 		icu = FB_NEW_POOL(*getDefaultMemoryPool()) ICU(majorVersion, minorVersion);
 
-		icu->ucModule = ModuleLoader::fixAndLoadModule(filename);
+		icu->ucModule = ModuleLoader::fixAndLoadModule(NULL, filename);
 
 		if (!icu->ucModule)
 		{
@@ -1009,7 +1009,7 @@ UnicodeUtil::ICU* UnicodeUtil::loadICU(const string& icuVersion, const string& c
 
 		formatFilename(filename, inTemplate, majorVersion, minorVersion);
 
-		icu->inModule = ModuleLoader::fixAndLoadModule(filename);
+		icu->inModule = ModuleLoader::fixAndLoadModule(NULL, filename);
 
 		if (!icu->inModule)
 		{
diff --git a/src/jrd/IntlManager.cpp b/src/jrd/IntlManager.cpp
index b3e37afb61..4c8368ed22 100644
--- a/src/jrd/IntlManager.cpp
+++ b/src/jrd/IntlManager.cpp
@@ -471,15 +471,16 @@ bool IntlManager::initialize()
 					ModuleLoader::Module* mod = NULL;
 					bool exists = modules->exist(filename);
 
+					ISC_STATUS_ARRAY status;
 					if (!exists)
 					{
-						mod = ModuleLoader::loadModule(filename);
+						mod = ModuleLoader::loadModule(status, filename);
 						if (!mod)
 						{
 							ModuleLoader::doctorModuleExtension(filename);
 							exists = modules->exist(filename);
 							if (!exists)
-								mod = ModuleLoader::loadModule(filename);
+								mod = ModuleLoader::loadModule(status, filename);
 						}
 					}
 
@@ -512,8 +513,8 @@ bool IntlManager::initialize()
 						}
 						else
 						{
-							gds__log((string("Can't load INTL module '") +
-								filename.c_str() + "'").c_str());
+							iscLogStatus((string("Can't load INTL module '") +
+								filename.c_str() + "'").c_str(), status);
 							ok = false;
 						}
 					}
diff --git a/src/jrd/flu.cpp b/src/jrd/flu.cpp
index c0b9c453a0..e8a5bd7878 100644
--- a/src/jrd/flu.cpp
+++ b/src/jrd/flu.cpp
@@ -245,7 +245,7 @@ namespace Jrd
 															 Arg::Str(initialModule));
 			}
 
-			ModuleLoader::Module* mlm = ModuleLoader::loadModule(fixedModule);
+			ModuleLoader::Module* mlm = ModuleLoader::loadModule(NULL, fixedModule);
 			if (mlm)
 			{
 				im = FB_NEW_POOL(*getDefaultMemoryPool())
diff --git a/src/jrd/fun.epp b/src/jrd/fun.epp
index ca964be72b..44fd5dde67 100644
--- a/src/jrd/fun.epp
+++ b/src/jrd/fun.epp
@@ -105,7 +105,7 @@ namespace
 	{
 		ModuleLoader::doctorModuleExtension(libName);
 
-		ModuleLoader::Module* module = ModuleLoader::loadModule(libName);
+		ModuleLoader::Module* module = ModuleLoader::loadModule(NULL, libName);
 		if (!module)
 		{
 			message.printf("%s library has not been found", libName.c_str());
diff --git a/src/plugins/udr_engine/UdrEngine.cpp b/src/plugins/udr_engine/UdrEngine.cpp
index 9c64ebee9a..a49ecf4120 100644
--- a/src/plugins/udr_engine/UdrEngine.cpp
+++ b/src/plugins/udr_engine/UdrEngine.cpp
@@ -567,47 +567,42 @@ UdrPluginImpl* Engine::loadModule(ThrowStatusWrapper* status, IRoutineMetadata*
 		PathName path;
 		PathUtils::concatPath(path, *i, *moduleName);
 
-		ModuleLoader::Module* module = ModuleLoader::fixAndLoadModule(path);
-
-		if (module)
-		{
-			FB_BOOLEAN* (*entryPoint)(IStatus*, FB_BOOLEAN*, IUdrPlugin*);
-
-			if (!module->findSymbol(STRINGIZE(FB_UDR_PLUGIN_ENTRY_POINT), entryPoint))
-			{
-				static const ISC_STATUS statusVector[] = {
-					isc_arg_gds, isc_random,
-					isc_arg_string, (ISC_STATUS) "UDR plugin entry point not found",
-					isc_arg_end
-				};
+		static ISC_STATUS_ARRAY statusArray = {
+			isc_arg_gds, isc_random,
+			isc_arg_string, (ISC_STATUS) "UDR module not loaded",
+			isc_arg_end
+		};
+		const unsigned ARG_END = 4;
 
-				throw FbException(status, statusVector);
-			}
+		ModuleLoader::Module* module = ModuleLoader::fixAndLoadModule(&statusArray[ARG_END], path);
+		if (!module)
+			throw FbException(status, statusArray);
 
-			UdrPluginImpl* udrPlugin = FB_NEW UdrPluginImpl(*moduleName, module);
-			udrPlugin->theirUnloadFlag = entryPoint(status, &udrPlugin->myUnloadFlag, udrPlugin);
+		FB_BOOLEAN* (*entryPoint)(IStatus*, FB_BOOLEAN*, IUdrPlugin*);
 
-			if (status->getState() & IStatus::STATE_ERRORS)
-			{
-				delete udrPlugin;
-				ThrowStatusWrapper::checkException(status);
-			}
-
-			modules->put(*moduleName, udrPlugin);
-
-			return udrPlugin;
-		}
-		else
+		if (!module->findSymbol(STRINGIZE(FB_UDR_PLUGIN_ENTRY_POINT), entryPoint))
 		{
 			static const ISC_STATUS statusVector[] = {
 				isc_arg_gds, isc_random,
-				isc_arg_string, (ISC_STATUS) "Module not found",
-				//// TODO: isc_arg_gds, isc_random, isc_arg_string, (ISC_STATUS) moduleName->c_str(),
+				isc_arg_string, (ISC_STATUS) "UDR plugin entry point not found",
 				isc_arg_end
 			};
 
 			throw FbException(status, statusVector);
 		}
+
+		UdrPluginImpl* udrPlugin = FB_NEW UdrPluginImpl(*moduleName, module);
+		udrPlugin->theirUnloadFlag = entryPoint(status, &udrPlugin->myUnloadFlag, udrPlugin);
+
+		if (status->getState() & IStatus::STATE_ERRORS)
+		{
+			delete udrPlugin;
+			ThrowStatusWrapper::checkException(status);
+		}
+
+		modules->put(*moduleName, udrPlugin);
+
+		return udrPlugin;
 	}
 
 	static const ISC_STATUS statusVector[] = {
diff --git a/src/remote/remote.cpp b/src/remote/remote.cpp
index 9b99080c0c..dc2bc0c9bc 100644
--- a/src/remote/remote.cpp
+++ b/src/remote/remote.cpp
@@ -1335,7 +1335,7 @@ namespace {
 #else
 			const char* name = "libz." SHRLIB_EXT ".1";
 #endif
-			z.reset(ModuleLoader::fixAndLoadModule(name));
+			z.reset(ModuleLoader::fixAndLoadModule(NULL, name));
 			if (z)
 				symbols();
 		}
diff --git a/src/yvalve/PluginManager.cpp b/src/yvalve/PluginManager.cpp
index b0067a0c36..2875f62983 100644
--- a/src/yvalve/PluginManager.cpp
+++ b/src/yvalve/PluginManager.cpp
@@ -928,24 +928,27 @@ namespace
 	RefPtr<PluginModule> PluginSet::loadModule(const PluginLoadInfo& info)
 	{
 		PathName fixedModuleName(info.curModule);
+		ISC_STATUS_ARRAY statusArray;
 
-		ModuleLoader::Module* module = ModuleLoader::loadModule(fixedModuleName);
+		ModuleLoader::Module* module = ModuleLoader::loadModule(statusArray, fixedModuleName);
 
 		if (!module && !ModuleLoader::isLoadableModule(fixedModuleName))
 		{
 			ModuleLoader::doctorModuleExtension(fixedModuleName);
-			module = ModuleLoader::loadModule(fixedModuleName);
+			module = ModuleLoader::loadModule(statusArray, fixedModuleName);
 		}
 
 		if (!module)
 		{
 			if (ModuleLoader::isLoadableModule(fixedModuleName))
 			{
-				loadError(Arg::Gds(isc_pman_module_bad) << fixedModuleName);
+				loadError(Arg::Gds(isc_pman_module_bad) << fixedModuleName <<
+					Arg::StatusVector(statusArray));
 			}
 			if (info.required)
 			{
-				loadError(Arg::Gds(isc_pman_module_notfound) << fixedModuleName);
+				loadError(Arg::Gds(isc_pman_module_notfound) << fixedModuleName <<
+					Arg::StatusVector(statusArray));
 			}
 
 			return RefPtr<PluginModule>(NULL);

From 4df43606a293ff3a9a6883a638b4559375449055 Mon Sep 17 00:00:00 2001
From: AlexPeshkoff <alexander.peshkoff@gmail.com>
Date: Tue, 18 Sep 2018 10:33:18 +0300
Subject: [PATCH] Backported CORE-5764: Installation of Firebird 3.0.3 on SLES
 12 SP3 fails with "Could not find acceptable ICU library"

---
 src/common/unicode_util.cpp | 75 +++++++++++++++++--------------------
 1 file changed, 34 insertions(+), 41 deletions(-)

diff --git a/src/common/unicode_util.cpp b/src/common/unicode_util.cpp
index a33f495910..d24eba9432 100644
--- a/src/common/unicode_util.cpp
+++ b/src/common/unicode_util.cpp
@@ -50,9 +50,6 @@
 #	include <unicode/utf_old.h>
 #endif
 
-// The next major ICU version after 4.8 is 49.
-#define ICU_NEW_VERSION_MEANING	49
-
 
 using namespace Firebird;
 
@@ -122,7 +119,7 @@ struct BaseICU
 
 namespace Jrd {
 
-static void formatFilename(PathName& filename, const char* templateName,
+static ModuleLoader::Module* formatAndLoad(const char* templateName,
 	int majorVersion, int minorVersion);
 
 
@@ -230,10 +227,7 @@ class ImplementConversionICU : public UnicodeUtil::ConversionICU, BaseICU
 	ImplementConversionICU(int aMajorVersion, int aMinorVersion)
 		: BaseICU(aMajorVersion, aMinorVersion)
 	{
-		PathName filename;
-		formatFilename(filename, ucTemplate, aMajorVersion, aMinorVersion);
-
-		module = ModuleLoader::fixAndLoadModule(NULL, filename);
+		module = formatAndLoad(ucTemplate, aMajorVersion, aMinorVersion);
 		if (!module)
 			return;
 
@@ -343,16 +337,27 @@ static const char* const COLL_30_VERSION = "41.128.4.4";	// ICU 3.0 collator ver
 static GlobalPtr<UnicodeUtil::ICUModules> icuModules;
 
 
-static void formatFilename(PathName& filename, const char* templateName,
+static ModuleLoader::Module* formatAndLoad(const char* templateName,
 	int majorVersion, int minorVersion)
 {
-	string s;
-	if (majorVersion >= ICU_NEW_VERSION_MEANING)
-		s.printf("%d", majorVersion);
-	else
-		s.printf("%d%d", majorVersion, minorVersion);
+	// ICU has several schemas for placing version into file name
+	const char* patterns[] =
+	{
+		"%d", "%d_%d", "%d%d", NULL
+	};
+
+	PathName s, filename;
+	for (const char** p = patterns; *p; ++p)
+	{
+		s.printf(*p, majorVersion, minorVersion);
+		filename.printf(templateName, s.c_str());
 
-	filename.printf(templateName, s.c_str());
+		ModuleLoader::Module* module = ModuleLoader::fixAndLoadModule(NULL, filename);
+		if (module)
+			return module;
+	}
+
+	return NULL;
 }
 
 
@@ -975,17 +980,14 @@ UnicodeUtil::ICU* UnicodeUtil::loadICU(const string& icuVersion, const string& c
 			continue;
 
 		string configVersion;
-
-		if (majorVersion >= ICU_NEW_VERSION_MEANING)
+		configVersion.printf("%d.%d", majorVersion, minorVersion);
+		if (version != configVersion)
 		{
 			minorVersion = 0;
 			configVersion.printf("%d", majorVersion);
+			if (version != configVersion)
+				continue;
 		}
-		else
-			configVersion.printf("%d.%d", majorVersion, minorVersion);
-
-		if (version != configVersion)
-			continue;
 
 		ReadLockGuard readGuard(icuModules->lock, "UnicodeUtil::loadICU");
 
@@ -993,27 +995,19 @@ UnicodeUtil::ICU* UnicodeUtil::loadICU(const string& icuVersion, const string& c
 		if (icuModules->modules.get(version, icu))
 			return icu;
 
-		PathName filename;
-		formatFilename(filename, ucTemplate, majorVersion, minorVersion);
-
 		icu = FB_NEW_POOL(*getDefaultMemoryPool()) ICU(majorVersion, minorVersion);
-
-		icu->ucModule = ModuleLoader::fixAndLoadModule(NULL, filename);
-
+		icu->ucModule = formatAndLoad(ucTemplate, majorVersion, minorVersion);
 		if (!icu->ucModule)
 		{
-			gds__log("failed to load module %s", filename.c_str());
+			gds__log("failed to load UC icu module version %s", configVersion.c_str());
 			delete icu;
 			continue;
 		}
 
-		formatFilename(filename, inTemplate, majorVersion, minorVersion);
-
-		icu->inModule = ModuleLoader::fixAndLoadModule(NULL, filename);
-
+		icu->inModule = formatAndLoad(inTemplate, majorVersion, minorVersion);
 		if (!icu->inModule)
 		{
-			gds__log("failed to load module %s", filename.c_str());
+			gds__log("failed to load IN icu module version %s", configVersion.c_str());
 			delete icu;
 			continue;
 		}
@@ -1138,26 +1132,25 @@ UnicodeUtil::ConversionICU& UnicodeUtil::getConversionICU()
 	LocalStatus ls;
 	CheckStatusWrapper lastError(&ls);
 	string version;
-	const int majorArray[] = {5, 4, 3, 6, 0};
 
-	for (const int* major = majorArray; *major; ++major)
+	for (int major = 4; major <= 79; ++major)
 	{
 		for (int minor = 20; minor--; ) // from 19 down to 0
 		{
-			if ((*major == favMaj) && (minor == favMin))
+			if ((major == favMaj) && (minor == favMin))
 			{
 				continue;
 			}
 
 			try
 			{
-				if ((convIcu = ImplementConversionICU::create(*major, minor)))
+				if ((convIcu = ImplementConversionICU::create(major, minor)))
 					return *convIcu;
 			}
 			catch (const Exception& ex)
 			{
 				ex.stuffException(&lastError);
-				version.printf("Error loading ICU library version %d.%d", *major, minor);
+				version.printf("Error loading ICU library version %d.%d", major, minor);
 			}
 		}
 	}
@@ -1180,7 +1173,7 @@ string UnicodeUtil::getDefaultIcuVersion()
 	string rc;
 	UnicodeUtil::ConversionICU& icu(UnicodeUtil::getConversionICU());
 
-	if (icu.vMajor >= ICU_NEW_VERSION_MEANING)
+	if (icu.vMajor >= 10 && icu.vMinor == 0)
 		rc.printf("%d", icu.vMajor);
 	else
 		rc.printf("%d.%d", icu.vMajor, icu.vMinor);
@@ -1425,7 +1418,7 @@ USHORT UnicodeUtil::Utf16Collation::stringToKey(USHORT srcLen, const USHORT* src
 				UErrorCode status = U_ZERO_ERROR;
 				int len = icu->usetGetItem(contractions, i, NULL, NULL, str, sizeof(str), &status);
 
-				if (len > srcLenLong)
+				if (len > SLONG(srcLenLong))
 					len = srcLenLong;
 				else
 					--len;