From 9fd3781d73286fadf971ab0b6fcc231fba008c94 Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Thu, 12 Jun 2025 23:10:24 +0200 Subject: [PATCH 1/3] 8319589: Attach from root to a user java process not supported in Mac --- src/hotspot/os/bsd/os_bsd.cpp | 19 ++++ src/hotspot/os/bsd/os_bsd.hpp | 4 +- src/hotspot/os/posix/os_posix.cpp | 4 + src/hotspot/os/posix/os_posix.hpp | 3 + src/hotspot/os/posix/perfMemory_posix.cpp | 91 ++++++++++++++++++- .../sun/tools/attach/VirtualMachineImpl.java | 52 ++++++++--- .../sun/jvmstat/PlatformSupportImpl.java | 91 +++++++++++++++++++ .../share/classes/module-info.java | 4 +- 8 files changed, 254 insertions(+), 14 deletions(-) create mode 100644 src/jdk.internal.jvmstat/macosx/classes/sun/jvmstat/PlatformSupportImpl.java diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 6f7d9a6de3708..6d7e77202c8f9 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -862,6 +862,25 @@ pid_t os::Bsd::gettid() { } } +// Returns the uid of a process or -1 on error +uid_t os::Bsd::get_process_uid(pid_t pid) { + struct kinfo_proc kp; + size_t size = sizeof kp; + int mib_kern[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; + if (sysctl(mib_kern, 4, &kp, &size, nullptr, 0) == 0) { + if (size > 0 && kp.kp_proc.p_pid == pid) { + return kp.kp_eproc.e_ucred.cr_uid; + } + } + return (uid_t)-1; +} + +// Returns true if the process is running as root +bool os::Bsd::is_process_root(pid_t pid) { + uid_t uid = get_process_uid(pid); + return (uid != (uid_t)-1) ? os::Posix::is_root(uid) : false; +} + intx os::current_thread_id() { #ifdef __APPLE__ return (intx)os::Bsd::gettid(); diff --git a/src/hotspot/os/bsd/os_bsd.hpp b/src/hotspot/os/bsd/os_bsd.hpp index 72de9ca597195..82913edb6a395 100644 --- a/src/hotspot/os/bsd/os_bsd.hpp +++ b/src/hotspot/os/bsd/os_bsd.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,6 +61,8 @@ class os::Bsd { static pthread_t main_thread(void) { return _main_thread; } static pid_t gettid(); + static uid_t get_process_uid(pid_t pid); + static bool is_process_root(pid_t pid); static intptr_t* ucontext_get_sp(const ucontext_t* uc); static intptr_t* ucontext_get_fp(const ucontext_t* uc); diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 303e44eadcb86..69e5df55bacce 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -1325,6 +1325,10 @@ bool os::Posix::is_root(uid_t uid){ return ROOT_UID == uid; } +bool os::Posix::is_current_user_root(){ + return is_root(geteuid()); +} + bool os::Posix::matches_effective_uid_or_root(uid_t uid) { return is_root(uid) || geteuid() == uid; } diff --git a/src/hotspot/os/posix/os_posix.hpp b/src/hotspot/os/posix/os_posix.hpp index 4b8b75ea07ef7..424d737cf422b 100644 --- a/src/hotspot/os/posix/os_posix.hpp +++ b/src/hotspot/os/posix/os_posix.hpp @@ -76,6 +76,9 @@ class os::Posix { // Returns true if given uid is root. static bool is_root(uid_t uid); + // Returns true if the current user is root. + static bool is_current_user_root(); + // Returns true if given uid is effective or root uid. static bool matches_effective_uid_or_root(uid_t uid); diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp index cbbecea3a6a0a..b6229f3169b02 100644 --- a/src/hotspot/os/posix/perfMemory_posix.cpp +++ b/src/hotspot/os/posix/perfMemory_posix.cpp @@ -39,6 +39,9 @@ #if defined(LINUX) #include "os_linux.hpp" #endif +#if defined(BSD) +#include "os_bsd.hpp" +#endif // put OS-includes here # include @@ -127,6 +130,80 @@ static void save_memory_to_file(char* addr, size_t size) { // simple file apis. // +#ifdef __APPLE__ + +// macOS has a secure per-user temporary directory. +// Root can attach to a non-root process, hence it needs +// to lookup /var/folders for the user specific temporary directory +// of the form /var/folders/*/*/T, that contains PERFDATA_NAME_user +// directory. +// +static const char VAR_FOLDERS[] = "/var/folders/"; +static int get_user_tmp_dir_macos(const char* user, int vmid, char *output_path /* size = PATH_MAX */) { + + // read the var/folders directory + DIR* varfolders_dir = os::opendir(VAR_FOLDERS); + if (varfolders_dir != nullptr) { + + // var/folders directory contains 2-characters subdirectories (buckets) + struct dirent* bucket_de; + + // loop until the PERFDATA_NAME_user directory has been found + while ((bucket_de = os::readdir(varfolders_dir)) != nullptr) { + + // skip over files and special "." and ".." + if (bucket_de->d_type != DT_DIR || bucket_de->d_name[0] == '.') { + continue; + } + + // absolute path to the bucket + char bucket[PATH_MAX]; + int b = snprintf(bucket, PATH_MAX, "%s%s/", VAR_FOLDERS, bucket_de->d_name); + + // the total length of the absolute path must not exceed the buffer size + if (b >= PATH_MAX || b < 0) { + continue; + } + + // each bucket contains next level subdirectories + DIR* bucket_dir = os::opendir(bucket); + if (bucket_dir == nullptr) { + continue; + } + + // read each subdirectory, skipping over regular files + struct dirent* subbucket_de; + while ((subbucket_de = os::readdir(bucket_dir)) != nullptr) { + if (subbucket_de->d_type != DT_DIR || subbucket_de->d_name[0] == '.') { + continue; + } + + // if the PERFDATA_NAME_user directory exists in the T subdirectory, + // this means the subdirectory is the temporary directory of the user. + // + char perfdata_path[PATH_MAX]; + int p = snprintf(perfdata_path, PATH_MAX, "%s%s/T/%s_%s/", bucket, subbucket_de->d_name, PERFDATA_NAME, user); + + // the total length must not exceed the output buffer size + if (p >= PATH_MAX || p < 0) { + continue; + } + + // check if the subdirectory exists + if (os::file_exists(perfdata_path)) { + + // the return value of snprintf is not checked for the second time + return snprintf(output_path, PATH_MAX, "%s%s/T", bucket, subbucket_de->d_name); + } + } + os::closedir(bucket_dir); + } + os::closedir(varfolders_dir); + } + return -1; +} +#endif + // return the user specific temporary directory name. // the caller is expected to free the allocated memory. // @@ -144,6 +221,17 @@ static char* get_user_tmp_dir(const char* user, int vmid, int nspid) { jio_snprintf(buffer, TMP_BUFFER_LEN, "/proc/%d/root%s", vmid, tmpdir); tmpdir = buffer; } +#endif +#ifdef __APPLE__ + char buffer[PATH_MAX] = {0}; + // Check if the current user is root and the target VM is running as non-root. + // Otherwise the output of os::get_temp_directory() is used. + // + if (os::Posix::is_current_user_root() && !os::Bsd::is_process_root(vmid)) { + if (get_user_tmp_dir_macos(user, vmid, buffer) != -1) { + tmpdir = buffer; + } + } #endif const char* perfdir = PERFDATA_NAME; size_t nbytes = strlen(tmpdir) + strlen(perfdir) + strlen(user) + 3; @@ -1161,7 +1249,8 @@ static void mmap_attach_shared(int vmid, char** addr, size_t* sizep, TRAPS) { // for linux, determine if vmid is for a containerized process int nspid = LINUX_ONLY(os::Linux::get_namespace_pid(vmid)) NOT_LINUX(-1); - const char* luser = get_user_name(vmid, &nspid, CHECK); + const char* luser = NOT_MACOS(get_user_name(vmid, &nspid, CHECK)) + MACOS_ONLY(get_user_name(os::Bsd::get_process_uid(vmid))); if (luser == nullptr) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), diff --git a/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java b/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java index 5c786db13665a..ce6d9006364c3 100644 --- a/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java +++ b/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java @@ -28,9 +28,13 @@ import com.sun.tools.attach.AttachNotSupportedException; import com.sun.tools.attach.spi.AttachProvider; +import sun.jvmstat.PlatformSupport; + import java.io.InputStream; import java.io.IOException; import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; import static java.nio.charset.StandardCharsets.UTF_8; @@ -39,14 +43,17 @@ */ @SuppressWarnings("restricted") public class VirtualMachineImpl extends HotSpotVirtualMachine { - // "tmpdir" is used as a global well-known location for the files - // .java_pid. and .attach_pid. It is important that this - // location is the same for all processes, otherwise the tools - // will not be able to find all Hotspot processes. - // This is intentionally not the same as java.io.tmpdir, since - // the latter can be changed by the user. - // Any changes to this needs to be synchronized with HotSpot. - private static final String tmpdir; + + /** + * HotSpot PerfData file prefix + */ + private static final String HSPERFDATA_PREFIX = "hsperfdata_"; + + /** + * Use platform specific methods for looking up temporary directories. + */ + private static final PlatformSupport platformSupport = PlatformSupport.getInstance(); + String socket_path; private OperationProperties props = new OperationProperties(VERSION_1); // updated in ctor @@ -67,7 +74,8 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { // Find the socket file. If not found then we attempt to start the // attach mechanism in the target VM by sending it a QUIT signal. // Then we attempt to find the socket file again. - File socket_file = new File(tmpdir, ".java_pid" + pid); + // In macOS the socket file is located in per-user temp directory. + File socket_file = new File(getTempDirFromPid(pid), ".java_pid" + pid); socket_path = socket_file.getPath(); if (!socket_file.exists()) { File f = createAttachFile(pid); @@ -212,11 +220,34 @@ protected void close(long fd) throws IOException { } private File createAttachFile(int pid) throws IOException { - File f = new File(tmpdir, ".attach_pid" + pid); + // In macOS the attach file is created in the target user temp directory + File f = new File(getTempDirFromPid(pid), ".attach_pid" + pid); createAttachFile0(f.getPath()); return f; } + /* + * Returns a platform-specific temporary directory for a given process. + * In VMs running as unprivileged user it returns the default platform-specific + * temporary directory. In VMs running as root it searches over the list of + * temporary directories for one containing HotSpot PerfData directory. + */ + private String getTempDirFromPid(int pid) { + ProcessHandle ph = ProcessHandle.of(pid).orElse(null); + if (ph != null) { + String user = ph.info().user().orElse(null); + if (user != null) { + for (String dir : platformSupport.getTemporaryDirectories(pid)) { + Path fullPath = Path.of(dir, HSPERFDATA_PREFIX + user, String.valueOf(pid)); + if(Files.exists(fullPath)) { + return dir; + } + } + } + } + return PlatformSupport.getTemporaryDirectory(); + } + //-- native methods static native boolean checkCatchesAndSendQuitTo(int pid, boolean throwIfNotReady) throws IOException, AttachNotSupportedException; @@ -239,6 +270,5 @@ private File createAttachFile(int pid) throws IOException { static { System.loadLibrary("attach"); - tmpdir = getTempDir(); } } diff --git a/src/jdk.internal.jvmstat/macosx/classes/sun/jvmstat/PlatformSupportImpl.java b/src/jdk.internal.jvmstat/macosx/classes/sun/jvmstat/PlatformSupportImpl.java new file mode 100644 index 0000000000000..f858fde4dcef9 --- /dev/null +++ b/src/jdk.internal.jvmstat/macosx/classes/sun/jvmstat/PlatformSupportImpl.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, BELLSOFT. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.jvmstat; + +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +/* + * macOS specific implementation of the PlatformSupport routines + * providing temporary directory support. + */ +public class PlatformSupportImpl extends PlatformSupport { + + private static final String VAR_FOLDERS_PATH = "/var/folders"; + private static final String USER_NAME_SYSTEM_PROPERTY = "user.name"; + private static final String USER_NAME_ROOT = "root"; + private static final String DIRHELPER_TEMP_STR = "T"; + + private static final boolean isCurrentUserRoot = + System.getProperty(USER_NAME_SYSTEM_PROPERTY).equals(USER_NAME_ROOT); + + public PlatformSupportImpl() { + super(); + } + + /* + * Return a list of the temporary directories that the VM uses + * for the attach and perf data files. + * + * This function returns the traditional temp directory. Additionally, + * when called by root, it returns other temporary directories of non-root + * users. + * + * macOS per-user temp directories are located under /var/folders + * and have the form /var/folders///T + */ + @Override + public List getTemporaryDirectories(int pid) { + if (!isCurrentUserRoot) { + // early exit for non-root + return List.of(PlatformSupport.getTemporaryDirectory()); + } + List result = new ArrayList<>(); + try (DirectoryStream bs = Files.newDirectoryStream(Path.of(VAR_FOLDERS_PATH))) { + for (Path bucket : bs) { + try (DirectoryStream encUuids = Files.newDirectoryStream(bucket)) { + for (Path encUuid : encUuids) { + try { + Path tempDir = encUuid.resolve(DIRHELPER_TEMP_STR); + if (Files.isDirectory(tempDir) && Files.isReadable(tempDir)) { + result.add(tempDir.toString()); + } + } catch (Exception ignore) { // ignored unreadable bucket/encUuid, continue + } + } + } catch (IOException ignore) { // IOException ignored, continue to the next bucket + } + } + } catch (Exception ignore) { // var/folders directory is inaccessible / other errors + } + return result.isEmpty() ? List.of(PlatformSupport.getTemporaryDirectory()) : result; + } +} diff --git a/src/jdk.internal.jvmstat/share/classes/module-info.java b/src/jdk.internal.jvmstat/share/classes/module-info.java index 9e12c98b0168f..d9e1bc68008cb 100644 --- a/src/jdk.internal.jvmstat/share/classes/module-info.java +++ b/src/jdk.internal.jvmstat/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,8 @@ jdk.jstatd; exports sun.jvmstat.perfdata.monitor to jdk.jstatd; + exports sun.jvmstat to + jdk.attach; uses sun.jvmstat.monitor.MonitoredHostService; From f35e7e6c0d780b3bdf6dc8a6c0d235cc5240b86c Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Wed, 18 Jun 2025 18:29:03 +0200 Subject: [PATCH 2/3] addressed review comments --- src/hotspot/os/bsd/os_bsd.cpp | 74 ++++++++++++++++++++++ src/hotspot/os/bsd/os_bsd.hpp | 4 ++ src/hotspot/os/posix/perfMemory_posix.cpp | 77 +---------------------- 3 files changed, 80 insertions(+), 75 deletions(-) diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 6d7e77202c8f9..6540b8636d20c 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -881,6 +881,80 @@ bool os::Bsd::is_process_root(pid_t pid) { return (uid != (uid_t)-1) ? os::Posix::is_root(uid) : false; } +#ifdef __APPLE__ + +// macOS has a secure per-user temporary directory. +// Root can attach to a non-root process, hence it needs +// to lookup /var/folders for the user specific temporary directory +// of the form /var/folders/*/*/T, that contains PERFDATA_NAME_user +// directory. +// +static const char VAR_FOLDERS[] = "/var/folders/"; +int os::Bsd::get_user_tmp_dir_macos(const char* user, int vmid, char *output_path, int output_size /* = PATH_MAX */) { + + // read the var/folders directory + DIR* varfolders_dir = os::opendir(VAR_FOLDERS); + if (varfolders_dir != nullptr) { + + // var/folders directory contains 2-characters subdirectories (buckets) + struct dirent* bucket_de; + + // loop until the PERFDATA_NAME_user directory has been found + while ((bucket_de = os::readdir(varfolders_dir)) != nullptr) { + + // skip over files and special "." and ".." + if (bucket_de->d_type != DT_DIR || bucket_de->d_name[0] == '.') { + continue; + } + + // absolute path to the bucket + char bucket[PATH_MAX]; + int b = snprintf(bucket, PATH_MAX, "%s%s/", VAR_FOLDERS, bucket_de->d_name); + + // the total length of the absolute path must not exceed the buffer size + if (b >= PATH_MAX || b < 0) { + continue; + } + + // each bucket contains next level subdirectories + DIR* bucket_dir = os::opendir(bucket); + if (bucket_dir == nullptr) { + continue; + } + + // read each subdirectory, skipping over regular files + struct dirent* subbucket_de; + while ((subbucket_de = os::readdir(bucket_dir)) != nullptr) { + if (subbucket_de->d_type != DT_DIR || subbucket_de->d_name[0] == '.') { + continue; + } + + // if the PERFDATA_NAME_user directory exists in the T subdirectory, + // this means the subdirectory is the temporary directory of the user. + // + char perfdata_path[PATH_MAX]; + int p = snprintf(perfdata_path, PATH_MAX, "%s%s/T/%s_%s/", bucket, subbucket_de->d_name, PERFDATA_NAME, user); + + // the total length must not exceed the output buffer size + if (p >= PATH_MAX || p < 0) { + continue; + } + + // check if the subdirectory exists + if (os::file_exists(perfdata_path)) { + + // the return value of snprintf is not checked for the second time + return snprintf(output_path, output_size, "%s%s/T", bucket, subbucket_de->d_name); + } + } + os::closedir(bucket_dir); + } + os::closedir(varfolders_dir); + } + return -1; +} +#endif + intx os::current_thread_id() { #ifdef __APPLE__ return (intx)os::Bsd::gettid(); diff --git a/src/hotspot/os/bsd/os_bsd.hpp b/src/hotspot/os/bsd/os_bsd.hpp index 82913edb6a395..0fe3aafa0b7e7 100644 --- a/src/hotspot/os/bsd/os_bsd.hpp +++ b/src/hotspot/os/bsd/os_bsd.hpp @@ -64,6 +64,10 @@ class os::Bsd { static uid_t get_process_uid(pid_t pid); static bool is_process_root(pid_t pid); +#ifdef __APPLE__ + static int get_user_tmp_dir_macos(const char* user, int vmid, char *output_buffer, int buffer_size /* = PATH_MAX */); +#endif + static intptr_t* ucontext_get_sp(const ucontext_t* uc); static intptr_t* ucontext_get_fp(const ucontext_t* uc); diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp index b6229f3169b02..d95aeda065026 100644 --- a/src/hotspot/os/posix/perfMemory_posix.cpp +++ b/src/hotspot/os/posix/perfMemory_posix.cpp @@ -130,80 +130,6 @@ static void save_memory_to_file(char* addr, size_t size) { // simple file apis. // -#ifdef __APPLE__ - -// macOS has a secure per-user temporary directory. -// Root can attach to a non-root process, hence it needs -// to lookup /var/folders for the user specific temporary directory -// of the form /var/folders/*/*/T, that contains PERFDATA_NAME_user -// directory. -// -static const char VAR_FOLDERS[] = "/var/folders/"; -static int get_user_tmp_dir_macos(const char* user, int vmid, char *output_path /* size = PATH_MAX */) { - - // read the var/folders directory - DIR* varfolders_dir = os::opendir(VAR_FOLDERS); - if (varfolders_dir != nullptr) { - - // var/folders directory contains 2-characters subdirectories (buckets) - struct dirent* bucket_de; - - // loop until the PERFDATA_NAME_user directory has been found - while ((bucket_de = os::readdir(varfolders_dir)) != nullptr) { - - // skip over files and special "." and ".." - if (bucket_de->d_type != DT_DIR || bucket_de->d_name[0] == '.') { - continue; - } - - // absolute path to the bucket - char bucket[PATH_MAX]; - int b = snprintf(bucket, PATH_MAX, "%s%s/", VAR_FOLDERS, bucket_de->d_name); - - // the total length of the absolute path must not exceed the buffer size - if (b >= PATH_MAX || b < 0) { - continue; - } - - // each bucket contains next level subdirectories - DIR* bucket_dir = os::opendir(bucket); - if (bucket_dir == nullptr) { - continue; - } - - // read each subdirectory, skipping over regular files - struct dirent* subbucket_de; - while ((subbucket_de = os::readdir(bucket_dir)) != nullptr) { - if (subbucket_de->d_type != DT_DIR || subbucket_de->d_name[0] == '.') { - continue; - } - - // if the PERFDATA_NAME_user directory exists in the T subdirectory, - // this means the subdirectory is the temporary directory of the user. - // - char perfdata_path[PATH_MAX]; - int p = snprintf(perfdata_path, PATH_MAX, "%s%s/T/%s_%s/", bucket, subbucket_de->d_name, PERFDATA_NAME, user); - - // the total length must not exceed the output buffer size - if (p >= PATH_MAX || p < 0) { - continue; - } - - // check if the subdirectory exists - if (os::file_exists(perfdata_path)) { - - // the return value of snprintf is not checked for the second time - return snprintf(output_path, PATH_MAX, "%s%s/T", bucket, subbucket_de->d_name); - } - } - os::closedir(bucket_dir); - } - os::closedir(varfolders_dir); - } - return -1; -} -#endif - // return the user specific temporary directory name. // the caller is expected to free the allocated memory. // @@ -228,7 +154,8 @@ static char* get_user_tmp_dir(const char* user, int vmid, int nspid) { // Otherwise the output of os::get_temp_directory() is used. // if (os::Posix::is_current_user_root() && !os::Bsd::is_process_root(vmid)) { - if (get_user_tmp_dir_macos(user, vmid, buffer) != -1) { + int path_size = os::Bsd::get_user_tmp_dir_macos(user, vmid, buffer, sizeof buffer); + if (path_size > 0 && (size_t)path_size < sizeof buffer) { tmpdir = buffer; } } From 779a1b35075dc5c2abed79761118a91584ef0939 Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Wed, 18 Jun 2025 18:37:59 +0200 Subject: [PATCH 3/3] Update src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java Co-authored-by: Andrey Turbanov --- .../macosx/classes/sun/tools/attach/VirtualMachineImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java b/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java index ce6d9006364c3..0a4fe1a29034b 100644 --- a/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java +++ b/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java @@ -239,7 +239,7 @@ private String getTempDirFromPid(int pid) { if (user != null) { for (String dir : platformSupport.getTemporaryDirectories(pid)) { Path fullPath = Path.of(dir, HSPERFDATA_PREFIX + user, String.valueOf(pid)); - if(Files.exists(fullPath)) { + if (Files.exists(fullPath)) { return dir; } }