From e0f2f4b216bc9358caa65975204aee086e4fcbd2 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Mon, 13 Jan 2025 18:25:42 +0000 Subject: [PATCH] 8313396: Portable implementation of FORBID_C_FUNCTION and ALLOW_C_FUNCTION Co-authored-by: Martin Doerr Reviewed-by: coleenp, dholmes, jsjolen --- src/hotspot/os/aix/libodm_aix.cpp | 3 +- src/hotspot/os/aix/loadlib_aix.cpp | 17 +++-- src/hotspot/os/aix/os_aix.cpp | 9 ++- src/hotspot/os/aix/porting_aix.cpp | 5 +- src/hotspot/os/bsd/decoder_machO.cpp | 10 ++- src/hotspot/os/linux/decoder_linux.cpp | 9 ++- .../os/linux/gc/z/zMountPoint_linux.cpp | 11 +-- src/hotspot/os/linux/mallocInfoDcmd.cpp | 11 +-- .../os/posix/forbiddenFunctions_posix.hpp | 54 ++++++++++++++ src/hotspot/os/posix/os_posix.cpp | 13 ++-- .../posix/permitForbiddenFunctions_posix.hpp | 45 ++++++++++++ .../os/windows/forbiddenFunctions_windows.hpp | 38 ++++++++++ src/hotspot/os/windows/os_windows.cpp | 11 +-- .../permitForbiddenFunctions_windows.hpp | 45 ++++++++++++ src/hotspot/os/windows/symbolengine.cpp | 7 +- src/hotspot/share/jvmci/jvmciEnv.cpp | 3 +- src/hotspot/share/logging/logTagSet.cpp | 7 +- src/hotspot/share/nmt/mallocSiteTable.cpp | 8 +- src/hotspot/share/nmt/memMapPrinter.cpp | 11 +-- src/hotspot/share/nmt/nmtPreInit.cpp | 9 ++- src/hotspot/share/runtime/os.cpp | 12 +-- .../share/utilities/compilerWarnings.hpp | 64 ++++++++++++---- .../share/utilities/compilerWarnings_gcc.hpp | 61 ++++++++++------ .../utilities/compilerWarnings_visCPP.hpp | 44 +++-------- .../share/utilities/forbiddenFunctions.hpp | 69 ++++++++++++++++++ .../share/utilities/globalDefinitions.hpp | 30 +------- .../utilities/permitForbiddenFunctions.hpp | 73 +++++++++++++++++++ test/hotspot/gtest/code/test_codestrings.cpp | 5 +- .../shenandoah/test_shenandoahNumberSeq.cpp | 4 +- .../test_shenandoahSimpleBitMap.cpp | 6 +- test/hotspot/gtest/gtestMain.cpp | 7 +- test/hotspot/gtest/unittest.hpp | 6 +- 32 files changed, 529 insertions(+), 178 deletions(-) create mode 100644 src/hotspot/os/posix/forbiddenFunctions_posix.hpp create mode 100644 src/hotspot/os/posix/permitForbiddenFunctions_posix.hpp create mode 100644 src/hotspot/os/windows/forbiddenFunctions_windows.hpp create mode 100644 src/hotspot/os/windows/permitForbiddenFunctions_windows.hpp create mode 100644 src/hotspot/share/utilities/forbiddenFunctions.hpp create mode 100644 src/hotspot/share/utilities/permitForbiddenFunctions.hpp diff --git a/src/hotspot/os/aix/libodm_aix.cpp b/src/hotspot/os/aix/libodm_aix.cpp index 9fe0fb7abd8..854fd5e2b79 100644 --- a/src/hotspot/os/aix/libodm_aix.cpp +++ b/src/hotspot/os/aix/libodm_aix.cpp @@ -30,6 +30,7 @@ #include #include "runtime/arguments.hpp" #include "runtime/os.hpp" +#include "utilities/permitForbiddenFunctions.hpp" dynamicOdm::dynamicOdm() { @@ -59,7 +60,7 @@ dynamicOdm::~dynamicOdm() { } -void odmWrapper::clean_data() { if (_data) { free(_data); _data = nullptr; } } +void odmWrapper::clean_data() { if (_data) { permit_forbidden_function::free(_data); _data = nullptr; } } int odmWrapper::class_offset(const char *field, bool is_aix_5) diff --git a/src/hotspot/os/aix/loadlib_aix.cpp b/src/hotspot/os/aix/loadlib_aix.cpp index bc21aef3836..88f660ad46f 100644 --- a/src/hotspot/os/aix/loadlib_aix.cpp +++ b/src/hotspot/os/aix/loadlib_aix.cpp @@ -38,6 +38,7 @@ #include "logging/log.hpp" #include "utilities/debug.hpp" #include "utilities/ostream.hpp" +#include "utilities/permitForbiddenFunctions.hpp" // For loadquery() #include @@ -55,7 +56,7 @@ class StringList { // Enlarge list. If oom, leave old list intact and return false. bool enlarge() { int cap2 = _cap + 64; - char** l2 = (char**) ::realloc(_list, sizeof(char*) * cap2); + char** l2 = (char**) permit_forbidden_function::realloc(_list, sizeof(char*) * cap2); if (!l2) { return false; } @@ -73,7 +74,7 @@ class StringList { } } assert0(_cap > _num); - char* s2 = ::strdup(s); + char* s2 = permit_forbidden_function::strdup(s); if (!s2) { return nullptr; } @@ -167,7 +168,7 @@ static void free_entry_list(loaded_module_t** start) { loaded_module_t* lm = *start; while (lm) { loaded_module_t* const lm2 = lm->next; - ::free(lm); + permit_forbidden_function::free(lm); lm = lm2; } *start = nullptr; @@ -190,7 +191,7 @@ static bool reload_table() { uint8_t* buffer = nullptr; size_t buflen = 1024; for (;;) { - buffer = (uint8_t*) ::realloc(buffer, buflen); + buffer = (uint8_t*) permit_forbidden_function::realloc(buffer, buflen); if (loadquery(L_GETINFO, buffer, buflen) == -1) { if (errno == ENOMEM) { buflen *= 2; @@ -210,7 +211,7 @@ static bool reload_table() { for (;;) { - loaded_module_t* lm = (loaded_module_t*) ::malloc(sizeof(loaded_module_t)); + loaded_module_t* lm = (loaded_module_t*) permit_forbidden_function::malloc(sizeof(loaded_module_t)); if (!lm) { log_warning(os)("OOM."); goto cleanup; @@ -226,7 +227,7 @@ static bool reload_table() { lm->path = g_stringlist.add(ldi->ldinfo_filename); if (!lm->path) { log_warning(os)("OOM."); - free(lm); + permit_forbidden_function::free(lm); goto cleanup; } @@ -248,7 +249,7 @@ static bool reload_table() { lm->member = g_stringlist.add(p_mbr_name); if (!lm->member) { log_warning(os)("OOM."); - free(lm); + permit_forbidden_function::free(lm); goto cleanup; } } else { @@ -296,7 +297,7 @@ cleanup: free_entry_list(&new_list); } - ::free(buffer); + permit_forbidden_function::free(buffer); return rc; diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 26627c2f8fb..2d0859a4d5e 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -74,6 +74,7 @@ #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" #include "utilities/growableArray.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include "utilities/vmError.hpp" #if INCLUDE_JFR #include "jfr/support/jfrNativeLibraryLoadEvent.hpp" @@ -364,9 +365,9 @@ static void query_multipage_support() { // or by environment variable LDR_CNTRL (suboption DATAPSIZE). If none is given, // default should be 4K. { - void* p = ::malloc(16*M); + void* p = permit_forbidden_function::malloc(16*M); g_multipage_support.datapsize = os::Aix::query_pagesize(p); - ::free(p); + permit_forbidden_function::free(p); } // Query default shm page size (LDR_CNTRL SHMPSIZE). @@ -1406,7 +1407,7 @@ static struct { } vmem; static void vmembk_add(char* addr, size_t size, size_t pagesize, int type) { - vmembk_t* p = (vmembk_t*) ::malloc(sizeof(vmembk_t)); + vmembk_t* p = (vmembk_t*) permit_forbidden_function::malloc(sizeof(vmembk_t)); assert0(p); if (p) { MiscUtils::AutoCritSect lck(&vmem.cs); @@ -1435,7 +1436,7 @@ static void vmembk_remove(vmembk_t* p0) { for (vmembk_t** pp = &(vmem.first); *pp; pp = &((*pp)->next)) { if (*pp == p0) { *pp = p0->next; - ::free(p0); + permit_forbidden_function::free(p0); return; } } diff --git a/src/hotspot/os/aix/porting_aix.cpp b/src/hotspot/os/aix/porting_aix.cpp index cbc45d3e122..2235d3da686 100644 --- a/src/hotspot/os/aix/porting_aix.cpp +++ b/src/hotspot/os/aix/porting_aix.cpp @@ -39,6 +39,7 @@ #include "runtime/os.hpp" #include "utilities/align.hpp" #include "utilities/debug.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include #include #include @@ -250,7 +251,7 @@ bool AixSymbols::get_function_name ( p_name[namelen-1] = '\0'; } if (demangled_name != nullptr) { - ALLOW_C_FUNCTION(::free, ::free(demangled_name)); + permit_forbidden_function::free(demangled_name); } } } else { @@ -1081,7 +1082,7 @@ void* Aix_dlopen(const char* filename, int Flags, int *eno, const char** error_r if (g_handletable_used == max_handletable) { // No place in array anymore; increase array. unsigned new_max = MAX2(max_handletable * 2, init_num_handles); - struct handletableentry* new_tab = (struct handletableentry*)::realloc(p_handletable, new_max * sizeof(struct handletableentry)); + struct handletableentry* new_tab = (struct handletableentry*) permit_forbidden_function::realloc(p_handletable, new_max * sizeof(struct handletableentry)); assert(new_tab != nullptr, "no more memory for handletable"); if (new_tab == nullptr) { *error_report = "dlopen: no more memory for handletable"; diff --git a/src/hotspot/os/bsd/decoder_machO.cpp b/src/hotspot/os/bsd/decoder_machO.cpp index 417e7139a58..2faf7197cb1 100644 --- a/src/hotspot/os/bsd/decoder_machO.cpp +++ b/src/hotspot/os/bsd/decoder_machO.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -28,6 +28,8 @@ #include "decoder_machO.hpp" #include "jvm.h" #include "memory/allocation.inline.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include #include @@ -43,9 +45,9 @@ bool MachODecoder::demangle(const char* symbol, char *buf, int buflen) { // may use different malloc/realloc mechanism that allocates 'buf'. if ((result = abi::__cxa_demangle(symbol, nullptr, nullptr, &status)) != nullptr) { jio_snprintf(buf, buflen, "%s", result); - // call c library's free - ::free(result); - return true; + // call c library's free + permit_forbidden_function::free(result); + return true; } return false; } diff --git a/src/hotspot/os/linux/decoder_linux.cpp b/src/hotspot/os/linux/decoder_linux.cpp index 26b435f69e1..bfe5c537864 100644 --- a/src/hotspot/os/linux/decoder_linux.cpp +++ b/src/hotspot/os/linux/decoder_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -27,6 +27,7 @@ #include "utilities/decoder_elf.hpp" #include "utilities/elfFile.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include @@ -46,9 +47,9 @@ bool ElfDecoder::demangle(const char* symbol, char *buf, int buflen) { // may use different malloc/realloc mechanism that allocates 'buf'. if ((result = abi::__cxa_demangle(symbol, nullptr, nullptr, &status)) != nullptr) { jio_snprintf(buf, buflen, "%s", result); - // call c library's free - ALLOW_C_FUNCTION(::free, ::free(result);) - return true; + // call c library's free + permit_forbidden_function::free(result); + return true; } return false; } diff --git a/src/hotspot/os/linux/gc/z/zMountPoint_linux.cpp b/src/hotspot/os/linux/gc/z/zMountPoint_linux.cpp index e24367219aa..a144cdc5877 100644 --- a/src/hotspot/os/linux/gc/z/zMountPoint_linux.cpp +++ b/src/hotspot/os/linux/gc/z/zMountPoint_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -29,6 +29,7 @@ #include "runtime/globals.hpp" #include "runtime/os.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include #include @@ -63,11 +64,11 @@ char* ZMountPoint::get_mountpoint(const char* line, const char* filesystem) cons strcmp(line_filesystem, filesystem) != 0 || access(line_mountpoint, R_OK|W_OK|X_OK) != 0) { // Not a matching or accessible filesystem - ALLOW_C_FUNCTION(::free, ::free(line_mountpoint);) + permit_forbidden_function::free(line_mountpoint); line_mountpoint = nullptr; } - ALLOW_C_FUNCTION(::free, ::free(line_filesystem);) + permit_forbidden_function::free(line_filesystem); return line_mountpoint; } @@ -91,14 +92,14 @@ void ZMountPoint::get_mountpoints(const char* filesystem, ZArray* mountpo } // readline will return malloced memory. Need raw ::free, not os::free. - ALLOW_C_FUNCTION(::free, ::free(line);) + permit_forbidden_function::free(line); fclose(fd); } void ZMountPoint::free_mountpoints(ZArray* mountpoints) const { ZArrayIterator iter(mountpoints); for (char* mountpoint; iter.next(&mountpoint);) { - ALLOW_C_FUNCTION(::free, ::free(mountpoint);) // *not* os::free + permit_forbidden_function::free(mountpoint); // *not* os::free } mountpoints->clear(); } diff --git a/src/hotspot/os/linux/mallocInfoDcmd.cpp b/src/hotspot/os/linux/mallocInfoDcmd.cpp index 9fd35e6fe6d..181d55e4371 100644 --- a/src/hotspot/os/linux/mallocInfoDcmd.cpp +++ b/src/hotspot/os/linux/mallocInfoDcmd.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -27,6 +27,7 @@ #include "os_linux.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include @@ -36,7 +37,7 @@ void MallocInfoDcmd::execute(DCmdSource source, TRAPS) { #ifdef __GLIBC__ char* buf; size_t size; - ALLOW_C_FUNCTION(::open_memstream, FILE* stream = ::open_memstream(&buf, &size);) + FILE* stream = ::open_memstream(&buf, &size); if (stream == nullptr) { _output->print_cr("Error: Could not call malloc_info(3)"); return; @@ -44,7 +45,7 @@ void MallocInfoDcmd::execute(DCmdSource source, TRAPS) { int err = os::Linux::malloc_info(stream); if (err == 0) { - ALLOW_C_FUNCTION(::fflush, fflush(stream);) + fflush(stream); _output->print_raw(buf); _output->cr(); } else if (err == -1) { @@ -54,8 +55,8 @@ void MallocInfoDcmd::execute(DCmdSource source, TRAPS) { } else { ShouldNotReachHere(); } - ALLOW_C_FUNCTION(::fclose, ::fclose(stream);) - ALLOW_C_FUNCTION(::free, ::free(buf);) + ::fclose(stream); + permit_forbidden_function::free(buf); #else _output->print_cr(malloc_info_unavailable); #endif // __GLIBC__ diff --git a/src/hotspot/os/posix/forbiddenFunctions_posix.hpp b/src/hotspot/os/posix/forbiddenFunctions_posix.hpp new file mode 100644 index 00000000000..358444252a6 --- /dev/null +++ b/src/hotspot/os/posix/forbiddenFunctions_posix.hpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef OS_POSIX_FORBIDDENFUNCTIONS_POSIX_HPP +#define OS_POSIX_FORBIDDENFUNCTIONS_POSIX_HPP + +#include "utilities/compilerWarnings.hpp" + +#include // for size_t +#include // clang workaround for _exit - see FORBID macro. + +// If needed, add os::strndup and use that instead. +FORBID_C_FUNCTION(char* strndup(const char*, size_t), "don't use"); + +// These are unimplementable for Windows, and they aren't useful for a +// POSIX implementation of NMT either. +// https://stackoverflow.com/questions/62962839/stdaligned-alloc-missing-from-visual-studio-2019 +FORBID_C_FUNCTION(int posix_memalign(void**, size_t, size_t), "don't use"); +FORBID_C_FUNCTION(void* aligned_alloc(size_t, size_t), "don't use"); + +// realpath with a null second argument mallocs a string for the result. +FORBID_C_FUNCTION(char* realpath(const char*, char*), "use os::realpath"); + +// Returns a malloc'ed string. +FORBID_C_FUNCTION(char* get_current_dir_name(), "use os::get_current_directory"); + +// Problematic API that should never be used. +FORBID_C_FUNCTION(char* getwd(char*), "use os::get_current_directory"); + +// BSD utility that is subtly different from realloc. +FORBID_C_FUNCTION(void* reallocf(void*, size_t), "use os::realloc"); + +#endif // OS_POSIX_FORBIDDENFUNCTIONS_POSIX_HPP diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 61214a42969..499adf19d92 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, 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 @@ -49,6 +49,7 @@ #include "utilities/formatBuffer.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include "utilities/vmError.hpp" #if INCLUDE_JFR #include "jfr/support/jfrNativeLibraryLoadEvent.hpp" @@ -930,11 +931,11 @@ ssize_t os::connect(int fd, struct sockaddr* him, socklen_t len) { } void os::exit(int num) { - ALLOW_C_FUNCTION(::exit, ::exit(num);) + permit_forbidden_function::exit(num); } void os::_exit(int num) { - ALLOW_C_FUNCTION(::_exit, ::_exit(num);) + permit_forbidden_function::_exit(num); } void os::naked_yield() { @@ -991,7 +992,7 @@ char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) { // This assumes platform realpath() is implemented according to POSIX.1-2008. // POSIX.1-2008 allows to specify null for the output buffer, in which case // output buffer is dynamically allocated and must be ::free()'d by the caller. - ALLOW_C_FUNCTION(::realpath, char* p = ::realpath(filename, nullptr);) + char* p = permit_forbidden_function::realpath(filename, nullptr); if (p != nullptr) { if (strlen(p) < outbuflen) { strcpy(outbuf, p); @@ -999,7 +1000,7 @@ char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) { } else { errno = ENAMETOOLONG; } - ALLOW_C_FUNCTION(::free, ::free(p);) // *not* os::free + permit_forbidden_function::free(p); // *not* os::free } else { // Fallback for platforms struggling with modern Posix standards (AIX 5.3, 6.1). If realpath // returns EINVAL, this may indicate that realpath is not POSIX.1-2008 compatible and @@ -1008,7 +1009,7 @@ char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) { // a memory overwrite. if (errno == EINVAL) { outbuf[outbuflen - 1] = '\0'; - ALLOW_C_FUNCTION(::realpath, p = ::realpath(filename, outbuf);) + p = permit_forbidden_function::realpath(filename, outbuf); if (p != nullptr) { guarantee(outbuf[outbuflen - 1] == '\0', "realpath buffer overwrite detected."); result = p; diff --git a/src/hotspot/os/posix/permitForbiddenFunctions_posix.hpp b/src/hotspot/os/posix/permitForbiddenFunctions_posix.hpp new file mode 100644 index 00000000000..3ff8c383a31 --- /dev/null +++ b/src/hotspot/os/posix/permitForbiddenFunctions_posix.hpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef OS_POSIX_PERMITFORBIDDENFUNCTIONS_POSIX_HPP +#define OS_POSIX_PERMITFORBIDDENFUNCTIONS_POSIX_HPP + +#include "utilities/compilerWarnings.hpp" +#include "utilities/globalDefinitions.hpp" + +// Provide wrappers for some functions otherwise forbidden from use in HotSpot. +// See forbiddenFunctions.hpp for details. + +namespace permit_forbidden_function { +BEGIN_ALLOW_FORBIDDEN_FUNCTIONS + +// Used by the POSIX implementation of os::realpath. +inline char* realpath(const char* path, char* resolved_path) { + return ::realpath(path, resolved_path); +} + +END_ALLOW_FORBIDDEN_FUNCTIONS +} // namespace permit_forbidden_function + +#endif // OS_POSIX_PERMITFORBIDDENFUNCTIONS_POSIX_HPP diff --git a/src/hotspot/os/windows/forbiddenFunctions_windows.hpp b/src/hotspot/os/windows/forbiddenFunctions_windows.hpp new file mode 100644 index 00000000000..81599522ed4 --- /dev/null +++ b/src/hotspot/os/windows/forbiddenFunctions_windows.hpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef OS_WINDOWS_FORBIDDENFUNCTIONS_WINDOWS_HPP +#define OS_WINDOWS_FORBIDDENFUNCTIONS_WINDOWS_HPP + +#include "utilities/compilerWarnings.hpp" + +#include // for size_t + +// _fullpath with a null first argument mallocs a string for the result. +FORBID_IMPORTED_C_FUNCTION(char* _fullpath(char*, const char*, size_t), "use os::realpath"); + +// _snprintf does NOT null terminate if the output would exceed the buffer size. +FORBID_C_FUNCTION(int _snprintf(char*, size_t, const char*, ...), "use os::snprintf"); + +#endif // OS_WINDOWS_FORBIDDENFUNCTIONS_WINDOWS_HPP diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index d2868275094..8f4a25fc854 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -77,6 +77,7 @@ #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" #include "utilities/macros.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include "utilities/population_count.hpp" #include "utilities/vmError.hpp" #include "windbghelp.hpp" @@ -4394,9 +4395,9 @@ static void exit_process_or_thread(Ept what, int exit_code) { if (what == EPT_THREAD) { _endthreadex((unsigned)exit_code); } else if (what == EPT_PROCESS) { - ALLOW_C_FUNCTION(::exit, ::exit(exit_code);) + permit_forbidden_function::exit(exit_code); } else { // EPT_PROCESS_DIE - ALLOW_C_FUNCTION(::_exit, ::_exit(exit_code);) + permit_forbidden_function::_exit(exit_code); } // Should not reach here @@ -5159,7 +5160,7 @@ char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) { } char* result = nullptr; - ALLOW_C_FUNCTION(::_fullpath, char* p = ::_fullpath(nullptr, filename, 0);) + char* p = permit_forbidden_function::_fullpath(nullptr, filename, 0); if (p != nullptr) { if (strlen(p) < outbuflen) { strcpy(outbuf, p); @@ -5167,7 +5168,7 @@ char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) { } else { errno = ENAMETOOLONG; } - ALLOW_C_FUNCTION(::free, ::free(p);) // *not* os::free + permit_forbidden_function::free(p); // *not* os::free } return result; } diff --git a/src/hotspot/os/windows/permitForbiddenFunctions_windows.hpp b/src/hotspot/os/windows/permitForbiddenFunctions_windows.hpp new file mode 100644 index 00000000000..99e77464fbd --- /dev/null +++ b/src/hotspot/os/windows/permitForbiddenFunctions_windows.hpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef OS_WINDOWS_PERMITFORBIDDENFUNCTIONS_WINDOWS_HPP +#define OS_WINDOWS_PERMITFORBIDDENFUNCTIONS_WINDOWS_HPP + +#include "utilities/compilerWarnings.hpp" +#include "utilities/globalDefinitions.hpp" + +// Provide wrappers for some functions otherwise forbidden from use in HotSpot. +// See forbiddenFunctions.hpp for details. + +namespace permit_forbidden_function { +BEGIN_ALLOW_FORBIDDEN_FUNCTIONS + +// Used by the Windows implementation of os::realpath. +inline char* _fullpath(char* absPath, const char* relPath, size_t maxLength) { + return ::_fullpath(absPath, relPath, maxLength); +} + +END_ALLOW_FORBIDDEN_FUNCTIONS +} // namespace permit_forbidden_function + +#endif // OS_WINDOWS_PERMITFORBIDDENFUNCTIONS_WINDOWS_HPP diff --git a/src/hotspot/os/windows/symbolengine.cpp b/src/hotspot/os/windows/symbolengine.cpp index 0d461e671bb..0a9234d4f81 100644 --- a/src/hotspot/os/windows/symbolengine.cpp +++ b/src/hotspot/os/windows/symbolengine.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -27,6 +27,7 @@ #include "symbolengine.hpp" #include "utilities/debug.hpp" #include "utilities/ostream.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include "windbghelp.hpp" #include @@ -103,7 +104,7 @@ public: virtual void initialize () { assert(_p == nullptr && _capacity == 0, "Only call once."); const size_t bytes = OPTIMAL_CAPACITY * sizeof(T); - T* q = (T*) ::malloc(bytes); + T* q = (T*) permit_forbidden_function::malloc(bytes); if (q != nullptr) { _p = q; _capacity = OPTIMAL_CAPACITY; @@ -119,7 +120,7 @@ public: // case, where two buffers need to be of identical capacity. void reset_to_fallback_capacity() { if (_p != _fallback_buffer) { - ::free(_p); + permit_forbidden_function::free(_p); } _p = _fallback_buffer; _capacity = (int)(sizeof(_fallback_buffer) / sizeof(T)); diff --git a/src/hotspot/share/jvmci/jvmciEnv.cpp b/src/hotspot/share/jvmci/jvmciEnv.cpp index 1a53f6b6d2c..3214d476fbe 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.cpp +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp @@ -47,6 +47,7 @@ #include "jvmci/jniAccessMark.inline.hpp" #include "jvmci/jvmciCompiler.hpp" #include "jvmci/jvmciRuntime.hpp" +#include "utilities/permitForbiddenFunctions.hpp" JVMCICompileState::JVMCICompileState(CompileTask* task, JVMCICompiler* compiler): _task(task), @@ -613,7 +614,7 @@ JVMCIEnv::~JVMCIEnv() { if (_init_error_msg != nullptr) { // The memory allocated in libjvmci was not allocated with os::malloc // so must not be freed with os::free. - ALLOW_C_FUNCTION(::free, ::free((void*) _init_error_msg);) + permit_forbidden_function::free((void*)_init_error_msg); } if (_init_error != JNI_OK) { return; diff --git a/src/hotspot/share/logging/logTagSet.cpp b/src/hotspot/share/logging/logTagSet.cpp index 04da1a1e28d..24fa5e2f1f5 100644 --- a/src/hotspot/share/logging/logTagSet.cpp +++ b/src/hotspot/share/logging/logTagSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -34,6 +34,7 @@ #include "memory/allocation.inline.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" +#include "utilities/permitForbiddenFunctions.hpp" LogTagSet* LogTagSet::_list = nullptr; size_t LogTagSet::_ntagsets = 0; @@ -149,7 +150,7 @@ void LogTagSet::vwrite(LogLevelType level, const char* fmt, va_list args) { } else { // Buffer too small, allocate a large enough buffer using malloc/free to avoid circularity. // Since logging is a very basic function, conceivably used within NMT itself, avoid os::malloc/free - ALLOW_C_FUNCTION(::malloc, char* newbuf = (char*)::malloc(newbuf_len * sizeof(char));) + char* newbuf = (char*)permit_forbidden_function::malloc(newbuf_len * sizeof(char)); if (newbuf != nullptr) { prefix_len = _write_prefix(newbuf, newbuf_len); ret = os::vsnprintf(newbuf + prefix_len, newbuf_len - prefix_len, fmt, saved_args); @@ -159,7 +160,7 @@ void LogTagSet::vwrite(LogLevelType level, const char* fmt, va_list args) { if (ret < 0) { log(level, "Log message newbuf issue"); } - ALLOW_C_FUNCTION(::free, ::free(newbuf);) + permit_forbidden_function::free(newbuf); } else { // Native OOM, use buf to output the least message. At this moment buf is full of either // truncated prefix or truncated prefix + string. Put trunc_msg at the end of buf. diff --git a/src/hotspot/share/nmt/mallocSiteTable.cpp b/src/hotspot/share/nmt/mallocSiteTable.cpp index 9411f76c491..c436cd17969 100644 --- a/src/hotspot/share/nmt/mallocSiteTable.cpp +++ b/src/hotspot/share/nmt/mallocSiteTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, 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 @@ -26,6 +26,8 @@ #include "memory/allocation.inline.hpp" #include "nmt/mallocSiteTable.hpp" #include "runtime/atomic.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/permitForbiddenFunctions.hpp" // Malloc site hashtable buckets MallocSiteHashtableEntry** MallocSiteTable::_table = nullptr; @@ -41,9 +43,7 @@ const MallocSiteHashtableEntry* MallocSiteTable::_hash_entry_allocation_site = n * time, it is in single-threaded mode from JVM perspective. */ bool MallocSiteTable::initialize() { - - ALLOW_C_FUNCTION(::calloc, - _table = (MallocSiteHashtableEntry**)::calloc(table_size, sizeof(MallocSiteHashtableEntry*));) + _table = (MallocSiteHashtableEntry**)permit_forbidden_function::calloc(table_size, sizeof(MallocSiteHashtableEntry*)); if (_table == nullptr) { return false; } diff --git a/src/hotspot/share/nmt/memMapPrinter.cpp b/src/hotspot/share/nmt/memMapPrinter.cpp index a6626faa95d..f8db2c5b7ad 100644 --- a/src/hotspot/share/nmt/memMapPrinter.cpp +++ b/src/hotspot/share/nmt/memMapPrinter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2023, 2024, Red Hat, Inc. and/or its affiliates. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -44,6 +44,7 @@ #include "runtime/vmThread.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" +#include "utilities/permitForbiddenFunctions.hpp" // Note: throughout this code we will use the term "VMA" for OS system level memory mapping @@ -97,8 +98,8 @@ public: _count(0), _capacity(0), _last(0) {} ~CachedNMTInformation() { - ALLOW_C_FUNCTION(free, ::free(_ranges);) - ALLOW_C_FUNCTION(free, ::free(_mem_tags);) + permit_forbidden_function::free(_ranges); + permit_forbidden_function::free(_mem_tags); } bool add(const void* from, const void* to, MemTag mem_tag) { @@ -113,8 +114,8 @@ public: // Enlarge if needed const size_t new_capacity = MAX2((size_t)4096, 2 * _capacity); // Unfortunately, we need to allocate manually, raw, since we must prevent NMT deadlocks (ThreadCritical). - ALLOW_C_FUNCTION(realloc, _ranges = (Range*)::realloc(_ranges, new_capacity * sizeof(Range));) - ALLOW_C_FUNCTION(realloc, _mem_tags = (MemTag*)::realloc(_mem_tags, new_capacity * sizeof(MemTag));) + _ranges = (Range*)permit_forbidden_function::realloc(_ranges, new_capacity * sizeof(Range)); + _mem_tags = (MemTag*)permit_forbidden_function::realloc(_mem_tags, new_capacity * sizeof(MemTag)); if (_ranges == nullptr || _mem_tags == nullptr) { // In case of OOM lets make no fuss. Just return. return false; diff --git a/src/hotspot/share/nmt/nmtPreInit.cpp b/src/hotspot/share/nmt/nmtPreInit.cpp index 0aa74566f42..9b78988c4ed 100644 --- a/src/hotspot/share/nmt/nmtPreInit.cpp +++ b/src/hotspot/share/nmt/nmtPreInit.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2022, 2023 SAP SE. All rights reserved. - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 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 @@ -30,12 +30,13 @@ #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" +#include "utilities/permitForbiddenFunctions.hpp" // Obviously we cannot use os::malloc for any dynamic allocation during pre-NMT-init, so we must use // raw malloc; to make this very clear, wrap them. -static void* raw_malloc(size_t s) { ALLOW_C_FUNCTION(::malloc, return ::malloc(s);) } -static void* raw_realloc(void* old, size_t s) { ALLOW_C_FUNCTION(::realloc, return ::realloc(old, s);) } -static void raw_free(void* p) { ALLOW_C_FUNCTION(::free, ::free(p);) } +static void* raw_malloc(size_t s) { return permit_forbidden_function::malloc(s); } +static void* raw_realloc(void* old, size_t s) { return permit_forbidden_function::realloc(old, s); } +static void raw_free(void* p) { permit_forbidden_function::free(p); } // To keep matters simple we just raise a fatal error on OOM. Since preinit allocation // is just used for pre-VM-initialization mallocs, none of which are optional, we don't diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 9c73e255db2..e24160bc769 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -77,7 +77,9 @@ #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" #include "utilities/fastrand.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include "utilities/powerOfTwo.hpp" #ifdef LINUX @@ -118,7 +120,7 @@ int os::snprintf_checked(char* buf, size_t len, const char* fmt, ...) { } int os::vsnprintf(char* buf, size_t len, const char* fmt, va_list args) { - ALLOW_C_FUNCTION(::vsnprintf, int result = ::vsnprintf(buf, len, fmt, args);) + int result = permit_forbidden_function::vsnprintf(buf, len, fmt, args); // If an encoding error occurred (result < 0) then it's not clear // whether the buffer is NUL terminated, so ensure it is. if ((result < 0) && (len > 0)) { @@ -655,7 +657,7 @@ void* os::malloc(size_t size, MemTag mem_tag, const NativeCallStack& stack) { return nullptr; } - ALLOW_C_FUNCTION(::malloc, void* const outer_ptr = ::malloc(outer_size);) + void* const outer_ptr = permit_forbidden_function::malloc(outer_size); if (outer_ptr == nullptr) { return nullptr; } @@ -722,7 +724,7 @@ void* os::realloc(void *memblock, size_t size, MemTag mem_tag, const NativeCallS header->mark_block_as_dead(); // the real realloc - ALLOW_C_FUNCTION(::realloc, void* const new_outer_ptr = ::realloc(header, new_outer_size);) + void* const new_outer_ptr = permit_forbidden_function::realloc(header, new_outer_size); if (new_outer_ptr == nullptr) { // realloc(3) failed and the block still exists. @@ -750,7 +752,7 @@ void* os::realloc(void *memblock, size_t size, MemTag mem_tag, const NativeCallS } else { // NMT disabled. - ALLOW_C_FUNCTION(::realloc, rc = ::realloc(memblock, size);) + rc = permit_forbidden_function::realloc(memblock, size); if (rc == nullptr) { return nullptr; } @@ -778,7 +780,7 @@ void os::free(void *memblock) { // When NMT is enabled this checks for heap overwrites, then deaccounts the old block. void* const old_outer_ptr = MemTracker::record_free(memblock); - ALLOW_C_FUNCTION(::free, ::free(old_outer_ptr);) + permit_forbidden_function::free(old_outer_ptr); } void os::init_random(unsigned int initval) { diff --git a/src/hotspot/share/utilities/compilerWarnings.hpp b/src/hotspot/share/utilities/compilerWarnings.hpp index ddcaf022fa6..49f13515b2b 100644 --- a/src/hotspot/share/utilities/compilerWarnings.hpp +++ b/src/hotspot/share/utilities/compilerWarnings.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -88,23 +88,57 @@ // Support warnings for use of certain C functions, except where explicitly // permitted. -// -// FORBID_C_FUNCTION(signature, alternative) -// - signature: the function that should not normally be used. -// - alternative: a string that may be used in a warning about a use, typically -// suggesting an alternative. -// -// ALLOW_C_FUNCTION(name, ... using statement ...) -// - name: the name of a forbidden function whose use is permitted in statement. -// - statement: a use of the otherwise forbidden function. Using a variadic -// tail allows the statement to contain non-nested commas. -#ifndef FORBID_C_FUNCTION -#define FORBID_C_FUNCTION(signature, alternative) +// FORBID_C_FUNCTION(Signature, Alternative) +// - Signature: the function that should not normally be used. +// - Alternative: a string literal that may be used in a warning about a use, +// often suggesting an alternative. +// Declares the C-linkage function designated by Signature to be deprecated, +// using the `deprecated` attribute with Alternative as an argument. +// +// The variants with IMPORTED in the name are to deal with Windows +// requirements, using FORBIDDEN_FUNCTION_IMPORT_SPEC. See the Visual +// Studio definition of that macro for more details. The default has +// an empty expansion. The potentially added spec must precede the +// base signature but follow all attributes. +// +// FORBID_NORETURN_C_FUNCTION deals with a clang issue. See the clang +// definition of FORBIDDEN_FUNCTION_NORETURN_ATTRIBUTE for more +// details. The default expands to `[[noreturn]]`. +#define FORBID_C_FUNCTION(Signature, Alternative) \ + extern "C" { [[deprecated(Alternative)]] Signature; } + +#ifndef FORBIDDEN_FUNCTION_IMPORT_SPEC +#define FORBIDDEN_FUNCTION_IMPORT_SPEC #endif -#ifndef ALLOW_C_FUNCTION -#define ALLOW_C_FUNCTION(name, ...) __VA_ARGS__ +#ifndef FORBIDDEN_FUNCTION_NORETURN_ATTRIBUTE +#define FORBIDDEN_FUNCTION_NORETURN_ATTRIBUTE [[noreturn]] #endif +#define FORBID_IMPORTED_C_FUNCTION(Signature, Alternative) \ + FORBID_C_FUNCTION(FORBIDDEN_FUNCTION_IMPORT_SPEC Signature, Alternative) + +#define FORBID_NORETURN_C_FUNCTION(Signature, Alternative) \ + FORBID_C_FUNCTION(FORBIDDEN_FUNCTION_NORETURN_ATTRIBUTE Signature, Alternative) + +#define FORBID_IMPORTED_NORETURN_C_FUNCTION(Signature, Alternative) \ + FORBID_NORETURN_C_FUNCTION(FORBIDDEN_FUNCTION_IMPORT_SPEC Signature, Alternative) + +// A BEGIN/END_ALLOW_FORBIDDEN_FUNCTIONS pair establishes a scope in which the +// deprecation warnings used to forbid the use of certain functions are +// suppressed. These macros are not intended for warning suppression at +// individual call sites; see permitForbiddenFunctions.hpp for the approach +// taken for that where needed. Rather, these are used to suppress warnings +// from 3rd-party code included by HotSpot, such as the gtest framework and +// C++ Standard Library headers, which may refer to functions that are +// disallowed in other parts of HotSpot. They are also used in the +// implementation of the "permit" mechanism. +#define BEGIN_ALLOW_FORBIDDEN_FUNCTIONS \ + PRAGMA_DIAG_PUSH \ + PRAGMA_DEPRECATED_IGNORED + +#define END_ALLOW_FORBIDDEN_FUNCTIONS \ + PRAGMA_DIAG_POP + #endif // SHARE_UTILITIES_COMPILERWARNINGS_HPP diff --git a/src/hotspot/share/utilities/compilerWarnings_gcc.hpp b/src/hotspot/share/utilities/compilerWarnings_gcc.hpp index 1dd5892e4c3..4f89a92f12c 100644 --- a/src/hotspot/share/utilities/compilerWarnings_gcc.hpp +++ b/src/hotspot/share/utilities/compilerWarnings_gcc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -70,32 +70,45 @@ #define PRAGMA_ZERO_AS_NULL_POINTER_CONSTANT_IGNORED \ PRAGMA_DISABLE_GCC_WARNING("-Wzero-as-null-pointer-constant") -#if (__GNUC__ >= 10) -// TODO: Re-enable warning attribute for Clang once -// https://github.com/llvm/llvm-project/issues/56519 is fixed and released. -// || (defined(__clang_major__) && (__clang_major__ >= 14)) +#define PRAGMA_DEPRECATED_IGNORED \ + PRAGMA_DISABLE_GCC_WARNING("-Wdeprecated-declarations") -// Use "warning" attribute to detect uses of "forbidden" functions. +// This macro is used by the NORETURN variants of FORBID_C_FUNCTION. // -// Note: The warning attribute is available since GCC 9, but disabling pragmas -// does not work reliably in ALLOW_C_FUNCTION. GCC 10+ and up work fine. +// The [[noreturn]] attribute requires that the first declaration of a +// function has it if any have it. clang does not treat an old-style noreturn +// attribute on the first declaration as meeting that requirement. But some +// libraries use old-style noreturn attributes. So if we use [[noreturn]] in +// the forbidding declaration, but the library header for the function has +// already been included, we get a compiler error. Similarly, if we use an +// old-style noreturn attribute and the library header is included after the +// forbidding declaration. // -// Note: _FORTIFY_SOURCE transforms calls to certain functions into calls to -// associated "checking" functions, and that transformation seems to occur -// *before* the attribute check. We use fortification in fastdebug builds, -// so uses of functions that are both forbidden and fortified won't cause -// forbidden warnings in such builds. -#define FORBID_C_FUNCTION(signature, alternative) \ - extern "C" __attribute__((__warning__(alternative))) signature; +// For now, we're only going to worry about the standard library, and not +// noreturn functions in some other library that we might want to forbid in +// the future. If there's more than one library to be accounted for, then +// things may get more complicated. +// +// There are several ways we could deal with this. +// +// Probably the most robust is to use the same style of noreturn attribute as +// is used by the library providing the function. That way it doesn't matter +// in which order the inclusion of the library header and the forbidding are +// performed. We could use configure to determine which to use and provide a +// macro to select on here. +// +// Another approach is to always use the old-style attribute in the forbidding +// declaration, but ensure the relevant library header has been included +// before the forbidding declaration. Since there are currently only a couple +// of affected functions, this is easier to implement. So this is the +// approach being taken for now. +// +// And remember, all of this is because clang treats an old-style noreturn +// attribute as not counting toward the [[noreturn]] requirement that the +// first declaration must have a noreturn attribute. -// Disable warning attribute over the scope of the affected statement. -// The name serves only to document the intended function. -#define ALLOW_C_FUNCTION(name, ...) \ - PRAGMA_DIAG_PUSH \ - PRAGMA_DISABLE_GCC_WARNING("-Wattribute-warning") \ - __VA_ARGS__ \ - PRAGMA_DIAG_POP - -#endif // gcc10+ +#ifdef __clang__ +#define FORBIDDEN_FUNCTION_NORETURN_ATTRIBUTE __attribute__((__noreturn__)) +#endif // __clang__ #endif // SHARE_UTILITIES_COMPILERWARNINGS_GCC_HPP diff --git a/src/hotspot/share/utilities/compilerWarnings_visCPP.hpp b/src/hotspot/share/utilities/compilerWarnings_visCPP.hpp index de76b522c7b..6321388c48a 100644 --- a/src/hotspot/share/utilities/compilerWarnings_visCPP.hpp +++ b/src/hotspot/share/utilities/compilerWarnings_visCPP.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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 @@ -30,39 +30,17 @@ #define PRAGMA_DIAG_PUSH _Pragma("warning(push)") #define PRAGMA_DIAG_POP _Pragma("warning(pop)") -// The Visual Studio implementation of FORBID_C_FUNCTION explicitly does -// nothing, because there doesn't seem to be a way to implement it for Visual -// Studio. What seems the most likely approach is to use deprecation warnings, -// but that runs into problems. -// -// (1) Declaring the function deprecated (using either __declspec(deprecated) -// or the C++14 [[deprecated]] attribute) fails with warnings like this: -// warning C4273: 'exit': inconsistent dll linkage -// It seems attributes are not simply additive with this compiler. -// -// (2) Additionally adding __declspec(dllimport) to deal with (1) fails with -// warnings like this: -// error C2375: 'vsnprintf': redefinition; different linkage -// It seems some functions in the set of interest have different linkage than -// others ("exit" is marked imported while "vsnprintf" is not, for example). -// That makes it difficult to provide a generic macro. -// -// (3) Using __pragma(deprecated(name)) fails with -// warning C4995: 'frobnicate': name was marked as #pragma deprecated -// for a *declaration* (not a use) of a 'frobnicate' function. -// -// ALLOW_C_FUNCTIONS disables deprecation warnings over the statement scope. -// Some of the functions we're interested in allowing are conditionally -// deprecated on Windows, under the control of various preprocessor defines -// such as _CRT_SECURE_NO_WARNINGS. Annotating vetted uses allows those -// warnings to catch unchecked uses. +#define PRAGMA_DEPRECATED_IGNORED PRAGMA_DISABLE_MSVC_WARNING(4996) -#define FORBID_C_FUNCTION(signature, alternative) +// This macro is used by the IMPORTED variants of FORBID_C_FUNCTION. +// +// Some, but not all, functions we want to forbid using must include a +// `__declspec(dllimport)` in the declaration. Failure to do so where needed +// leads to "redefinition; different linkage" errors for the forbidding +// declaration. But including a dllimport specifier if not present in the +// compiler's header leads to the same errors. It seems one must just know +// which are imported and which are not, and use the specifier accordingly. -#define ALLOW_C_FUNCTION(name, ...) \ - PRAGMA_DIAG_PUSH \ - PRAGMA_DISABLE_MSVC_WARNING(4996) \ - __VA_ARGS__ \ - PRAGMA_DIAG_POP +#define FORBIDDEN_FUNCTION_IMPORT_SPEC __declspec(dllimport) #endif // SHARE_UTILITIES_COMPILERWARNINGS_VISCPP_HPP diff --git a/src/hotspot/share/utilities/forbiddenFunctions.hpp b/src/hotspot/share/utilities/forbiddenFunctions.hpp new file mode 100644 index 00000000000..67e45037f62 --- /dev/null +++ b/src/hotspot/share/utilities/forbiddenFunctions.hpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2024, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef SHARE_UTILITIES_FORBIDDENFUNCTIONS_HPP +#define SHARE_UTILITIES_FORBIDDENFUNCTIONS_HPP + +#include "utilities/compilerWarnings.hpp" +#include "utilities/macros.hpp" + +#include // for va_list +#include // for size_t +#include // clang workaround for exit, _exit, _Exit - see FORBID macro. + +#ifdef _WINDOWS +#include "forbiddenFunctions_windows.hpp" +#else +#include "forbiddenFunctions_posix.hpp" +#endif + +// Forbid the use of various C library functions. Some of these have os:: +// replacements that should be used instead. Others are considered obsolete +// or have security concerns, either with preferred alternatives, or to be +// avoided entirely. + +FORBID_IMPORTED_NORETURN_C_FUNCTION(void exit(int), "use os::exit") +FORBID_IMPORTED_NORETURN_C_FUNCTION(void _Exit(int), "use os::exit") + +// Windows puts _exit in , POSIX in . +FORBID_IMPORTED_NORETURN_C_FUNCTION(void _exit(int), "use os::exit") + +FORBID_IMPORTED_C_FUNCTION(char* strerror(int), "use os::strerror"); +FORBID_IMPORTED_C_FUNCTION(char* strtok(char*, const char*), "use strtok_r"); + +FORBID_C_FUNCTION(int sprintf(char*, const char*, ...), "use os::snprintf"); +FORBID_C_FUNCTION(int vsprintf(char*, const char*, va_list), "use os::vsnprintf"); +FORBID_C_FUNCTION(int vsnprintf(char*, size_t, const char*, va_list), "use os::vsnprintf"); + +// All of the following functions return raw C-heap pointers (sometimes as an +// option, e.g. realpath or getwd) or, in case of free(), take raw C-heap +// pointers. We generally want allocation to be done through NMT. +FORBID_IMPORTED_C_FUNCTION(void* malloc(size_t size), "use os::malloc"); +FORBID_IMPORTED_C_FUNCTION(void free(void *ptr), "use os::free"); +FORBID_IMPORTED_C_FUNCTION(void* calloc(size_t nmemb, size_t size), "use os::malloc and zero out manually"); +FORBID_IMPORTED_C_FUNCTION(void* realloc(void *ptr, size_t size), "use os::realloc"); +FORBID_IMPORTED_C_FUNCTION(char* strdup(const char *s), "use os::strdup"); +FORBID_IMPORTED_C_FUNCTION(wchar_t* wcsdup(const wchar_t *s), "don't use"); + +#endif // SHARE_UTILITIES_FORBIDDENFUNCTIONS_HPP diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 86bee7a071f..22e322f4dc6 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -27,6 +27,7 @@ #include "utilities/compilerWarnings.hpp" #include "utilities/debug.hpp" +#include "utilities/forbiddenFunctions.hpp" #include "utilities/macros.hpp" // Get constants like JVM_T_CHAR and JVM_SIGNATURE_INT, before pulling in . @@ -194,35 +195,6 @@ inline uintptr_t p2u(const volatile void* p) { #define BOOL_TO_STR(_b_) ((_b_) ? "true" : "false") -//---------------------------------------------------------------------------------------------------- -// Forbid the use of various C library functions. -// Some of these have os:: replacements that should normally be used instead. -// Others are considered security concerns, with preferred alternatives. - -FORBID_C_FUNCTION(void exit(int), "use os::exit"); -FORBID_C_FUNCTION(void _exit(int), "use os::exit"); -FORBID_C_FUNCTION(char* strerror(int), "use os::strerror"); -FORBID_C_FUNCTION(char* strtok(char*, const char*), "use strtok_r"); -FORBID_C_FUNCTION(int sprintf(char*, const char*, ...), "use os::snprintf"); -FORBID_C_FUNCTION(int vsprintf(char*, const char*, va_list), "use os::vsnprintf"); -FORBID_C_FUNCTION(int vsnprintf(char*, size_t, const char*, va_list), "use os::vsnprintf"); - -// All of the following functions return raw C-heap pointers (sometimes as an option, e.g. realpath or getwd) -// or, in case of free(), take raw C-heap pointers. Don't use them unless you are really sure you must. -FORBID_C_FUNCTION(void* malloc(size_t size), "use os::malloc"); -FORBID_C_FUNCTION(void* calloc(size_t nmemb, size_t size), "use os::malloc and zero out manually"); -FORBID_C_FUNCTION(void free(void *ptr), "use os::free"); -FORBID_C_FUNCTION(void* realloc(void *ptr, size_t size), "use os::realloc"); -FORBID_C_FUNCTION(char* strdup(const char *s), "use os::strdup"); -FORBID_C_FUNCTION(char* strndup(const char *s, size_t n), "don't use"); -FORBID_C_FUNCTION(int posix_memalign(void **memptr, size_t alignment, size_t size), "don't use"); -FORBID_C_FUNCTION(void* aligned_alloc(size_t alignment, size_t size), "don't use"); -FORBID_C_FUNCTION(char* realpath(const char* path, char* resolved_path), "use os::realpath"); -FORBID_C_FUNCTION(char* get_current_dir_name(void), "use os::get_current_directory()"); -FORBID_C_FUNCTION(char* getwd(char *buf), "use os::get_current_directory()"); -FORBID_C_FUNCTION(wchar_t* wcsdup(const wchar_t *s), "don't use"); -FORBID_C_FUNCTION(void* reallocf(void *ptr, size_t size), "don't use"); - //---------------------------------------------------------------------------------------------------- // Constants diff --git a/src/hotspot/share/utilities/permitForbiddenFunctions.hpp b/src/hotspot/share/utilities/permitForbiddenFunctions.hpp new file mode 100644 index 00000000000..1ba42f8e386 --- /dev/null +++ b/src/hotspot/share/utilities/permitForbiddenFunctions.hpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef SHARE_UTILITIES_PERMITFORBIDDENFUNCTIONS_HPP +#define SHARE_UTILITIES_PERMITFORBIDDENFUNCTIONS_HPP + +#include "utilities/compilerWarnings.hpp" +#include "utilities/globalDefinitions.hpp" + +#ifdef _WINDOWS +#include "permitForbiddenFunctions_windows.hpp" +#else +#include "permitForbiddenFunctions_posix.hpp" +#endif + +// Provide wrappers for some functions otherwise forbidden from use in HotSpot. +// +// There may be special circumstances where an otherwise forbidden function +// really does need to be used. One example is in the implementation of a +// corresponding os:: function. +// +// Wrapper functions are provided for such forbidden functions. These +// wrappers are defined in a context where the forbidding warnings are +// suppressed. They are defined in a special namespace, to highlight uses as +// unusual and requiring increased scrutiny. +// +// Note that there are several seemingly plausible shorter alternatives to +// these written-out wrapper functions. All that have been tried don't work +// for one reason or another. + +namespace permit_forbidden_function { +BEGIN_ALLOW_FORBIDDEN_FUNCTIONS + +[[noreturn]] inline void exit(int status) { ::exit(status); } +[[noreturn]] inline void _exit(int status) { ::_exit(status); } + +ATTRIBUTE_PRINTF(3, 0) +inline int vsnprintf(char* str, size_t size, const char* format, va_list ap) { + return ::vsnprintf(str, size, format, ap); +} + +inline void* malloc(size_t size) { return ::malloc(size); } +inline void free(void* ptr) { return ::free(ptr); } +inline void* calloc(size_t nmemb, size_t size) { return ::calloc(nmemb, size); } +inline void* realloc(void* ptr, size_t size) { return ::realloc(ptr, size); } + +inline char* strdup(const char* s) { return ::strdup(s); } + +END_ALLOW_FORBIDDEN_FUNCTIONS +} // namespace permit_forbidden_function + +#endif // SHARE_UTILITIES_PERMITFORBIDDENFUNCTIONS_HPP diff --git a/test/hotspot/gtest/code/test_codestrings.cpp b/test/hotspot/gtest/code/test_codestrings.cpp index ff01b6f94d1..ba1a54f4db9 100644 --- a/test/hotspot/gtest/code/test_codestrings.cpp +++ b/test/hotspot/gtest/code/test_codestrings.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -29,9 +29,12 @@ #include "asm/macroAssembler.inline.hpp" #include "compiler/disassembler.hpp" #include "memory/resourceArea.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/vmassert_uninstall.hpp" +BEGIN_ALLOW_FORBIDDEN_FUNCTIONS #include +END_ALLOW_FORBIDDEN_FUNCTIONS #include "utilities/vmassert_reinstall.hpp" #include "unittest.hpp" diff --git a/test/hotspot/gtest/gc/shenandoah/test_shenandoahNumberSeq.cpp b/test/hotspot/gtest/gc/shenandoah/test_shenandoahNumberSeq.cpp index 8f51bf2db3b..9a33b522937 100644 --- a/test/hotspot/gtest/gc/shenandoah/test_shenandoahNumberSeq.cpp +++ b/test/hotspot/gtest/gc/shenandoah/test_shenandoahNumberSeq.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -27,7 +27,9 @@ #include "utilities/ostream.hpp" #include "utilities/vmassert_uninstall.hpp" +BEGIN_ALLOW_FORBIDDEN_FUNCTIONS #include +END_ALLOW_FORBIDDEN_FUNCTIONS #include "utilities/vmassert_reinstall.hpp" #include "unittest.hpp" diff --git a/test/hotspot/gtest/gc/shenandoah/test_shenandoahSimpleBitMap.cpp b/test/hotspot/gtest/gc/shenandoah/test_shenandoahSimpleBitMap.cpp index c9a6d638ba8..4b8d878c850 100644 --- a/test/hotspot/gtest/gc/shenandoah/test_shenandoahSimpleBitMap.cpp +++ b/test/hotspot/gtest/gc/shenandoah/test_shenandoahSimpleBitMap.cpp @@ -24,10 +24,12 @@ #include "precompiled.hpp" #include "gc/shenandoah/shenandoahSimpleBitMap.hpp" #include "gc/shenandoah/shenandoahSimpleBitMap.inline.hpp" - -#include #include "utilities/ostream.hpp" + #include "utilities/vmassert_uninstall.hpp" +BEGIN_ALLOW_FORBIDDEN_FUNCTIONS +#include +END_ALLOW_FORBIDDEN_FUNCTIONS #include "utilities/vmassert_reinstall.hpp" #include "unittest.hpp" diff --git a/test/hotspot/gtest/gtestMain.cpp b/test/hotspot/gtest/gtestMain.cpp index 0bd251e8094..cfe6dec60fe 100644 --- a/test/hotspot/gtest/gtestMain.cpp +++ b/test/hotspot/gtest/gtestMain.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -26,6 +26,7 @@ #include "runtime/os.hpp" #include "runtime/thread.inline.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include "unittest.hpp" #include @@ -193,7 +194,7 @@ static int num_args_to_skip(char* arg) { static char** remove_test_runner_arguments(int* argcp, char **argv) { int argc = *argcp; - ALLOW_C_FUNCTION(::malloc, char** new_argv = (char**) malloc(sizeof(char*) * argc);) + char** new_argv = (char**)permit_forbidden_function::malloc(sizeof(char*) * argc); int new_argc = 0; int i = 0; @@ -289,7 +290,7 @@ static void runUnitTestsInner(int argc, char** argv) { int result = RUN_ALL_TESTS(); - ALLOW_C_FUNCTION(::free, ::free(argv);) + permit_forbidden_function::free(argv); // vm_assert and other_vm tests never reach this point as they either abort, or call // exit() - see TEST_OTHER_VM macro. We will reach here when all same_vm tests have diff --git a/test/hotspot/gtest/unittest.hpp b/test/hotspot/gtest/unittest.hpp index e8f5817c4a6..780ec23edc6 100644 --- a/test/hotspot/gtest/unittest.hpp +++ b/test/hotspot/gtest/unittest.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -24,6 +24,8 @@ #ifndef UNITTEST_HPP #define UNITTEST_HPP +#include "utilities/globalDefinitions.hpp" + #include #include @@ -49,8 +51,10 @@ #undef F2 #include "utilities/vmassert_uninstall.hpp" +BEGIN_ALLOW_FORBIDDEN_FUNCTIONS #include "gmock/gmock.h" #include "gtest/gtest.h" +END_ALLOW_FORBIDDEN_FUNCTIONS #include "utilities/vmassert_reinstall.hpp" #ifdef UNDEFINED_Log