1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Regression3 |
4 | * Description: |
5 | * Helper radix_tree_iter_retry resets next_index to the current index. |
6 | * In following radix_tree_next_slot current chunk size becomes zero. |
7 | * This isn't checked and it tries to dereference null pointer in slot. |
8 | * |
9 | * Helper radix_tree_iter_resume reset slot to NULL and next_index to index + 1, |
10 | * for tagger iteraction it also must reset cached tags in iterator to abort |
11 | * next radix_tree_next_slot and go to slow-path into radix_tree_next_chunk. |
12 | * |
13 | * Running: |
14 | * This test should run to completion immediately. The above bug would |
15 | * cause it to segfault. |
16 | * |
17 | * Upstream commit: |
18 | * Not yet |
19 | */ |
20 | #include <linux/kernel.h> |
21 | #include <linux/gfp.h> |
22 | #include <linux/slab.h> |
23 | #include <linux/radix-tree.h> |
24 | #include <stdlib.h> |
25 | #include <stdio.h> |
26 | |
27 | #include "regression.h" |
28 | |
29 | void regression3_test(void) |
30 | { |
31 | RADIX_TREE(root, GFP_KERNEL); |
32 | void *ptr0 = (void *)4ul; |
33 | void *ptr = (void *)8ul; |
34 | struct radix_tree_iter iter; |
35 | void **slot; |
36 | bool first; |
37 | |
38 | printv(1, "running regression test 3 (should take milliseconds)\n" ); |
39 | |
40 | radix_tree_insert(&root, index: 0, ptr0); |
41 | radix_tree_tag_set(&root, index: 0, tag: 0); |
42 | |
43 | first = true; |
44 | radix_tree_for_each_tagged(slot, &root, &iter, 0, 0) { |
45 | printv(2, "tagged %ld %p\n" , iter.index, *slot); |
46 | if (first) { |
47 | radix_tree_insert(&root, index: 1, ptr); |
48 | radix_tree_tag_set(&root, index: 1, tag: 0); |
49 | first = false; |
50 | } |
51 | if (radix_tree_deref_retry(arg: *slot)) { |
52 | printv(2, "retry at %ld\n" , iter.index); |
53 | slot = radix_tree_iter_retry(iter: &iter); |
54 | continue; |
55 | } |
56 | } |
57 | radix_tree_delete(&root, 1); |
58 | |
59 | first = true; |
60 | radix_tree_for_each_slot(slot, &root, &iter, 0) { |
61 | printv(2, "slot %ld %p\n" , iter.index, *slot); |
62 | if (first) { |
63 | radix_tree_insert(&root, index: 1, ptr); |
64 | first = false; |
65 | } |
66 | if (radix_tree_deref_retry(arg: *slot)) { |
67 | printv(2, "retry at %ld\n" , iter.index); |
68 | slot = radix_tree_iter_retry(iter: &iter); |
69 | continue; |
70 | } |
71 | } |
72 | |
73 | radix_tree_for_each_slot(slot, &root, &iter, 0) { |
74 | printv(2, "slot %ld %p\n" , iter.index, *slot); |
75 | if (!iter.index) { |
76 | printv(2, "next at %ld\n" , iter.index); |
77 | slot = radix_tree_iter_resume(slot, iter: &iter); |
78 | } |
79 | } |
80 | |
81 | radix_tree_tag_set(&root, index: 0, tag: 0); |
82 | radix_tree_tag_set(&root, index: 1, tag: 0); |
83 | radix_tree_for_each_tagged(slot, &root, &iter, 0, 0) { |
84 | printv(2, "tagged %ld %p\n" , iter.index, *slot); |
85 | if (!iter.index) { |
86 | printv(2, "next at %ld\n" , iter.index); |
87 | slot = radix_tree_iter_resume(slot, iter: &iter); |
88 | } |
89 | } |
90 | |
91 | radix_tree_delete(&root, 0); |
92 | radix_tree_delete(&root, 1); |
93 | |
94 | printv(1, "regression test 3 passed\n" ); |
95 | } |
96 | |