Golang CGO使用大型字符指针-SEGSERV

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

Golang CGO with large char pointer - SEGSERV

问题

我有大量的数据从TagLib库中读取,并传递给GoLang(mpeg图像数据)。

这是获取数据的地方:

  1. void audiotags_mpeg_artwork(TagLib::MPEG::File *mpegFile, int id) {
  2. TagLib::ID3v2::Tag *id3v2 = mpegFile->ID3v2Tag(false);
  3. if (id3v2!=nullptr) {
  4. const TagLib::ID3v2::FrameList frameList = id3v2->frameListMap()["APIC"];
  5. for(auto it = frameList.begin(); it != frameList.end(); it++) {
  6. TagLib::ID3v2::AttachedPictureFrame * frame = (TagLib::ID3v2::AttachedPictureFrame *)(*it);
  7. if (frame!=nullptr && frame->size() > 0) {
  8. const auto &apicBase64 = frame->picture().toBase64();
  9. auto len = apicBase64.size();
  10. if (len > 0) {
  11. // Generate memory for key
  12. char* key = new char[5];
  13. memcpy(key, "APIC", 4);
  14. key[4]='
    void audiotags_mpeg_artwork(TagLib::MPEG::File *mpegFile, int id) {
  15.     TagLib::ID3v2::Tag *id3v2 = mpegFile->ID3v2Tag(false);
  16.     if (id3v2!=nullptr) {
  17.         const TagLib::ID3v2::FrameList frameList = id3v2->frameListMap()["APIC"];
  18.         for(auto it = frameList.begin(); it != frameList.end(); it++) {
  19.             TagLib::ID3v2::AttachedPictureFrame * frame = (TagLib::ID3v2::AttachedPictureFrame *)(*it);
  20.             if (frame!=nullptr && frame->size() > 0) {
  21.                 const auto &apicBase64 = frame->picture().toBase64();
  22.                 auto len = apicBase64.size();
  23.                 if (len > 0) {
  24.                     // Generate memory for key
  25.                     char* key = new char[5];
  26.                     memcpy(key, "APIC", 4);
  27.                     key[4]='\0';
  28.                     // Generate memory for picture data
  29.                     char* val = new char[len];
  30.                     memcpy (val, apicBase64.data(), len);
  31.                     // Send to GoLang
  32.                     go_map_audiotags(id, key, val);
  33.                     // Free memory
  34.                     delete[] key;
  35.                     delete[] val;
  36.                 }
  37.             }
  38.         }
  39.     }
  40. }
  41. ';
  42. // Generate memory for picture data
  43. char* val = new char[len];
  44. memcpy (val, apicBase64.data(), len);
  45. // Send to GoLang
  46. go_map_audiotags(id, key, val);
  47. // Free memory
  48. delete[] key;
  49. delete[] val;
  50. }
  51. }
  52. }
  53. }
  54. }

在这一点上,go_map_autotags起作用(我对其他数据使用类似的方法)。这对于其他图片数据也起作用,但是根据大小的不同,会导致崩溃:

unexpected fault address 0x766a000
fatal error: fault
[signal SIGSEGV: segmentation violation code=0x1 addr=0x766a000 pc=0x404530b]

在GoLang中,我有以下导出函数:

  1. //export go_map_audiotags
  2. func go_map_audiotags(id C.int, key *C.char, val *C.char) {
  3. m := maps[int(id)]
  4. k := strings.ToLower(C.GoString(key))
  5. log.Println("go_map_audiotags k:", k) // <--- works
  6. v := C.GoString(val) // <--- crashes
  7. log.Println("go_map_audiotags v:", v) // <--- Does not reach
  8. m[k] = v
  9. }

有没有更好的方法来传输这些数据?我猜测发生的情况是:

  1. 达到了C.char的限制
  2. C++由于某种原因在设置GoLang中的v之前回收了内存
英文:

I have a large amount of data being read from TagLib library and passed to GoLang (mpeg image data).

Here is where data is fetched:

  1. void audiotags_mpeg_artwork(TagLib::MPEG::File *mpegFile, int id) {
  2. TagLib::ID3v2::Tag *id3v2 = mpegFile-&gt;ID3v2Tag(false);
  3. if (id3v2!=nullptr) {
  4. const TagLib::ID3v2::FrameList frameList = id3v2-&gt;frameListMap()[&quot;APIC&quot;];
  5. for(auto it = frameList.begin(); it != frameList.end(); it++) {
  6. TagLib::ID3v2::AttachedPictureFrame * frame = (TagLib::ID3v2::AttachedPictureFrame *)(*it);
  7. if (frame!=nullptr &amp;&amp; frame-&gt;size() &gt; 0) {
  8. const auto &amp;apicBase64 = frame-&gt;picture().toBase64();
  9. auto len = apicBase64.size();
  10. if (len &gt; 0) {
  11. // Generate memory for key
  12. char* key = new char[5];
  13. memcpy(key, &quot;APIC&quot;, 4);
  14. key[4]=&#39;
    void audiotags_mpeg_artwork(TagLib::MPEG::File *mpegFile, int id) {
  15. TagLib::ID3v2::Tag *id3v2 = mpegFile-&gt;ID3v2Tag(false);
  16. if (id3v2!=nullptr) {
  17. const TagLib::ID3v2::FrameList frameList = id3v2-&gt;frameListMap()[&quot;APIC&quot;];
  18. for(auto it = frameList.begin(); it != frameList.end(); it++) {
  19. TagLib::ID3v2::AttachedPictureFrame * frame = (TagLib::ID3v2::AttachedPictureFrame *)(*it);
  20. if (frame!=nullptr &amp;&amp; frame-&gt;size() &gt; 0) {
  21. const auto &amp;apicBase64 = frame-&gt;picture().toBase64();
  22. auto len = apicBase64.size();
  23. if (len &gt; 0) {
  24. // Generate memory for key
  25. char* key = new char[5];
  26. memcpy(key, &quot;APIC&quot;, 4);
  27. key[4]=&#39;\0&#39;;
  28. // Generate memory for picture data
  29. char* val = new char[len];
  30. memcpy (val, apicBase64.data(), len);
  31. // Send to GoLang
  32. go_map_audiotags(id, key, val);
  33. // Free memory
  34. delete[] key;
  35. delete[] val;
  36. }
  37. }
  38. }
  39. }
  40. }
  41. &#39;;
  42. // Generate memory for picture data
  43. char* val = new char[len];
  44. memcpy (val, apicBase64.data(), len);
  45. // Send to GoLang
  46. go_map_audiotags(id, key, val);
  47. // Free memory
  48. delete[] key;
  49. delete[] val;
  50. }
  51. }
  52. }
  53. }
  54. }

At this point, go_map_autotags works (I use a similar method for other data). This also works for other picture data, however depending on the size this will crash with:
> unexpected fault address 0x766a000

> fatal error: fault

> [signal SIGSEGV: segmentation violation code=0x1 addr=0x766a000 pc=0x404530b]

Within GoLang, I have the following export:

  1. //export go_map_audiotags
  2. func go_map_audiotags(id C.int, key *C.char, val *C.char) {
  3. m := maps[int(id)]
  4. k := strings.ToLower(C.GoString(key))
  5. log.Println(&quot;go_map_audiotags k:&quot;, k) // &lt;--- works
  6. v := C.GoString(val) // &lt;--- crashes
  7. log.Println(&quot;go_map_audiotags v:&quot;, v) // &lt;--- Does not reach
  8. m[k] = v
  9. }

Is there a bette way I should be transporting this data? I assume what's happening is:

  1. The C.char limit be being reached
  2. C++ is, for some reason, recycling the memory before setting v in GoLang

答案1

得分: 1

在你的C代码中,val中存储的数据没有以空字符结尾。当你使用memcpy进行复制时,没有包含空字符终止符。在C代码中,将代码更改为:

  1. // 为图片数据生成内存
  2. char* val = new char[len+1];
  3. memcpy(val, apicBase64.data(), len);
  4. val[len] = '
    // 为图片数据生成内存
  5. char* val = new char[len+1];
  6. memcpy(val, apicBase64.data(), len);
  7. val[len] = '\0';
  8. ';
英文:

The data stored in val is not null-terminated. In your C code, when you make a copy using memcpy, the null terminator is not included. In the C code, change the code to:

  1. // Generate memory for picture data
  2. char* val = new char[len+1];
  3. memcpy (val, apicBase64.data(), len);
  4. val[len] = &#39;
    // Generate memory for picture data
  5. char* val = new char[len+1];
  6. memcpy (val, apicBase64.data(), len);
  7. val[len] = &#39;\0&#39;;
  8. &#39;;

huangapple
  • 本文由 发表于 2017年8月26日 06:39:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/45890244.html
匿名

发表评论

匿名网友

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

确定