perlre长度限制

l0b*_*0b0 6 regex perl

来自man perlre:

"*"量词相当于"{0,}","+"量词相当于"{1,}"和"?" 量词为"{0,1}".n和m限于小于建立perl时定义的预设限制的整数值.在最常见的平台上,这通常是32766.实际限制可以在代码生成的错误消息中看到,例如:

       $_ **= $_ , / {$_} / for 2 .. 42;
Run Code Online (Sandbox Code Playgroud)

哎这很难看 - 难道不是我可以得到一些常数吗?

编辑:正如daxim指出的那样(并且perlretut提示)可能是32767是一个神奇的硬编码.在Perl代码中进行一些搜索有很长的路要走,但我不确定如何进入下一步并实际找出实际设置的默认reg_infty或REG_INFTY的位置:

~/dev/perl-5.12.2
$ grep -ri 'reg_infty.*=' *
regexec.c:      if (max != REG_INFTY && ST.count == max)
t/re/pat.t:        $::reg_infty   = $Config {reg_infty} // 32767;
t/re/pat.t:        $::reg_infty_m = $::reg_infty - 1;
t/re/pat.t:        $::reg_infty_p = $::reg_infty + 1;
t/re/pat.t:        $::reg_infty_m = $::reg_infty_m;   # Surpress warning.
Run Code Online (Sandbox Code Playgroud)

编辑2:DVK当然是正确的:它是define在编译时,并且可能只能被覆盖REG_INFTY.

DVK*_*DVK 8

总结:我有三种方法可以想到找到极限:经验,"匹配Perl测试"和"理论".

  • 经验:

    eval {$_ **= $_ , / {$_} / for 2 .. 129};
    # To be truly portable, the above should ideally loop forever till $@ is true.
    $@ =~ /bigger than (-?\d+) /; 
    print "LIMIT: $1\n"'
    
    Run Code Online (Sandbox Code Playgroud)

    这似乎很明显,不需要解释.

  • 匹配Perl测试:

    Perl对正则表达式进行了一系列测试,其中一些(in pat.t)处理测试这个最大值.因此,您可以估算出在这些测试中计算的最大值"足够好"并遵循测试的逻辑:

    use Config;
    $reg_infty = $Config {reg_infty} // 2 ** 15 - 1; # 32767
    print "Test-based reg_infinity limit: $reg_infty\n";
    
    Run Code Online (Sandbox Code Playgroud)

    在此基础上的测试中的解释如下.

  • 理论:这是试图复制C代码使用的EXACT逻辑来生成此值.

    这听起来更难,因为它受到两件事的影响:Perl构建配置和一堆#define带有分支逻辑的C 语句.我能够深入研究这个逻辑,但是在两个问题上停滞不前:#ifdefs引用了一堆令牌,这些令牌实际上并没有在我能找到的Perl代码中的任何地方定义 - 而且我不知道如何从内部找到Perl这些define值是什么,以及最终的默认值(假设我是正确的,并且那些#ifdef总是以默认值结束)#define PERL_USHORT_MAX ((unsigned short)~(unsigned)0)(实际限制是通过删除1比特得到的全部数字得到的 - 详情如下) .

    我也不确定如何使用shortPerl 来访问用于构建perl可执行文件的任何实现的字节数.

    因此,即使可以找到这两个问题的答案(我也不确定),结果逻辑肯定会比我提供的直接的"基于经验评估"的逻辑"更丑"和更复杂.第一种选择.

下面我将提供Perl代码中与此限制相关的各种逻辑部分的详细信息,以及我尝试获得匹配C逻辑的"理论正确"解决方案.


好的,这是一些调查的一部分,你可以自己完成它,因为我已经运行或我将在稍后完成:

  • 来自regcomp.c:vFAIL2("Quantifier in {,} bigger than %d", REG_INFTY - 1);

    因此,限制显然来自于REG_INFTY定义.其中声明:

  • rehcomp.h:

     /* XXX fix this description.
        Impose a limit of REG_INFTY on various pattern matching operations
        to limit stack growth and to avoid "infinite" recursions.
     */
     /* The default size for REG_INFTY is I16_MAX, which is the same as
        SHORT_MAX (see perl.h).  Unfortunately I16 isn't necessarily 16 bits
        (see handy.h).  On the Cray C90, sizeof(short)==4 and hence I16_MAX is
        ((1<<31)-1), while on the Cray T90, sizeof(short)==8 and I16_MAX is
        ((1<<63)-1).  To limit stack growth to reasonable sizes, supply a
        smaller default.
             --Andy Dougherty  11 June 1998
     */
     #if SHORTSIZE > 2
     #  ifndef REG_INFTY
     #    define REG_INFTY ((1<<15)-1)
     #  endif
     #endif
     #ifndef REG_INFTY
     #  define REG_INFTY I16_MAX
     #endif
    
    Run Code Online (Sandbox Code Playgroud)

    请注意SHORTSIZE是可以覆盖的Config- 我会留下详细信息,但逻辑需要包含$Config{shortsize}:)

  • 来自handy.h(乍一看似乎不是Perl源代码的一部分所以它看起来像一个iffy步骤):

     #if defined(UINT8_MAX) && defined(INT16_MAX) && defined(INT32_MAX)
     #define I16_MAX INT16_MAX
     #else
     #define I16_MAX PERL_SHORT_MAX
    
    Run Code Online (Sandbox Code Playgroud)
  • 我找不到任何定义的地方INT16_MAX:(

    有人帮忙请!!!

  • PERL_SHORT_MAX在perl.h中定义:

     #ifdef SHORT_MAX
     #  define PERL_SHORT_MAX ((short)SHORT_MAX)
     #else
     #  ifdef MAXSHORT    /* Often used in <values.h> */
     #    define PERL_SHORT_MAX ((short)MAXSHORT)
     #  else
     #    ifdef SHRT_MAX
     #      define PERL_SHORT_MAX ((short)SHRT_MAX)
     #    else
     #      define PERL_SHORT_MAX      ((short) (PERL_USHORT_MAX >> 1))
     #    endif
     #  endif
     #endif
    
    Run Code Online (Sandbox Code Playgroud)

    到目前为止,我找不到任何定义SHORT_MAX,MAXSHORT或SHRT_MAX的地方.所以默认((short) (PERL_USHORT_MAX >> 1))它现在是:)

  • PERL_USHORT_MAX的定义非常相似perl.h,我再也找不到USHORT_MAX/ MAXUSHORT/ 的定义USHRT_MAX.

    这似乎暗示它默认设置为:#define PERL_USHORT_MAX ((unsigned short)~(unsigned)0).如何从Perl端提取该值,我没有线索 - 它基本上是通过按位否定短0得到的数字,所以如果无符号短是16个字节,那么PERL_USHORT_MAX将是16个,并且PERL_SHORT_MAX将是15个,例如2 ^ 15-1,例如32767.

  • 另外,从t/re/pat.t(正则表达式测试):( $::reg_infty = $Config {reg_infty} // 32767;来说明存储的非默认编译值的位置).

所以,为了让你的常数,你做:

use Config;
my $shortsize = $Config{shortsize} // 2;
$c_reg_infty = (defined $Config {reg_infty}) ? $Config {reg_infty}
                                             : ($shortsize > 2) ? 2**16-1
                                             : get_PERL_SHORT_MAX();
# Where get_PERL_SHORT_MAX() depends on logic for PERL_SHORT_MAX in perl.h
# which I'm not sure how to extract into Perl with any precision
# due to a bunch of never-seen "#define"s and unknown size of "short".
# You can probably do fairly well by simply returning 2**8-1 if shortsize==1 
# and 2^^16-1 otherwise.
say "REAL reg_infinity based on C headers: $c_reg_infty";
Run Code Online (Sandbox Code Playgroud)