summaryrefslogtreecommitdiffstats
path: root/plugins/sudoers/gc.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--plugins/sudoers/gc.c151
1 files changed, 151 insertions, 0 deletions
diff --git a/plugins/sudoers/gc.c b/plugins/sudoers/gc.c
new file mode 100644
index 0000000..1c14b71
--- /dev/null
+++ b/plugins/sudoers/gc.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2016 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This is an open source non-commercial project. Dear PVS-Studio, please check it.
+ * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sudoers.h"
+
+struct sudoers_gc_entry {
+ SLIST_ENTRY(sudoers_gc_entry) entries;
+ enum sudoers_gc_types type;
+ union {
+ char **vec;
+ void *ptr;
+ } u;
+};
+SLIST_HEAD(sudoers_gc_list, sudoers_gc_entry);
+#ifdef NO_LEAKS
+static struct sudoers_gc_list sudoers_gc_list =
+ SLIST_HEAD_INITIALIZER(sudoers_gc_list);
+#endif
+
+bool
+sudoers_gc_add(enum sudoers_gc_types type, void *v)
+{
+#ifdef NO_LEAKS
+ struct sudoers_gc_entry *gc;
+ debug_decl(sudoers_gc_add, SUDOERS_DEBUG_UTIL)
+
+ if (v == NULL)
+ debug_return_bool(false);
+
+ gc = calloc(1, sizeof(*gc));
+ if (gc == NULL) {
+ sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
+ debug_return_bool(false);
+ }
+ switch (type) {
+ case GC_PTR:
+ gc->u.ptr = v;
+ break;
+ case GC_VECTOR:
+ gc->u.vec = v;
+ break;
+ default:
+ free(gc);
+ sudo_warnx("unexpected garbage type %d", type);
+ debug_return_bool(false);
+ }
+ gc->type = type;
+ SLIST_INSERT_HEAD(&sudoers_gc_list, gc, entries);
+ debug_return_bool(true);
+#else
+ return true;
+#endif /* NO_LEAKS */
+}
+
+bool
+sudoers_gc_remove(enum sudoers_gc_types type, void *v)
+{
+#ifdef NO_LEAKS
+ struct sudoers_gc_entry *gc, *prev = NULL;
+ debug_decl(sudoers_gc_remove, SUDOERS_DEBUG_UTIL)
+
+ SLIST_FOREACH(gc, &sudoers_gc_list, entries) {
+ switch (gc->type) {
+ case GC_PTR:
+ if (gc->u.ptr == v)
+ goto found;
+ break;
+ case GC_VECTOR:
+ if (gc->u.vec == v)
+ goto found;
+ break;
+ default:
+ sudo_warnx("unexpected garbage type %d in %p", gc->type, gc);
+ }
+ prev = gc;
+ }
+ return false;
+found:
+ if (prev == NULL)
+ SLIST_REMOVE_HEAD(&sudoers_gc_list, entries);
+ else
+ SLIST_REMOVE_AFTER(prev, entries);
+ return true;
+#else
+ return false;
+#endif /* NO_LEAKS */
+}
+
+#ifdef NO_LEAKS
+static void
+sudoers_gc_run(void)
+{
+ struct sudoers_gc_entry *gc;
+ char **cur;
+ debug_decl(sudoers_gc_run, SUDOERS_DEBUG_UTIL)
+
+ /* Collect garbage. */
+ while ((gc = SLIST_FIRST(&sudoers_gc_list))) {
+ SLIST_REMOVE_HEAD(&sudoers_gc_list, entries);
+ switch (gc->type) {
+ case GC_PTR:
+ free(gc->u.ptr);
+ free(gc);
+ break;
+ case GC_VECTOR:
+ for (cur = gc->u.vec; *cur != NULL; cur++)
+ free(*cur);
+ free(gc->u.vec);
+ free(gc);
+ break;
+ default:
+ sudo_warnx("unexpected garbage type %d", gc->type);
+ }
+ }
+
+ debug_return;
+}
+#endif /* NO_LEAKS */
+
+void
+sudoers_gc_init(void)
+{
+#ifdef NO_LEAKS
+ atexit(sudoers_gc_run);
+#endif
+}