Constructing a HashMap through JNI

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

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.

  1. import java.util.*;
  2. public class test
  3. {
  4. native Map<String, String[]> ACLInfo(String s);
  5. static
  6. {
  7. System.loadLibrary("test");
  8. }
  9. static public void main(String args[])
  10. {
  11. test obj = new test();
  12. Map<String, String[]> map = obj.ACLInfo("C:/Windows/Boot/Resources/bootres.dll");
  13. for (Map.Entry<String, String[]> entry : map.entrySet())
  14. {
  15. String name = entry.getKey();
  16. System.out.println("Name:"+name);
  17. System.out.println("Properties are:");
  18. for(String text : entry.getValue())
  19. {
  20. if(text.equals("Full Control")){
  21. System.out.println(text);
  22. continue;
  23. }
  24. if(text.equals("Read"))
  25. System.out.println(text);
  26. if(text.equals("Write"))
  27. System.out.println(text);
  28. if(text.equals("Execute"))
  29. System.out.println(text);
  30. }
  31. }
  32. }
  33. }

The native code is.

  1. #include <iostream>
  2. #include <jni.h>
  3. #include <string.h>
  4. #include <windows.h>
  5. #include <tchar.h>
  6. #include <Lmcons.h>
  7. #include "test.h"
  8. #include "accctrl.h"
  9. #include "aclapi.h"
  10. using namespace std;
  11. JNIEXPORT jobject JNICALL Java_test_ACLInfo(JNIEnv *env, jobject jobj, jstring s)
  12. {
  13. jobjectArray ret;
  14. jstring jstr;
  15. PSID pSidOwner = NULL;
  16. BOOL bRtnBool = TRUE;
  17. DWORD dwRtnCode = 0;
  18. SID_NAME_USE eUse = SidTypeUnknown;
  19. HANDLE hFile;
  20. PSECURITY_DESCRIPTOR pSD = NULL;
  21. PACL pOldDACL = NULL;
  22. int i,aceNum;
  23. const char* test;
  24. std::string name,reslt;
  25. const char* nativeString = env->GetStringUTFChars(s, 0);
  26. LPCSTR file = nativeString;
  27. // Get the handle of the file object.
  28. hFile = CreateFile(
  29. file,
  30. GENERIC_READ,
  31. FILE_SHARE_READ,
  32. NULL,
  33. OPEN_EXISTING,
  34. FILE_ATTRIBUTE_NORMAL,
  35. NULL);
  36. // Get the SID of the file.
  37. dwRtnCode = GetSecurityInfo(
  38. hFile,
  39. SE_FILE_OBJECT,
  40. DACL_SECURITY_INFORMATION,
  41. &pSidOwner,
  42. NULL,
  43. &pOldDACL,
  44. NULL,
  45. &pSD);
  46. PACL pAcl = pOldDACL;
  47. aceNum = pOldDACL->AceCount;
  48. ret = (jobjectArray)env->NewObjectArray(3, env->FindClass("java/lang/String"), env->NewStringUTF(""));
  49. jclass mapClass = env->FindClass("java/util/HashMap"); //HashMap class in java library
  50. if(mapClass == NULL)
  51. {
  52. return NULL;
  53. }
  54. jsize map_len = aceNum;
  55. jmethodID init = env->GetMethodID(mapClass, "<init>", "(I)V"); //constructor of HashMap class
  56. jobject hashMap = env->NewObject(mapClass, init, map_len); //creating a new object for that class
  57. jmethodID put = env->GetMethodID(mapClass, "put", "(Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;");
  58. for (i = 0; i < aceNum; i++)
  59. {
  60. PACCESS_ALLOWED_ACE AceItem;
  61. ACE_HEADER *aceAddr = NULL;
  62. if (GetAce(pOldDACL, i, (LPVOID*)&AceItem) && GetAce(pOldDACL, i, (LPVOID*)&aceAddr))
  63. {
  64. LPTSTR AccountBuff = NULL, DomainBuff = NULL;
  65. DWORD AccountBufflength = 1, DomainBufflength = 1;
  66. PSID_NAME_USE peUse = new SID_NAME_USE;
  67. PSID Sid = &AceItem->SidStart;
  68. LookupAccountSid(NULL, Sid, AccountBuff, (LPDWORD)&AccountBufflength, DomainBuff, (LPDWORD)&DomainBufflength, peUse);
  69. AccountBuff = (LPSTR)malloc(AccountBufflength * sizeof(LPSTR));
  70. DomainBuff = (LPSTR)malloc(DomainBufflength * sizeof(LPSTR));
  71. LookupAccountSid(NULL, Sid, AccountBuff, &AccountBufflength, DomainBuff, &DomainBufflength, peUse);
  72. std::string acc=AccountBuff;
  73. std::string dom=DomainBuff;
  74. name = acc+"\\"+dom;
  75. ACCESS_MASK Mask = AceItem->Mask;
  76. if (((Mask & GENERIC_ALL) == GENERIC_ALL) || ((Mask & FILE_ALL_ACCESS) == FILE_ALL_ACCESS)){
  77. reslt="Full Control";
  78. test = reslt.c_str();
  79. env->SetObjectArrayElement(ret,i,env->NewStringUTF(test));
  80. env->CallObjectMethod(hashMap, put, env->NewStringUTF(name.c_str()), ret);
  81. continue;
  82. }
  83. int j=0;
  84. if (((Mask & GENERIC_READ) == GENERIC_READ) || ((Mask & FILE_GENERIC_READ) == FILE_GENERIC_READ))
  85. {
  86. reslt="Read";
  87. test = reslt.c_str();
  88. env->SetObjectArrayElement(ret,j++,env->NewStringUTF(test));
  89. }
  90. if (((Mask & GENERIC_WRITE) == GENERIC_WRITE) || ((Mask & FILE_GENERIC_WRITE) == FILE_GENERIC_WRITE))
  91. {
  92. reslt="Write";
  93. test = reslt.c_str();
  94. env->SetObjectArrayElement(ret,j++,env->NewStringUTF(test));
  95. }
  96. if (((Mask & GENERIC_EXECUTE) == GENERIC_EXECUTE) || ((Mask & FILE_GENERIC_EXECUTE) == FILE_GENERIC_EXECUTE))
  97. {
  98. reslt="Execute";
  99. test = reslt.c_str();
  100. env->SetObjectArrayElement(ret,j++,env->NewStringUTF(test));
  101. }
  102. env->CallObjectMethod(hashMap, put, env->NewStringUTF(name.c_str()), ret);
  103. }
  104. }
  105. return hashMap;
  106. }

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.

  1. import java.util.*;
  2. public class test
  3. {
  4. native Map&lt;String, String[]&gt; ACLInfo(String s);
  5. static
  6. {
  7. System.loadLibrary(&quot;test&quot;);
  8. }
  9. static public void main(String args[])
  10. {
  11. test obj = new test();
  12. Map&lt;String, String[]&gt; map = obj.ACLInfo(&quot;C:/Windows/Boot/Resources/bootres.dll&quot;);
  13. for (Map.Entry&lt;String, String[]&gt; entry : map.entrySet())
  14. {
  15. String name = entry.getKey();
  16. System.out.println(&quot;Name:&quot;+name);
  17. System.out.println(&quot;Properties are:&quot;);
  18. for(String text : entry.getValue())
  19. {
  20. if(text.equals(&quot;Full Control&quot;)){
  21. System.out.println(text);
  22. continue;
  23. }
  24. if(text.equals(&quot;Read&quot;))
  25. System.out.println(text);
  26. if(text.equals(&quot;Write&quot;))
  27. System.out.println(text);
  28. if(text.equals(&quot;Execute&quot;))
  29. System.out.println(text);
  30. }
  31. }
  32. }
  33. }

The native code is.

  1. #include &lt;iostream&gt;
  2. #include &lt;jni.h&gt;
  3. #include &lt;string.h&gt;
  4. #include &lt;windows.h&gt;
  5. #include &lt;tchar.h&gt;
  6. #include &lt;Lmcons.h&gt;
  7. #include &quot;test.h&quot;
  8. #include &quot;accctrl.h&quot;
  9. #include &quot;aclapi.h&quot;
  10. using namespace std;
  11. JNIEXPORT jobject JNICALL Java_test_ACLInfo(JNIEnv *env, jobject jobj, jstring s)
  12. {
  13. jobjectArray ret;
  14. jstring jstr;
  15. PSID pSidOwner = NULL;
  16. BOOL bRtnBool = TRUE;
  17. DWORD dwRtnCode = 0;
  18. SID_NAME_USE eUse = SidTypeUnknown;
  19. HANDLE hFile;
  20. PSECURITY_DESCRIPTOR pSD = NULL;
  21. PACL pOldDACL = NULL;
  22. int i,aceNum;
  23. const char* test;
  24. std::string name,reslt;
  25. const char* nativeString = env-&gt;GetStringUTFChars(s, 0);
  26. LPCSTR file = nativeString;
  27. // Get the handle of the file object.
  28. hFile = CreateFile(
  29. file,
  30. GENERIC_READ,
  31. FILE_SHARE_READ,
  32. NULL,
  33. OPEN_EXISTING,
  34. FILE_ATTRIBUTE_NORMAL,
  35. NULL);
  36. // Get the SID of the file.
  37. dwRtnCode = GetSecurityInfo(
  38. hFile,
  39. SE_FILE_OBJECT,
  40. DACL_SECURITY_INFORMATION,
  41. &amp;pSidOwner,
  42. NULL,
  43. &amp;pOldDACL,
  44. NULL,
  45. &amp;pSD);
  46. PACL pAcl = pOldDACL;
  47. aceNum = pOldDACL-&gt;AceCount;
  48. ret = (jobjectArray)env-&gt;NewObjectArray(3, env-&gt;FindClass(&quot;java/lang/String&quot;), env-&gt;NewStringUTF(&quot;&quot;));
  49. jclass mapClass = env-&gt;FindClass(&quot;java/util/HashMap&quot;); //HashMap class in java library
  50. if(mapClass == NULL)
  51. {
  52. return NULL;
  53. }
  54. jsize map_len = aceNum;
  55. jmethodID init = env-&gt;GetMethodID(mapClass, &quot;&lt;init&gt;&quot;, &quot;(I)V&quot;); //constructor of HashMap class
  56. jobject hashMap = env-&gt;NewObject(mapClass, init, map_len); //creating a new object for that class
  57. jmethodID put = env-&gt;GetMethodID(mapClass, &quot;put&quot;, &quot;(Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;&quot;);
  58. for (i = 0; i &lt; aceNum; i++)
  59. {
  60. PACCESS_ALLOWED_ACE AceItem;
  61. ACE_HEADER *aceAddr = NULL;
  62. if (GetAce(pOldDACL, i, (LPVOID*)&amp;AceItem) &amp;&amp; GetAce(pOldDACL, i, (LPVOID*)&amp;aceAddr))
  63. {
  64. LPTSTR AccountBuff = NULL, DomainBuff = NULL;
  65. DWORD AccountBufflength = 1, DomainBufflength = 1;
  66. PSID_NAME_USE peUse = new SID_NAME_USE;
  67. PSID Sid = &amp;AceItem-&gt;SidStart;
  68. LookupAccountSid(NULL, Sid, AccountBuff, (LPDWORD)&amp;AccountBufflength, DomainBuff, (LPDWORD)&amp;DomainBufflength, peUse);
  69. AccountBuff = (LPSTR)malloc(AccountBufflength * sizeof(LPSTR));
  70. DomainBuff = (LPSTR)malloc(DomainBufflength * sizeof(LPSTR));
  71. LookupAccountSid(NULL, Sid, AccountBuff, &amp;AccountBufflength, DomainBuff, &amp;DomainBufflength, peUse);
  72. std::string acc=AccountBuff;
  73. std::string dom=DomainBuff;
  74. name = acc+&quot;\\&quot;+dom;
  75. ACCESS_MASK Mask = AceItem-&gt;Mask;
  76. if (((Mask &amp; GENERIC_ALL) == GENERIC_ALL) || ((Mask &amp; FILE_ALL_ACCESS) == FILE_ALL_ACCESS)){
  77. reslt=&quot;Full Control&quot;;
  78. test = reslt.c_str();
  79. env-&gt;SetObjectArrayElement(ret,i,env-&gt;NewStringUTF(test));
  80. env-&gt;CallObjectMethod(hashMap, put, env-&gt;NewStringUTF(name.c_str()), ret);
  81. continue;
  82. }
  83. int j=0;
  84. if (((Mask &amp; GENERIC_READ) == GENERIC_READ) || ((Mask &amp; FILE_GENERIC_READ) == FILE_GENERIC_READ))
  85. {
  86. reslt=&quot;Read&quot;;
  87. test = reslt.c_str();
  88. env-&gt;SetObjectArrayElement(ret,j++,env-&gt;NewStringUTF(test));
  89. }
  90. if (((Mask &amp; GENERIC_WRITE) == GENERIC_WRITE) || ((Mask &amp; FILE_GENERIC_WRITE) == FILE_GENERIC_WRITE))
  91. {
  92. reslt=&quot;Write&quot;;
  93. test = reslt.c_str();
  94. env-&gt;SetObjectArrayElement(ret,j++,env-&gt;NewStringUTF(test));
  95. }
  96. if (((Mask &amp; GENERIC_EXECUTE) == GENERIC_EXECUTE) || ((Mask &amp; FILE_GENERIC_EXECUTE) == FILE_GENERIC_EXECUTE))
  97. {
  98. reslt=&quot;Execute&quot;;
  99. test = reslt.c_str();
  100. env-&gt;SetObjectArrayElement(ret,j++,env-&gt;NewStringUTF(test));
  101. }
  102. env-&gt;CallObjectMethod(hashMap, put, env-&gt;NewStringUTF(name.c_str()), ret);
  103. }
  104. }
  105. return hashMap;
  106. }

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的冗余内容。请尽量保持您的示例代码简洁明了。

  1. JNIEXPORT jobject JNICALL Java_test_ACLInfo(JNIEnv *env, jobject jobj, jstring s)
  2. {
  3. // 移除的部分
  4. jclass mapClass = env->FindClass("java/util/HashMap"); // Java库中的HashMap类
  5. jclass stringClass = env->FindClass("java/lang/String");
  6. if (mapClass == NULL)
  7. {
  8. return NULL;
  9. }
  10. jsize map_len = aceNum;
  11. jmethodID init = env->GetMethodID(mapClass, "<init>", "(I)V"); // HashMap类的构造函数
  12. jobject hashMap = env->NewObject(mapClass, init, map_len); // 创建该类的新对象
  13. jmethodID put = env->GetMethodID(mapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
  14. for (i = 0; i < aceNum; i++)
  15. {
  16. // 移除的部分
  17. PACCESS_ALLOWED_ACE AceItem;
  18. ACE_HEADER *aceAddr = NULL;
  19. if (GetAce(pOldDACL, i, (LPVOID*)&AceItem) && GetAce(pOldDACL, i, (LPVOID*)&aceAddr))
  20. {
  21. // 移除的更多部分
  22. std::string name = std::string(AccountBuff) + "\\" + std::string(DomainBuff);
  23. std::vector<std::string> perms;
  24. ACCESS_MASK Mask = AceItem->Mask;
  25. if (((Mask & GENERIC_ALL) == GENERIC_ALL) || ((Mask & FILE_ALL_ACCESS) == FILE_ALL_ACCESS))
  26. {
  27. perms.emplace_back("Full Control");
  28. }
  29. else
  30. {
  31. if (((Mask & GENERIC_READ) == GENERIC_READ) || ((Mask & FILE_GENERIC_READ) == FILE_GENERIC_READ))
  32. {
  33. perms.emplace_back("Read");
  34. }
  35. if (((Mask & GENERIC_WRITE) == GENERIC_WRITE) || ((Mask & FILE_GENERIC_WRITE) == FILE_GENERIC_WRITE))
  36. {
  37. perms.emplace_back("Write");
  38. }
  39. if (((Mask & GENERIC_EXECUTE) == GENERIC_EXECUTE) || ((Mask & FILE_GENERIC_EXECUTE) == FILE_GENERIC_EXECUTE))
  40. {
  41. perms.emplace_back("Execute");
  42. }
  43. }
  44. env->PushLocalFrame(10);
  45. jobject ret = env->NewObjectArray(perms.size(), stringClass, nullptr);
  46. for (int i = 0; i < perms.size(); i++)
  47. {
  48. env->SetObjectArrayElement(ret, i, env->NewStringUTF(perms[i].c_str()));
  49. }
  50. env->CallObjectMethod(hashMap, put, env->NewStringUTF(name.c_str()), ret);
  51. env->PopLocalFrame(nullptr);
  52. }
  53. }
  54. return hashMap;
  55. }

希望这对您有所帮助。

英文:

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.

  1. JNIEXPORT jobject JNICALL Java_test_ACLInfo(JNIEnv *env, jobject jobj, jstring s)
  2. {
  3. // removed stuff
  4. jclass mapClass = env-&gt;FindClass(&quot;java/util/HashMap&quot;); //HashMap class in java library
  5. jclass stringClass = env-&gt;FindClass(&quot;java/lang/String&quot;);
  6. if(mapClass == NULL)
  7. {
  8. return NULL;
  9. }
  10. jsize map_len = aceNum;
  11. jmethodID init = env-&gt;GetMethodID(mapClass, &quot;&lt;init&gt;&quot;, &quot;(I)V&quot;); //constructor of HashMap class
  12. jobject hashMap = env-&gt;NewObject(mapClass, init, map_len); //creating a new object for that class
  13. jmethodID put = env-&gt;GetMethodID(mapClass, &quot;put&quot;, &quot;(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;&quot;);
  14. for (i = 0; i &lt; aceNum; i++) {
  15. // removed stuff
  16. PACCESS_ALLOWED_ACE AceItem;
  17. ACE_HEADER *aceAddr = NULL;
  18. if (GetAce(pOldDACL, i, (LPVOID*)&amp;AceItem) &amp;&amp; GetAce(pOldDACL, i, (LPVOID*)&amp;aceAddr)) {
  19. // removed more stuff
  20. std::string name = std::string(AccountBuff)+&quot;\\&quot;+std::string(DomainBuff);
  21. std::vector&lt;std::string&gt; perms;
  22. ACCESS_MASK Mask = AceItem-&gt;Mask;
  23. if (((Mask &amp; GENERIC_ALL) == GENERIC_ALL) || ((Mask &amp; FILE_ALL_ACCESS) == FILE_ALL_ACCESS)) {
  24. perms.emplace_back(&quot;Full Control&quot;);
  25. } else {
  26. if (((Mask &amp; GENERIC_READ) == GENERIC_READ) || ((Mask &amp; FILE_GENERIC_READ) == FILE_GENERIC_READ)) {
  27. perms.emplace_back(&quot;Read&quot;);
  28. }
  29. if (((Mask &amp; GENERIC_WRITE) == GENERIC_WRITE) || ((Mask &amp; FILE_GENERIC_WRITE) == FILE_GENERIC_WRITE)) {
  30. perms.emplace_back(&quot;Write&quot;);
  31. }
  32. if (((Mask &amp; GENERIC_EXECUTE) == GENERIC_EXECUTE) || ((Mask &amp; FILE_GENERIC_EXECUTE) == FILE_GENERIC_EXECUTE)) {
  33. perms.emplace_back(&quot;Execute&quot;);
  34. }
  35. }
  36. env-&gt;PushLocalFrame(10);
  37. jobject ret = env-&gt;NewObjectArray(perms.size(), stringClass, nullptr);
  38. for (int i = 0; i &lt; perms.size(); i++) {
  39. env-&gt;SetObjectArrayElement(ret, i, env-&gt;NewStringUTF(perms[i].c_str()));
  40. }
  41. env-&gt;CallObjectMethod(hashMap, put, env-&gt;NewStringUTF(name.c_str()), ret);
  42. env-&gt;PopLocalFrame(nullptr);
  43. }
  44. }
  45. return hashMap;
  46. }

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:

确定