radix-tree tests: add regression3 test
authorKonstantin Khlebnikov <koct9i@gmail.com>
Thu, 17 Mar 2016 21:22:08 +0000 (14:22 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 17 Mar 2016 22:09:34 +0000 (15:09 -0700)
After calling radix_tree_iter_retry(), 'slot' will be set to NULL.  This
can cause radix_tree_next_slot() to dereference the NULL pointer.  Add
Konstantin Khlebnikov's test to the regression framework.

Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
Reported-by: Konstantin Khlebnikov <koct9i@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
tools/testing/radix-tree/Makefile
tools/testing/radix-tree/linux/kernel.h
tools/testing/radix-tree/main.c
tools/testing/radix-tree/regression.h
tools/testing/radix-tree/regression3.c [new file with mode: 0644]

index e33ac31..604212d 100644 (file)
@@ -3,7 +3,7 @@ CFLAGS += -I. -g -Wall -D_LGPL_SOURCE
 LDFLAGS += -lpthread -lurcu
 TARGETS = main
 OFILES = main.o radix-tree.o linux.o test.o tag_check.o find_next_bit.o \
-        regression1.o regression2.o
+        regression1.o regression2.o regression3.o
 
 targets: $(TARGETS)
 
index 27d5fe4..ae013b0 100644 (file)
@@ -13,6 +13,7 @@
 
 #define BUG_ON(expr)   assert(!(expr))
 #define __init
+#define __must_check
 #define panic(expr)
 #define printk printf
 #define __force
index 6b8a412..0e83cad 100644 (file)
@@ -261,6 +261,7 @@ int main(void)
 
        regression1_test();
        regression2_test();
+       regression3_test();
        single_thread_tests();
 
        sleep(1);
index bb1c2ab..e018c48 100644 (file)
@@ -3,5 +3,6 @@
 
 void regression1_test(void);
 void regression2_test(void);
+void regression3_test(void);
 
 #endif
diff --git a/tools/testing/radix-tree/regression3.c b/tools/testing/radix-tree/regression3.c
new file mode 100644 (file)
index 0000000..17d3ba5
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Regression3
+ * Description:
+ * Helper radix_tree_iter_retry resets next_index to the current index.
+ * In following radix_tree_next_slot current chunk size becomes zero.
+ * This isn't checked and it tries to dereference null pointer in slot.
+ *
+ * Running:
+ * This test should run to completion immediately. The above bug would
+ * cause it to segfault.
+ *
+ * Upstream commit:
+ * Not yet
+ */
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/slab.h>
+#include <linux/radix-tree.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "regression.h"
+
+void regression3_test(void)
+{
+       RADIX_TREE(root, GFP_KERNEL);
+       void *ptr = (void *)4ul;
+       struct radix_tree_iter iter;
+       void **slot;
+       bool first;
+
+       printf("running regression test 3 (should take milliseconds)\n");
+
+       radix_tree_insert(&root, 0, ptr);
+       radix_tree_tag_set(&root, 0, 0);
+
+       first = true;
+       radix_tree_for_each_tagged(slot, &root, &iter, 0, 0) {
+//             printk("tagged %ld %p\n", iter.index, *slot);
+               if (first) {
+                       radix_tree_insert(&root, 1, ptr);
+                       radix_tree_tag_set(&root, 1, 0);
+                       first = false;
+               }
+               if (radix_tree_deref_retry(*slot)) {
+//                     printk("retry %ld\n", iter.index);
+                       slot = radix_tree_iter_retry(&iter);
+                       continue;
+               }
+       }
+       radix_tree_delete(&root, 1);
+
+       first = true;
+       radix_tree_for_each_slot(slot, &root, &iter, 0) {
+//             printk("slot %ld %p\n", iter.index, *slot);
+               if (first) {
+                       radix_tree_insert(&root, 1, ptr);
+                       first = false;
+               }
+               if (radix_tree_deref_retry(*slot)) {
+//                     printk("retry %ld\n", iter.index);
+                       slot = radix_tree_iter_retry(&iter);
+                       continue;
+               }
+       }
+       radix_tree_delete(&root, 1);
+
+       first = true;
+       radix_tree_for_each_contig(slot, &root, &iter, 0) {
+//             printk("contig %ld %p\n", iter.index, *slot);
+               if (first) {
+                       radix_tree_insert(&root, 1, ptr);
+                       first = false;
+               }
+               if (radix_tree_deref_retry(*slot)) {
+//                     printk("retry %ld\n", iter.index);
+                       slot = radix_tree_iter_retry(&iter);
+                       continue;
+               }
+       }
+
+       radix_tree_delete(&root, 0);
+       radix_tree_delete(&root, 1);
+
+       printf("regression test 3 passed\n");
+}