]> git.ozlabs.org Git - ccan/blobdiff - ccan/ptr_valid/ptr_valid.h
ptr_valid: test whether a ptr is valid.
[ccan] / ccan / ptr_valid / ptr_valid.h
diff --git a/ccan/ptr_valid/ptr_valid.h b/ccan/ptr_valid/ptr_valid.h
new file mode 100644 (file)
index 0000000..3871cad
--- /dev/null
@@ -0,0 +1,229 @@
+// Licensed under BSD-MIT: See LICENSE.
+#ifndef CCAN_PTR_VALID_H
+#define CCAN_PTR_VALID_H
+#include "config.h"
+#include <stdbool.h>
+#include <stdlib.h>
+
+/**
+ * ptr_valid_read - can I safely read from a pointer?
+ * @p: the proposed pointer.
+ *
+ * This function verifies that the pointer @p is safe to dereference for
+ * reading.  It is very slow, particularly if the answer is "no".
+ *
+ * Sets errno to EFAULT on failure.
+ *
+ * See Also:
+ *     ptr_valid_batch_read()
+ */
+#define ptr_valid_read(p)                                              \
+       ptr_valid_r((p), PTR_VALID_ALIGNOF(*(p)), sizeof(*(p)))
+
+/**
+ * ptr_valid_write - can I safely write to a pointer?
+ * @p: the proposed pointer.
+ *
+ * This function verifies that the pointer @p is safe to dereference
+ * for writing (and reading).  It is very slow, particularly if the
+ * answer is "no".
+ *
+ * Sets errno to EFAULT on failure.
+ *
+ * See Also:
+ *     ptr_valid_batch_write()
+ */
+#define ptr_valid_write(p)                                             \
+       ptr_valid_w((p), PTR_VALID_ALIGNOF(*(p)), sizeof(*(p)))
+
+/**
+ * ptr_valid_string - can I safely read a string?
+ * @p: the proposed string.
+ *
+ * This function verifies that the pointer @p is safe to dereference
+ * up to a nul character.  It is very slow, particularly if the answer
+ * is "no".
+ *
+ * Sets errno to EFAULT on failure.
+ *
+ * See Also:
+ *     ptr_valid_batch_string()
+ */
+bool ptr_valid_string(const char *p);
+
+/**
+ * ptr_valid - generic pointer check function
+ * @p: the proposed pointer.
+ * @align: the alignment requirements of the pointer.
+ * @size: the size of the region @p should point to
+ * @write: true if @p should be writable as well as readable.
+ *
+ * This function verifies that the pointer @p is safe to dereference.
+ * It is very slow, particularly if the answer is "no".
+ *
+ * Sets errno to EFAULT on failure.
+ *
+ * See Also:
+ *     ptr_valid_batch()
+ */
+bool ptr_valid(const void *p, size_t align, size_t size, bool write);
+
+/**
+ * struct ptr_valid_batch - pointer to store state for batch ptr ops
+ *
+ * Treat as private.
+ */
+struct ptr_valid_batch {
+       unsigned int num_maps;
+       struct ptr_valid_map *maps;
+       int child_pid;
+       int to_child, from_child;
+       void *last;
+       bool last_ok;
+};
+
+/**
+ * ptr_valid_batch_start - prepare for a batch of ptr_valid checks.
+ * @batch: an uninitialized ptr_valid_batch structure.
+ *
+ * This initializes @batch; this same @batch pointer can be reused
+ * until the memory map changes (eg. via mmap(), munmap() or even
+ * malloc() and free()).
+ *
+ * This is useful to check many pointers, because otherwise it can be
+ * extremely slow.
+ *
+ * Example:
+ * struct linked {
+ *     struct linked *next;
+ *     const char *str;
+ * };
+ *
+ * static bool check_linked_carefully(struct linked *head)
+ * {
+ *     struct ptr_valid_batch batch;
+ *     struct linked *old = head;
+ *     bool half = true;
+ *
+ *     // If this fails, we can't check.  Assume OK.
+ *     if (!ptr_valid_batch_start(&batch))
+ *             return true;
+ *
+ *     while (head) {
+ *             if (!ptr_valid_batch_read(&batch, head))
+ *                     goto fail;
+ *             if (!ptr_valid_batch_string(&batch, head->str))
+ *                     goto fail;
+ *             // Loop detection; move old at half speed of head.
+ *             if (half)
+ *                     old = old->next;
+ *             half = !half;
+ *             if (head == old) {
+ *                     errno = ELOOP;
+ *                     goto fail;
+ *             }
+ *     }
+ *     ptr_valid_batch_end(&batch);
+ *     return true;
+ *
+ * fail:
+ *     ptr_valid_batch_end(&batch);
+ *     return false;
+ * }
+ *
+ * See Also:
+ *     ptr_valid_batch_stop()
+ */
+bool ptr_valid_batch_start(struct ptr_valid_batch *batch);
+
+/**
+ * ptr_valid_batch_read - can I safely read from a pointer?
+ * @batch: the batch initialized by ptr_valid_batch_start().
+ * @p: the proposed pointer.
+ *
+ * Batched version of ptr_valid_read().
+ */
+#define ptr_valid_batch_read(batch, p)                                 \
+       ptr_valid_batch_r((batch),                                      \
+                         (p), PTR_VALID_ALIGNOF(*(p)), sizeof(*(p)))
+
+/**
+ * ptr_valid_batch_write - can I safely write to a pointer?
+ * @batch: the batch initialized by ptr_valid_batch_start().
+ * @p: the proposed pointer.
+ *
+ * Batched version of ptr_valid_write().
+ */
+#define ptr_valid_batch_write(batch, p)                                        \
+       ptr_valid_batch_w((batch),                                      \
+                         (p), PTR_VALID_ALIGNOF(*(p)), sizeof(*(p)))
+
+/**
+ * ptr_valid_batch_string - can I safely read a string?
+ * @batch: the batch initialized by ptr_valid_batch_start().
+ * @p: the proposed string.
+ *
+ * Batched version of ptr_valid_string().
+ */
+bool ptr_valid_batch_string(struct ptr_valid_batch *batch, const char *p);
+
+/**
+ * ptr_valid_batch - generic batched pointer check function
+ * @batch: the batch initialized by ptr_valid_batch_start().
+ * @p: the proposed pointer.
+ * @align: the alignment requirements of the pointer.
+ * @size: the size of the region @p should point to
+ * @write: true if @p should be writable as well as readable.
+ *
+ * Batched version of ptr_valid().
+ */
+bool ptr_valid_batch(struct ptr_valid_batch *batch,
+                    const void *p, size_t alignment, size_t size, bool write);
+
+/**
+ * ptr_valid_batch_end - end a batch of ptr_valid checks.
+ * @batch: a ptr_valid_batch structure.
+ *
+ * This is used after all checks are complete.
+ *
+ * See Also:
+ *     ptr_valid_batch_start()
+ */
+void ptr_valid_batch_end(struct ptr_valid_batch *batch);
+
+
+/* These wrappers get constness correct. */
+static inline bool ptr_valid_r(const void *p, size_t align, size_t size)
+{
+       return ptr_valid(p, align, size, false);
+}
+
+static inline bool ptr_valid_w(void *p, size_t align, size_t size)
+{
+       return ptr_valid(p, align, size, true);
+}
+
+static inline bool ptr_valid_batch_r(struct ptr_valid_batch *batch,
+                                    const void *p, size_t align, size_t size)
+{
+       return ptr_valid_batch(batch, p, align, size, false);
+}
+
+static inline bool ptr_valid_batch_w(struct ptr_valid_batch *batch,
+                                    void *p, size_t align, size_t size)
+{
+       return ptr_valid_batch(batch, p, align, size, true);
+}
+
+struct ptr_valid_map {
+       const char *start, *end;
+       bool is_write;
+};
+
+#if HAVE_ALIGNOF
+#define PTR_VALID_ALIGNOF(var) __alignof__(var)
+#else
+/* Can't check this... */
+#define PTR_VALID_ALIGNOF(var) 1
+#endif
+#endif /* CCAN_PTR_VALID_H */