| // Copyright 2016 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <zircon/status.h> |
| #include <zircon/syscalls.h> |
| |
| #include <zxtest/zxtest.h> |
| |
| // How many times to try a given window size. |
| #define NUM_PASSES_PER_WINDOW 100 |
| |
| // qsort comparison function for zx_handle_t. |
| static int handle_cmp(const void* left, const void* right) { |
| return *(const zx_handle_t*)left - *(const zx_handle_t*)right; |
| } |
| |
| // Prints a message and exits the process with a non-zero status. |
| // This will stop any further tests in this file from running. |
| #define FATALF(str, x...) \ |
| do { \ |
| printf("\nFATAL:%s:%d: " str, __FILE__, __LINE__, ##x); \ |
| exit(-2); \ |
| } while (false) |
| |
| // Creates/closes |window_size| handles as quickly as possible and looks |
| // for aliases. Returns true if any aliases were found. |
| static bool find_handle_value_aliases(const size_t window_size) { |
| zx_handle_t event; |
| zx_status_t s = zx_event_create(0, &event); |
| if (s != ZX_OK) { |
| FATALF("Can't create event: %s\n", zx_status_get_string(s)); |
| } |
| zx_handle_t* handle_log = (zx_handle_t*)malloc(window_size * sizeof(zx_handle_t)); |
| |
| bool saw_aliases = false; |
| int pass = 0; |
| while (pass++ < NUM_PASSES_PER_WINDOW && !saw_aliases) { |
| // Create and close a bunch of handles as quickly as possible. |
| memset(handle_log, 0, window_size * sizeof(zx_handle_t)); |
| for (size_t i = 0; i < window_size; i++) { |
| s = zx_handle_duplicate(event, ZX_RIGHT_SAME_RIGHTS, &handle_log[i]); |
| if (s != ZX_OK) { |
| FATALF("[i == %zd] Can't duplicate event: %s\n", i, zx_status_get_string(s)); |
| } |
| if (handle_log[i] <= 0) { |
| FATALF("[i == %zd] Got bad handle %d\n", i, handle_log[i]); |
| } |
| s = zx_handle_close(handle_log[i]); |
| if (s != ZX_OK) { |
| FATALF("[i == %zd] Can't close handle %d: %s\n", i, handle_log[i], zx_status_get_string(s)); |
| } |
| } |
| |
| // Look for any aliases. |
| qsort(handle_log, window_size, sizeof(zx_handle_t), handle_cmp); |
| for (size_t i = 1; i < window_size; i++) { |
| if (handle_log[i] == handle_log[i - 1]) { |
| saw_aliases = true; |
| break; |
| } |
| } |
| } |
| |
| free(handle_log); |
| zx_handle_close(event); |
| return saw_aliases; |
| } |
| |
| // Searches for the largest window size that doesn't contain |
| // handle value aliases. |
| static size_t find_handle_alias_window_size(void) { |
| size_t min_fail = 8192; // "fail" meaning "aliases found" |
| size_t max_pass = 1; // "pass" meaning "no aliases found" |
| while (true) { |
| size_t cur_win = (min_fail - 1 + max_pass + 1) / 2; |
| if (cur_win <= max_pass) { |
| return max_pass; |
| } |
| printf(" window_size %4zd: ", cur_win); |
| fflush(stdout); |
| if (find_handle_value_aliases(cur_win)) { |
| printf("ALIAS FOUND\n"); |
| min_fail = cur_win; |
| } else { |
| printf("no alias found\n"); |
| max_pass = cur_win; |
| } |
| } |
| } |
| |
| // This test is disabled because it is potentially flaky. |
| // |
| // This test isn't deterministic, because its behavior depends on the |
| // system-wide usage of the kernel's handle arena. |
| // It can produce a false failure if someone else consumes/recycles handle |
| // slots in the same way this test does. |
| // It can produce a false success if someone else consumes and holds onto |
| // handle slots, so that this test never gets a chance to see the same |
| // slot each time. |
| TEST(HandleReuse, DISABLED_handle_value_alias_test) { |
| printf("\n"); |
| size_t window_size = find_handle_alias_window_size(); |
| printf(" Converged at %zd (largest window_size with no aliases)\n", window_size); |
| |
| // The handle table as of 13 Mar 2017 should let us re-use a handle |
| // slot 4096 times before producing an alias. Use half that as our |
| // target to bias the test away from false failures. |
| const size_t min_window_size = 2048; |
| EXPECT_GE(window_size, min_window_size, ""); |
| } |