ERROR: ... Unknown authentication scheme 'ntlm'.
When a translation unit does not contain main() and its code is not used
by the rest of the executable, the linker may exclude that translation
unit from the executable. This exclusion by LTO may happen even if that
code _is_ used to initialize static variables in that translation unit:
"If no variable or function is odr-used from a given translation unit,
the non-local variables defined in that translation unit may never be
initialized"[^1].
[^1]: https://en.cppreference.com/w/cpp/language/initialization
For example, src/auth/ntlm/Scheme.o translation unit contains nothing
but NtlmAuthRr class definition and static initialization code. The
linker knows that the rest of Squid does not use NtlmAuthRr and excludes
that translation unit from the squid executable, effectively disabling
NTLM module registration required to parse "auth_param ntlm" directives.
The problem does affect existing NTLM module, and may affect any future
module code as we reduce module's external footprint. This change
converts all RegisteredRunner registrations from using side effects of
static initialization to explicit registration calls from SquidMain().
Relying on "life before main()" is a design bug. This PR fixes that bug
with respect to RegisteredRunner registrations.
Due to indeterminate C++ static initialization order, no module can
require registration before main() starts. Thus, moving registration
timing to the beginning of SquidMain() should have no negative effects.
The new registration API still does not expose main.cc to any module
details (other than the name of the registration function itself). We
still do not need to #include any module headers into main.cc. Compiler
or linker does catch most typos in RegisteredRunner names.
Unfortunately, explicit registration still cannot prevent bugs where we
forget to register a module or fail to register a module due to wrong
registration code guards. Eventually, CI will expose such bugs.
Ipc::MultiQueue::Owner *owner;
};
-RunnerRegistrationEntry(CollapsedForwardingRr);
+DefineRunnerRegistrator(CollapsedForwardingRr);
void CollapsedForwardingRr::create()
{
Ipc::FewToFewBiQueue::Owner *owner;
};
-RunnerRegistrationEntry(IpcIoRr);
+DefineRunnerRegistrator(IpcIoRr);
void
IpcIoRr::claimMemoryNeeds()
Ipc::Mem::Owner<MemStoreMapExtras> *extrasOwner; ///< PageIds Owner
};
-RunnerRegistrationEntry(MemStoreRr);
+DefineRunnerRegistrator(MemStoreRr);
void
MemStoreRr::claimMemoryNeeds()
void syncConfig() override;
};
-RunnerRegistrationEntry(PeerPoolMgrsRr);
+DefineRunnerRegistrator(PeerPoolMgrsRr);
void
PeerPoolMgrsRr::syncConfig()
TransientsMap::Owner *mapOwner = nullptr;
};
-RunnerRegistrationEntry(TransientsRr);
+DefineRunnerRegistrator(TransientsRr);
void
TransientsRr::useConfig()
debugs(29, 2, "Initialized Authentication Scheme '" << type << "'");
}
};
-RunnerRegistrationEntry(NtlmAuthRr);
+
+DefineRunnerRegistrator(NtlmAuthRr);
Auth::Scheme::Pointer
Auth::Ntlm::Scheme::GetInstance()
// else do nothing past finishShutdown
}
-bool
-UseThisStatic(const void *)
-{
- return true;
-}
-
debugs(1, 2, "running " # m); \
RunRegistered(&m)
-/// convenience function to "use" an otherwise unreferenced static variable
-bool UseThisStatic(const void *);
-
-/// convenience macro: register one RegisteredRunner kid as early as possible
-#define RunnerRegistrationEntry(Who) \
- static const bool Who ## _Registered_ = \
- RegisterRunner(new Who) > 0 && \
- UseThisStatic(& Who ## _Registered_);
+/// helps DefineRunnerRegistrator() and CallRunnerRegistrator() (and their
+/// namespace-sensitive variants) to use the same registration function name
+#define NameRunnerRegistrator_(Namespace, ClassName) \
+ Register ## ClassName ## In ## Namespace()
+
+/// helper macro that implements DefineRunnerRegistrator() and
+/// DefineRunnerRegistratorIn() using supplied constructor expression
+#define DefineRunnerRegistrator_(Namespace, ClassName, Constructor) \
+ void NameRunnerRegistrator_(Namespace, ClassName); \
+ void NameRunnerRegistrator_(Namespace, ClassName) { \
+ const auto registered = RegisterRunner(new Constructor); \
+ assert(registered); \
+ }
+
+/// Define registration code for the given RegisteredRunner-derived class known
+/// as ClassName in Namespace. A matching CallRunnerRegistratorIn() call should
+/// run this code before any possible use of the being-registered module.
+/// \sa DefineRunnerRegistrator() for classes declared in the global namespace.
+#define DefineRunnerRegistratorIn(Namespace, ClassName) \
+ DefineRunnerRegistrator_(Namespace, ClassName, Namespace::ClassName)
+
+/// Define registration code for the given RegisteredRunner-derived class known
+/// as ClassName (in global namespace). A matching CallRunnerRegistrator() call
+/// should run this code before any possible use of the being-registered module.
+/// \sa DefineRunnerRegistratorIn() for classes declared in named namespaces.
+#define DefineRunnerRegistrator(ClassName) \
+ DefineRunnerRegistrator_(Global, ClassName, ClassName)
+
+/// Register one RegisteredRunner kid, known as ClassName in Namespace.
+/// \sa CallRunnerRegistrator() for classes declared in the global namespace.
+#define CallRunnerRegistratorIn(Namespace, ClassName) \
+ do { \
+ void NameRunnerRegistrator_(Namespace, ClassName); \
+ NameRunnerRegistrator_(Namespace, ClassName); \
+ } while (false)
+
+/// Register one RegisteredRunner kid, known as ClassName (in the global namespace).
+/// \sa CallRunnerRegistratorIn() for classes declared in named namespaces.
+#define CallRunnerRegistrator(ClassName) \
+ CallRunnerRegistratorIn(Global, ClassName)
#endif /* SQUID_BASE_RUNNERSREGISTRY_H */
Ssl::BumpMode sslBumpCfgRr::lastDeprecatedRule = Ssl::bumpEnd;
-RunnerRegistrationEntry(sslBumpCfgRr);
+DefineRunnerRegistrator(sslBumpCfgRr);
void
sslBumpCfgRr::finalizeConfig()
/* RegisteredRunner API */
void useConfig() override;
};
-RunnerRegistrationEntry(ClientDbRr);
+DefineRunnerRegistrator(ClientDbRr);
void
ClientDbRr::useConfig()
void endingShutdown() override;
};
-RunnerRegistrationEntry(ConfigRr);
-
} // namespace Dns
+DefineRunnerRegistratorIn(Dns, ConfigRr);
+
struct _sp {
char domain[NS_MAXDNAME];
int queries;
std::unique_ptr<ESIParser::Register> registration;
};
-RunnerRegistrationEntry(ExpatRr);
-
}
+DefineRunnerRegistratorIn(Esi, ExpatRr);
+
EsiParserDefinition(ESIExpatParser);
ESIExpatParser::ESIExpatParser(ESIParserClient *aClient) : theClient (aClient)
std::unique_ptr<ESIParser::Register> registration;
};
-RunnerRegistrationEntry(Libxml2Rr);
-
}
+DefineRunnerRegistratorIn(Esi, Libxml2Rr);
+
// the global document that will store the resolved entity
// definitions
static htmlDocPtr entity_doc = nullptr;
return map->hasReadableEntry(reinterpret_cast<const cache_key*>(e.key));
}
-namespace Rock
-{
-RunnerRegistrationEntry(SwapDirRr);
-}
+DefineRunnerRegistratorIn(Rock, SwapDirRr);
void Rock::SwapDirRr::create()
{
Ipc::Mem::PagePool::Owner *owner;
};
-RunnerRegistrationEntry(SharedMemPagesRr);
+DefineRunnerRegistrator(SharedMemPagesRr);
void
SharedMemPagesRr::useConfig()
}
}
+/// register all known modules for handling future RegisteredRunner events
+static void
+RegisterModules()
+{
+ // These registration calls do not represent a RegisteredRunner "event". The
+ // modules registered here should be initialized later, during those events.
+
+ // RegisteredRunner event handlers should not depend on handler call order
+ // and, hence, should not depend on the registration call order below.
+
+ CallRunnerRegistrator(ClientDbRr);
+ CallRunnerRegistrator(CollapsedForwardingRr);
+ CallRunnerRegistrator(MemStoreRr);
+ CallRunnerRegistrator(PeerPoolMgrsRr);
+ CallRunnerRegistrator(SharedMemPagesRr);
+ CallRunnerRegistrator(SharedSessionCacheRr);
+ CallRunnerRegistrator(TransientsRr);
+ CallRunnerRegistratorIn(Dns, ConfigRr);
+
+#if HAVE_DISKIO_MODULE_IPCIO
+ CallRunnerRegistrator(IpcIoRr);
+#endif
+
+#if HAVE_AUTH_MODULE_NTLM
+ CallRunnerRegistrator(NtlmAuthRr);
+#endif
+
+#if USE_OPENSSL
+ CallRunnerRegistrator(sslBumpCfgRr);
+#endif
+
+#if USE_SQUID_ESI && HAVE_LIBEXPAT
+ CallRunnerRegistratorIn(Esi, ExpatRr);
+#endif
+
+#if USE_SQUID_ESI && HAVE_LIBXML2
+ CallRunnerRegistratorIn(Esi, Libxml2Rr);
+#endif
+
+#if HAVE_FS_ROCK
+ CallRunnerRegistratorIn(Rock, SwapDirRr);
+#endif
+}
+
int
SquidMain(int argc, char **argv)
{
+ // We must register all modules before the first RunRegisteredHere() call.
+ // We do it ASAP/here so that we do not need to move this code when we add
+ // earlier hooks to the RegisteredRunner API.
+ RegisterModules();
+
const CommandLine cmdLine(argc, argv, shortOpStr, squidOptions);
ConfigureCurrentKid(cmdLine);
Ipc::MemMap::Owner *owner;
};
-RunnerRegistrationEntry(SharedSessionCacheRr);
+DefineRunnerRegistrator(SharedSessionCacheRr);
void
SharedSessionCacheRr::useConfig()