欢迎访问OpenSource.org.cn博客群!

服务器进行了调整,所以一切都回到了原点,现在服务器已经稳定下来了。以前的几位。请联系HD。现在我们可以在这里自由的写自己想写的内容了。 :)

* 服务器迁回国内。如有任何问题,敬请使用MSN/GTalk/E-Mail联系我。
本来怕惹事生非,我选择半途而废──这篇我写了一半就取消了,想了想本着暴露自身问题、虚心接受批评的原则,还是写出来吧。

老师推荐我读下《编程匠艺》[1] 这本书,确实写得很有意思。其中第一章谈的是"防御性编程"。在书的"1.5.8 使用安全的数据结构"小节,作者写到:

"......通过把strcpy更换为有大小限制的字符串复制操作strncpy,就可以使上面的C代码段得到保护。

char *safer_copy(const char *source)
{
    char *buffer = new char[10];
    strncpy(buffer, source, 10);
    return buffer;
}

"

其实单就这段代码并无太大问题,只是和描述略有出入──这段更像是C和C++的混写。我们延伸开来讨论下。

首先做一个假设,我假设代码作者的本意是将source用做以NUL结尾的字符串,buffer只是source的(子)字符串,这段代码的含义仅为演示从不定长字符串复制到定长字符串,并利用带长度限制的"n系列"字符串函数增加一定的安全性。毕竟C中还是有那么些函数能完成将数据从一块内存区域移动到另一块内存区域的,也不见得非用str×××这样的玩意。

下面引入正题:(好吧,我就把我的想法直说了)根据strncpy(3)的man page,如果source的长度超过buffer,则buffer是一个未结束的字符串(即,末尾没有填入NUL字符)。再有就是基于这样一个事实,(new返回的内存空间是否干净我不知道 Update:"neither malloc() nor new initialize the space to zeros"[2])malloc(3)返回的堆内存是没有被初始化、并且是对齐的,也就是说,申请10 * sizeof(char)的空间并非得到的是整10个char,可能会按需padding并且padding的空间也是可用的。在我所用的Mac OS X 10.6上,执行2次new char[10]会得到两块连续的16个字节(char)大小的内存。我还发现未赋值的空间是填零的(详情见文后"Update"部分)。

考虑如下代码:

#include <iostream>

char *safer_copy(const char *source)
{
        char *buffer = new char[10];
        // 这里模拟未初始化的内存
        for (int i = 0; i < 16; ++i)
                buffer[i] = 'P';
        strncpy(buffer, source, 10);
        return buffer;
}

int main (int argc, char * const argv[])
{
        char *str = "012345678901234567890123456789";
        char *what = safer_copy(str);

        char *c1 = new char[10];
        char *c2 = new char[10];
        strncpy(c1, str, 16);
        // 基于填零这一事实,只复制15个字符
        strncpy(c2, str, 15);

        printf("%s", what);
        return 0;
}

此时内存布局如下所示:

0x0000000100100080|30 31 32 33 34 35 36 37 38 39 50 50 50 50 50 50|0123456789PPPPPP
0x0000000100100090|30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35|0123456789012345
0x00000001001000a0|30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 00|012345678901234.
0x00000001001000b0|2f 44 65 76 65 6c 6f 70 65 72 2f 41 70 70 6c 69|/Developer/Appli
此段代码的输出为:

0123456789PPPPPP0123456789012345012345678901234

这并不是我们预期的结果。

其实修正也很简单,就是strncpy完以后不管怎样将NUL字符赋值给buffer[9]:

        strncpy(buffer, source, 10);
        buffer[9] = '\0';

这样如果source指向的字符串比buffer短,那么buffer本身就是NUL-terminated,多余的NUL也无伤大雅。如果比buffer长也没关系,只是被截断罢了。

本文测试用到的工具为Xcode 3.2.1,体系结构设置为x86_64,操作系统:Mac OS X 10.6.2。

__UPDATE__

1. 咨询了下三金大师,大师说堆是OS给的,新分配的都被OS prezero了。更好的办法是用strlcpy(3)。
2. 在 Microsoft® Visual C++ 6.0 下运行,看上去像这样:
vc6-safer_copy.png
[1]《编程匠艺》,原名《Code Craft: The Practice of Writing Excellent Code》(ISBN-10: 1-59327-119-0, December 2006, NO STARCH PRESS, link)。中文版由电子工业出版社出版。
[2] "Operator New/Delete" http://www.glenmccl.com/bett_003.htm

Using Perl to fix corrupted WAVE files

| No Comments | No TrackBacks
本文的方法适用于WAVE文件头部信息不正确(该问题一种可能的表现为:一个几百M的文件,播放时长却是00:00)而引起的无法播放。

一个对WAVE文件格式简单介绍,具体请见参考文档。

WAVE文件头部信息主要由以下几个部分组成:RIFF(Resources lnterchange File Format)块描述子、"fmt"子块、"data"子块。其中RIFF块对文件的格式、数据长度做出了初步描述,接下去分别是以大端("big-endian")存储的字母"fmt"(0x666d7420)和"data"(0x64617461)开头的两个子段,对文件的码率、声道、长度等做了进一步说明。其中各段的每一项值的长度、偏移都有规定。各类播放软件主要利用这里的内容判断并显示播放时长等信息。

这里以一个错误的头部信息为例(取自一PCM格式文件):

00000000  52 49 46 46 00 00 00 00  57 41 56 45 66 6d 74 20  |RIFF....WAVEfmt |
00000010  12 00 00 00 01 00 02 00  44 ac 00 00 10 b1 02 00  |........D.......|
00000020  04 00 10 00 00 00 64 61  74 61 12 00 00 00 00 00  |......data......|
00000030  00 00 00 00 00 00 00 00  00 00 ff ff ff ff ff ff  |................|

主要问题为:

  • ChunkSize部分为0(如上粗体所示);
  • "data"标记(大端,0x64617461)后移了2个字节,应始于下划线处;
  • 数据长度部分(粗斜体部分,4字节)错误。

可以对比下列某一头部信息正确的WAVE文件:

00000000  52 49 46 46 e4 cd a1 03  57 41 56 45 66 6d 74 20  |RIFF....WAVEfmt |
00000010  10 00 00 00 01 00 02 00  44 ac 00 00 10 b1 02 00  |........D.......|
00000020  04 00 10 00 64 61 74 61  c0 cd a1 03 00 00 00 00  |....data........|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

得知问题所在,即可修复,下面给出我所用的Perl脚本的源代码。

#!/usr/bin/perl

use strict;
use warnings;

open my $fh, '+<', $ARGV[0] or die "$!";
seek($fh, 0, 2);
my $len = tell($fh) - 44;
my $head = pack('A4VA4A4VvvVVvvA4V', 'RIFF', $len + 36, 'WAVE', 'fmt', 16, 1, 2, 44100, 176400, 4, 16, 'data', $len);
seek($fh, 0, 0);
print $fh $head;
close $fh;

说明如下:

  • 文件由第一个命令行参数给出;
  • pack函数中的模板(template)部分,用"A"或"a",因此处并不存在padding,无影响;
  • WAVE头部ChunkSize部分的计算为SubChunk2Size + 36,具体见参考文档;
  • 文件长度($len),由文件末尾位置减去头部长度(44个字节)得出;
  • pack函数参数中的"44100"等部分,按原头部信息硬编码,可按需修改。

修复后的头部信息摘录:

00000000  52 49 46 46 26 e0 f6 6d  57 41 56 45 66 6d 74 20  |RIFF&..mWAVEfmt |
00000010  10 00 00 00 01 00 02 00  44 ac 00 00 10 b1 02 00  |........D.......|
00000020  04 00 10 00 64 61 74 61  02 e0 f6 6d 0a 00 00 00  |....data...m....|
00000030  00 00 00 00 00 00 00 00  00 00 ff ff ff ff ff ff  |................|

至此,该文件已经可以由相关播放器播放。本文的方法也可用其他语言(如:Python)加以实现。

Reference & Further Reading

* 本文所涉及WAVE文件头部相关知识来源于:Sapp, Craig (Dec. 1997). "Microsoft WAVE soundfile format"

Movable Type upgraded to 5.0

| No Comments | No TrackBacks
顺便改成了FastCGI,貌似有点提速的意思。

Movable Type 5 有个东西一下没适应,它的概念是先有一个website配上域名,然后再是每个站点,即该主域名下面的/path或是子域名。
另外在刚跑FastCGI之前需要FCGI之类的Perl module,光Apache上有mod_fastcgi还不够,错误症状就是在日志里面出这样的:

[Sat Mar 06 11:41:16 2010] [warn] FastCGI: (dynamic) server ".../mt.fcgi" (pid .....) terminated by calling exit with status '0'
[Sat Mar 06 11:41:44 2010] [warn] FastCGI: (dynamic) server ".../mt.fcgi" restarted (pid .....)

From: CSDN,原Hi上面的已经被删。

今天下午1时20分,百度首席产品设计师孙云丰在自己的博客中撰文关于谷歌退出中国,直指Google退出中国的姿态证明自己是市侩分子,对此感到恶心。

博客全文如下:

google宣称要退出中国,所证明的,恰恰不是市面上的那些g粉所宣称的那样,google是个人权斗士,而刚好反了过来,正好证明google是个市侩分子。

google的首席法律顾问的调调让我感到恶心。因经济利益退出,就直白白的说好了,把自己涂脂抹粉一番,还煞有介事的提到google被中国人攻击,中国异议分子的Gmail信箱被攻击,把这些事情作为退出中国的铺垫,这种论调是侮辱中国普通老百姓的智商,但还真有可能迎合那帮目空一切,但从未到过中国、对中国没有丝毫了解,却又喜欢对中国说三道四的西方人的假想。

只提一个假设,如果谷歌占据了中国80%的搜索市场份额,google的高管,还会这么高调的宣称要do no evil,从中国退出吗?

整个事情给我的唯一感受,就是恶心。
-------------- 以上是作为一个曾经的忠实google用户而说的,和百度无关。市面上沾沾自喜于了解一点google的产品技术细节将google奉为道德楷模而自封G粉的兄弟,请勿跟帖瞎喷,你们根本不懂什么叫搜索引擎,什么叫自由人权。

=== 转载结束 ===

据说被要求删帖,我也来藏一份。

顺便和我身边热爱BIDU的计算机专业本科生说下,多用用啊,抄东西多方便。
家人这边没法劝了⋯⋯

Install LispWorks 5.1.1 on FreeBSD 8.0-RC1

| No Comments | No TrackBacks
YBVVQWAM.jpg
系统:FreeBSD 8.0-RC1 i386
LispWorks: 5.1.1 Personal for FreeBSD 32bit
以非 root 用户安装:

用 Ports 安装 misc/compat5x、misc/compat6x、x11-toolkits/open-motif/。
运行License脚本,同意内述条款。
然后运行pkg_add(1):
$ pkg_add -p /home/你的帐户名/LispWorks -R 下载得到的LispWorks安装包.tgz
-p: 由于是非 root 用户,需指定安装路径。
-R:私下安装,并不向系统注册。

然后向 /etc/libmap.conf (amd64 则为 libmap32.conf ) 中添加如下内容:


libpthread.so.1		libthr.so.2
libc.so.5		libc.so.6

具体可以参考 libmap.conf(5)。

然后按如下链接中提供的步骤安装兼容老版本X11需要的文件:
http://www.lispworks.com/kb/67634814074628b180257490005cb9d3.html

完成安装。

运行:

$ env LD_LIBRARY_PATH=/usr/local/lib/compatX11 ./lispworks-personal-5-1-1-x86-freebsd
(请按实际情况修改文中所提到的步骤)

一个<pre>的小tip

| No Comments | No TrackBacks
在CSS也好style属性也好里面加上这行:

white-space: pre-wrap;

我想这个也许能避免某些悲剧的发生。

Find recent content on the main index or look in the archives to find all content.

Tag Cloud

Categories

Pages

Powered by Movable Type 5.01