signal_state(mod_info, TEST_DONE);
}
+static inline void shrink_vma(const struct vma_modifier_info *mod_info)
+{
+ assert(mremap(mod_info->addr, page_size * 3, page_size, 0) != MAP_FAILED);
+}
+
+static inline void expand_vma(const struct vma_modifier_info *mod_info)
+{
+ assert(mremap(mod_info->addr, page_size, page_size * 3, 0) != MAP_FAILED);
+}
+
+static inline void check_shrink_result(struct line_content *mod_last_line,
+ struct line_content *mod_first_line,
+ struct line_content *restored_last_line,
+ struct line_content *restored_first_line)
+{
+ /* Make sure only the last vma of the first page is changing */
+ assert(strcmp(mod_last_line->text, restored_last_line->text) != 0);
+ assert(strcmp(mod_first_line->text, restored_first_line->text) == 0);
+}
+
+static void test_maps_tearing_from_resize(int maps_fd,
+ struct vma_modifier_info *mod_info,
+ struct page_content *page1,
+ struct page_content *page2,
+ struct line_content *last_line,
+ struct line_content *first_line)
+{
+ struct line_content shrunk_last_line;
+ struct line_content shrunk_first_line;
+ struct line_content restored_last_line;
+ struct line_content restored_first_line;
+
+ wait_for_state(mod_info, SETUP_READY);
+
+ /* re-read the file to avoid using stale data from previous test */
+ read_boundary_lines(maps_fd, page1, page2, last_line, first_line);
+
+ mod_info->vma_modify = shrink_vma;
+ mod_info->vma_restore = expand_vma;
+ mod_info->vma_mod_check = check_shrink_result;
+
+ capture_mod_pattern(maps_fd, mod_info, page1, page2, last_line, first_line,
+ &shrunk_last_line, &shrunk_first_line,
+ &restored_last_line, &restored_first_line);
+
+ /* Now start concurrent modifications for test_duration_sec */
+ signal_state(mod_info, TEST_READY);
+
+ struct line_content new_last_line;
+ struct line_content new_first_line;
+ struct timespec start_ts, end_ts;
+
+ clock_gettime(CLOCK_MONOTONIC_COARSE, &start_ts);
+ do {
+ read_boundary_lines(maps_fd, page1, page2, &new_last_line, &new_first_line);
+
+ /* Check if we read vmas after shrinking it */
+ if (!strcmp(new_last_line.text, shrunk_last_line.text)) {
+ /*
+ * The vmas should be consistent with shrunk results,
+ * however if the vma was concurrently restored, it
+ * can be reported twice (first as shrunk one, then
+ * as restored one) because we found it as the next vma
+ * again. In that case new first line will be the same
+ * as the last restored line.
+ */
+ assert(!strcmp(new_first_line.text, shrunk_first_line.text) ||
+ !strcmp(new_first_line.text, restored_last_line.text));
+ } else {
+ /* The vmas should be consistent with the original/resored state */
+ assert(!strcmp(new_last_line.text, restored_last_line.text) &&
+ !strcmp(new_first_line.text, restored_first_line.text));
+ }
+ clock_gettime(CLOCK_MONOTONIC_COARSE, &end_ts);
+ } while (end_ts.tv_sec - start_ts.tv_sec < test_duration_sec);
+
+ /* Signal the modifyer thread to stop and wait until it exits */
+ signal_state(mod_info, TEST_DONE);
+}
+
int usage(void)
{
fprintf(stderr, "Userland /proc/pid/{s}maps race test cases\n");
test_maps_tearing_from_split(maps_fd, mod_info, &page1, &page2,
&last_line, &first_line);
+ test_maps_tearing_from_resize(maps_fd, mod_info, &page1, &page2,
+ &last_line, &first_line);
+
stop_vma_modifier(mod_info);
free(page2.data);