JNI avec Visual Studi 2015 + Java 1.8.0.60 - Exception : segment de mémoire endommagé
Bonjour à tous et à toutes.
Gros problème qui me bloque depuis plus de 24h00 !
J'utilise une librairie (Shapelib) depuis des années dans un soft, librairie appelé depuis JNI (wrapé par SWIG).
Ce code fonctionnait correctement.
Nous sommes passé à java 1.8.0.60 + Visual Studio 2015 SP3.
Une méthode de la shapelib ne fonctionne pas : ça ne retourne pas la bonne chaîne de caractères...
Je creuse et je fais un projet java contenant une seule classe :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package test;
import javax.swing.JOptionPane;
public class Main {
public static void main(String[] args) {
run();
}
public static void run() {
JOptionPane.showConfirmDialog(null, "Title");
}
} |
On ne peut pas faire plus simple !
Un petit programme en C++ sous Visual Studio 2015.
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| // ShapeLibConsole.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "jni.h"
#include <jni_md.h>
#include <stdlib.h>
#include <string>
#include <iostream>
int main()
{
JavaVM *jvm; /* denotes a Java VM */
JNIEnv *pEnv; /* pointer to native method interface */
jint square;
jboolean not;
JavaVMInitArgs vm_args; /* JDK/JRE 6 VM initialization arguments */
JavaVMOption *options = new JavaVMOption[4];
options[0].optionString = "-Djava.class.path=D:/Dev/Workspace/Geomaps/TestJava/TestShapelib/bin";
options[1].optionString = "-Djava.library.path=D:\\Dev\\Workspace\\Geomaps\\TestJava\\TestShapelib\\jar"; /* set native library path */
options[2].optionString = "-verbose:jni"; /* print JNI-related messages */
options[3].optionString = "-Djava.compiler=NONE"; /* disable JIT */
vm_args.version = JNI_VERSION_1_4;
vm_args.options = options;
vm_args.nOptions = 3;
vm_args.ignoreUnrecognized = true;
int res = JNI_CreateJavaVM(&jvm, (void **)&pEnv, &vm_args);
if (res != JNI_OK)
{
exit(EXIT_FAILURE);
}
else
{
std::cout << "JVM load succeeded: Version ";
jint ver = pEnv->GetVersion();
std::cout << ((ver >> 16) & 0x0f) << "." << (ver & 0x0f) << std::endl;
}
char szBuffferTEST[2048];
strncpy_s(szBuffferTEST, 2048, "Salut c'est ma chaine !", 2048);
jstring jarg1 = pEnv->NewStringUTF(szBuffferTEST);
jboolean isCopy;
char *arg1 = (char *)(pEnv)->GetStringUTFChars(jarg1, &isCopy);
strncpy_s(szBuffferTEST, 2048, "Voila, ça, c'est ma deuxieme chaine !", 2048);
arg1 = szBuffferTEST;
if (arg1 != nullptr)
{
jclass cls1 = pEnv->FindClass("test/Main"); // try to find the class
if (cls1 == nullptr)
{
std::cerr << "ERROR: class not found !";
}
else
{ // if class found, continue
std::cout << "Class MyTest found" << std::endl;
jmethodID mid = pEnv->GetStaticMethodID(cls1, "run", "()V"); // find method
if (mid == nullptr)
{
std::cerr << "ERROR: method void mymain() not found !" << std::endl;
}
else
{
pEnv->CallStaticVoidMethod(cls1, mid); // call method
std::cout << std::endl;
}
}
if (isCopy)
{
(pEnv)->ReleaseStringUTFChars(jarg1, (const char *)arg1);
}
jthrowable jth = pEnv->ExceptionOccurred();
if (jth != nullptr)
{
printf("There was an exception Getting Value \n");
pEnv->ExceptionDescribe();
pEnv->ExceptionClear();
}
char *argRet = (char *)(pEnv)->GetStringUTFChars(jarg1, nullptr);
pEnv->DeleteLocalRef(jarg1);
}
return 0;
} |
En faisant ce code, il faut bien entendu dans Environnement des propriétés projet / debugging modifier le path :
PATH=$(PATH);C:\Program Files (x86)\Java\jdk1.8.0_60\jre\bin;C:\Program Files (x86)\Java\jdk1.8.0_60\jre\bin\client
Et là presque tout fonctionne, le chargement du .class, l'appel de la méthode java statique.
Tout, sauf l'appel de la méthode :
Code:
(pEnv)->ReleaseStringUTFChars(jarg1, (const char *)arg1);
elle provoque une erreur :
Citation:
Exception thrown at 0x77AAED0B (ntdll.dll) in ShapeLibConsole.exe: 0xC0000374: Un segment de mémoire a été endommagé (parameters: 0x77AE4270).
Or c'est exactement ce problème là que j'avais dans le 'vrai' programme et que je débuggais (attach to process + debug directement dans la shapelib).
Là, dans ce cas, pas de shapelib, pas de JNI mais une simulation via du code c++ de ce qui est exécuté par le wrapper SWIG.
C'est incompréhensible, ça pue le bug Visual / Java...
Une idée ?
Ce qui pourrait être bien c'est d'avoir le fichier pdb + code source pour débugger DANS la fonction ReleaseStringUTFChars parce que là, il faut débugger en assembleur...
Je ne pense pas trouver de réponse, je n'ai pas trouvé ce genre de problème ailleurs... Mais sait-on jamais.