Constructing a HashMap through JNI

huangapple go评论81阅读模式
英文:

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&lt;String, String[]&gt; ACLInfo(String s);
static
{
System.loadLibrary(&quot;test&quot;);
}
static public void main(String args[])
{
test obj = new test();
Map&lt;String, String[]&gt; map = obj.ACLInfo(&quot;C:/Windows/Boot/Resources/bootres.dll&quot;);
for (Map.Entry&lt;String, String[]&gt; entry : map.entrySet())
{
String name = entry.getKey();
System.out.println(&quot;Name:&quot;+name);
System.out.println(&quot;Properties are:&quot;);
for(String text : entry.getValue())
{
if(text.equals(&quot;Full Control&quot;)){
System.out.println(text);
continue;
}
if(text.equals(&quot;Read&quot;))
System.out.println(text);
if(text.equals(&quot;Write&quot;))
System.out.println(text);
if(text.equals(&quot;Execute&quot;))
System.out.println(text);
}
}
}
}

The native code is.

#include &lt;iostream&gt;
#include &lt;jni.h&gt;
#include &lt;string.h&gt;
#include &lt;windows.h&gt;
#include &lt;tchar.h&gt;
#include &lt;Lmcons.h&gt;
#include &quot;test.h&quot;
#include &quot;accctrl.h&quot;
#include &quot;aclapi.h&quot;
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-&gt;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,
&amp;pSidOwner,
NULL,
&amp;pOldDACL,
NULL,
&amp;pSD);
PACL pAcl = pOldDACL;
aceNum = pOldDACL-&gt;AceCount;
ret = (jobjectArray)env-&gt;NewObjectArray(3, env-&gt;FindClass(&quot;java/lang/String&quot;), env-&gt;NewStringUTF(&quot;&quot;));
jclass mapClass = env-&gt;FindClass(&quot;java/util/HashMap&quot;);      //HashMap class in java library
if(mapClass == NULL)
{
return NULL;
}
jsize map_len = aceNum;
jmethodID init = env-&gt;GetMethodID(mapClass, &quot;&lt;init&gt;&quot;, &quot;(I)V&quot;);  //constructor of HashMap class
jobject hashMap = env-&gt;NewObject(mapClass, init, map_len);      //creating a new object for that class
jmethodID put = env-&gt;GetMethodID(mapClass, &quot;put&quot;, &quot;(Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;&quot;);
for (i = 0; i &lt; aceNum; i++)
{
PACCESS_ALLOWED_ACE AceItem;
ACE_HEADER *aceAddr = NULL;
if (GetAce(pOldDACL, i, (LPVOID*)&amp;AceItem) &amp;&amp; GetAce(pOldDACL, i, (LPVOID*)&amp;aceAddr))
{
LPTSTR AccountBuff = NULL, DomainBuff = NULL;
DWORD AccountBufflength = 1, DomainBufflength = 1;
PSID_NAME_USE peUse = new SID_NAME_USE;
PSID Sid = &amp;AceItem-&gt;SidStart;
LookupAccountSid(NULL, Sid, AccountBuff, (LPDWORD)&amp;AccountBufflength, DomainBuff, (LPDWORD)&amp;DomainBufflength, peUse);
AccountBuff = (LPSTR)malloc(AccountBufflength * sizeof(LPSTR));
DomainBuff = (LPSTR)malloc(DomainBufflength * sizeof(LPSTR));
LookupAccountSid(NULL, Sid, AccountBuff, &amp;AccountBufflength, DomainBuff, &amp;DomainBufflength, peUse);
std::string acc=AccountBuff;
std::string dom=DomainBuff;
name = acc+&quot;\\&quot;+dom;
ACCESS_MASK Mask = AceItem-&gt;Mask;
if (((Mask &amp; GENERIC_ALL) == GENERIC_ALL) || ((Mask &amp; FILE_ALL_ACCESS) == FILE_ALL_ACCESS)){
reslt=&quot;Full Control&quot;;
test = reslt.c_str();
env-&gt;SetObjectArrayElement(ret,i,env-&gt;NewStringUTF(test));
env-&gt;CallObjectMethod(hashMap, put, env-&gt;NewStringUTF(name.c_str()), ret);
continue;
}
int j=0;
if (((Mask &amp; GENERIC_READ) == GENERIC_READ) || ((Mask &amp; FILE_GENERIC_READ) == FILE_GENERIC_READ))
{
reslt=&quot;Read&quot;;
test = reslt.c_str();
env-&gt;SetObjectArrayElement(ret,j++,env-&gt;NewStringUTF(test));
}
if (((Mask &amp; GENERIC_WRITE) == GENERIC_WRITE) || ((Mask &amp; FILE_GENERIC_WRITE) == FILE_GENERIC_WRITE))
{
reslt=&quot;Write&quot;;
test = reslt.c_str();
env-&gt;SetObjectArrayElement(ret,j++,env-&gt;NewStringUTF(test));
}
if (((Mask &amp; GENERIC_EXECUTE) == GENERIC_EXECUTE) || ((Mask &amp; FILE_GENERIC_EXECUTE) == FILE_GENERIC_EXECUTE))
{
reslt=&quot;Execute&quot;;
test = reslt.c_str();
env-&gt;SetObjectArrayElement(ret,j++,env-&gt;NewStringUTF(test));
}
env-&gt;CallObjectMethod(hashMap, put, env-&gt;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&amp;lq=1

答案1

得分: 2

我已经重写了您的代码,以消除最严重的错误:

  • 您的HashMap#put方法签名错误。
  • 每次将元素放入哈希映射时,您都必须创建一个string[]。如果重用相同的对象,您将获得相同的string[]的N个副本。
  • 您不能一开始创建大小为3的数组,然后只填充一些槽位。最好在C++领域使用临时向量,稍后创建正确大小的数组。
  • 您需要使用PushLocalFramePopLocalFrame来确保不超出本地引用预算。

我还删除了许多非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 same string[].
  • 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-&gt;FindClass(&quot;java/util/HashMap&quot;);      //HashMap class in java library
jclass stringClass = env-&gt;FindClass(&quot;java/lang/String&quot;);
if(mapClass == NULL)
{
return NULL;
}
jsize map_len = aceNum;
jmethodID init = env-&gt;GetMethodID(mapClass, &quot;&lt;init&gt;&quot;, &quot;(I)V&quot;);  //constructor of HashMap class
jobject hashMap = env-&gt;NewObject(mapClass, init, map_len);      //creating a new object for that class
jmethodID put = env-&gt;GetMethodID(mapClass, &quot;put&quot;, &quot;(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;&quot;);
for (i = 0; i &lt; aceNum; i++) {
// removed stuff
PACCESS_ALLOWED_ACE AceItem;
ACE_HEADER *aceAddr = NULL;
if (GetAce(pOldDACL, i, (LPVOID*)&amp;AceItem) &amp;&amp; GetAce(pOldDACL, i, (LPVOID*)&amp;aceAddr)) {
// removed more stuff
std::string name = std::string(AccountBuff)+&quot;\\&quot;+std::string(DomainBuff);
std::vector&lt;std::string&gt; perms;
ACCESS_MASK Mask = AceItem-&gt;Mask;
if (((Mask &amp; GENERIC_ALL) == GENERIC_ALL) || ((Mask &amp; FILE_ALL_ACCESS) == FILE_ALL_ACCESS)) {
perms.emplace_back(&quot;Full Control&quot;);
} else {
if (((Mask &amp; GENERIC_READ) == GENERIC_READ) || ((Mask &amp; FILE_GENERIC_READ) == FILE_GENERIC_READ)) {
perms.emplace_back(&quot;Read&quot;);
}
if (((Mask &amp; GENERIC_WRITE) == GENERIC_WRITE) || ((Mask &amp; FILE_GENERIC_WRITE) == FILE_GENERIC_WRITE)) {
perms.emplace_back(&quot;Write&quot;);
}
if (((Mask &amp; GENERIC_EXECUTE) == GENERIC_EXECUTE) || ((Mask &amp; FILE_GENERIC_EXECUTE) == FILE_GENERIC_EXECUTE)) {
perms.emplace_back(&quot;Execute&quot;);
}
}
env-&gt;PushLocalFrame(10);
jobject ret = env-&gt;NewObjectArray(perms.size(), stringClass, nullptr);
for (int i = 0; i &lt; perms.size(); i++) {
env-&gt;SetObjectArrayElement(ret, i, env-&gt;NewStringUTF(perms[i].c_str()));
}
env-&gt;CallObjectMethod(hashMap, put, env-&gt;NewStringUTF(name.c_str()), ret);
env-&gt;PopLocalFrame(nullptr);
}
}
return hashMap;
}

huangapple
  • 本文由 发表于 2020年8月13日 22:05:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/63396954.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定