在下面的代码中,$1
被污染了,我不明白为什么。
我在使用perl v5.14.2且启用了-T
污点检查模式的系统上运行Foswiki。
调试该设置的问题,我设法构建以下SSCCE。 (请注意,我编辑了这篇文章,第一个版本更长,更复杂,评论仍然提到了这一点。)
#!/usr/bin/perl -T
use strict;
use warnings;
use locale;
use Scalar::Util qw(tainted);
my $var = "foo.bar_baz";
$var =~ m/^(.*)[._](.*?)$/;
print(tainted($1) ? "tainted\n" : "untainted\n");
虽然输入字符串$var
未受污染且正则表达式已修复,但生成的捕获组$1
仍然受到污染。我觉得这很奇怪。
perlsec manual有关于污点和正则表达式的说法:
通过将它们用作哈希中的键,可能无法使用值;否则 绕过污点机制的唯一方法是参考 正则表达式匹配的子模式。 Perl假定如果 你使用
$1
,$2
等引用一个子串,你知道你是什么 你写这个模式的时候正在做。
我会想象即使输入被污染,输出仍然没有污染。要观察来自无污染输入的反向,污染输出,感觉就像perl中的一个奇怪的错误。但如果一个人读取更多的perlsec,它也会指向the SECURITY section of perllocale的用户。我们读到:
当使用locale生效时,Perl使用污染机制(参见 perlsec)标记与语言环境相关的字符串结果,以及 这可能是不值得信任的。以下是摘要 可能受到影响的操作员和功能的污点行为 语言环境:
比较运算符(
lt
,le
,ge
,gt
和cmp
)[...]案例映射插值(
\l
,\L
,\u
或\U
)[...]匹配运算符(
m//
):标量真/假结果永远不会被污染。
子模式,作为列表上下文结果或
$1
传递 如果使用区域设置(但不是use locale ':not_characters'
)生效,并且子模式是常规的,则会受到污染 表达式包含\w
(以匹配字母数字字符),\W
(非字母数字字符),\s
(空格字符)或\S
(非空白字符)。匹配模式变量$&
,$`
(赛前),$'
(赛后)和$+
(最后一场比赛)也是 如果使用区域设置生效且正则表达式包含,则会受到污染\w
,\W
,\s
或\S
。替换运算符(
s///
)[...][⋮]
这看起来应该是一个详尽的清单。我不明白它是如何应用的:我的正则表达式不使用\w
,\W
,\s
或\S
中的任何一个,因此它不应该依赖于语言环境。
有人可以解释为什么这段代码会污染变种$1
?
答案 0 :(得分:0)
目前问题中引用的文档与perl 5.18.1的实际实现之间存在差异。问题是字符类。该文档提到\w
,\s
,\W
,\S
听起来像一个详尽的列表,而实现几乎每次使用[…]
都会受到影响。
正确的解决方案可能介于两者之间:像[[:word:]]
这样的字符类应该受到污染,因为它取决于区域设置。我的固定清单不应该。像[a-z]
这样的字符范围取决于整理,所以在我个人看来,它们也应该受到污染。 \d
取决于区域设置对数字的考虑,因此即使它既不是目前提到的转义序列也不是括号内的类,它也应该会污染。
所以在我看来,文档和实现都需要修复。 Perl开发人员正在研究这个问题。有关进度信息,请查看我提交的the perl bug report。
对于固定的字符列表,一个可行的解决方法似乎是作为分离的公式,即(?:\.|_)
而不是[._]
。它更详细,但即使使用当前(在我看来有错误)perl版本也应该工作。