前言

给web同事写了so, 人家找来了,说运行java程序时报错.
报错信息如下:

[root@localhost src_linux_fedora22]# ./run_java_prj.sh run java prj begin, please wait a moment... Java HotSpot(TM) Server VM warning: You have loaded library /usr/lib/libmy_test.so which might have disabled stack guard. The VM will try to fix the stack guard now.
It's highly recommended that you fix the library with 'execstack -c <libfile>', or link it with '-z noexecstack'. Exception in thread "main" java.lang.UnsatisfiedLinkError: /usr/lib/libmy_test.so: /usr/lib/libmy_test.so: wrong ELF class: ELFCLASS64 (Possible cause: architecture word width mismatch)
    at java.lang.ClassLoader$NativeLibrary.load(Native Method)
    at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1941)
    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1824)
    at java.lang.Runtime.load0(Runtime.java:809)
    at java.lang.System.load(System.java:1086)
    at com.my_test.<clinit>(my_test.java:30)

折腾到最后,发现是同事的虚拟机中的java环境有问题,最后重新装了oracle原版的linux_jre和open_jdk搞定。

记录一下bug的排查过程(问题的重现,定位,解决), 这是一个证明自己清白的过程:)
自己实现的组件,自己测试的时候没问题,别人用的时候有问题,这事要搞定。不管是实现的有问题,还是环境有问题,都要找出原因来,要给个说法.

实验

我做so时,有个自己搭的虚拟机debian7.5, java和C开发环境都全的,在自己的虚拟机环境,编译运行都正常。

同事的虚拟机是centos6.5final, 他自己搭的,在这个环境下有问题。他自己玩时,只有java环境。为了给他解决装C开发环境的问题,正好将克隆后的虚拟机拷贝回来了。在这个环境下可以重现这个问题。

so工程编译完,没错。
编译选项如下:

BIN = libmy_test.so
CC = g++
CFLAGS = -Wall -g -shared -z noexecstack
INC = -I. \
    -I/opt/jdk1.8.0_151/include/ \
    -I/opt/jdk1.8.0_151/include/linux/ \

MY_3RD_LIB = ./lib_3rd/x64/lib3rd.so.1.0.0
SHLIBS = /usr/lib/lib3rd.so.1.0.0

# LIBS = -lstdc++ -pthread -lpthread -lm -lusb -fPIC $(SHLIBS)
LIBS = -lstdc++ -pthread -lpthread -lm -fPIC

LIBPATH = -L/usr/lib/ -L/usr/local/lib/ -L./lib/

原来没有-z noexecstack选项的,根据报错提示加上

运行测试程序(C语言),证明so的功能是正常的。
这时运行java测试程序,还是有问题。
加不加-z noexecstack选项,so工程和测试工程(C语言),都是正常的。

上网查了下,其他同学遇到这个问题,都是用 execstack -c x.so, 去清掉目标so的栈检查标记,然后再运行java程序,就正常了,但是这招在我这不好使。

查看execstack版本

[root@localhost test_dbs_epass_so]# execstack --version 
execstack 1.0 

如果没有装execstack,就先安装execstack

yum install prelink

测试用execstack来清目标so的栈检查标记

不好使,无论是清栈检查,还是设置栈检查,java程序载入so时,还是报错

--------------------------------------------------------------------------------
execstack -c /usr/lib/libmy_test.so
[root@localhost src_linux_fedora22]# execstack -q /usr/lib/libmy_test.so
- /usr/lib/libmy_test.so
[root@localhost src_linux_fedora22]# ./run_java_prj.sh 
run java prj begin, please wait a moment... 
Java HotSpot(TM) Server VM warning: You have loaded library /usr/lib/libmy_test.so which might have disabled stack guard. The VM will try to fix the stack guard now.
It's highly recommended that you fix the library with 'execstack -c <libfile>', or link it with '-z noexecstack'. Exception in thread "main" java.lang.UnsatisfiedLinkError: /usr/lib/libmy_test.so: /usr/lib/libmy_test.so: wrong ELF class: ELFCLASS64 (Possible cause: architecture word width mismatch)
    at java.lang.ClassLoader$NativeLibrary.load(Native Method)
    at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1941)
    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1824)
    at java.lang.Runtime.load0(Runtime.java:809)
    at java.lang.System.load(System.java:1086)
    at com.my_test.<clinit>(my_test.java:30)
--------------------------------------------------------------------------------
[root@localhost src_linux_fedora22]# execstack -s /usr/lib/libmy_test.so 
[root@localhost src_linux_fedora22]# execstack -q /usr/lib/libmy_test.so 
X /usr/lib/libmy_test.so
[root@localhost src_linux_fedora22]# ./run_java_prj.sh 
run java prj begin, please wait a moment... 
Java HotSpot(TM) Server VM warning: You have loaded library /usr/lib/libmy_test.so which might have disabled stack guard. The VM will try to fix the stack guard now.
It's highly recommended that you fix the library with 'execstack -c <libfile>', or link it with '-z noexecstack'. Exception in thread "main" java.lang.UnsatisfiedLinkError: /usr/lib/libmy_test.so: /usr/lib/libmy_test.so: wrong ELF class: ELFCLASS64 (Possible cause: architecture word width mismatch)
    at java.lang.ClassLoader$NativeLibrary.load(Native Method)
    at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1941)
    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1824)
    at java.lang.Runtime.load0(Runtime.java:809)
    at java.lang.System.load(System.java:1086)
    at com.my_test.<clinit>(my_test.java:30)

重新装java环境

现在已经怀疑java环境有问题了,准备重新装一下java环境。

查看旧的java环境

[root@localhost dev]# echo $JAVA_HOME
/usr/local/java/
[root@localhost dev]# echo $JRE_HOME

[root@localhost dev]# find / -name 'jni.h'
/opt/jdk1.8.0_151/include/jni.h

看到旧的java环境在/usr/local/java/, /opt/jdk1.8.0_151/

卸载旧的java环境

直接删除java环境的文件夹 :)

rm -rf /usr/local/java
rm -rf /opt/jdk1.8.0_151

安装新java环境

https://www.java.com/en/download/linux_manual.jsp
Linux x64 RPM => jre-8u161-linux-x64.rpm

rpm -ivh ./jre-8u161-linux-x64.rpm

查看java版本

[root@localhost dbs_ukey_ePass3000]# /usr/java/jre1.8.0_161/bin/java -version
java version "1.8.0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)

这时,还没有jni环境

yum install java-1.8.0-openjdk-devel

查看jni头文件路径

[root@localhost dbs_ukey_ePass3000]# find / -name 'jni.h'
/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.161-3.b14.el6_9.x86_64/include/jni.h

修改so工程中引用的jni头文件路径,重新编译so, 重新编译C测试程序, 用测试程序证明so是好的。
再运行java测试程序,调用so的功能已经正常了:)

GitHub 加速计划 / li / linux-dash
6
1
下载
A beautiful web dashboard for Linux
最近提交(Master分支:3 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐