perl脚本中使用eval函数执行可能有异常的操作

news2024/10/6 10:31:46

perl脚本中有时候执行的操作可能会引发异常,为了直观的说明,这里举一个json反序列化的例子,脚本如下:

#! /usr/bin/perl
use v5.14;
use JSON;
use Data::Dumper;

# 读取json字符串数据
my $json_str = join('', <DATA>);
# 反序列化操作
my $json = from_json($json_str);

say to_json($json, { pretty => 1 });

__DATA__
bad {
   "id" : 1024,
   "desc" : "hello world",
   "other" : {
      "test_null" : null,
      "test_false" : false,
      "test_true" : true
   }
}


在这里插入图片描述

脚本中有意把正确json字符串之前加了几个字符,显然这个json字符串是不符合规范格式的,在git bash中执行这个脚本,结果如下:
在这里插入图片描述

下面用perl的eval函数改造这个脚本:

#! /usr/bin/perl
use v5.14;
use JSON;
use Data::Dumper;

# 读取json字符串数据
my $json_str = join('', <DATA>);
# 反序列化操作
my $json = eval {
	return from_json($json_str);
};

unless (defined $json) {
	say "from_json failed !!!!";
} else {
	say to_json($json, { pretty => 1 });
}

__DATA__
bad {
   "id" : 1024,
   "desc" : "hello world",
   "other" : {
      "test_null" : null,
      "test_false" : false,
      "test_true" : true
   }
}


脚本中用把from_json的操作放在eval函数中,输出结果如下:
在这里插入图片描述
显然,这个结果是可控的,可预期的。比如就可以使用这种方法判断json字符串是否合法,能够正常反序列化的就是合法的,否则就是非法的。eval函数的具体使用可以使用perldoc -f eval查看。

    eval EXPR
    eval BLOCK
    eval    "eval" in all its forms is used to execute a little Perl
            program, trapping any errors encountered so they don't crash the
            calling program.

            Plain "eval" with no argument is just "eval EXPR", where the
            expression is understood to be contained in $_. Thus there are
            only two real "eval" forms; the one with an EXPR is often called
            "string eval". In a string eval, the value of the expression
            (which is itself determined within scalar context) is first
            parsed, and if there were no errors, executed as a block within
            the lexical context of the current Perl program. This form is
            typically used to delay parsing and subsequent execution of the
            text of EXPR until run time. Note that the value is parsed every
            time the "eval" executes.

            The other form is called "block eval". It is less general than
            string eval, but the code within the BLOCK is parsed only once
            (at the same time the code surrounding the "eval" itself was
            parsed) and executed within the context of the current Perl
            program. This form is typically used to trap exceptions more
            efficiently than the first, while also providing the benefit of
            checking the code within BLOCK at compile time. BLOCK is parsed
            and compiled just once. Since errors are trapped, it often is
            used to check if a given feature is available.

            In both forms, the value returned is the value of the last
            expression evaluated inside the mini-program; a return statement
            may also be used, just as with subroutines. The expression
            providing the return value is evaluated in void, scalar, or list
            context, depending on the context of the "eval" itself. See
            "wantarray" for more on how the evaluation context can be
            determined.

            If there is a syntax error or runtime error, or a "die"
            statement is executed, "eval" returns "undef" in scalar context,
            or an empty list in list context, and $@ is set to the error
            message. (Prior to 5.16, a bug caused "undef" to be returned in
            list context for syntax errors, but not for runtime errors.) If
            there was no error, $@ is set to the empty string. A control
            flow operator like "last" or "goto" can bypass the setting of
            $@. Beware that using "eval" neither silences Perl from printing
            warnings to STDERR, nor does it stuff the text of warning
            messages into $@. To do either of those, you have to use the
            $SIG{__WARN__} facility, or turn off warnings inside the BLOCK
            or EXPR using "no warnings 'all'". See "warn", perlvar, and
            warnings.

            Note that, because "eval" traps otherwise-fatal errors, it is
            useful for determining whether a particular feature (such as
            "socket" or "symlink") is implemented. It is also Perl's
            exception-trapping mechanism, where the "die" operator is used
            to raise exceptions.

            Before Perl 5.14, the assignment to $@ occurred before
            restoration of localized variables, which means that for your
            code to run on older versions, a temporary is required if you
            want to mask some, but not all errors:

             # alter $@ on nefarious repugnancy only
             {
                my $e;
                {
                  local $@; # protect existing $@
                  eval { test_repugnancy() };
                  # $@ =~ /nefarious/ and die $@; # Perl 5.14 and higher only
                  $@ =~ /nefarious/ and $e = $@;
                }
                die $e if defined $e
             }

            There are some different considerations for each form:

            String eval
                Since the return value of EXPR is executed as a block within
                the lexical context of the current Perl program, any outer
                lexical variables are visible to it, and any package
                variable settings or subroutine and format definitions
                remain afterwards.

                Under the "unicode_eval" feature
                    If this feature is enabled (which is the default under a
                    "use 5.16" or higher declaration), EXPR is considered to
                    be in the same encoding as the surrounding program. Thus
                    if "use utf8" is in effect, the string will be treated
                    as being UTF-8 encoded. Otherwise, the string is
                    considered to be a sequence of independent bytes. Bytes
                    that correspond to ASCII-range code points will have
                    their normal meanings for operators in the string. The
                    treatment of the other bytes depends on if the
                    "'unicode_strings"" feature is in effect.

                    In a plain "eval" without an EXPR argument, being in
                    "use utf8" or not is irrelevant; the UTF-8ness of $_
                    itself determines the behavior.

                    Any "use utf8" or "no utf8" declarations within the
                    string have no effect, and source filters are forbidden.
                    ("unicode_strings", however, can appear within the
                    string.) See also the "evalbytes" operator, which works
                    properly with source filters.

                    Variables defined outside the "eval" and used inside it
                    retain their original UTF-8ness. Everything inside the
                    string follows the normal rules for a Perl program with
                    the given state of "use utf8".

                Outside the "unicode_eval" feature
                    In this case, the behavior is problematic and is not so
                    easily described. Here are two bugs that cannot easily
                    be fixed without breaking existing programs:

                    *   It can lose track of whether something should be
                        encoded as UTF-8 or not.

                    *   Source filters activated within "eval" leak out into
                        whichever file scope is currently being compiled. To
                        give an example with the CPAN module
                        Semi::Semicolons:

                         BEGIN { eval "use Semi::Semicolons; # not filtered" }
                         # filtered here!

                        "evalbytes" fixes that to work the way one would
                        expect:

                         use feature "evalbytes";
                         BEGIN { evalbytes "use Semi::Semicolons; # filtered" }
                         # not filtered

                Problems can arise if the string expands a scalar containing
                a floating point number. That scalar can expand to letters,
                such as "NaN" or "Infinity"; or, within the scope of a "use
                locale", the decimal point character may be something other
                than a dot (such as a comma). None of these are likely to
                parse as you are likely expecting.

                You should be especially careful to remember what's being
                looked at when:

                    eval $x;        # CASE 1
                    eval "$x";      # CASE 2

                    eval '$x';      # CASE 3
                    eval { $x };    # CASE 4

                    eval "\$$x++";  # CASE 5
                    $$x++;          # CASE 6

                Cases 1 and 2 above behave identically: they run the code
                contained in the variable $x. (Although case 2 has
                misleading double quotes making the reader wonder what else
                might be happening (nothing is).) Cases 3 and 4 likewise
                behave in the same way: they run the code '$x', which does
                nothing but return the value of $x. (Case 4 is preferred for
                purely visual reasons, but it also has the advantage of
                compiling at compile-time instead of at run-time.) Case 5 is
                a place where normally you *would* like to use double
                quotes, except that in this particular situation, you can
                just use symbolic references instead, as in case 6.

                An "eval ''" executed within a subroutine defined in the
                "DB" package doesn't see the usual surrounding lexical
                scope, but rather the scope of the first non-DB piece of
                code that called it. You don't normally need to worry about
                this unless you are writing a Perl debugger.

                The final semicolon, if any, may be omitted from the value
                of EXPR.

            Block eval
                If the code to be executed doesn't vary, you may use the
                eval-BLOCK form to trap run-time errors without incurring
                the penalty of recompiling each time. The error, if any, is
                still returned in $@. Examples:

                    # make divide-by-zero nonfatal
                    eval { $answer = $a / $b; }; warn $@ if $@;

                    # same thing, but less efficient
                    eval '$answer = $a / $b'; warn $@ if $@;

                    # a compile-time error
                    eval { $answer = }; # WRONG

                    # a run-time error
                    eval '$answer =';   # sets $@

                If you want to trap errors when loading an XS module, some
                problems with the binary interface (such as Perl version
                skew) may be fatal even with "eval" unless
                $ENV{PERL_DL_NONLAZY} is set. See perlrun.

                Using the "eval {}" form as an exception trap in libraries
                does have some issues. Due to the current arguably broken
                state of "__DIE__" hooks, you may wish not to trigger any
                "__DIE__" hooks that user code may have installed. You can
                use the "local $SIG{__DIE__}" construct for this purpose, as
                this example shows:

                    # a private exception trap for divide-by-zero
                    eval { local $SIG{'__DIE__'}; $answer = $a / $b; };
                    warn $@ if $@;

                This is especially significant, given that "__DIE__" hooks
                can call "die" again, which has the effect of changing their
                error messages:

                    # __DIE__ hooks may modify error messages
                    {
                       local $SIG{'__DIE__'} =
                              sub { (my $x = $_[0]) =~ s/foo/bar/g; die $x };
                       eval { die "foo lives here" };
                       print $@ if $@;                # prints "bar lives here"
                    }

                Because this promotes action at a distance, this
                counterintuitive behavior may be fixed in a future release.

                "eval BLOCK" does *not* count as a loop, so the loop control
                statements "next", "last", or "redo" cannot be used to leave
                or restart the block.

                The final semicolon, if any, may be omitted from within the
                BLOCK.


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1303646.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

.Net6.0 Microsoft.AspNetCore.Http.Abstractions 2.20 已弃用

您想要升级 Microsoft.AspNetCore.Http.Abstractions 包&#xff0c;您需要注意以下几点&#xff1a; Microsoft.AspNetCore.Http.Abstractions 包在 ASP.NET Core 2.2 版本后已经被标记为过时&#xff0c;因为它已经被包含在 Microsoft.AspNetCore.App 框架引用中12。因此&am…

分配栈空间的三种方式(基于适配qemu的FreeRTOS分析)

1、定义全局的数组 定义的全局数组属于bss段&#xff0c;相当于把bss段的一部分作为栈空间&#xff0c;栈空间的大小就是数组的大小如果把栈空间放在bss段&#xff0c;则在bss段清零时会多清零一段地址空间 2、在链接脚本中指定 用链接脚本在所有段的后面增加stack段&#xff…

FFmpeg的AVcodecParser

文章目录 结构体操作函数支持的AVCodecParser 这个模块是AVCodec中的子模块&#xff0c;专门用来提前解析码流的元数据&#xff0c;为后面的解码做准备&#xff0c;这一点对cuda-NVdec非常明显&#xff0c;英伟达解码器的元数据解析是放在CPU上的&#xff0c;所以就非常依赖这个…

我心目中的杰出工程师

参考原文&#xff1a;The difference between good and great engineers 在工程师成长的这条路上&#xff0c;我从普通工程师 → 高级工程师 → 技术专家 → 技术管理 → 技术总监&#xff0c;一路走来&#xff0c;对何为杰出工程师是一直在思考和追寻的。如今我在公司培养工程…

【Kubernetes】存储类StorageClass

存储类StorageClass 一、StorageClass介绍二、安装nfs provisioner&#xff0c;用于配合存储类动态生成pv2.1、创建运行nfs-provisioner需要的sa账号2.2、对sa授权2.3、安装nfs-provisioner程序 三、创建storageclass&#xff0c;动态供给pv四、创建pvc&#xff0c;通过storage…

泛微e-cology XmlRpcServlet文件读取漏洞复现

0x01 产品简介 泛微e-cology是专为大中型企业制作的OA办公系统,支持PC端、移动端和微信端同时办公等。 0x02 漏洞概述 泛微e-cology XmlRpcServlet接口处存在任意文件读取漏洞,攻击者可通过该漏洞读取系统重要文件(如数据库配置文件、系统配置文件)、数据库配置文件等等,…

【洛谷算法题】P5717-【深基3.习8】三角形分类【入门2分支结构】Java题解

&#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P5717-【深基3.习8】三角形分类【入门2分支结构】&#x1f30f;题目描述&#x1…

Opencascad(C++)-导出整个模型到stl文件

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1、前言2、首先创建几个简单的模型3、导出stl的代码为4、查看导出的结果5、结论 1、前言 最近研究下Opencascad&#xff0c;还不是很深入&#xff0c;对于Opencasc…

大语言模型有什么意义?亚马逊训练自己的大语言模型有什么用?

近年来&#xff0c;大语言模型的崭露头角引起了广泛的关注&#xff0c;成为科技领域的一项重要突破。而在这个领域的巅峰之上&#xff0c;亚马逊云科技一直致力于推动人工智能的发展。那么&#xff0c;作为一家全球科技巨头&#xff0c;亚马逊为何会如此注重大语言模型的研发与…

04-Nacos中负载均衡规则的配置

负载均衡规则 同集群优先 默认的ZoneAvoidanceRule实现并不能根据同集群优先的规则来实现负载均衡,Nacos中提供了一个实现叫NacosRule可以优先从同集群中挑选服务实例 当服务消费者在本地集群找不到服务提供者时也会去其他集群中寻找,但此时会在服务消费者的控制台报警告 第…

基于SSM的摄影服务线上选购预约系统设计与实现-计算机毕业设计源码83784

摘 要 随着互联网趋势的到来&#xff0c;各行各业都在考虑利用互联网将自己推广出去&#xff0c;最好方式就是建立自己的互联网系统&#xff0c;并对其进行维护和管理。在现实运用中&#xff0c;应用软件的工作规则和开发步骤&#xff0c;采用SSM技术建设摄影服务线上选购预约系…

设计模式——策略模式(Strategy Pattern)

概述 策略模式又叫政策模式&#xff0c;是一种对象行为型模式。它是将定义的算法家族分别封装起来&#xff0c;让它们之间可以互相替换&#xff0c;从而让算法的变化不会影响到使用算法的用户。策略模式的主要目的是将算法的定义与使用分开&#xff0c;也就是将算法的行为和环…

IoTDB JavaAPI

文章目录 使用样例Java使用样例 官方已经给出了相关使用Demo&#xff0c;下载地址为: https://github.com/apache/iotdb 直接拉取相对应版本的源码 使用样例 Java使用样例 代码位置 iotdb/example/session/src/main/java/org/apache/iotdb/SessionExample.java iotdb/exa…

springboot打成war包及VUE打成war包放入tomcat启动

1.springboot打成war包步骤 首先在springboot启动类中继承SpringBootServletInitializer&#xff0c;重写configure方法&#xff0c;如下: SpringBootApplication() public class StartApplication extends SpringBootServletInitializer {public static void main(String[] …

计算机网络编程

网络编程 Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机&#xff0c; Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. 计算机网络基础 2. So…

Network 灰鸽宝典【目录】

目前已有文章 11 篇 Network 灰鸽宝典专栏主要关注服务器的配置&#xff0c;前后端开发环境的配置&#xff0c;编辑器的配置&#xff0c;网络服务的配置&#xff0c;网络命令的应用与配置&#xff0c;windows常见问题的解决等。 文章目录 canvas理论基础canvas高级应用示例canv…

Java 线程的基本概念

创建和运行线程 方法一&#xff0c;直接使用 Thread // 创建线程对象 Thread t new Thread() {public void run() {// 要执行的任务}};// 启动线程 t.start();例如&#xff1a; // 构造方法的参数是给线程指定名字&#xff0c;推荐 Thread t1 new Thread("t1") …

软件测试:基础概念

目录 ​编辑 一、前言 二、软件测试的原则和方法论 1.测试的原则 2.测试的方法论 2. 软件测试策略 2.1 单元测试 2.2 集成测试 2.3 系统测试 2.4 用户验收测试 3. 软件测试的最佳实践 3.1 自动化测试 3.2 持续集成 3.3 边界值测试 三、软件测试的技术和实践 1.…

深度学习——第4.3章 深度学习的数学基础

第4章 深度学习的数学基础 目录 4.7 指数函数和对数函数 4.7 指数函数和对数函数 深度学习经常会用到Sigmoid函数和Softmax函数&#xff0c;这些函数是通过包含exp(x)的指数函数创建的。后面我们需要求解这些函数的导数。 4.7.1 指数 指数是一个基于“乘以某个数多少次”&a…

远程工作:自由职业者如何成功赚钱

前言 在这个不断进步的数字化时代&#xff0c;远程工作已经从一个可选的边缘工作方式&#xff0c;成长为主流职业趋势的一部分。特别是自从全球疫情改变了我们的生活和工作方式以来&#xff0c;远程工作的概念不再是遥不可及的理想&#xff0c;而是已经成为许多人日常工作的现…