Avoid on-exit crashes when adaptation is enabled. After trunk r13269 (Vector refactor) destroyed vector objects still have positive item counts. This exposes use-after-delete bugs. In this particular case, global adaptation rule/group/service arrays are destructed by global destruction sequence first and then again by Adaptation::*::TheConfig objects destructors. This change avoiding static destruction order dependencies by storing those global adaptation arrays on heap. === modified file 'src/adaptation/AccessRule.cc' --- src/adaptation/AccessRule.cc 2013-05-13 22:48:23 +0000 +++ src/adaptation/AccessRule.cc 2014-02-20 01:27:36 +0000 @@ -34,42 +34,42 @@ Adaptation::AccessRule::finalize() g->finalize(); // explicit groups were finalized before rules AllGroups().push_back(g); } } if (!group()) { debugs(93, DBG_CRITICAL, "ERROR: Unknown adaptation service or group name: '" << groupId << "'"); // TODO: fail on failures } } Adaptation::ServiceGroupPointer Adaptation::AccessRule::group() { return FindGroup(groupId); } Adaptation::AccessRules & Adaptation::AllRules() { - static AccessRules TheRules; - return TheRules; + static AccessRules *TheRules = new AccessRules; + return *TheRules; } // TODO: make AccessRules::find work Adaptation::AccessRule * Adaptation::FindRule(const AccessRule::Id &id) { typedef AccessRules::iterator ARI; for (ARI i = AllRules().begin(); i != AllRules().end(); ++i) { if ((*i)->id == id) return *i; } return NULL; } Adaptation::AccessRule * Adaptation::FindRuleByGroupId(const String &groupId) { typedef AccessRules::iterator ARI; for (ARI i = AllRules().begin(); i != AllRules().end(); ++i) { === modified file 'src/adaptation/Service.cc' --- src/adaptation/Service.cc 2014-02-04 19:47:14 +0000 +++ src/adaptation/Service.cc 2014-02-20 01:28:25 +0000 @@ -37,42 +37,42 @@ Adaptation::Service::wants(const Service // sending a message to a broken service is likely to cause errors if (cfg().bypass && broken()) return false; if (up()) { // Sending a message to a service that does not want it is useless. // note that we cannot check wantsUrl for service that is not "up" // note that even essential services are skipped on unwanted URLs! return wantsUrl(filter.request->urlpath); } // The service is down and is either not bypassable or not probed due // to the bypass && broken() test above. Thus, we want to use it! return true; } Adaptation::Services & Adaptation::AllServices() { - static Services TheServices; - return TheServices; + static Services *TheServices = new Services; + return *TheServices; } Adaptation::ServicePointer Adaptation::FindService(const Service::Id& key) { typedef Services::iterator SI; for (SI i = AllServices().begin(); i != AllServices().end(); ++i) { if ((*i)->cfg().key == key) return *i; } return NULL; } void Adaptation::DetachServices() { while (!AllServices().empty()) { AllServices().back()->detach(); AllServices().pop_back(); } } === modified file 'src/adaptation/ServiceGroups.cc' --- src/adaptation/ServiceGroups.cc 2014-02-02 09:42:23 +0000 +++ src/adaptation/ServiceGroups.cc 2014-02-20 01:26:45 +0000 @@ -298,35 +298,35 @@ Adaptation::ServicePlan::next(const Serv if (!atEof && !group->findLink(filter, ++pos)) atEof = true; return current(); } std::ostream & Adaptation::ServicePlan::print(std::ostream &os) const { if (!group) return os << "[nil]"; return os << group->id << '[' << pos << ".." << group->services.size() << (atEof ? ".]" : "]"); } /* globals */ Adaptation::Groups & Adaptation::AllGroups() { - static Groups TheGroups; - return TheGroups; + static Groups *TheGroups = new Groups; + return *TheGroups; } Adaptation::ServiceGroupPointer Adaptation::FindGroup(const ServiceGroup::Id &id) { typedef Groups::iterator GI; for (GI i = AllGroups().begin(); i != AllGroups().end(); ++i) { if ((*i)->id == id) return *i; } return NULL; }