diff --git a/src/quick-lint-js/cli/main.cpp b/src/quick-lint-js/cli/main.cpp index 78d6c286bd..1055c84c54 100644 --- a/src/quick-lint-js/cli/main.cpp +++ b/src/quick-lint-js/cli/main.cpp @@ -348,12 +348,14 @@ Linter_Options get_linter_options_from_language( } void list_debug_apps() { + Monotonic_Allocator temporary_allocator("list_debug_apps"); + struct Table_Row { std::string process_id; std::string server_url; }; std::vector table; - for (const Found_Debug_Server &s : find_debug_servers()) { + for (const Found_Debug_Server &s : find_debug_servers(&temporary_allocator)) { table.push_back(Table_Row{ .process_id = std::to_string(s.process_id), .server_url = diff --git a/src/quick-lint-js/debug/find-debug-server.cpp b/src/quick-lint-js/debug/find-debug-server.cpp index ac4e42dda0..2e237275cb 100644 --- a/src/quick-lint-js/debug/find-debug-server.cpp +++ b/src/quick-lint-js/debug/find-debug-server.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -22,7 +23,6 @@ #include #include #include -#include #if defined(__linux__) #include @@ -257,8 +257,9 @@ void enumerate_all_process_thread_names(Callback&& callback) { #endif #if defined(__linux__) -std::vector find_debug_servers() { - std::vector debug_servers; +Span find_debug_servers(Monotonic_Allocator* allocator) { + Bump_Vector debug_servers( + "debug_servers", allocator); enumerate_all_process_thread_names([&](std::string_view process_id_string, std::string_view thread_name) { @@ -277,13 +278,14 @@ std::vector find_debug_servers() { } }); - return debug_servers; + return debug_servers.release_to_span(); } #endif #if defined(__APPLE__) template -void enumerate_all_process_threads(Callback&& callback) { +void enumerate_all_process_threads(Monotonic_Allocator& allocator, + Callback&& callback) { // Kernel code uses sizeof(int), not sizeof(::pid_t): // https://github.com/apple/darwin-xnu/blob/8f02f2a044b9bb1ad951987ef5bab20ec9486310/bsd/kern/proc_info.c#L339 // @@ -300,10 +302,12 @@ void enumerate_all_process_threads(Callback&& callback) { QLJS_ASSERT( narrow_cast(process_id_buffer_size) % sizeof(::pid_t) == 0); + Bump_Vector<::pid_t, Monotonic_Allocator> process_ids("process_ids", + &allocator); // NOTE(strager): It's okay if our buffer is to small. We miss out on some // processes, but they were just created anyway. Harmless race condition. - std::vector<::pid_t> process_ids( - narrow_cast(process_id_buffer_size) / sizeof(::pid_t)); + process_ids.resize(narrow_cast(process_id_buffer_size) / + sizeof(::pid_t)); process_id_buffer_size = ::proc_listpids(PROC_ALL_PIDS, 0, process_ids.data(), narrow_cast(process_ids.size() * sizeof(::pid_t))); @@ -315,7 +319,8 @@ void enumerate_all_process_threads(Callback&& callback) { process_ids.resize(narrow_cast(process_id_buffer_size) / sizeof(int)); - std::vector thread_ids; + Bump_Vector thread_ids("thread_ids", + &allocator); constexpr std::size_t initial_thread_ids_buffer_count = 128; // Arbitrary. for (::pid_t process_id : process_ids) { thread_ids.resize(initial_thread_ids_buffer_count); @@ -336,7 +341,7 @@ void enumerate_all_process_threads(Callback&& callback) { std::size_t thread_count = narrow_cast(thread_ids_buffer_size) / sizeof(std::uint64_t); - if (thread_count == thread_ids.size()) { + if (narrow_cast(thread_count) == thread_ids.size()) { // We can't tell if we read exactly all the threads or if there are more // threads. Assume there are more threads. thread_ids.resize(thread_ids.size() * 2); @@ -352,42 +357,45 @@ void enumerate_all_process_threads(Callback&& callback) { #endif #if defined(__APPLE__) -std::vector find_debug_servers() { +Span find_debug_servers(Monotonic_Allocator* allocator) { static constexpr char func[] = "find_debug_servers"; - std::vector debug_servers; - enumerate_all_process_threads([&](::pid_t process_id, - std::uint64_t thread_id) -> void { - ::proc_threadinfo thread_info; - int rc = - ::proc_pidinfo(process_id, PROC_PIDTHREADID64INFO, - /*arg=*/thread_id, &thread_info, sizeof(thread_info)); - if (rc == -1) { - QLJS_DEBUG_LOG( - "%s: ignoring failure to get name of thread %llu in process %d: %s\n", - func, narrow_cast(thread_id), process_id, - std::strerror(errno)); - return; - } - QLJS_ASSERT(rc == sizeof(thread_info)); - - std::string_view thread_name( - thread_info.pth_name, - ::strnlen(thread_info.pth_name, MAXTHREADNAMESIZE)); - if (std::optional port_number = - parse_port_number_from_thread_name(to_string8_view(thread_name))) { - debug_servers.push_back(Found_Debug_Server{ - .process_id = narrow_cast(process_id), - .port_number = *port_number, + Bump_Vector debug_servers( + "debug_servers", allocator); + enumerate_all_process_threads( + *allocator, [&](::pid_t process_id, std::uint64_t thread_id) -> void { + ::proc_threadinfo thread_info; + int rc = ::proc_pidinfo(process_id, PROC_PIDTHREADID64INFO, + /*arg=*/thread_id, &thread_info, + sizeof(thread_info)); + if (rc == -1) { + QLJS_DEBUG_LOG( + "%s: ignoring failure to get name of thread %llu in process %d: " + "%s\n", + func, narrow_cast(thread_id), process_id, + std::strerror(errno)); + return; + } + QLJS_ASSERT(rc == sizeof(thread_info)); + + std::string_view thread_name( + thread_info.pth_name, + ::strnlen(thread_info.pth_name, MAXTHREADNAMESIZE)); + if (std::optional port_number = + parse_port_number_from_thread_name( + to_string8_view(thread_name))) { + debug_servers.push_back(Found_Debug_Server{ + .process_id = narrow_cast(process_id), + .port_number = *port_number, + }); + } }); - } - }); - return debug_servers; + return debug_servers.release_to_span(); } #endif #if defined(__FreeBSD__) -std::vector find_debug_servers() { +Span find_debug_servers(Monotonic_Allocator* allocator) { static constexpr char func[] = "find_debug_servers"; // NOTE(Nico): On FreeBSD we can just fetch the list of all active LWPs by @@ -409,7 +417,8 @@ std::vector find_debug_servers() { size_t own_jid_size; ::kinfo_proc* p; ::kvm_t* kd; - std::vector debug_servers; + Bump_Vector debug_servers( + "debug_servers", allocator); // Query our own jail id own_jid_size = sizeof own_jid; @@ -458,7 +467,7 @@ std::vector find_debug_servers() { error_get_procs: ::kvm_close(kd); error_open_kvm: - return debug_servers; + return debug_servers.release_to_span(); } #endif // __FreeBSD__ @@ -505,10 +514,11 @@ void enumerate_all_process_threads(Callback&& callback) { #endif #if defined(_WIN32) -std::vector find_debug_servers() { +Span find_debug_servers(Monotonic_Allocator* allocator) { static constexpr char func[] = "find_debug_servers"; - std::vector debug_servers; + Bump_Vector debug_servers( + "debug_servers", allocator); enumerate_all_process_threads([&](::DWORD process_id, ::DWORD thread_id) -> void { Windows_Handle_File thread_handle( @@ -564,14 +574,15 @@ std::vector find_debug_servers() { ::LocalFree(thread_name); }); - return debug_servers; + return debug_servers.release_to_span(); } #endif #if !QLJS_CAN_FIND_DEBUG_SERVERS -std::vector find_debug_servers() { +Span find_debug_servers([ + [maybe_unused]] Monotonic_Allocator* allocator) { #warning "--debug-apps is not supported on this platform" - return std::vector(); + return Span(); } #endif } diff --git a/src/quick-lint-js/debug/find-debug-server.h b/src/quick-lint-js/debug/find-debug-server.h index e116d7b05b..55da591328 100644 --- a/src/quick-lint-js/debug/find-debug-server.h +++ b/src/quick-lint-js/debug/find-debug-server.h @@ -4,8 +4,8 @@ #pragma once #include +#include #include -#include namespace quick_lint_js { #if QLJS_FEATURE_DEBUG_SERVER @@ -32,8 +32,10 @@ struct Found_Debug_Server { // This function is inherently racy. By the time this function returns, any // number of returned debug servers might be dead. // +// allocator is used to allocate memory for the returned Span. +// // NOTE[find-debug-server] for implementation details. -std::vector find_debug_servers(); +Span find_debug_servers(Monotonic_Allocator* allocator); } // quick-lint-js finds bugs in JavaScript programs. diff --git a/test/test-debug-server.cpp b/test/test-debug-server.cpp index 34257e363b..c069352f49 100644 --- a/test/test-debug-server.cpp +++ b/test/test-debug-server.cpp @@ -538,7 +538,8 @@ TEST_F(Test_Debug_Server, find_debug_servers_finds_running_instance_SLOW) { ASSERT_TRUE(wait_result.ok()) << wait_result.error_to_string(); std::uint16_t server_port = server->tcp_port_number(); - std::vector servers = find_debug_servers(); + Monotonic_Allocator allocator("Test_Debug_Server"); + Span servers = find_debug_servers(&allocator); auto found_server_it = find_first_if(servers, [&](const Found_Debug_Server &s) -> bool { return s.port_number == server_port;