(转)程序出错后,程序员给测试人员的20条高频回复

呵呵,开发和测试的暗战

编者按:程序员和软件测试员之间的关系无须多言。这些经典回复是国外程序员总结分享的,“全球通用”。
  20. "That’s weird…" 很奇怪……
  19. "It’s never done that before." 以前没这样过的。
  18. "It worked yesterday." 昨天还好好的。
17. "How is that possible?" 那怎么可能?(怎么会出问题?)
  16. "It must be a hardware problem." 这一定是硬件问题。
  15. "What did you type in wrong to get it to crash?" 你输入什么东西后才崩溃的?
  14. "There is something funky in your data." 你的数据有问题。
  13. "I haven’t touched that module in weeks!" 我好几个礼拜没动那个程序了!
  12. "You must have the wrong version." 你一定在用错误的版本。
  11. "It’s just some unlucky coincidence." 这只是凑巧。
  10. "I can’t test everything!" 我无法测试所有东西。(我的机器环境下,无法测试所有的可能情况。)
  09. "THIS can’t be the source of THAT." “这”不可能是问题的原因。
  08. "It works, but it hasn’t been tested." 程序能用,不过还没有测试。
  07. "Somebody must have changed my code." 一定有人改了我的代码。
  06. "Did you check for a virus on your system?" 你的电脑扫描病毒了么?
  05. "Even though it doesn’t work, how does it feel? 即便程序不行了,(你觉得)程序写得如何?
  04. "You can’t use that version on your system." 你不能在你系统上使用那个版本的程序。(程序版本和系统有冲突。)
  03. "Why do you want to do it that way?" 你怎么会想着那样操作啊?
  02. "Where were you when the program blew up?" 程序崩溃时,你在做什么呢?(做了哪些操作?)
  01. "It works on my machine" 在我机器上好好的!!!(潜台词:怎么在你那就出问题了呢!!!)

  编者后话

  虽然已经远离编程,但经常还是会用到第20、19条,当然也不会“错过”第1条。各位看过之后,不知你都用上了哪几条哦~

(转)至今仍未被破译的五个世界级密码

十二宫杀手密码

  1969 年 7 月 31 日,三家报社各自收到了一封密文的三分之一,密文的作者就是大名鼎鼎的十二宫杀手。十二宫杀手要求这三家报社把密文发表在报纸上,否则他将在当周周末再次杀人。三家报社只好照做。

  这个密文共有 408 个符号,以后大家都习惯称它为 408 密文(408-cipher)。408 密文是十二宫杀手的第一封密信。一个星期后,一位教师和他的妻子破解了这篇密文。大卫·芬奇的电影《十二宫杀手》完整地记述了这一事件。

  408 密文用的是最简单的字母替换法,所不同的是一个字母可能对应多个符号。这种加密方法可以很好地防止字频破解法,因为你可以让常用的字母对应更多的符号,保证每个符号出现的次数大致相等。不过,破解这样的密码也不是完全没有突破口,“字母 Q 后面一定是 U”等英文特点能提供不少线索。这种一对多的替换加密方法就叫做同音替换法(Homophonic Substitution Cipher)。

  同年 11 月 8 日,十二宫杀手又寄出了一篇密文。这篇密文有 340 个字符,被称作 340 密文。与 408 密文不同的是,虽然大家都相信 340 密文同样使用的是同音替换加密,但直到现在 340 密文也没有解开。

  340 密码全文如下:
1.jpg

CIA 的雕塑密码

  1990 年,美国艺术家吉姆·桑伯恩(Jim Sanborn)花费 25 万美元,创作了一个刻满密码的雕塑作品——Kryptos。这个雕塑作品现在坐落于弗吉尼亚 CIA 的广场内。丹·布朗的悬疑小说《失落的符号》里提到了这个雕塑密码,无疑让这个密码再度名声大噪。

▲位于CIA 的雕塑密码
2.jpg

  整个密码分为四个部分。前三个部分已被破译,其中第一、二部分是多表替换密码(polyalphabetic substitution),第三部分是置换密码(transposition cipher)。尽管 2010 年 11 月桑伯恩本人给出了一点提示,但目前第四部分仍然没有被解决。

  第四部分的密文全文如下:

NGHIJLMNQUVWXZKRYPTOSABCDEFGHIJL
OHIJLMNQUVWXZKRYPTOSABCDEFGHIJL
PIJLMNQUVWXZKRYPTOSABCDEFGHIJLM
QJLMNQUVWXZKRYPTOSABCDEFGHIJLMN
RLMNQUVWXZKRYPTOSABCDEFGHIJLMNQ
SMNQUVWXZKRYPTOSABCDEFGHIJLMNQU
TNQUVWXZKRYPTOSABCDEFGHIJLMNQUV
UQUVWXZKRYPTOSABCDEFGHIJLMNQUVW
VUVWXZKRYPTOSABCDEFGHIJLMNQUVWX
WVWXZKRYPTOSABCDEFGHIJLMNQUVWXZ
XWXZKRYPTOSABCDEFGHIJLMNQUVWXZK
YXZKRYPTOSABCDEFGHIJLMNQUVWXZKR
ZZKRYPTOSABCDEFGHIJLMNQUVWXZKRY
ABCDEFGHIJKLMNOPQRSTUVWXYZABCD

D'Agapeyeff 密码

  1939 年,地图学专家 Alexander D'Agapeyeff 出版了一本名为 Codes and Ciphers 的密码学普及读物。在文章末尾的“难题挑战”部分,D'Agapeyeff 自己编写了一段很难的密码,目前还没有人破解出来。不过,后来 D'Agapeyeff 本人居然把加密过程给忘了,于是这段密码就变成了一个永久的谜。

  密码全文如下:

75628 28591 62916 48164 91748 58464 74748 28483 81638 18174
74826 26475 83828 49175 74658 37575 75936 36565 81638 17585
75756 46282 92857 46382 75748 38165 81848 56485 64858 56382
72628 36281 81728 16463 75828 16483 63828 58163 63630 47481
91918 46385 84656 48565 62946 26285 91859 17491 72756 46575
71658 36264 74818 28462 82649 18193 65626 48484 91838 57491
81657 27483 83858 28364 62726 26562 83759 27263 82827 27283
82858 47582 81837 28462 82837 58164 75748 58162 92000

比尔密码

  梦想自己能得到一张藏宝地图,上演一段破译密码探寻宝藏的传奇故事?你的机会来了。据说,在 1820 年,一个叫做托马斯·杰斐逊·比尔(Thomas Jefferson Beale)的人在弗吉尼亚贝德福县的某个地方埋藏了大量的宝藏,随后把装有三封密信的盒子交给了一个名叫罗伯特·莫里斯(Robert Morriss)的旅店老板代为保管,之后就永久地消失了。莫里斯死前把盒子里的三份密文交给了他的朋友。这位朋友把这段故事连同密码全文一道印成了小册子,宝藏之谜就这样流传了下来。
3.jpg

  1885 年出现的一本小册子。上述所有故事都出自这本小册子里,其真实性不得而知。

  利用《独立宣言》作为密钥,可以破解出第二份密码。第二份密码中详细记录了所藏宝藏的数量,现在看来至少值 6500 万美金。这份密文中还说到,宝藏的埋藏地点详细地记在了第一份密码内,而第三份密码里则记录着宝藏的原主人。虽然各方神圣都把五花八门的手段试了个遍,但到目前为止,剩下的两份密码都还没被破解。不过,也有一些人对整个故事进行了理性的分析,认为比尔密码不过是一场骗局。

  比尔密码第一部分的全文:

71,194,38,1701,89,76,11,83,1629,48,94,63,132,16,111,95,84,341
975,14,40,64,27,81,139,213,63,90,1120,8,15,3,126,2018,40,74
758,485,604,230,436,664,582,150,251,284,308,231,124,211,486,225
401,370,11,101,305,139,189,17,33,88,208,193,145,1,94,73,416
918,263,28,500,538,356,117,136,219,27,176,130,10,460,25,485,18
436,65,84,200,283,118,320,138,36,416,280,15,71,224,961,44,16,401
39,88,61,304,12,21,24,283,134,92,63,246,486,682,7,219,184,360,780
18,64,463,474,131,160,79,73,440,95,18,64,581,34,69,128,367,460,17
81,12,103,820,62,110,97,103,862,70,60,1317,471,540,208,121,890
346,36,150,59,568,614,13,120,63,219,812,2160,1780,99,35,18,21,136
872,15,28,170,88,4,30,44,112,18,147,436,195,320,37,122,113,6,140
8,120,305,42,58,461,44,106,301,13,408,680,93,86,116,530,82,568,9
102,38,416,89,71,216,728,965,818,2,38,121,195,14,326,148,234,18
55,131,234,361,824,5,81,623,48,961,19,26,33,10,1101,365,92,88,181
275,346,201,206,86,36,219,324,829,840,64,326,19,48,122,85,216,284
919,861,326,985,233,64,68,232,431,960,50,29,81,216,321,603,14,612
81,360,36,51,62,194,78,60,200,314,676,112,4,28,18,61,136,247,819
921,1060,464,895,10,6,66,119,38,41,49,602,423,962,302,294,875,78
14,23,111,109,62,31,501,823,216,280,34,24,150,1000,162,286,19,21
17,340,19,242,31,86,234,140,607,115,33,191,67,104,86,52,88,16,80
121,67,95,122,216,548,96,11,201,77,364,218,65,667,890,236,154,211
10,98,34,119,56,216,119,71,218,1164,1496,1817,51,39,210,36,3,19
540,232,22,141,617,84,290,80,46,207,411,150,29,38,46,172,85,194
39,261,543,897,624,18,212,416,127,931,19,4,63,96,12,101,418,16,140
230,460,538,19,27,88,612,1431,90,716,275,74,83,11,426,89,72,84
1300,1706,814,221,132,40,102,34,868,975,1101,84,16,79,23,16,81,122
324,403,912,227,936,447,55,86,34,43,212,107,96,314,264,1065,323
428,601,203,124,95,216,814,2906,654,820,2,301,112,176,213,71,87,96
202,35,10,2,41,17,84,221,736,820,214,11,60,760

Dorabella 密码

  1897 年,英国作曲家爱德华·艾尔加(Edward Elgar)给挚友多拉小姐(Miss Dora Penny)留下了一封信。这封信上写着 87 个歪歪扭扭的符号,里面明显藏着艾尔加想对多拉小姐说的话。多拉本人一直没能读懂这封信。1937 年,多拉出版了自己的回忆录,将这份密码公之于众。这个密码直到现在仍未被破解。

  密码全文如下:
4.jpg

(转)C++为什么不用delete代替delete[]?

总结:一直想不通c++为什么多此一举,呵呵,前几天给Bjarne Stroustrup大师写了一份信,第二天就收到回复了,自己再仔细琢磨了一下,终于好像弄明白了:-)

我的理解是这样的,无论new还是new[ ],C++的确知道返回的这个指针它指向多大的内存块,否则它就不可能正确地释放掉这块内存了。但是delete需要知道的不仅仅是指针指向多大的内存,而更重要的是要知道指针指向的数组中有多少个对象,知道了对象数量才能依次一一调用它们的析构函数。那么,下面的代码会产生什么样的结果??

int * pArray = new int[100];

……

delete pArray; //本来应该是 delete [ ] pArray;

根据上面的解释,我们不难想象,上述代码错误的原因并不是因为它只释放掉第一个元素的空间而没有能完全释放整个pArray所指的内存。 也就是说,在内存释放上不存在问题。问题出在在这里只对第一个元素调用了析构函数,而其他99个元素并没有被妥善地析构掉。呵呵,这才是真正的问题所在!! 当然对于整数类型来说并不会导致什么问题,但假如在每个对象中都分配了额外的资源,那么不调用对象的析构函数可就会导致严重的后果了……

那使用delete[ ]有什么用?这要从new[ ]说起,在new一个数组时,编译器会悄悄地在内存中保存一个整数用来表示数组中元素的个数。这样在使用delete[ ]时,编译器就会生成读取这个整数的代码,然后逐个调用析构函数。如果使用delete,则编译器只当作指针所指的是单个对象。再说了,new单个对象时,编译器也不会悄悄记录数组中元素的个数。呵呵,从这也可以感觉出C++的设计风格和宗旨,决不多费一点手脚,单个对象我就不记录长度,只有是数组时我才记录!:-)

下面是我给Bjarne Stroustrup的邮件及他的回信。在此对Bjarne Stroustrup大师平易近人的风范再次表示钦佩!!

Hi, Dr. Stroustrup

Firstly,Thank you for your great invention, the c++ programming language is
really a great job, it gives me a lot of help in my study, it makes my work much
more convenient!

Thanks

Well, today ,I run into a confused problem about delete and delete[], so I
wonder if you could give me some explanation or tips. I simply can't understand
why c++ don't treat them in the same way. In other words, I think there is no
need for delete[].

For example, "delete [] ps", many textbooks just say that the operator
delete[] is used to tell the compiler that the pointer "ps" refers to an array,
but not a single object. Of course, I know that, but the thing is that I think
the c++ compiler is totally clever enough to figure out whether "ps" points to a
single object or an array. There is no need to bother the programmer to point it
out explicitly.

No. The compiler cannot know.

void f(int* p)
{
delete p; // or maybe delete [] p?
}

void g()
{
int* q = new int[70];
f(q);
q = new int;;
f(q);
}

separately compile those two functions an the compiler had no way of
knowing how many ints p points to.

It's no doubt that the compiler knows the size of storage to which is pointed
by "ps". Otherwise, it's impossible for c++ to deallocate the memory properly.
OK, now that the compiler exactly knows how many bytes is allocated there and
which type the object is, it can compute how many object are there, I mean,
" number of object = number of bytes allocated / sizeof(object type) "
Ok, after that, c++ may call destructor iteratively to destroy each object in
the array and then deallocates the memory.

It is a bit trickier than that. Many allocators allocates space for at
least N ints when you ask for new int[N]. It is not uncommon for an
allocator to allocate more to minimize fragmentation.

I don't know if I have made my question clear:-) In conclusion, I think a
single object is just a special case of an array, so c++ is supposed to deal
with them in the same way. There is no need for us to differentiate delete and
delete[].

The snag is that many allocators (at least traditionally) just keep
track of the number of bytes allocated (rounding the allocation up to
something convenient). With destructors, the compiler has to know how
many objects are there (not just how much space is allocated). Some
implementers use (or used) two different layouts for individual objects
and arrays - the array layout (only) included an object count.

In fact, I know certainly this is my misunderstanding. if not that, the c++
committe should have changed the c++ syntax:-) I just hope to get some
convincing explanation.

Thank you, really appreciate for your help!

Supermonkey,China,Nankai University
2007-09-03

LFS 6.7中配置telnet服务并使用PuTTY链接

  安装完了LFS,有个问题比较烦人,那就是中文乱码。
  1.jpg

  没办法,毕竟字符界面下中文编码无法做到原生支持,要在Linux字符界面中支持中文显示,需要安装中文环境,上网找了些资料,感觉都不太好,zhcon虽然经典,但是很久没有更新了,最后放弃了,还是曲线救国吧。
  
  其实字符界面中的中文字符编码都是正确的,只是显示出了问题,那就换个前端显示,以远程连接的方式连接到LFS,所以就想到了telnet和ssh,先试试telnet吧,只要telnet客户端能够支持中文显示就可以了,这样的客户端很多呀,像PuTTY、SecureCRT等等,既然定了方案,那就开工吧。。。
  
  首先,在LFS中安装telnet服务telnetd,由于inetutils附带了一份,只是被LFS屏蔽了,配置编译时使用了--disable-servers禁止了telnetd的构建,只要去掉改该编译选项就可以了:
  ./configure --prefix=/usr --libexecdir=/usr/sbin \
  --localstatedir=/var --disable-ifconfig \
  --disable-logger --disable-syslogd --disable-whois \
  [--disable-servers,去掉该编译选项]
  
  重新编译安装inetutils就可以了
  
  然后,配置telnetd服务
  在/etc目录中创建inetd.conf,添加如下参数行:
  telnet stream tcp nowait root /usr/sbin/telnetd telnetd
  
  最后,启动inetd服务
  
  直接执行命令inetd即可
  
  如果要让inetd开机自启动,方案很多,这里给出一种:
  在/etc/rc.d/rc3.d目录下创建脚本S30inetd:
  输入内容:
  #! /bin/sh
  inetd
  
  即可,如果运行级不是3,在对应的rc*.d目录下创建即可
  
  好了telnet服务已经开启,远程连接到LFS虚拟机即可。
  
  又有新的问题了,使用PuTTY连接的时候,登陆很慢,因为telnet服务需要反向验证客户端,需要在hosts文件中对客户端IP添加一条DNS记录来解决该问题
  
  好了,最后在PuTTY中将字符编码设置为UTF8,这样PuTTY就能正确解码UTF8编码的中文字符了。
2.jpg

  OK,终于看到正确的中文显示了
3.png
  

基于Ubuntu 10.10 构建LFS 6.7总结

  首先扫个盲,呵呵。
  LFS,即Linux From Scratch,LFS不像Ubuntu,Fedora,SUSE等Linux发行版以最终产品的形式发布,而是以文档的形式发布一套构建流程,指导使用者,从源代码自行构建一个LFS系统,也就是说你拿到的LFS实际上只是一个指导手册,其中指明了以下几点::

  1. 什么是LFS
  2. 如何准备构建LFS
  3. 如何获取构建LFS所需的源码包
  4. 如何编译LFS
  5. 如何配置LFS

  从LFS的构建过程中,能够学习到一个常规Linux系统的结构,以及如何去配置Linux系统,毕竟Linus给你的只是Linux内核,而一个真正可用的Linux系统是由很多部件一起工作的。
  当然不能期望通过一个LFS就让你知晓Linux的一切,毕竟这不太现实,而且LFS的目标很明确,就是指导用户构建一个可用的Linux系统,所以LFS不会对其中的操作用动辄几百字去解释透彻,但是对于一个具备Linux基本使用能力的人来说,LFS的解释已经很详细了,能够让使用者知其然,还能知其所以然。

  这里我想把自己的LFS构建经验总结一下,主要是过程中遇到的问题,列出来,欢迎大家围观,呵呵

LFS的主要构建流程:

  1. 准备。包括为LFS分配空间,设置分区,在宿主系统安装相关组件等
  2. 编译一个临时的纯净系统。考虑到现行的发行版中都会或多或少做一些优化调整,这会导致直接编译出来的系统不具备通用性,所以需要基于宿主系统构建一个临时的纯净系统,新的LFS系统所需的相关组件都会在这个纯净的环境中编译
  3. 在上面的纯净系统中编译LFS系统
  4. 配置LFS系统,以使系统能够正常工作
      上面的流程在LFS Book中都以指令的形式列了出来,我们要做的就是按照LFS Book中的说明,一点一点敲字母就可以了,这需要具备一些Linux的基本使用知识来理解操作的含义。

  具体细节这里就不多说了,大家看LFS Book就可以了,这里顺便共享几个文件,方便大家使用。

  我这里主要想把自己编译LFS时遇到的问题总结一下,共享出来:

  我这次编译的LFS是最新(2011.2.12)的6.7版本,用的宿主系统是Ubuntu 10.10,基于VMware WOrkstation 7.1虚拟机。虚拟机使用的是双硬盘,其中一个/dev/sda安装了Ubuntu 10.10,LFS则编译在了另一个硬盘/dev/sdb,这也是为了在制作完LFS后,能够方便的在独立的虚拟机中运行。

Ubuntu的安装就不说了,下面直接说说编译LFS时出现的问题:

  1. 编译Binutls出错
    一开始的时候就出错了,比较打击人。。。
    这里需要安装build-essential和texinfo两个包,因为Ubuntu中没有

  2. 编译gcc出错
    原因很简单,查找问题很恼火。。。
    因为在输出指令的时候,输入languages时少输了末尾的s

  3. 编译glibc出错

因为Ubuntu中安装的是mawk,不是gawk
这里需要安装gawk

  1. 编译过程中要注意指令的大小写,否则很容易出现问题
      这是个细节问题,因为Linux中是区分大小写的,所以要格外注意。因为我是一边在VMWare中操作,一边看LFS Book,LFS Book不是最大化的显示,所以输入指令的时候不容易区分大小写,像C和c,S和s,容易出错,结果编译不过去,仔细一些就可以了

  2. 安装完成LFS后,启动出现问题
      重新启动以引导LFS的时候卡在了这里:kernel_thread_helper 0x6/0x10,原因是根文件系统无法加载,这个问题被称作kernel panic,似乎遇到的朋友还比较多。
      我之前没有编译过Linux内核,并不懂内核配置,但是LFS Book对这里没有任何说明,所以在这里郁闷了很久。最后,找到原因是Linux内核的默认编译选项对sata硬件的支持不完整,有些sata硬件的驱动没有编译进去,比如我使用的VMware 7.1中的sata驱动:
    LSI Logic / Symbios Logic 53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI
      这里需要修改编译选项,以支持该sata驱动。我想其他的驱动支持,道理也差不多,注意添加对应的驱动支持就可以了。可以通过lspci命令了解到系统中的pci设备都有哪些,便于在编译内核时选择正确的驱动。这里的lspci是pciutils包中的工具,没有的话需要安装。

我这里说说我选择的编译选项,这里参考了网上的一些资料,对于同样使用VMWare体验LFS的朋友或许会有帮助:

Linux Kernel Configuration
    -> Device Drivers
        -> SCSI device support
            - > SCSI disk support   选中

Linux Kernel Configuration
   -> Device Drivers
       -> Fusion MPT device support   选中
            -> 选中子项(不确定的话就全部选中好了)

Linux Kernel Configuration
    -> Device Drivers
        -> SCSI device support
            - > SCSI low-level drivers  选中
                -> 选中和Fusion-MPT相关的底层驱动以及VMWare PVSCSI driver support
  1. 调整/etc/ftab和/boot/grub/grub.cfg以正确引导独立的LFS并加载分区

  因为我的目的是在独立的硬盘中编译LFS,这样将LFS的虚拟硬盘文件拷贝到新的虚拟机中就可以加载运行了,所以目标系统中是只有一个硬盘的,需要调整上面的两个文件,将原来的sdb对应的改成sda即可,因为LFS所在硬盘是以第二硬盘的形式挂到虚拟机中的。

  grub.cfg是在加载Linux时使用的,这里需要调整;fstab是在Linux启动时,加载分区中的文件系统的,这里也需要修改。

  好了一切正常,截几张图过来看看,呵呵:
1.png

2.png

用PuTTY Telnet过去的效果,算是临时解决了中文无法显示的问题
3.jpg