during reconfiguration.
Group ACLs created later may use other ACLs created earlier and vice versa, a
group ACL created earlier may use other ACLs created later. The latter is
possible when an ACL (e.g., A2 below) is declared when the group already
exists:
acl A1 src 127.0.0.1
acl Group all-of A1
acl A2 src 127.0.0.2
acl Group all-of A2
Thus, the group (i.e., InnerNode) ACL destructor may access already deleted
children regardless of the global ACL deletion order (FIFO or LIFO with
respect to ACL creation). Instead of relying on the deletion order to protect
InnerNode, we remove the InnerNode ACL destructor completely and rely on a
global set of registered ACLs to destroy all ACLs.
The old code was destroying all explicit ACLs in the same centralized fashion.
We now add implicit ACLs (commonly used by InnerNodes) to the centralized
destruction sequence. We added a new destruction-dedicated container to avoid
messing with the by-name ACL search that Config.aclList global is used for.
This new container will become unnecessary once we start refcounting ACLs.
#include "squid.h"
#include "acl/Acl.h"
#include "acl/Checklist.h"
+#include "acl/Gadgets.h"
#include "anyp/PortCfg.h"
#include "cache_cf.h"
#include "ConfigParser.h"
A->cfgline);
}
- // prepend so that ACLs declared later (and possibly using earlier ACLs)
- // are destroyed earlier (before the ACLs they use are destroyed)
+ // add to the global list for searching explicit ACLs by name
assert(head && *head == Config.aclList);
- A->registered = true;
A->next = *head;
*head = A;
+
+ // register for centralized cleanup
+ aclRegister(A);
}
bool
char *cfgline;
ACL *next; // XXX: remove or at least use refcounting
ACLFlags flags; ///< The list of given ACL flags
- bool registered; ///< added to Config.aclList and can be reused via by FindByName()
+ bool registered; ///< added to the global list of ACLs via aclRegister()
public:
#include "HttpRequest.h"
#include "Mem.h"
+#include <set>
+#include <algorithm>
+
+
+typedef std::set<ACL*> AclSet;
+/// Accumulates all ACLs to facilitate their clean deletion despite reuse.
+static AclSet *RegisteredAcls; // TODO: Remove when ACLs are refcounted
+
/* does name lookup, returns page_id */
err_type
aclGetDenyInfoPage(AclDenyInfoList ** head, const char *name, int redirect_allowed)
*treep = tree;
}
+void
+aclRegister(ACL *acl)
+{
+ if (!acl->registered) {
+ if (!RegisteredAcls)
+ RegisteredAcls = new AclSet;
+ RegisteredAcls->insert(acl);
+ acl->registered = true;
+ }
+}
+
/*********************/
/* Destroy functions */
/*********************/
+/// helper for RegisteredAcls cleanup
+static void
+aclDeleteOne(ACL *acl)
+{
+ delete acl;
+}
+
+/// called to delete ALL Acls.
void
aclDestroyAcls(ACL ** head)
{
- ACL *next = NULL;
-
- debugs(28, 8, "aclDestroyACLs: invoked");
-
- for (ACL *a = *head; a; a = next) {
- next = a->next;
- delete a;
+ *head = NULL; // Config.aclList
+ if (AclSet *acls = RegisteredAcls) {
+ debugs(28, 8, "deleting all " << acls->size() << " ACLs");
+ std::for_each(acls->begin(), acls->end(), &aclDeleteOne);
+ acls->clear();
}
-
- *head = NULL;
}
void
class StoreEntry;
class wordlist;
+/// Register an ACL object for future deletion. Repeated registrations are OK.
+/// \ingroup ACLAPI
+void aclRegister(ACL *acl);
/// \ingroup ACLAPI
void aclDestroyAccessList(acl_access **list);
/// \ingroup ACLAPI
#include "wordlist.h"
#include <algorithm>
-// "delete acl" class to use with std::for_each() in InnerNode::~InnerNode()
-class AclDeleter
-{
-public:
- void operator()(ACL* acl) {
- // Do not delete explicit ACLs; they are maintained by Config.aclList.
- if (acl && !acl->registered)
- delete acl;
- }
-};
-
-Acl::InnerNode::~InnerNode()
-{
- std::for_each(nodes.begin(), nodes.end(), AclDeleter());
-}
-
void
Acl::InnerNode::prepareForUse()
{
class InnerNode: public ACL
{
public:
- virtual ~InnerNode();
+ // No ~InnerNode() to delete children. They are aclRegister()ed instead.
/// Resumes matching (suspended by an async call) at the given position.
bool resumeMatchingAt(ACLChecklist *checklist, Acl::Nodes::const_iterator pos) const;