gpt4 book ai didi

java - 为什么JVM在进入无限递归时不会崩溃?

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:51:11 34 4
gpt4 key购买 nike

我正在编写一个要加载到 JVM 中的共享库,但下面的行为让我卡住了。这是我的 Java 类:

package com.test;

public class UnixUtil {
static {
System.loadLibrary("myfancylibrary");
}
static native int openReadOnlyFd(String path);
static native int closeFd(int fd);
}

public class Main {

public static void main(String[] args){
int fd = UnixUtil.openReadOnlyFd("/tmp/testc");
UnixUtil.closeFd(fd);
}
}

要加载的库如下所示:

test_jni.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_test_UnixUtil */

#ifndef _Included_com_test_UnixUtil
#define _Included_com_test_UnixUtil
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_test_UnixUtil
* Method: openReadOnlyFd
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_com_test_UnixUtil_openReadOnlyFd
(JNIEnv *, jclass, jstring);

/*
* Class: com_test_UnixUtil
* Method: closeFd
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_com_test_UnixUtil_closeFd
(JNIEnv *, jclass, jint);

#ifdef __cplusplus
}
#endif
#endif

test_jni.c

#include "test_jni.h"
#include "fs.h"


JNIEXPORT jint JNICALL Java_com_test_UnixUtil_openReadOnlyFd
(JNIEnv *e, jclass jc, jstring path){
const char *const native_path = ((*e) -> GetStringUTFChars)(e, path, NULL);
int fd = read_only_open(native_path);
((*e) -> ReleaseStringUTFChars)(e, path, native_path);
return fd;
}


JNIEXPORT jint JNICALL Java_com_test_UnixUtil_closeFd
(JNIEnv *e, jclass jc, jint fd){
printf("Closing files descriptord %d... \n", fd);
return close(fd);
}

fs.h

#ifndef FS_H
#define FS_H

int read_only_open(const char *path);

int close(int fd);

#endif //FS_H

fs.c

#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <sys/fcntl.h>

#include "fs.h"

int read_only_open(const char *path){
printf("Entering %s.%s:%d\n", __FILE__, __func__, __LINE__);
int fd = open(path, O_RDONLY);
return fd;
}

int close(int fd){ //Java_com_test_UnixUtil_closeFd does not invoke this function
printf("Entering %s.%s:%d\n", __FILE__, __func__, __LINE__);
int close_result = close(fd);
return close_result;
}

当编译和运行这个 Main 类时,JVM 不会崩溃。它根本不进入函数fs.h::close(int)。相反,stdlibclose 被调用,如 GDB 中所示:

Thread 2 "java" hit Breakpoint 1, Java_com_test_UnixUtil_closeFd (e=<optimized out>,
jc=<optimized out>, fd=4) at /home/rjlomov/test_jni/src/main/java/com/test/lib/test_jni.c:17
17 return close(fd);
(gdb) step
18 }
(gdb)
17 return close(fd);
(gdb)
__close (fd=4) at ../sysdeps/unix/sysv/linux/close.c:27
27 ../sysdeps/unix/sysv/linux/close.c: No such file or directory.
(gdb)
26 in ../sysdeps/unix/sysv/linux/close.c

运行 objdump -dS libmyfancylibrary.so 显示

JNIEXPORT jint JNICALL Java_com_test_UnixUtil_closeFd                                                                                                                                                              
(JNIEnv *e, jclass jc, jint fd){
7d0: 53 push %rbx
}

//...

return close(fd);
7e9: e9 62 fe ff ff jmpq 650 <close@plt> // <--- PLT section,
// resolved by linker to stdlib::close?
7ee: 66 90 xchg %ax,%ax

问题: 为什么 stdlib::closeJava_com_test_UnixUtil_closeFd 而不是 fs.c 中调用::关闭(整数)?我唯一能想到的是 JVM 有自己的动态链接器来完成这项工作......

最佳答案

由于您正在编译共享库,并且函数 close() 不是 static,因此编译器会通过过程链接表 (PLT) 进行间接调用。反汇编库时,您可能会看到一条说明

    call <close@plt>

myfancylibrary 被加载时,进程已经从 libc 中实现了 close,因此动态 liker 更新 PLT 以指向 libc 版本的 close( )

关于java - 为什么JVM在进入无限递归时不会崩溃?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54456939/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com