| // SPDX-License-Identifier: GPL-2.0 | 
 | /* | 
 |  * 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. | 
 |  * | 
 |  * Helper radix_tree_iter_resume reset slot to NULL and next_index to index + 1, | 
 |  * for tagger iteraction it also must reset cached tags in iterator to abort | 
 |  * next radix_tree_next_slot and go to slow-path into radix_tree_next_chunk. | 
 |  * | 
 |  * 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 *ptr0 = (void *)4ul; | 
 | 	void *ptr = (void *)8ul; | 
 | 	struct radix_tree_iter iter; | 
 | 	void **slot; | 
 | 	bool first; | 
 |  | 
 | 	printv(1, "running regression test 3 (should take milliseconds)\n"); | 
 |  | 
 | 	radix_tree_insert(&root, 0, ptr0); | 
 | 	radix_tree_tag_set(&root, 0, 0); | 
 |  | 
 | 	first = true; | 
 | 	radix_tree_for_each_tagged(slot, &root, &iter, 0, 0) { | 
 | 		printv(2, "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)) { | 
 | 			printv(2, "retry at %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) { | 
 | 		printv(2, "slot %ld %p\n", iter.index, *slot); | 
 | 		if (first) { | 
 | 			radix_tree_insert(&root, 1, ptr); | 
 | 			first = false; | 
 | 		} | 
 | 		if (radix_tree_deref_retry(*slot)) { | 
 | 			printv(2, "retry at %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) { | 
 | 		printv(2, "contig %ld %p\n", iter.index, *slot); | 
 | 		if (first) { | 
 | 			radix_tree_insert(&root, 1, ptr); | 
 | 			first = false; | 
 | 		} | 
 | 		if (radix_tree_deref_retry(*slot)) { | 
 | 			printv(2, "retry at %ld\n", iter.index); | 
 | 			slot = radix_tree_iter_retry(&iter); | 
 | 			continue; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	radix_tree_for_each_slot(slot, &root, &iter, 0) { | 
 | 		printv(2, "slot %ld %p\n", iter.index, *slot); | 
 | 		if (!iter.index) { | 
 | 			printv(2, "next at %ld\n", iter.index); | 
 | 			slot = radix_tree_iter_resume(slot, &iter); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	radix_tree_for_each_contig(slot, &root, &iter, 0) { | 
 | 		printv(2, "contig %ld %p\n", iter.index, *slot); | 
 | 		if (!iter.index) { | 
 | 			printv(2, "next at %ld\n", iter.index); | 
 | 			slot = radix_tree_iter_resume(slot, &iter); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	radix_tree_tag_set(&root, 0, 0); | 
 | 	radix_tree_tag_set(&root, 1, 0); | 
 | 	radix_tree_for_each_tagged(slot, &root, &iter, 0, 0) { | 
 | 		printv(2, "tagged %ld %p\n", iter.index, *slot); | 
 | 		if (!iter.index) { | 
 | 			printv(2, "next at %ld\n", iter.index); | 
 | 			slot = radix_tree_iter_resume(slot, &iter); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	radix_tree_delete(&root, 0); | 
 | 	radix_tree_delete(&root, 1); | 
 |  | 
 | 	printv(1, "regression test 3 passed\n"); | 
 | } |