2010年的最后两个数字~

2010年,中国互联网出现了很多新鲜事,也流行过很多新鲜词

两个数字

2010年的最后两天,微博上最流行的却是两个数字:

三张图片

第一张叫:Google真坏!

f5b2d1decc7ac658620038654d7b33bf

第二张叫:360威武!

image

第三张叫:人肉威武而肉食者鄙!

77块

更多链接

2010年,马上就要过去了。我是懒人,就不总结了,看看别人的吧:

Mac Book初体验~

在2010即将结束的时候,博主作了一个非常艰难的决定:暂别Windows平台,全职转向移动开发。书、iTouch、Mac Book,这三样已经到手了,接下来就是折腾了。

iTouch就一玩物,上手自然很快。而Mack Book是要拿来写代码的,玩起来就没那么顺手了。好在这年头有Google,有啥问题就放狗。为了自己好记,也为了别人好找,简单列一下:

Mac OS常用快捷键:

话说这是在Mac Book上写的“处女博”,第一次在Mac上做这事还真是费劲啊!暂时还没找着Mac上的Blog Writer软件,只好手写HTML。Mac自带的五笔也没有QQ五笔好用,只能慢慢来了〜

免费域名与DNS解析服务~

为了满足学习与测试的需要,使用过一些不错的免费域名与DNS解析服务。现在稍加整理分享给大家,希望对大家有所帮助。

早期的免费域名服务

记忆中最早的免费域名是网易提供的,依稀记得网易那时还提供免费空间。其实那个年代的免费域名,基本上都只是一个URL转向,算不上是严格的域名了。然而那个年代的网友、那个年代的技术、还有那个年代的网吧与免费服务,都让我深感怀念。哥,当年也年轻过哇~

扯远了,说回免费域名。现在URL转向类型的二级、三级域名已经不吃香了。特别是在国内,由于前些年出现过很多利用免费域名转向进行欺诈的现象,现在基本上没有流行的URL转向服务了。即使国外还有此类服务,也大多被封在了国门之外。

可解析免费域名服务

如今比较流行的免费域名都是可解析的免费域名。也就是说,除了“长相”差一点之外,功能上和.com/.net之类其实没啥差别。此类服务较早且较有名的好像是pp.ru之类,由于是俄罗斯提供的,当年申请的界面还是俄语的,博主其实没有亲自尝试过(或许也申请过,忘记了)。

下面列举一下博主验证过的可解析免费域名服务:

免费DNS解析服务

以上列举的免费域名都支持修改NS记录,这一点其实很重要。比如说,有些朋友可能会觉得官方的解析服务器不是很稳定;或者,有些免费域名的解析服务器甚至已经被墙了。

然而,只要能修改NS记录,以上问题都不会是问题了。通过修改DNS,你想使用哪家的DNS解析服务都是可以的。

下面列举一下博主经常使用的免费DNS解析服务:

  • DnsPod
    • 国内最优秀的免费智能DNS解析服务商
    • 支持A, CNAME, MX, NS, TXT, AAAA记录
    • 免费用户可以解析无限个域名(暂不支持co.be)
  • Godaddy
  • EditDns
    • EditDns分为收费和免费两个版本的服务
    • 支持一堆的记录类型,该有的基本都有
    • 好像没有域名个数限制
  • DnsPark,
    • 支持A, CNAME, MX, NS, TXT记录
    • 免费用户可以解析2个域名
  • EveryDns
    • 支持A, CNAME, MX, NS, AAAA记录
    • 免费用户可以解析20个域名,共200条记录
    • (好像已经不接受新用户注册)

博主一般使用DnsPod来解析自己手里的免费域名,DnsPod不支持的除外。

特别推介:Dot.TK

Dot.TK域名其实资历很老了,只是最早的时候只提供免费URL转向,加上在国内访问不是很稳定,一直以来知名度貌似不是很高。现在.TK终于开放了全功能的解析服务,相当实用了。

是的,Dot.TK提供的是yourname.tk形式的免费域名。给力的、顶级的免费域名,不是二级、更不是三级!Dot.TK现在还提供了中文网页:http://www.dot.tk/zh/index.html ,相当的实在哇!

468x60_tkitpromo_banner-1

另外,Dot.TK官方有一条规定:每个免费域名在90天内必须有25个以上的访问量,使用.TK的朋友需要注意一下。

139与监控宝~

网站监控很重要

辛辛苦苦写Blog,自然是想写给大家多看看了。可是每个网站总免不了有那么几天,抽抽风、出点小毛病啥的——什么ping不通啊、404啊、500啊,总之就是访问不了了。

作为一个对读者负责的博主,第一时间发现并修复网站,那几乎就是应尽的义务。然而大多数的博主都还是要上班、要赚钱糊口+养网站的,总不能一天二十四小时盯着自己的小网站吧?

于是,给力的网站监控服务就显得很重要了~

监控宝是个好服务

经过本博长达数月的体验,很负责任地告诉大家:监控宝是个好服务!列举不完全理由如下:

  • 为个人用户提供免费套餐,最多可以免费监控5个网站;
  • 可以通过指定匹配内容来检查响应内容是否正确,实现精准检测;
  • 提供多种告警途径,Email告警、Email监控日报均可免费使用;
  • 管理界面简单易用,监控结果、统计参数均一目了然;
  • 监控服务稳定、及时,服务质量相当之高……

监控宝的优点还有许多,然而对于个人来讲,上述几条已经足够了。

免费使用短信告警

短信告警作为监控宝的一项增值服务,需要付费购买才能获得。如果对于短信通知的实时性要求不是特别高的话,也可以配合使用139邮箱实现间接的短信告警通知,方法如下:

  • 使用139邮箱注册监控宝服务(已注册用户可以在监控宝后台更改注册邮箱);
  • 在139邮箱中设置邮件到达通知,这样139邮箱收到邮件就会发送短信到手机;
  • 建议启用手机邮件过滤白名单,过滤掉非监控宝发来的邮件,减少骚扰.

上述139邮箱中邮件到达通知的设置入口如下:

image

按上述方法设置成功之后,一旦网站发生故障,监控宝就会发邮件到139邮箱;收到告警邮件后,139邮箱又会发短信到博主的手机。瞧:相当凑合的短信告警服务,赞!

当然,对于重要网站、不缺钱的主,强烈建议购买监控宝付费服务,支持监控宝发展。

服务器访问速度跟踪

除了网站监控,监控宝提供另一功能:服务器访问速度跟踪。有兴趣的朋友,可点击本博右下方链接体验其效果:

image

服务器访问速度跟踪的实现原理和使用方法就不多讲了,有兴趣请前往监控宝官方网站

警惕:网络诈骗无处不在!

去年我发过几个截图,感叹道“诈骗与崩溃伴您成长”。今儿个,这话题继续~

百度一页全广告

这个可以说是有目共睹,百毒!

百度一页全广告 

微博也诈骗

当下微博正火。本着“谁火就灭谁”的精神,诈骗集团成功进驻!

微博也诈骗

“漂流瓶”也不能放过!

QQ Mail最近推出的“漂流瓶”功能,甚是好玩。当然,诈骗专家们肯定也要上!

QQ漂流瓶诈骗

用文件名诈骗那才叫专业!

最后来个专业的,利用文件名诈骗!你QQ不是过滤垃圾消息么,可是你忘记过滤了“文件名”!

文件名也诈骗

看看,谁说中国人没有智慧?谁说我跟谁急!

由《一道QT小题》想到的~

一道小题

偶然的一个机会,读到了CSDN推荐的一篇blog:《一道Qt小题考考你》。原题引用如下:

请问下面的Qt代码有什么问题?

#include <QtGui/QApplication>
#include <QtGui/QLabel>
#include <QtGui/QWidget>
int main(int argc, char* argv[])
{
	QApplication hwApp(argc, argv);
	QLabel hwLabel("http://www.cuteqt.com/blog");
	QWidget window;
	hwLabel.setParent(&window);
	window.show();
	return hwApp.exec();
}

我读懂了这段小代码,也看出了问题的所在,虽然我从来没有使用过QT。这说明QT的类库设计得很不错,起码简单易懂。

如原文所述,上述代码的问题在于window对象和hwLabel对象的析构顺序反了,解决的方法也很简单,将windows对象和hwLabel对象的声明语句调换顺序即可。

一点思考

当然,现在我专门写一篇blog,不是要赞一下QT,也不是要再次强调一下C++程序都会面临的对象析构的顺序问题。

很明显,QT对于界面的抽象和当下许多流行的做法一样,即将程序窗口及窗口控件抽象成一棵对象树。从最终界面呈现的角度讲,上述代码逻辑中的hwLabel总是需要依赖一个window才有存在的意义,于是setParent或者类似的接口总是必须存在的。

一方面,这里必定会存在两个有父子关系的对象;另一方面,对象的析构顺序也存在约束。而我的问题是,有没有一种编程方法能够做到当这两个对象声明顺序相反的时候,编译器就会报错?或者,有没有一种编程风格压根就不care对象声明的顺序呢?

对于我自己抛出来的上述两问,我当然是作过一点思考,也做过一点尝试的。一种解决方法是,将setParent的功能提前到hwLabel的构造函数;极端一点,只允许使用引用!另一种解决方法是向DotNet等框架学习,提倡一种全部使用动态对象的风格。

一点结论

当然,真正实践的时候,总是会有一些理论所预期不到的问题。上述的解决方法遇到实际的场景也必定是各有利弊。

无论是对于开发人员来讲,还是对于应用本身来讲,将问题在编译时暴露出来,总是比在运行时暴露出来更好解决。然而综合考虑一下架构的灵活性、程序性能等多方面的因素,或许结论会有所不同。

或许,所谓的架构,就是在不同的解决之道之间权衡、选择;实事求是。

奇声QHD-808初体验~

10.1的时候,HDC论坛组织团购,忍不住入了一台奇声QHD-808高清播放机。

QHD-808

从快递手中接过机器之后,立马拆箱。第一眼便看到一根好粗的HDMI线,赞。赶紧接上电视,开始摸索一番。先看看各项系统设置,基本上都很好使。之后找出一堆新片老片,一边测试机器,一边回味经典。

兼容性

经过一堆新片老片的测试,感觉QHD-808的视频格式兼容性算是可以。特别是对于我这种并不发烧的普通高清爱好者来讲,QHD-808可以说是完全够用。从rmvb文件到蓝光ISO、蓝光目录,基本上都能流畅播放。

输入接口方面,QHD-808前后面板上各有一个USB接口。经过测试,前后面板都可以连接USB移动硬盘进行正常播放。内置100M网卡,连上网线之后经过简单设置即可接入网络。据网友体验,QHD-808可以自动连接局域网中的NAS设备(NFS服务器),非常方便。

遗憾的是,目前的固件版本还不能播放ape文件,好像也不能读取cue列表文件。如果需要播放ape文件,可以先转换成flac或者wav格式。据HDC论坛网友爆料,新版的固件将支持ape播放,而且已经在内测了。

人性化

奇声不愧是家电行业的老牌大厂,其人性化设计的功力在QHD-808上体现得非常到位。

QHD-808的系统界面简单实用,大部份操作只须使用遥控器上的方向键和“OK建”便可完成。QHD-808的遥控器,按键不多,但非常实用。字幕切换、声音选择、声音大小、时间选择、DVD菜单等最常用功能,都在遥控器上有专门的快捷键。

对比了一下新买的三星电视机的遥控器,QHD-808遥控器明显更容易上手。对比两者的说明书,差别就更加明显了。QHD-808的说明书多达40多页,图文并茂。更难得的是,在一些不常见功能的操作说明旁边,加上了对于当前功能选项的注解。

相信大家都有过这样的经历,打开一本说明书,发现上面详细讲解了某个设置项的设置方法。然而就是不告诉你这个设置项的实际意义。对于大多数人来讲,这种说明书有跟没有都是一个样。因为设置方法,基本上都不会太难,摸索下也就上手了。而对于不了解的设置项的意义,说明书上又只字不提,依然是让人一头雾水。

奇声显然是了解了用户的这一困惑,QHD-808的注解便是体现。

小功能

这些天来,有两个QHD-808的小功能使用得较多:声音选项中的“夜间模式”和影像选项中的“电影24Hz模式”。

夜间模式

夜深人静的时候,观看一些音效动态较大的影片时,便要用到“夜间模式”。由于人物对白与场景效果声音之间往往存在较大的功率落差,普通声音模式下,要么声音开得过小而听不清人物对白,要么声音开得过大而影响了家人休息。而“夜间模式”会自动减小声音动态,达到两者的平衡。

电影24Hz模式

当QHD-808检测到当前所播放的为电影内容时,便可以自动切换到24Hz刷新率进行输出。该模式最终体现在画面效果上,会让人有一种更接近于电影院荧幕观影的感觉。

一些不足

说了这么多好处,下边也说说QHD-808的不足。

网络邻居界面无法输入用户名

在网络邻居界面进行浏览,找到局域网的机器之后,如果共享服务器需要登录的话,QHD-808会弹出用户登录界面。遗憾的是,在随后的用户名输入界面,由于左、右键的状态不对,始终无法输入英文字母。多次仔细对照说明书操作,仍然无法解决。

无法使用BT下载

在系统设置项下,打开“BT与SAMBA”选项之后,在电脑上可以看到QHD-808上所挂的硬盘被共享了出来,而且可写。

在IE中输入QHD-808的系统IP,可以打开内置BT的Web操作界面:

QHD-808 BT Web UI

点击”Setting”按钮可以进行一些设置,点击”Add new torrent”按钮可以添加种子。但遗憾的是,经过多次尝试,发现BT下载速度总是0,无法进行下载。QHD-808的说明书上对于BT功能也未提及,估计现在的版本BT功能并未完成。

系统信息

上述不足应该都是由于当前固件版本的缺陷所致,相信以后可以通过升级固件来解决。顺便telnet到QHD-808系统,收集到如下系统信息:

QHD-808 Shell

可以看到QHD-808使用了BusyBox系统。另外,从BT Web UI的”Setting”界面看到了”BitTorrent”的字样。

译文:使用CRT诊断函数检测内存泄露(VC)

声明

本文为CodeProject网站 Detecting memory leaks: by using CRT diagnostic functions 的中文译稿;本文以“现状”提供,译者eRay Jiang)将尽量保持、但不保证与CodeProject网站的同步更新。

注:转载此文,请遵守Codeproject相关约定

引言

程序员的一大噩梦便是发现自己的程序存在内存泄露。不管程序规模是大是小,一个程序员犯点错误总是难免的。本文就是专门为那些想从内存泄露梦魇中解脱出来的程序员人员而作的。

为何而作

很多不错的开发工具中都带有不错的调试器,可以用来检测内存泄露,既然如此,本文还有什么好讲的呢?自己动手打造一个(完好的内存泄露检测)工具的理由之一便是:一般的调试器不能给出足够详细的输出。而我写作本文的另一重要动机是:我在MSDN论坛上看到许多帖子在询问检测内存泄露的有效方法。

内存堆简介

或许你已经意识到,所谓的“堆”(heap),只不过是你的应用程序动态申请/释放的一大块内存。Windows堆管理器负责处理应用程序的请求。Windows提供一系列函数处理堆操作,其中包括对压缩与内存重新分配的支持。这里不打算展开讨论内存堆管理,或许在我将来的文章里会细讲。本文主要讲堆内存分配、释放与重分配的HOOK操作。

Win32系统支持4GB的逻辑地址空间,其中2GB保留给OS自己使用,另外2GB才是留给应用程序的。如果应用程序希望使用多于2GB的地址空间,则可以请求OS留出更多的地址空间;即让OS只保留1GB的空间,而另外3GB空间则留给应用程序。应用程序最多可以使用3GB的逻辑地址空间,而实际需要的物理空间可以小于这个数。

默认情况下,应用程序保留留1M(256个内存分页,每页4KB)的堆空间,并提交一个内存分页。每当应用程序请求动态内存的时候,堆管理器尝试从已提交的4KB页中分配内存;如果请求超过了4KB的界限,那么堆管理器会提交更多的内存分页。如果应用程序请求超过1MB的动态内存,那么堆管理器将再提供更多的1MB。堆管理器以4KB为一小步,1MB为一大步地提供空间,直到满足应用程序的请求为止。

在Win16系统中,维护了两种内存堆:全局堆(Global Heap)和本地堆(Local Heap)。每一个Win16应用程序都拥有一个全局堆和一个本地堆;应用程序可以从这两个堆中自由请求内存。WINNT去除了全局堆和本地堆的概念之分;在WINNT中,应用程序有一个默认堆和多个动态堆(Dynamic Heap)。不过为了兼容Win16,WINNT中依然保留有GlobalAlloc和LocalAlloc之类的函数。如果应用程序使用了Win16的堆管理函数,WINNT会将这些请求映射到WINNT的默认堆上。

默认情况下,应用程序拥有一个默认堆,但可以创建许多的动态堆。(也许动态堆的个数会有限制,怕不会比HANDLE的数量多,如65535;不过我不确定。)默认堆是进程持有的;通常应用程序不会用到默认堆的HANDLE,实在要用的话也可以通过GetProcessHeap获取。通常malloc, new等调用都会映射到默认堆操作。动态堆则是应用程序可以在运行时创建或销毁的内存区域。有一组函数用于动态堆操作,如HeapCreate, AllocHeap等。我会在后续的文章中详细介绍内存堆管理的详情。

本文中提及了MS Visual Studio中(VC CRT)的诊断函数。为了避免混淆,当我提及“内存”的时候,我指的是”堆内存”,而不是通常所说的主内存、物理内存。

关于调试堆

调试堆是对基本内存堆操作的扩展。调试堆提供了非常强大的方法用于在DEBUG版的应用程序中管理内存分配的细节。通过使用调试堆,你可以跟踪多样的内存问题,比如检测内存泄露,又比如检查缓冲区访问越界等。在DEBUG版本中,当你调用malloc, new时,会被映射到相应的调试堆函数,如_malloc_dbg。这些调试堆函数(在作了一些标记工作之后)最终使用系统的堆管理函数处理请求。

调试堆维护了多样的信息以完成对内存分配操作的跟踪。假如你请求了20字节,调试版本实际上在调试堆中分配了更多的内存。其中20字节交给用户使用,而额外的字节则用于存放调试堆函数的校验信息和簿记信息。调试堆实际上为每一次分配操作使用了一个结构体CrtMemBlockHeader(定义于dbgint.h文件)。

_CrtMemBlockHeader结构体定义如下:

typedef struct _CrtMemBlockHeader
{
    struct _CrtMemBlockHeader * pBlockHeaderNext;
    struct _CrtMemBlockHeader * pBlockHeaderPrev;
    char*  szFileName;
    int    nLine;
    size_t nDataSize;
    int nBlackUse ;
    long lRequest;
    unsigned char gap[nNoMansLandSize];
    /* followed by
    * unsigned char data[nDataSize] ;
    * unsigned char anotherGap[nNoMansLandSize];
    */
} _CrtMemBlockHeader;

如上所示,这些_CrtMemBlockHeader以一个双向链表的形式维护。_CrtMemBlockHeader的前两个参数分别指向下一个和上一个_CrtMemBlockHeader分配块,每个_CrtMemBlockHeader结构除了链表指针,还拥有如下成员:

  • szFileName保存了分配内存代码所在的文件名(译注:对应__FILE__);
  • nLine保存了分配内存代码所在的行数(译注:对应__LIEN__);
  • nDataSize保存了用户请求的内存块的大小(译注:不包括因为分配头而带来的额外开销,即应用程序真正请求的内存大小);
  • nBlockUse表示分配块的类型,这些类型可能为以下之一:
    • _CRT_BLOCK: CRT块,CRT函数用这个类型标识CRT(C Runtime)内部的分配块(译注:后文会用到这个标识);
    • _NORMAL_BLOCK: 普通块,当用malloc或者new之类分配内存块时,就是这种类型。
    • _CLIENT_BLOGCK: 客户块,用于跟踪某一特定类型的内存块;这个类型还可以包括一些子类型。MFC就使用这种类型来标记所有从CObject继承的类的分配,详情请参考MSDN。
    • _FREE_BLOCK: 释放块,即已经被释放的内存块。(使用_CRTDBG_DELAY_FREE_MEM_DF诊断标记可以让CRT在释放内存时并不是真正地进行释放操作,而只是将目标块填充上0xDD之类的标记,并将nBlockUse记为_FREE_BLOCK。该分配块还是在双链表中,这样可以检查内存的增长量。 )
    • _IGNORE_BLOCK:在某一段时间内,你也许想关闭调试堆的跟踪;这段时间内分配的内存块就会被标记上_IGNORE_BLOCK标识。
  • lRequest保存了内存块分配的序号(译注:递增的,可以用于内存泄漏检查)。
  • 接下来是一个gap填充位,后跟data[nDataSize]数组,后边再接一个gap填充位。
    • data[nDataSize]数组即是返回给应用程序使用的内存;
    • gap和anotherGap分别位于data数组的前边和后边。这个两个填充位都是4个字节,MS将其称为NoMansland buffer。在运行的时候,这两个位都填充为0xFD,主要用来检查数组越界。

不难看出,在Debug版本上,无论何时请求一块内存,其实都分配了比你所请求内存更多的额外空间以记录一些簿记信息。

使用内存快照检测内存泄露

结构体_CrtMemState用来保存内存堆状态。通过调用_CrtMemCheckpoint函数,并传入一个_CrtMemState指针;CRT会将当前内存的状态填充到指针指向的_CrtMemState结构体中。以下代码片段用于记录下一个状态点:

_CrtMemState memstate1 ;
_CrtMemCheckpoint(&memstate) ;

接下来,通过比较两个不同的状态点来探测内存泄露。通常,在程序开始的时候打下一个状态点,然后在程序结束前再打下一个状态点。通过比较这两个状态点即可以发现是否存在内存泄露。代码示例:

CrtMemState memstate1, memstate2, memstate3 ;

_CrtMemCheckpoint(&memstate1) // call at the start of your program
.............
............
_CrtMemCheckpoint(&memstate2) // call at the end of the function

然后可以使用_CrtMemDiffernce()函数整理出内存泄露的信息。函数原型如下:

_CRTIMP int __cdecl _CrtMemDifference(
    _CrtMemState *diff,
    const _CrtMemState *oldstate,
    const _CrtMemState *newstate,
);

_CrtMemDiffernce()函数的前两个参数分别指向要比较的两个状态点的_CrtMemState结构;而结果则保存在第三个参数中。代码示例:

_CrtMemeDifference(&memstate3, &memstate1, &memstate2) ;

如果检测到了内存泄露,则返回true,否则返回false。

最后,使用_CrtDumpMemoryLeaks()输出两个状态点之间的内存泄露信息;或者使用_CrtMemDumpAllObjectsSince()输出从某一个状态点之后的所有分配信息。

完整例子:

#include <stdio.h>
#include <string.h>
#include <crtdbg.h>

#ifndef _CRTBLD
#define _CRTBLD
#include <dbgint.h>
#endif

int main(void)
{
   _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT );

   _CrtMemState memstate1, memstate2, memstate3 ; // 内存状态点
   _CrtMemCheckpoint(&memstate1) ; // 打下第一个状态点

    int *x = new int(1177) ;	// 分配内存
    char *f = new char[50] ;	// 分配内存

    strcpy(f, "Hi Naren") ;	// 使用内存
    delete x ; // 释放X 

    _CrtMemCheckpoint(&memstate2) ; // 打第二个点,注意这时f没有释放

   // 比较两个快照:调试堆可以探测到char *f这一处泄露。
   if(_CrtMemDifference(&memstate3, &memstate1, &memstate2))
   {
      printf("\nOOps! Memory leak detected\n") ;
      _CrtDumpMemoryLeaks() ; 

      // alternatively you can use _CrtMemDumpAllObjectsSince for
      //dumping from specific check point
   }
   else
      printf("\nNo memory leaks") ;
      return 0 ;
}

输出:

OOps! Memory leak detected
Detected memory leaks!
Dumping objects ->
{42} normal block at 0x002F07E0, 50 bytes long.
Data: <Hi Naren        > 48 69 20 4E 61 72 65 6E 00 CD CD CD CD CD CD CD
Object dump complete.

使用钩子函数(Hooks)检测内存泄漏

我所使用的跟踪内存分配与释放操作的方法便是使用钩子函数。VC Debug CRT提供了Hook内存操作的方法。一旦通过调用Hook函数,设定了一个自定义的钩子方法,那么不管应用程序是分配或者释放内存,指定的钩子方法都会接到通知。

_CrtSetAllocHook便是用来设定钩子方法的CRT函数。原型如下:

_CRTIMP _CRT_ALLOC_HOOK __cdecl _CrtSetAllocHook(
_CRT_ALLOC_HOOK hookFunctionPtr
);

hookFunctionPtr是用于接收内存操作通知的函数指针。其原型如下:

int CustomAllocHook(int nAllocType, void *userData, size_t size,
                             int nBlockType, long requestNumber,
                                  const unsigned char *filename,
                                                 int lineNumber)

上述钩子函数的参数说明如下:

  • nAllocType用于标明操作的类型,其取值范围如下:
    • _HOOK_ALLOC – 分配操作
    • _HOOK_REALLOC – 重分配操作
    • _HOOK_FREE – 释放操作
  • userData是内存块的头指针,其实际类型为_CrtMemBlockHeader。该能数只有释放操作才有效,其它操作的时候,该参数总是NULL
  • size 是指整个内存块的大小(与userData对应)。
  • nBlockType 标明块类型(如 _NORMAL_BLOCK)。如果该参数为 _CRT_BLOCK ,那么自定义钩子最好返回 true,否则很容易引起死循环。也就是说,你最好不要去管 _CRT_BLOCK操作。
  • requestNumber 是指操作所请求的内存块大小(与应用程序获得的内存对应)。
  • Filename 标明调用当前操作的源文件。
  • lineNumber 标明调用当前操作的代码行数。

一个基本的钩子函数框架如下:

_CrtSetAllocHook(CustomAllocHook)

int CustomAllocHook( int nAllocType, void *userData, size_t size,
                              int nBlockType, long requestNumber,
                                   const unsigned char *filename,
                                                  int lineNumber)
{
    if( nBlockType == _CRT_BLOCK)
        return TRUE ; // 如上文所述,最好别管这种类型

        switch(nAllocType)
        {
            case _HOOK_ALLOC :
            // 在这里添加分配操作的处理代码;

            break ;

            case _HOOK_REALLOC:
            // 在这里添加reallocation操作的处理代码;

            break ;

            case _HOOK_FREE :
            // 在这里添加释放操作的处理代码;

            break ;
        }

    return TRUE ;
}

通过实现钩子函数,你可以添加自己的代码,以跟踪CRT的内存管理操作。然而,我仅仅在钩子函数打一些简单的Log。当遇到分配操作的时候,我把内存分配的相关信息存储在我自定义的有序链表中;当遇到相应的释放操作的时候,从自定义链表中移除相应节点。CrtMemBlockHeader中的lRequest字段,即block number,被用来当作释放与分配操作配对的key字段。

更多信息

原文提供的示列代码下载,以及作者narendra_ b的详细介绍,参见以下网址:

狗日的中国电信,狗日的ADSL!

疑似广告

某日使用ADSL上网,浏览cnBeta的时候发现页面右下解出现一个不常见的浮动广告:

cnBeta右下角出现广告块 

当时心想,以前cnBeta没见这种浮动广告啊。难道现在缺钱花?还是堕落了?

页面出错

继续浏览网页,发现网页标题出现异常。具体表现:打开某些页面的时候,浏览器标题栏显示的不是标题,是对应页面的网址。

当时以为这些网站的开发人员忘记写<title>标签了,不想细究了。不想随即发现了更为严重的情况——某些页面下方会出现老大一空白块,偶尔还有出错提示:

ADSL导致的页面异常

逮个正着

问题已经很明显了,上图中cnBeta的页面显然是被框架套住了!查看网页源代码如下:

ADSL广告页面代码

显然,浏览网页的时候,下载回来的代码已经被篡改了。

变本加厉

第二天,问题依旧,而且变本加厉了!无论我打开什么网站,都会弹出如下窗口:

广告页面技术故障

典型的ADSL劫持症状啊!

投诉无效

忍无可忍,抓起电话直接拨打10000号,本“上帝”要投诉了!

就如我料想的一样,电信客服听完我的描述之后,第一句话就把球踢回来了:请检查系统是否中毒!

我说:电脑是新装的系统,不可能是系统中毒所致。对方回了句:那就是路由器中毒了!我操你大爷的,真TM有才啊,路由器也能中毒了。

嘴上说:我使用的是您家安装ADSL送的路由器,没改过没破解过。要是真的中毒了那也是你们网络有问题!

僵持不下,对方出招了:你重启下路由器试试,还有问题再打过来吧。

重启有效

好吧,重启就重启,试试就试。

怪了,重启路由器之后,症状不见了!

然而没过两天,问题又出现了!

技术分析

技术上讲,除了病毒,就只有电信能干这事了。而我的系统是新装的Windows7,而且使用的是Chrome浏览器,中病毒的可能性几乎为0。也就是说,这事9成9是电信干的了。

至于重启之后故障暂时性消失,我想想也懂了:电信学乖了,往ADSL上插广告不是每条线路同时都插。而是随机的时间段,挑选随机的IP来搞!只要重启就不能重现问题,这下再怎么投诉电信也可以不认了。

好吧,只能时不时重启一把,撞大运了。

不得不骂

Google一下上述图中出现的IP地址”121.15.207.29 / 145”,发现中招受伤的大有人在啊~

天杀的中国电信,“上帝”们花钱包年的ADSL是用来上网的,不是用来看您家广告的吧?

您家实在要加广告,也把技术搞好点、把用户体验做好点啊!总不能像现在这样影响到大家的正常使用吧?

狗日的中国电信,狗日的ADSL!

“多来.ME”上线手记~

“多来.ME”是eRay Jiang建立的独立博客。

“多来.ME”采用WordPress 3.x程序,架设在GegeHost虚拟主机之上。

“多来.ME”的域名DuoLai.ME于Hover优惠期注册,一次性注册到2015年。

“多来.ME”使用随eRayJiang.Com域名附送的Godaddy免费空间作为图床。

“多来.ME”采用监控宝全天候监控站点,并借助139邮箱实现异常短信通知。

“多来.ME”全文输出RSS,建议使用Google Reader进行阅读。

“多来.ME”使用过的主题有:

  • zSofa(当前主题)
  • omegX

“多来.ME”后续拟在以下方面进一步完善:

  • 采用StartSSL免费证书,实现HTTPS访问;
  • 添加相关文章链接插件;

更多介绍请点击:关于多来.ME