英文:
Constructing a HashMap<String, String[]> through JNI
问题
I have a Java class calling a native method ACLInfo(String path), this native method should return HashMap to be used in java. Here's the java code.
import java.util.*;
public class test
{
native Map<String, String[]> ACLInfo(String s);
static
{
System.loadLibrary("test");
}
static public void main(String args[])
{
test obj = new test();
Map<String, String[]> map = obj.ACLInfo("C:/Windows/Boot/Resources/bootres.dll");
for (Map.Entry<String, String[]> entry : map.entrySet())
{
String name = entry.getKey();
System.out.println("Name:"+name);
System.out.println("Properties are:");
for(String text : entry.getValue())
{
if(text.equals("Full Control")){
System.out.println(text);
continue;
}
if(text.equals("Read"))
System.out.println(text);
if(text.equals("Write"))
System.out.println(text);
if(text.equals("Execute"))
System.out.println(text);
}
}
}
}
The native code is.
#include <iostream>
#include <jni.h>
#include <string.h>
#include <windows.h>
#include <tchar.h>
#include <Lmcons.h>
#include "test.h"
#include "accctrl.h"
#include "aclapi.h"
using namespace std;
JNIEXPORT jobject JNICALL Java_test_ACLInfo(JNIEnv *env, jobject jobj, jstring s)
{
jobjectArray ret;
jstring jstr;
PSID pSidOwner = NULL;
BOOL bRtnBool = TRUE;
DWORD dwRtnCode = 0;
SID_NAME_USE eUse = SidTypeUnknown;
HANDLE hFile;
PSECURITY_DESCRIPTOR pSD = NULL;
PACL pOldDACL = NULL;
int i,aceNum;
const char* test;
std::string name,reslt;
const char* nativeString = env->GetStringUTFChars(s, 0);
LPCSTR file = nativeString;
// Get the handle of the file object.
hFile = CreateFile(
file,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
// Get the SID of the file.
dwRtnCode = GetSecurityInfo(
hFile,
SE_FILE_OBJECT,
DACL_SECURITY_INFORMATION,
&pSidOwner,
NULL,
&pOldDACL,
NULL,
&pSD);
PACL pAcl = pOldDACL;
aceNum = pOldDACL->AceCount;
ret = (jobjectArray)env->NewObjectArray(3, env->FindClass("java/lang/String"), env->NewStringUTF(""));
jclass mapClass = env->FindClass("java/util/HashMap"); //HashMap class in java library
if(mapClass == NULL)
{
return NULL;
}
jsize map_len = aceNum;
jmethodID init = env->GetMethodID(mapClass, "<init>", "(I)V"); //constructor of HashMap class
jobject hashMap = env->NewObject(mapClass, init, map_len); //creating a new object for that class
jmethodID put = env->GetMethodID(mapClass, "put", "(Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;");
for (i = 0; i < aceNum; i++)
{
PACCESS_ALLOWED_ACE AceItem;
ACE_HEADER *aceAddr = NULL;
if (GetAce(pOldDACL, i, (LPVOID*)&AceItem) && GetAce(pOldDACL, i, (LPVOID*)&aceAddr))
{
LPTSTR AccountBuff = NULL, DomainBuff = NULL;
DWORD AccountBufflength = 1, DomainBufflength = 1;
PSID_NAME_USE peUse = new SID_NAME_USE;
PSID Sid = &AceItem->SidStart;
LookupAccountSid(NULL, Sid, AccountBuff, (LPDWORD)&AccountBufflength, DomainBuff, (LPDWORD)&DomainBufflength, peUse);
AccountBuff = (LPSTR)malloc(AccountBufflength * sizeof(LPSTR));
DomainBuff = (LPSTR)malloc(DomainBufflength * sizeof(LPSTR));
LookupAccountSid(NULL, Sid, AccountBuff, &AccountBufflength, DomainBuff, &DomainBufflength, peUse);
std::string acc=AccountBuff;
std::string dom=DomainBuff;
name = acc+"\\"+dom;
ACCESS_MASK Mask = AceItem->Mask;
if (((Mask & GENERIC_ALL) == GENERIC_ALL) || ((Mask & FILE_ALL_ACCESS) == FILE_ALL_ACCESS)){
reslt="Full Control";
test = reslt.c_str();
env->SetObjectArrayElement(ret,i,env->NewStringUTF(test));
env->CallObjectMethod(hashMap, put, env->NewStringUTF(name.c_str()), ret);
continue;
}
int j=0;
if (((Mask & GENERIC_READ) == GENERIC_READ) || ((Mask & FILE_GENERIC_READ) == FILE_GENERIC_READ))
{
reslt="Read";
test = reslt.c_str();
env->SetObjectArrayElement(ret,j++,env->NewStringUTF(test));
}
if (((Mask & GENERIC_WRITE) == GENERIC_WRITE) || ((Mask & FILE_GENERIC_WRITE) == FILE_GENERIC_WRITE))
{
reslt="Write";
test = reslt.c_str();
env->SetObjectArrayElement(ret,j++,env->NewStringUTF(test));
}
if (((Mask & GENERIC_EXECUTE) == GENERIC_EXECUTE) || ((Mask & FILE_GENERIC_EXECUTE) == FILE_GENERIC_EXECUTE))
{
reslt="Execute";
test = reslt.c_str();
env->SetObjectArrayElement(ret,j++,env->NewStringUTF(test));
}
env->CallObjectMethod(hashMap, put, env->NewStringUTF(name.c_str()), ret);
}
}
return hashMap;
}
On running this java class it shows: A fatal error has been detected by the Java Runtime Environment: EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000006d6cd4ed, pid=19504, tid=0x0000000000003da0
What's the issue?
I have made use of this stackoverflow post for creating hashmap https://stackoverflow.com/questions/47224571/how-to-create-hashmapstring-string-through-jni-then-parse-to-java?noredirect=1&lq=1
英文:
I have a Java class calling a native method ACLInfo(String path), this native method should return HashMap to be used in java. Here's the java code.
import java.util.*;
public class test
{
native Map<String, String[]> ACLInfo(String s);
static
{
System.loadLibrary("test");
}
static public void main(String args[])
{
test obj = new test();
Map<String, String[]> map = obj.ACLInfo("C:/Windows/Boot/Resources/bootres.dll");
for (Map.Entry<String, String[]> entry : map.entrySet())
{
String name = entry.getKey();
System.out.println("Name:"+name);
System.out.println("Properties are:");
for(String text : entry.getValue())
{
if(text.equals("Full Control")){
System.out.println(text);
continue;
}
if(text.equals("Read"))
System.out.println(text);
if(text.equals("Write"))
System.out.println(text);
if(text.equals("Execute"))
System.out.println(text);
}
}
}
}
The native code is.
#include <iostream>
#include <jni.h>
#include <string.h>
#include <windows.h>
#include <tchar.h>
#include <Lmcons.h>
#include "test.h"
#include "accctrl.h"
#include "aclapi.h"
using namespace std;
JNIEXPORT jobject JNICALL Java_test_ACLInfo(JNIEnv *env, jobject jobj, jstring s)
{
jobjectArray ret;
jstring jstr;
PSID pSidOwner = NULL;
BOOL bRtnBool = TRUE;
DWORD dwRtnCode = 0;
SID_NAME_USE eUse = SidTypeUnknown;
HANDLE hFile;
PSECURITY_DESCRIPTOR pSD = NULL;
PACL pOldDACL = NULL;
int i,aceNum;
const char* test;
std::string name,reslt;
const char* nativeString = env->GetStringUTFChars(s, 0);
LPCSTR file = nativeString;
// Get the handle of the file object.
hFile = CreateFile(
file,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
// Get the SID of the file.
dwRtnCode = GetSecurityInfo(
hFile,
SE_FILE_OBJECT,
DACL_SECURITY_INFORMATION,
&pSidOwner,
NULL,
&pOldDACL,
NULL,
&pSD);
PACL pAcl = pOldDACL;
aceNum = pOldDACL->AceCount;
ret = (jobjectArray)env->NewObjectArray(3, env->FindClass("java/lang/String"), env->NewStringUTF(""));
jclass mapClass = env->FindClass("java/util/HashMap"); //HashMap class in java library
if(mapClass == NULL)
{
return NULL;
}
jsize map_len = aceNum;
jmethodID init = env->GetMethodID(mapClass, "<init>", "(I)V"); //constructor of HashMap class
jobject hashMap = env->NewObject(mapClass, init, map_len); //creating a new object for that class
jmethodID put = env->GetMethodID(mapClass, "put", "(Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;");
for (i = 0; i < aceNum; i++)
{
PACCESS_ALLOWED_ACE AceItem;
ACE_HEADER *aceAddr = NULL;
if (GetAce(pOldDACL, i, (LPVOID*)&AceItem) && GetAce(pOldDACL, i, (LPVOID*)&aceAddr))
{
LPTSTR AccountBuff = NULL, DomainBuff = NULL;
DWORD AccountBufflength = 1, DomainBufflength = 1;
PSID_NAME_USE peUse = new SID_NAME_USE;
PSID Sid = &AceItem->SidStart;
LookupAccountSid(NULL, Sid, AccountBuff, (LPDWORD)&AccountBufflength, DomainBuff, (LPDWORD)&DomainBufflength, peUse);
AccountBuff = (LPSTR)malloc(AccountBufflength * sizeof(LPSTR));
DomainBuff = (LPSTR)malloc(DomainBufflength * sizeof(LPSTR));
LookupAccountSid(NULL, Sid, AccountBuff, &AccountBufflength, DomainBuff, &DomainBufflength, peUse);
std::string acc=AccountBuff;
std::string dom=DomainBuff;
name = acc+"\\"+dom;
ACCESS_MASK Mask = AceItem->Mask;
if (((Mask & GENERIC_ALL) == GENERIC_ALL) || ((Mask & FILE_ALL_ACCESS) == FILE_ALL_ACCESS)){
reslt="Full Control";
test = reslt.c_str();
env->SetObjectArrayElement(ret,i,env->NewStringUTF(test));
env->CallObjectMethod(hashMap, put, env->NewStringUTF(name.c_str()), ret);
continue;
}
int j=0;
if (((Mask & GENERIC_READ) == GENERIC_READ) || ((Mask & FILE_GENERIC_READ) == FILE_GENERIC_READ))
{
reslt="Read";
test = reslt.c_str();
env->SetObjectArrayElement(ret,j++,env->NewStringUTF(test));
}
if (((Mask & GENERIC_WRITE) == GENERIC_WRITE) || ((Mask & FILE_GENERIC_WRITE) == FILE_GENERIC_WRITE))
{
reslt="Write";
test = reslt.c_str();
env->SetObjectArrayElement(ret,j++,env->NewStringUTF(test));
}
if (((Mask & GENERIC_EXECUTE) == GENERIC_EXECUTE) || ((Mask & FILE_GENERIC_EXECUTE) == FILE_GENERIC_EXECUTE))
{
reslt="Execute";
test = reslt.c_str();
env->SetObjectArrayElement(ret,j++,env->NewStringUTF(test));
}
env->CallObjectMethod(hashMap, put, env->NewStringUTF(name.c_str()), ret);
}
}
return hashMap;
}
On running this java class it shows: A fatal error has been detected by the Java Runtime Environment: EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000006d6cd4ed, pid=19504, tid=0x0000000000003da0
What's the issue?
I have made used of this stackoverflow post for creating hashmap https://stackoverflow.com/questions/47224571/how-to-create-hashmapstring-string-through-jni-then-parse-to-java?noredirect=1&lq=1
答案1
得分: 2
我已经重写了您的代码,以消除最严重的错误:
- 您的
HashMap#put
方法签名错误。 - 每次将元素放入哈希映射时,您都必须创建一个
string[]
。如果重用相同的对象,您将获得相同的string[]
的N个副本。 - 您不能一开始创建大小为3的数组,然后只填充一些槽位。最好在C++领域使用临时向量,稍后创建正确大小的数组。
- 您需要使用
PushLocalFrame
和PopLocalFrame
来确保不超出本地引用预算。
我还删除了许多非JVM的冗余内容。请尽量保持您的示例代码简洁明了。
JNIEXPORT jobject JNICALL Java_test_ACLInfo(JNIEnv *env, jobject jobj, jstring s)
{
// 移除的部分
jclass mapClass = env->FindClass("java/util/HashMap"); // Java库中的HashMap类
jclass stringClass = env->FindClass("java/lang/String");
if (mapClass == NULL)
{
return NULL;
}
jsize map_len = aceNum;
jmethodID init = env->GetMethodID(mapClass, "<init>", "(I)V"); // HashMap类的构造函数
jobject hashMap = env->NewObject(mapClass, init, map_len); // 创建该类的新对象
jmethodID put = env->GetMethodID(mapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
for (i = 0; i < aceNum; i++)
{
// 移除的部分
PACCESS_ALLOWED_ACE AceItem;
ACE_HEADER *aceAddr = NULL;
if (GetAce(pOldDACL, i, (LPVOID*)&AceItem) && GetAce(pOldDACL, i, (LPVOID*)&aceAddr))
{
// 移除的更多部分
std::string name = std::string(AccountBuff) + "\\" + std::string(DomainBuff);
std::vector<std::string> perms;
ACCESS_MASK Mask = AceItem->Mask;
if (((Mask & GENERIC_ALL) == GENERIC_ALL) || ((Mask & FILE_ALL_ACCESS) == FILE_ALL_ACCESS))
{
perms.emplace_back("Full Control");
}
else
{
if (((Mask & GENERIC_READ) == GENERIC_READ) || ((Mask & FILE_GENERIC_READ) == FILE_GENERIC_READ))
{
perms.emplace_back("Read");
}
if (((Mask & GENERIC_WRITE) == GENERIC_WRITE) || ((Mask & FILE_GENERIC_WRITE) == FILE_GENERIC_WRITE))
{
perms.emplace_back("Write");
}
if (((Mask & GENERIC_EXECUTE) == GENERIC_EXECUTE) || ((Mask & FILE_GENERIC_EXECUTE) == FILE_GENERIC_EXECUTE))
{
perms.emplace_back("Execute");
}
}
env->PushLocalFrame(10);
jobject ret = env->NewObjectArray(perms.size(), stringClass, nullptr);
for (int i = 0; i < perms.size(); i++)
{
env->SetObjectArrayElement(ret, i, env->NewStringUTF(perms[i].c_str()));
}
env->CallObjectMethod(hashMap, put, env->NewStringUTF(name.c_str()), ret);
env->PopLocalFrame(nullptr);
}
}
return hashMap;
}
希望这对您有所帮助。
英文:
I have rewritten your code to get rid of the most egregious bugs:
- Your signature for
HashMap#put
was wrong. - You have to create one
string[]
for every element you put in the hashmap. If you reuse the same object you will get N copies of the samestring[]
. - You cannot create an array of size 3 up front and only fill in some slots. Better to use a temporary vector in C++ land and create the right array size later on.
- You need to use PushLocalFrame and PopLocalFrame to ensure you do not exceed your local reference budget.
I have also removed a lot of the non-JVM cruft. Please try to keep your example code small and to the point.
JNIEXPORT jobject JNICALL Java_test_ACLInfo(JNIEnv *env, jobject jobj, jstring s)
{
// removed stuff
jclass mapClass = env->FindClass("java/util/HashMap"); //HashMap class in java library
jclass stringClass = env->FindClass("java/lang/String");
if(mapClass == NULL)
{
return NULL;
}
jsize map_len = aceNum;
jmethodID init = env->GetMethodID(mapClass, "<init>", "(I)V"); //constructor of HashMap class
jobject hashMap = env->NewObject(mapClass, init, map_len); //creating a new object for that class
jmethodID put = env->GetMethodID(mapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
for (i = 0; i < aceNum; i++) {
// removed stuff
PACCESS_ALLOWED_ACE AceItem;
ACE_HEADER *aceAddr = NULL;
if (GetAce(pOldDACL, i, (LPVOID*)&AceItem) && GetAce(pOldDACL, i, (LPVOID*)&aceAddr)) {
// removed more stuff
std::string name = std::string(AccountBuff)+"\\"+std::string(DomainBuff);
std::vector<std::string> perms;
ACCESS_MASK Mask = AceItem->Mask;
if (((Mask & GENERIC_ALL) == GENERIC_ALL) || ((Mask & FILE_ALL_ACCESS) == FILE_ALL_ACCESS)) {
perms.emplace_back("Full Control");
} else {
if (((Mask & GENERIC_READ) == GENERIC_READ) || ((Mask & FILE_GENERIC_READ) == FILE_GENERIC_READ)) {
perms.emplace_back("Read");
}
if (((Mask & GENERIC_WRITE) == GENERIC_WRITE) || ((Mask & FILE_GENERIC_WRITE) == FILE_GENERIC_WRITE)) {
perms.emplace_back("Write");
}
if (((Mask & GENERIC_EXECUTE) == GENERIC_EXECUTE) || ((Mask & FILE_GENERIC_EXECUTE) == FILE_GENERIC_EXECUTE)) {
perms.emplace_back("Execute");
}
}
env->PushLocalFrame(10);
jobject ret = env->NewObjectArray(perms.size(), stringClass, nullptr);
for (int i = 0; i < perms.size(); i++) {
env->SetObjectArrayElement(ret, i, env->NewStringUTF(perms[i].c_str()));
}
env->CallObjectMethod(hashMap, put, env->NewStringUTF(name.c_str()), ret);
env->PopLocalFrame(nullptr);
}
}
return hashMap;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论