简体   繁体   English

Perl XS:创建并返回字符串数组 (char*),取自调用 C function 或失败时的 undef

[英]Perl XS: create and return array of strings (char*) taken from calling a C function or undef on failure

I have Perl XS code which calls a function from an external C library which returns char ** (array of strings).我有 Perl XS 代码,它从返回char ** (字符串数组)的外部 C 库调用 function。

The XS code will eventually return back to Perl an array ref with all the string results in there. XS 代码最终将返回 Perl 一个数组引用,其中包含所有字符串结果。 Or undef on failure.或者undef失败。

I have 2 problems:我有两个问题:

  1. On program exit I get a core dump with messages about memory corruption, double free etc. (eg double free or corruption (fasttop) ).在程序退出时,我得到一个核心转储,其中包含有关 memory 损坏、双重释放等的消息(例如double free or corruption (fasttop) )。
  2. How to return an undef value from XS sub denoting that something went wrong (not an empty array)?如何从 XS sub 返回一个 undef 值,表示出现问题(不是空数组)?

Additionally, if anyone can confirm that I am handling correctly the cases where strings from Perl into the C function are utf8-encoded (eg the input filename) or the results back from the C function (which may contain utf8 strings) are sent back to Perl OK.此外,如果有人可以确认我正在正确处理以下情况:从 Perl 到 C function 的字符串是 utf8 编码的(例如输入文件名)或从 C function 返回的结果(可能包含 utf8 字符串)被发送回Perl 好的。

Here's my code (which is modelled after https://stackoverflow.com/a/46719397/385390 If I got that correctly, example #1):这是我的代码(以https://stackoverflow.com/a/46719397/385390为蓝本,如果我理解正确,示例 #1):

AV *
decode(infilename_SV)
    SV *infilename_SV
  PREINIT:
    char *infilename;
    STRLEN infilename_len;
    char **results;
    size_t results_sz;
    char *aresult;
    size_t I;
    SV **aresultPP;
    char *dummy;
    STRLEN dummy_len;
  CODE:
    infilename = SvPVbyte(infilename_SV, infilename_len)
    // call C function
    results = myfunc(infilename, &results_sz);
    if( results == NULL ){
      printf("error!");
      // HOW TO return undef (and not an empty array?)
    }
    // create a Perl array to be returned
    RETVAL = (AV*)sv_2mortal((SV*)newAV());
    for(I=0;I<results_sz;I++){
      results_sz = strlen(results[I]);
      // create a new Perl string and copy this result
      aresult = newSVpv(results[I], 0);
      av_push(RETVAL, aresult);
      // free results as returned by C call
      free(results[I]);
    }
    // free results as returned by C call
    free(results);
    // debug print results
    for(I=0;I<results_sz;I++){
      aresultPP = av_fetch((AV *)RETVAL, I, 0);
      dummy = SvPVbyte(*apayloadPP, dummy_len);
      printf("result: %s\n", dummy);
    }
  OUTPUT:
     RETVAL

On program exit I get a core dump with messages about memory corruption, double free etc. (eg double free or corruption (fasttop)).在程序退出时,我得到一个核心转储,其中包含有关 memory 损坏、双重释放等的消息(例如双重释放或损坏 (fasttop))。

This was probably because you overwrote the loop variable results_sz inside the for causing undefined behavior.这可能是因为您覆盖了for中的循环变量results_sz导致未定义的行为。

How to return an undef value from XS sub denoting that something went wrong (not an empty array)?如何从 XS sub 返回一个 undef 值,表示出现问题(不是空数组)?

You can return &PL_sv_undef to signal an undefined value, see perlxs for more information.您可以返回&PL_sv_undef以表示未定义的值,有关更多信息,请参阅perlxs For example like this:例如像这样:

SV *
decode(infilename_SV)
    SV *infilename_SV
  PREINIT:
    char *infilename;
    STRLEN infilename_len;
    char **results;
    size_t results_sz;
    char *aresult;
    size_t I;
  CODE:
    infilename = SvPVbyte(infilename_SV, infilename_len);
    results = myfunc(infilename, &results_sz);
    if( results == NULL ){
      RETVAL = &PL_sv_undef;
    }
    else {
       AV *av = newAV();
       for(I=0; I < results_sz; I++){
          aresult = newSVpv(results[I], 0);
          av_push(av, aresult);
          free(results[I]);
       }
       free(results);
       RETVAL = sv_2mortal(newRV_noinc((SV*)av));
    }
  OUTPUT:
     RETVAL

if anyone can confirm that I am handling correctly the cases where strings from Perl into the C function are utf8-encoded (eg the input filename)如果有人可以确认我正在正确处理从 Perl 到 C function 的字符串是 utf8 编码的情况(例如输入文件名)

To pass a Perl UTF-8 string to the C-function as an UTF-8 encoded character string you can use SvPVutf8() instead of SvPVbyte() , see perlguts for more information.要将 Perl UTF-8 字符串作为 UTF-8 编码字符串传递给 C 函数,您可以使用SvPVutf8()而不是SvPVbyte() ,请参阅perlguts了解更多信息。 Example:例子:

infilename = SvPVutf8(infilename_SV, infilename_len);

or the results back from the C function (which may contain utf8 strings) are sent back to Perl或者将 C function 返回的结果(可能包含 utf8 字符串)发送回 Perl

You can use newSVpvn_flags() instead of newSVpvn() to convert an UTF-8 encoded C-string to a Perl string.您可以使用newSVpvn_flags()而不是newSVpvn()将 UTF-8 编码的 C 字符串转换为 Perl 字符串。 For example:例如:

aresult = newSVpvn_flags(results[I], strlen(results[I]), SVf_UTF8);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM