Module Name: src
Committed By: riastradh
Date: Tue Aug 13 20:52:52 UTC 2024
Modified Files:
src/sys/uvm: uvm_map.c
Log Message:
Redo uvm_map.c 1.414 without the null pointer dereference.
uvm_map(9): Sprinkle assertions and interface contract comments.
No functional change intended.
PR kern/51254: uvm assertion "!topdown || hint <= orig_hint" failed
To generate a diff of this commit:
cvs rdiff -u -r1.416 -r1.417 src/sys/uvm/uvm_map.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/uvm/uvm_map.c
diff -u src/sys/uvm/uvm_map.c:1.416 src/sys/uvm/uvm_map.c:1.417
--- src/sys/uvm/uvm_map.c:1.416 Tue Aug 13 20:23:23 2024
+++ src/sys/uvm/uvm_map.c Tue Aug 13 20:52:52 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_map.c,v 1.416 2024/08/13 20:23:23 riastradh Exp $ */
+/* $NetBSD: uvm_map.c,v 1.417 2024/08/13 20:52:52 riastradh Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -66,7 +66,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_map.c,v 1.416 2024/08/13 20:23:23 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_map.c,v 1.417 2024/08/13 20:52:52 riastradh Exp $");
#include "opt_ddb.h"
#include "opt_pax.h"
@@ -303,11 +303,23 @@ int _uvm_map_sanity(struct vm_map *);
int _uvm_tree_sanity(struct vm_map *);
static vsize_t uvm_rb_maxgap(const struct vm_map_entry *);
-#define ROOT_ENTRY(map) ((struct vm_map_entry *)(map)->rb_tree.rbt_root)
-#define LEFT_ENTRY(entry) ((struct vm_map_entry *)(entry)->rb_node.rb_left)
-#define RIGHT_ENTRY(entry) ((struct vm_map_entry *)(entry)->rb_node.rb_right)
-#define PARENT_ENTRY(map, entry) \
- (ROOT_ENTRY(map) == (entry) \
+/*
+ * Tree iteration. We violate the rbtree(9) abstraction for various
+ * things here. Entries are ascending left to right, so, provided the
+ * child entry in question exists:
+ *
+ * LEFT_ENTRY(entry)->end <= entry->start
+ * entry->end <= RIGHT_ENTRY(entry)->start
+ */
+__CTASSERT(offsetof(struct vm_map_entry, rb_node) == 0);
+#define ROOT_ENTRY(map) \
+ ((struct vm_map_entry *)(map)->rb_tree.rbt_root)
+#define LEFT_ENTRY(entry) \
+ ((struct vm_map_entry *)(entry)->rb_node.rb_left)
+#define RIGHT_ENTRY(entry) \
+ ((struct vm_map_entry *)(entry)->rb_node.rb_right)
+#define PARENT_ENTRY(map, entry) \
+ (ROOT_ENTRY(map) == (entry) \
? NULL : (struct vm_map_entry *)RB_FATHER(&(entry)->rb_node))
/*
@@ -1619,6 +1631,18 @@ done:
/*
* uvm_map_lookup_entry_bytree: lookup an entry in tree
+ *
+ * => map must at least be read-locked by caller.
+ *
+ * => If address lies in an entry, set *entry to it and return true;
+ * then (*entry)->start <= address < (*entry)->end.
+
+ * => If address is below all entries in map, return false and set
+ * *entry to &map->header.
+ *
+ * => Otherwise, return false and set *entry to the highest entry below
+ * address, so (*entry)->end <= address, and if (*entry)->next is
+ * not &map->header, address < (*entry)->next->start.
*/
static inline bool
@@ -1628,7 +1652,10 @@ uvm_map_lookup_entry_bytree(struct vm_ma
struct vm_map_entry *prev = &map->header;
struct vm_map_entry *cur = ROOT_ENTRY(map);
+ KASSERT(rw_lock_held(&map->lock));
+
while (cur) {
+ KASSERT(prev == &map->header || prev->end <= address);
UVMMAP_EVCNT_INCR(mlk_treeloop);
if (address >= cur->start) {
if (address < cur->end) {
@@ -1636,10 +1663,14 @@ uvm_map_lookup_entry_bytree(struct vm_ma
return true;
}
prev = cur;
+ KASSERT(prev->end <= address);
cur = RIGHT_ENTRY(cur);
+ KASSERT(cur == NULL || prev->end <= cur->start);
} else
cur = LEFT_ENTRY(cur);
}
+ KASSERT(prev == &map->header || prev->end <= address);
+ KASSERT(prev->next == &map->header || address < prev->next->start);
*entry = prev;
return false;
}
@@ -1647,9 +1678,17 @@ uvm_map_lookup_entry_bytree(struct vm_ma
/*
* uvm_map_lookup_entry: find map entry at or before an address
*
- * => map must at least be read-locked by caller
- * => entry is returned in "entry"
- * => return value is true if address is in the returned entry
+ * => map must at least be read-locked by caller.
+ *
+ * => If address lies in an entry, set *entry to it and return true;
+ * then (*entry)->start <= address < (*entry)->end.
+
+ * => If address is below all entries in map, return false and set
+ * *entry to &map->header.
+ *
+ * => Otherwise, return false and set *entry to the highest entry below
+ * address, so (*entry)->end <= address, and if (*entry)->next is
+ * not &map->header, address < (*entry)->next->start.
*/
bool
@@ -1661,6 +1700,8 @@ uvm_map_lookup_entry(struct vm_map *map,
UVMHIST_CALLARGS(maphist,"(map=%#jx,addr=%#jx,ent=%#jx)",
(uintptr_t)map, address, (uintptr_t)entry, 0);
+ KDASSERT(rw_lock_held(&map->lock));
+
/*
* make a quick check to see if we are already looking at
* the entry we want (which is usually the case). note also
@@ -1960,18 +2001,23 @@ uvm_map_findspace(struct vm_map *map, va
* optimization or find a better way to do it.
*/
entry = map->first_free;
+ } else if (uvm_map_lookup_entry(map, hint, &entry)) {
+ KASSERT(entry->start <= hint);
+ KASSERT(hint < entry->end);
+ /* "hint" address already in use ... */
+ if (flags & UVM_FLAG_FIXED) {
+ UVMHIST_LOG(maphist, "<- fixed & VA in use",
+ 0, 0, 0, 0);
+ return (NULL);
+ }
+ if (topdown)
+ /* Start from lower gap. */
+ entry = entry->prev;
} else {
- if (uvm_map_lookup_entry(map, hint, &entry)) {
- /* "hint" address already in use ... */
- if (flags & UVM_FLAG_FIXED) {
- UVMHIST_LOG(maphist, "<- fixed & VA in use",
- 0, 0, 0, 0);
- return (NULL);
- }
- if (topdown)
- /* Start from lower gap. */
- entry = entry->prev;
- } else if (flags & UVM_FLAG_FIXED) {
+ KASSERT(entry == &map->header || entry->end <= hint);
+ KASSERT(entry->next == &map->header ||
+ hint < entry->next->start);
+ if (flags & UVM_FLAG_FIXED) {
if (entry->next->start >= hint + length &&
hint + length > hint)
goto found;