1 /*
2 * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 #include "classfile/javaClasses.hpp"
26 #include "classfile/symbolTable.hpp"
27 #include "classfile/systemDictionary.hpp"
28 #include "classfile/vmClasses.hpp"
29 #include "classfile/vmSymbols.hpp"
30 #include "logging/log.hpp"
31 #include "logging/logTag.hpp"
32 #include "memory/oopFactory.hpp"
33 #include "memory/resourceArea.hpp"
34 #include "oops/instanceKlass.hpp"
35 #include "oops/klass.inline.hpp"
36 #include "oops/method.hpp"
37 #include "oops/oop.inline.hpp"
38 #include "oops/symbol.hpp"
39 #include "prims/jvm_misc.hpp"
40 #include "prims/jvmtiAgentList.hpp"
41 #include "prims/jvmtiExport.hpp"
42 #include "prims/nativeLookup.hpp"
43 #include "prims/scopedMemoryAccess.hpp"
44 #include "prims/unsafe.hpp"
45 #include "runtime/arguments.hpp"
46 #include "runtime/handles.inline.hpp"
47 #include "runtime/interfaceSupport.inline.hpp"
48 #include "runtime/javaCalls.hpp"
49 #include "runtime/os.hpp"
50 #include "runtime/sharedRuntime.hpp"
51 #include "runtime/signature.hpp"
52 #include "utilities/macros.hpp"
53 #include "utilities/utf8.hpp"
54 #if INCLUDE_JFR
55 #include "jfr/jfr.hpp"
56 #endif
57
58 /*
59
60 The JNI specification defines the mapping from a Java native method name to
61 a C native library implementation function name as follows:
62
63 The mapping produces a native method name by concatenating the following components
64 derived from a `native` method declaration:
65
66 1. the prefix Java_
67 2. given the binary name, in internal form, of the class which declares the native method:
68 the result of escaping the name.
69 3. an underscore ("_")
70 4. the escaped method name
71 5. if the native method declaration is overloaded: two underscores ("__") followed by the
72 escaped parameter descriptor (JVMS 4.3.3) of the method declaration.
73
74 Escaping leaves every alphanumeric ASCII character (A-Za-z0-9) unchanged, and replaces each
75 UTF-16 code unit n the table below with the corresponding escape sequence. If the name to be
76 escaped contains a surrogate pair, then the high-surrogate code unit and the low-surrogate code
77 unit are escaped separately. The result of escaping is a string consisting only of the ASCII
78 characters A-Za-z0-9 and underscore.
79
80 ------------------------------ ------------------------------------
81 UTF-16 code unit Escape sequence
82 ------------------------------ ------------------------------------
83 Forward slash (/, U+002F) _
84 Underscore (_, U+005F) _1
85 Semicolon (;, U+003B) _2
86 Left square bracket ([, U+005B) _3
87 Any UTF-16 code unit \u_WXYZ_ that does not _0wxyz where w, x, y, and z are the lower-case
88 represent alphanumeric ASCII (A-Za-z0-9), forms of the hexadecimal digits W, X, Y, and Z.
89 forward slash, underscore, semicolon, (For example, U+ABCD becomes _0abcd.)
90 or left square bracket
91 ------------------------------ ------------------------------------
92
93 Note that escape sequences can safely begin _0, _1, etc, because class and method
94 names in Java source code never begin with a number. However, that is not the case in
95 class files that were not generated from Java source code.
96
97 To preserve the 1:1 mapping to a native method name, the VM checks the resulting name as
98 follows. If the process of escaping any precursor string from the native method declaration
99 (class or method name, or argument type) causes a "0", "1", "2", or "3" character
100 from the precursor string to appear unchanged in the result *either* immediately after an
101 underscore *or* at the beginning of the escaped string (where it will follow an underscore
102 in the fully assembled name), then the escaping process is said to have "failed".
103 In such cases, no native library search is performed, and the attempt to link the native
104 method invocation will throw UnsatisfiedLinkError.
105
106
107 For example:
108
109 package/my_class/method
110
111 and
112
113 package/my/1class/method
114
115 both map to
116
117 Java_package_my_1class_method
118
119 To address this potential conflict we need only check if the character after
120 / is a digit 0..3, or if the first character after an injected '_' separator
121 is a digit 0..3. If we encounter an invalid identifier we reset the
122 stringStream and return false. Otherwise the stringStream contains the mapped
123 name and we return true.
124
125 */
126 static bool map_escaped_name_on(stringStream* st, Symbol* name, int begin, int end) {
127 char* bytes = (char*)name->bytes() + begin;
128 char* end_bytes = (char*)name->bytes() + end;
129 bool check_escape_char = true; // initially true as first character here follows '_'
130 while (bytes < end_bytes) {
131 jchar c;
132 bytes = UTF8::next(bytes, &c);
133 if (c <= 0x7f && isalnum(c)) {
134 if (check_escape_char && (c >= '0' && c <= '3')) {
135 // This is a non-Java identifier and we won't escape it to
136 // ensure no name collisions with a Java identifier.
137 if (log_is_enabled(Debug, jni, resolve)) {
138 ResourceMark rm;
139 log_debug(jni, resolve)("[Lookup of native method with non-Java identifier rejected: %s]",
140 name->as_C_string());
141 }
142 st->reset(); // restore to "" on error
143 return false;
144 }
145 st->put((char) c);
146 check_escape_char = false;
147 } else {
148 check_escape_char = false;
149 if (c == '_') st->print("_1");
150 else if (c == '/') {
151 st->print("_");
152 // Following a / we must have non-escape character
153 check_escape_char = true;
154 }
155 else if (c == ';') st->print("_2");
156 else if (c == '[') st->print("_3");
157 else st->print("_%.5x", c);
158 }
159 }
160 return true;
161 }
162
163
164 static bool map_escaped_name_on(stringStream* st, Symbol* name) {
165 return map_escaped_name_on(st, name, 0, name->utf8_length());
166 }
167
168
169 char* NativeLookup::pure_jni_name(const methodHandle& method) {
170 stringStream st;
171 // Prefix
172 st.print("Java_");
173 // Klass name
174 if (!map_escaped_name_on(&st, method->klass_name())) {
175 return nullptr;
176 }
177 st.print("_");
178 // Method name
179 if (!map_escaped_name_on(&st, method->name())) {
180 return nullptr;
181 }
182 return st.as_string();
183 }
184
185 char* NativeLookup::long_jni_name(const methodHandle& method) {
186 // Signatures ignore the wrapping parentheses and the trailing return type
187 stringStream st;
188 Symbol* signature = method->signature();
189 st.print("__");
190 // find ')'
191 int end;
192 for (end = 0; end < signature->utf8_length() && signature->char_at(end) != JVM_SIGNATURE_ENDFUNC; end++);
193 // skip first '('
194 if (!map_escaped_name_on(&st, signature, 1, end)) {
195 return nullptr;
196 }
197
198 return st.as_string();
199 }
200
201 extern "C" {
202 void JNICALL JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass unsafecls);
203 void JNICALL JVM_RegisterReferencesMethods(JNIEnv *env, jclass unsafecls);
204 void JNICALL JVM_RegisterUpcallHandlerMethods(JNIEnv *env, jclass unsafecls);
205 void JNICALL JVM_RegisterUpcallLinkerMethods(JNIEnv *env, jclass unsafecls);
206 void JNICALL JVM_RegisterNativeEntryPointMethods(JNIEnv *env, jclass unsafecls);
207 void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass);
208 void JNICALL JVM_RegisterWhiteBoxMethods(JNIEnv *env, jclass wbclass);
209 void JNICALL JVM_RegisterVectorSupportMethods(JNIEnv *env, jclass vsclass);
210 #if INCLUDE_JVMCI
211 jobject JNICALL JVM_GetJVMCIRuntime(JNIEnv *env, jclass c);
212 jlong JNICALL JVM_ReadSystemPropertiesInfo(JNIEnv *env, jclass c, jintArray offsets);
213 void JNICALL JVM_RegisterJVMCINatives(JNIEnv *env, jclass compilerToVMClass);
214 #endif
215 }
216
217 #define CC (char*) /* cast a literal from (const char*) */
218 #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
219
220 static JNINativeMethod lookup_special_native_methods[] = {
221 { CC"Java_jdk_internal_misc_Unsafe_registerNatives", nullptr, FN_PTR(JVM_RegisterJDKInternalMiscUnsafeMethods) },
222 { CC"Java_java_lang_invoke_MethodHandleNatives_registerNatives", nullptr, FN_PTR(JVM_RegisterMethodHandleMethods) },
223 { CC"Java_jdk_internal_foreign_abi_UpcallStubs_registerNatives", nullptr, FN_PTR(JVM_RegisterUpcallHandlerMethods) },
224 { CC"Java_jdk_internal_foreign_abi_UpcallLinker_registerNatives", nullptr, FN_PTR(JVM_RegisterUpcallLinkerMethods) },
225 { CC"Java_jdk_internal_foreign_abi_NativeEntryPoint_registerNatives", nullptr, FN_PTR(JVM_RegisterNativeEntryPointMethods) },
226 { CC"Java_jdk_internal_perf_Perf_registerNatives", nullptr, FN_PTR(JVM_RegisterPerfMethods) },
227 { CC"Java_sun_hotspot_WhiteBox_registerNatives", nullptr, FN_PTR(JVM_RegisterWhiteBoxMethods) },
228 { CC"Java_jdk_test_whitebox_WhiteBox_registerNatives", nullptr, FN_PTR(JVM_RegisterWhiteBoxMethods) },
229 { CC"Java_jdk_internal_vm_vector_VectorSupport_registerNatives", nullptr, FN_PTR(JVM_RegisterVectorSupportMethods)},
230 #if INCLUDE_JVMCI
231 { CC"Java_jdk_vm_ci_runtime_JVMCI_initializeRuntime", nullptr, FN_PTR(JVM_GetJVMCIRuntime) },
232 { CC"Java_jdk_vm_ci_services_Services_readSystemPropertiesInfo", nullptr, FN_PTR(JVM_ReadSystemPropertiesInfo) },
233 { CC"Java_jdk_vm_ci_hotspot_CompilerToVM_registerNatives", nullptr, FN_PTR(JVM_RegisterJVMCINatives) },
234 #endif
235 #if INCLUDE_JFR
236 { CC"Java_jdk_jfr_internal_JVM_registerNatives", nullptr, FN_PTR(jfr_register_natives) },
237 #endif
238 { CC"Java_jdk_internal_misc_ScopedMemoryAccess_registerNatives", nullptr, FN_PTR(JVM_RegisterJDKInternalMiscScopedMemoryAccessMethods) },
239 };
240
241 static address lookup_special_native(const char* jni_name) {
242 int count = sizeof(lookup_special_native_methods) / sizeof(JNINativeMethod);
243 for (int i = 0; i < count; i++) {
244 // NB: To ignore the jni prefix and jni postfix strstr is used matching.
245 if (strstr(jni_name, lookup_special_native_methods[i].name) != nullptr) {
246 return CAST_FROM_FN_PTR(address, lookup_special_native_methods[i].fnPtr);
247 }
248 }
249 return nullptr;
250 }
251
252 address NativeLookup::lookup_style(const methodHandle& method, char* pure_name, const char* long_name, int args_size, TRAPS) {
253 address entry;
254 const char* jni_name = compute_complete_jni_name(pure_name, long_name, args_size);
255
256
257 // If the loader is null we have a system class, so we attempt a lookup in
258 // the native Java library. This takes care of any bootstrapping problems.
259 // Note: It is critical for bootstrapping that Java_java_lang_ClassLoader_findNative
260 // gets found the first time around - otherwise an infinite loop can occur. This is
261 // another VM/library dependency
262 Handle loader(THREAD, method->method_holder()->class_loader());
263 if (loader.is_null()) {
264 entry = lookup_special_native(jni_name);
265 if (entry == nullptr) {
266 entry = (address) os::dll_lookup(os::native_java_library(), jni_name);
267 }
268 if (entry != nullptr) {
269 return entry;
270 }
271 }
272
273 // Otherwise call static method findNative in ClassLoader
274 Klass* klass = vmClasses::ClassLoader_klass();
275 Handle jni_class(THREAD, method->method_holder()->java_mirror());
276 Handle jni_name_arg = java_lang_String::create_from_str(jni_name, CHECK_NULL);
277 Handle java_name_arg = java_lang_String::create_from_str(method->name()->as_C_string(), CHECK_NULL);
278
279 JavaCallArguments args;
280 args.push_oop(loader);
281 args.push_oop(jni_class);
282 args.push_oop(jni_name_arg);
283 args.push_oop(java_name_arg);
284
285 JavaValue result(T_LONG);
286 JavaCalls::call_static(&result,
287 klass,
288 vmSymbols::findNative_name(),
289 vmSymbols::classloader_class_string_string_long_signature(),
290 &args,
291 CHECK_NULL);
292 entry = (address) (intptr_t) result.get_jlong();
293
294 if (entry == nullptr) {
295 // findNative didn't find it, if there are any agent libraries look in them
296 JvmtiAgentList::Iterator it = JvmtiAgentList::agents();
297 while (it.has_next()) {
298 entry = (address)os::dll_lookup(it.next()->os_lib(), jni_name);
299 if (entry != nullptr) {
300 return entry;
301 }
302 }
303 }
304
305 return entry;
306 }
307
308 const char* NativeLookup::compute_complete_jni_name(const char* pure_name, const char* long_name, int args_size) {
309 stringStream st;
310 st.print_raw(pure_name);
311 st.print_raw(long_name);
312
313 return st.as_string();
314 }
315
316 // Check all the formats of native implementation name to see if there is one
317 // for the specified method.
318 address NativeLookup::lookup_entry(const methodHandle& method, TRAPS) {
319 address entry = nullptr;
320 // Compute pure name
321 char* pure_name = pure_jni_name(method);
322 if (pure_name == nullptr) {
323 // JNI name mapping rejected this method so return
324 // null to indicate UnsatisfiedLinkError should be thrown.
325 return nullptr;
326 }
327
328 // Compute argument size
329 int args_size = 1 // JNIEnv
330 + (method->is_static() ? 1 : 0) // class for static methods
331 + method->size_of_parameters(); // actual parameters
332
333 // 1) Try JNI short style
334 entry = lookup_style(method, pure_name, "", args_size, CHECK_NULL);
335 if (entry != nullptr) return entry;
336
337 // Compute long name
338 char* long_name = long_jni_name(method);
339 if (long_name == nullptr) {
340 // JNI name mapping rejected this method so return
341 // null to indicate UnsatisfiedLinkError should be thrown.
342 return nullptr;
343 }
344
345 // 2) Try JNI long style
346 entry = lookup_style(method, pure_name, long_name, args_size, CHECK_NULL);
347
348 return entry; // null indicates not found
349 }
350
351 // Check if there are any JVM TI prefixes which have been applied to the native method name.
352 // If any are found, remove them before attempting the look up of the
353 // native implementation again.
354 // See SetNativeMethodPrefix in the JVM TI Spec for more details.
355 address NativeLookup::lookup_entry_prefixed(const methodHandle& method, TRAPS) {
356 #if INCLUDE_JVMTI
357 ResourceMark rm(THREAD);
358
359 int prefix_count;
360 char** prefixes = JvmtiExport::get_all_native_method_prefixes(&prefix_count);
361 char* in_name = method->name()->as_C_string();
362 char* wrapper_name = in_name;
363 // last applied prefix will be first -- go backwards
364 for (int i = prefix_count-1; i >= 0; i--) {
365 char* prefix = prefixes[i];
366 size_t prefix_len = strlen(prefix);
367 if (strncmp(prefix, wrapper_name, prefix_len) == 0) {
368 // has this prefix remove it
369 wrapper_name += prefix_len;
370 }
371 }
372 if (wrapper_name != in_name) {
373 // we have a name for a wrapping method
374 int wrapper_name_len = (int)strlen(wrapper_name);
375 TempNewSymbol wrapper_symbol = SymbolTable::probe(wrapper_name, wrapper_name_len);
376 if (wrapper_symbol != nullptr) {
377 Klass* k = method->method_holder();
378 Method* wrapper_method = k->lookup_method(wrapper_symbol, method->signature());
379 if (wrapper_method != nullptr && !wrapper_method->is_native()) {
380 // we found a wrapper method, use its native entry
381 method->set_is_prefixed_native();
382 return lookup_entry(methodHandle(THREAD, wrapper_method), THREAD);
383 }
384 }
385 }
386 #endif // INCLUDE_JVMTI
387 return nullptr;
388 }
389
390 address NativeLookup::lookup_base(const methodHandle& method, TRAPS) {
391 address entry = nullptr;
392 ResourceMark rm(THREAD);
393
394 entry = lookup_entry(method, CHECK_NULL);
395 if (entry != nullptr) return entry;
396
397 // standard native method resolution has failed. Check if there are any
398 // JVM TI prefixes which have been applied to the native method name.
399 entry = lookup_entry_prefixed(method, CHECK_NULL);
400 if (entry != nullptr) return entry;
401
402 if (THREAD->has_pending_exception()) {
403 oop exception = THREAD->pending_exception();
404 if (exception->is_a(vmClasses::IllegalCallerException_klass())) {
405 // we already have a pending exception from the restricted method check, just return
406 return nullptr;
407 }
408 }
409
410 // Native function not found, throw UnsatisfiedLinkError
411 stringStream ss;
412 ss.print("'");
413 method->print_external_name(&ss);
414 ss.print("'");
415 THROW_MSG_NULL(vmSymbols::java_lang_UnsatisfiedLinkError(), ss.as_string());
416 }
417
418
419 address NativeLookup::lookup(const methodHandle& method, TRAPS) {
420 if (!method->has_native_function()) {
421 address entry = lookup_base(method, CHECK_NULL);
422 method->set_native_function(entry,
423 Method::native_bind_event_is_interesting);
424 // -verbose:jni printing
425 if (log_is_enabled(Debug, jni, resolve)) {
426 ResourceMark rm(THREAD);
427 log_debug(jni, resolve)("[Dynamic-linking native method %s.%s ... JNI]",
428 method->method_holder()->external_name(),
429 method->name()->as_C_string());
430 }
431 }
432 return method->native_function();
433 }