返回列表 回复 发帖

[转帖]perl学习经验谈

这些日子我沉浸在perl的强大功能之中,学习perl是因为eastdark给我的启示,本来是想继续深入研究delphi的,但我发现了perl的绝妙之处,嘻嘻我暂时放下了delphi投入到了perl的怀抱了,但我可不是见异思迁啊。在学习perl过程中遇到了不少问题,有解决了的,也有未解决的,现在把我的经验拿出来大家共同分享了。下文有不当之处请大家指正:



程序开发的过程中可看作一种层次树,在树顶端是输入值,根部是输出值或程序的结果。大量的应用程序开发始自下而上的开发,而不是自上而下。自上而下的方式迫使开发人员考虑能够得到的结果的所有步骤,自下而上的方式意味着一直尝试不同的技术,直到获得自上而下的工作结果。

自下而上的方式更慢,但从开发人员的观点来看通常更加实用。因为这种方式有助于开发人员打开思路并在大脑中形成方法和步骤,从而终究反映在最后的应用程序中。

选择的方式对引入程序的漏洞产生一些影响,或是无法区分漏洞及其影响。尽管一般不被看作主要问题----漏洞就是这个漏洞---但其影响解决漏洞问题的方式(这可能对其他漏洞造成影响),并同样将引起完全被忽略的其他漏洞。

我个人认为,编程时本质上存在三类漏洞:输入漏洞,逻辑漏洞,和执行漏洞。下面我就对这几类漏洞谈谈我自己的看法。

1.输入漏洞

导致输入漏洞的原因要么是错误的输入,要么是注意力瞬间不集中导致忽视了语言的语法。在perl中这种漏洞很容易发生,比如在引用一个变量时使用了$代替了@,或者在函数中忘记在语句头尾插入圆括号以保证函数的列表上下文,而不是标量上下文。

由于这些错误中的某些错误违背了perl解析引擎中的基本规则,因此当然可被perl编译器在编译过程中支出。其他错误则通过编译,甚至可能通过常见的warning和strict编译选项,而对问题的存在没有任何形式的说明。下面的代码就是一个典型的例子:

$string ="the cat sat on the mat";

$animal =($string =~ m/the (.*) sat/);

print $animal;

如果认为上面代码存在一个漏洞,那么你将采取什么行动?相信即使经验丰富的开发人员阅读代码也可能不会立即看出问题。请求perl通过打开警告开关的语法分析器检查代码,将不出现任何错误。但是当运行代码时错误显而易见---得到的值是1,而不是期望的“cat”。其他的输入漏洞可能更隐蔽(如果哪位高手碰到过类似的情况阿南非常希望能指教,可以e--mail至hufery@263.net)最近一个web工程的登录进程突然停止工作。登录系统的工作方式是通过数据库检查用户名和口令,假定两者均通过,脚本产生一个唯一的会话ID,同样放在数据库中。问题是ID获得通过而且创建了会话ID,但是用户无法使用新的会话ID连接。

将返回给用户的会话ID与数据库中的会话ID相比较虽然花点时间,但是显而易见27位的会话ID超出了26位的域宽度。这是另一种输入漏洞:将错误的宽度值输入数据库中创建脚本。

在仔细的阅读代码的同时正确的理解perl分析语句的方式,通常即可解决输入漏洞。(至于perl在分析每条语句时遇到哪些问题,阿南所知有限,在这儿就不班门弄斧了,可不是懒呀,:)希望各位高手把经验教授给我一下。。。)

2.逻辑漏洞

有这种情况吗:当开发人员没有找出程序逻辑流程中的缺陷时将产生逻辑漏洞?答案是肯定的。与输入漏洞类似,这些漏洞可能非常显而易见----例如,无法识别函数的其中一个可能返回值或者不正确的指定一个测试操作和其他操作。这些不是输入漏洞----开发人员确实认为他或她当时做的是对的,不是吗?

举一个延伸前面输入漏洞的例子,在针对登录代码执行一些优化之后,同样的登录系统突然开始返回错误的登录。登录函数为错误返回一个负数,如果会话或登录过期则返回0,成功则返回正数。在跟踪错误数小时之后,最终明显发现问题的根源在于检查返回值的if语句严格的将返回值0作为失败,而其他返回值作为有效的响应。

另一个例子是代码中使用的饮用。当使用引用时,在变量内容可被访问之前必须指定变量的引用。例如当前访问对哈系表(有人问哈系表是什么?在这里我不想介绍这个,这个对你理解这篇文章没什么大的障碍)的引用时,不要使用:$hash{$key}而应使用$hash-->{$key}这不是一个输入漏洞,而是一个逻辑漏洞。某些人忽略了这样一个事实:访问对象是对哈系表的引用,而不是哈系表本身。

与输入漏洞相比,逻辑漏洞更容易被识别。对于输入漏洞通常可以将问题跟踪到一个可能的位置,但是没有perl分析器的帮助很难找到确切的位置。针对逻辑漏洞可以一直追溯并跟踪执行序列,直到找出引发问题的特定行为。

查找逻辑漏洞的途径有很多种,最显著的途径是我们应理解perl编译器的逻辑,从基本变量到如何使用操作符、函数和常见表达方式访问变量。逻辑漏洞全部与开发人员如何访问和使用脚本内保存的信息相关----如果能够理解并辨别perl如何遭遇问题,那么跟踪问题就迎刃而解。(至于如何找出程序的逻辑漏洞,我以后会写出来,也希望perl高手前来执教)

(注:跟踪逻辑漏洞的其他方式包括分离的使用---讲程序的组件调整为子程序,模块,包,甚至对象。通过分离独立的元素,可一段一段的消除问题的根源。分离同时使代码更便于移植并且更易于管理)

3.执行漏洞

执行漏洞是最难发现的错误之一,而且这种漏洞可能被认为根本不是错误。执行漏洞是影响程序执行过程的错误,不是因为按键错误或逻辑错误,而是由于应用程序的设计方式允许某个时间链减缓或中断应用程序的执行。执行漏洞使应用程序缓慢,但可能实际并不产生恶果,也不以其他任何方式表现。例如,设想一个从数据库中取数据的数据库应用程序。一个典型的查询返回200个记录,脚本工作的范围是几条记录,那么在这些限制下我们或许希望从数据库中提取数据。当查询返回1000条记录时,而脚本大约花费一分钟执行。

问题与逻辑无关----脚本的运转和行为恰如其分----这也不是输入漏洞-----信息的编排无误并且确实显示了数据库中的1000条记录。那么究竟是什么导致花费这么长的时间?此处问题就出于某一步的执行-----要么我们应引入一个限制器降低访问和显示如此多记录的影响,要么应用程序的某一部分花费了过多的时间分析信息。这是一个执行漏洞,即应用程序没有任何错误,只是执行的水平没有达到期望的高度。

执行漏洞难以跟踪,但是一旦发现并予以解决可有一些好处。执行漏洞被消除干净的应用程序比一般的应用程序更加健壮,而且使用起来可能更加稳定。因为执行漏洞时常影响性能,所以消除这些错误有助于优化应用程序。

附注:下面是我参考了一些资料整理的调试perl的基本原则,希望能给有困惑的朋友一些帮助,由于本人水平有限所以不当之处也请各位见谅,并希望赐予指教。

调试perl的基本原则:

无论使用哪些技巧和方法设法追溯和跟踪源代码中的错误,也无论途径如何,通常均应遵循一些相当基本的原则。

l 始终检查明显指出-----如果让中等水平的开发人员条是一段代码,他或她几乎一定会先看不正确的位置。上文给出的一些例子表明通常是最显然的事情导致最大的麻烦。

l 始终自内而外的检查----始终应遵循从代码的外部向内部的执行途径,除非对错误发生的位置已经得到正确的指引,否则应关注出现错误的函数。然后从该函数跟踪错误到其他嵌套函数,直到找出根源。从内部向外跟踪将引发问题,因为不知道有什么其他可能导致错误的发生过程。例如,返回错误值得函数可能已经被提供了错误信息------检测函数而发现没有任何错误是一件没有意义的事情。

l 当处理输入漏洞时始终中从顶部开始----查看代码应从代码顶部依次向下进行,不要反向工作。输入漏洞有一个坏习性是导致相关联的后果。为了说明这种情况,将一个额外的前括号放在脚本中----perl返回的是与实际问题无关的各种各样的错误。

l 当解决分析器错误时始终从底部开始-----perl输出错误可能位于的行号。如果从顶部开始将打乱行编号,则需要重新解析脚本以确认新的行号。如果从底部开始工作,那么行的变化就不会影响前面的行号,这样在需要重新解析脚本之前能够解决更多的错误。

l 始终打开警告开关-----与只允许解析器正常工作相比,警告针对可能被忽略的潜在错误提供了更多信息。警告加亮显示潜在的问题,比如未被使用的变量(加亮显示的键入错误),误用的变量类型(加亮显示的逻辑漏洞),以及可能从未触及的代码。

l 始终采用strict编译选项------严格的编译选项强制执行比正常标准高出很多的perl解析规则。这致使perl检查某些操作的语法----变量、引用和子程序-----大大高出正常的等级,累死在解析过程中警告可以加亮显示问题所在。

好了,终于写完了,可累死我了!

摘自:http://61.141.218.20/seceye/article/go.asp?id=125
作者:阿南
[color=#FF00FF]『有一种天空,喜欢接近阴霾 有一种生活,不知是否存在』  『有一种希望,注定走向毁灭 有一种死亡,渐渐被人期待』  『有一种心境,分辨不清好坏 有一种爱情,不再渴望表白』  『有一种眼泪,只能流向心底 有一种悲伤,从不表现出来』
返回列表