上周游戏突发一个严重的漏洞,玩家通过在聊天世界频道发送€符号,会导致接下来发言的玩家看到的内容混乱,这种捣乱的行为,我立即去查了一下,发现这是引擎在处理字符编码时的一个错误导致的,这个错误非常隐蔽,以至于我也是开始的时候看上去一切非常正常。
错误是这样出现的,首先程序采用多字符集,即ANSI编码,在多字符编码下,用单字节表示英文编码,用两个字节表示非英文编码,程序中为了显示一段文字,先要判断这个字符时一个单字节的英文还是多字节汉字的第一个字符。
程序是这样判断的,假设到来的字符是 char c,如果c>0就是英文字符,否则就是汉字的第一个。因为引擎认为 0X00<c<0X80 范围是标准ASC2表示的英文字符,而汉字字符的首位采用0X80以上的。乍一看起来没问题啊,可是问题就在这个临界的0X80上,ansi编码的标准上说,用0X80-0Xff之间的字节表示多字节的字符,也就是说其实0X80和0Xff这两个字符还是单字节的英文字符,所以使用0X00<c<0X80 显然遗漏了0X80和0Xff,引擎错误的把0X80和0XfF当成了双字节的第一个。而0X80正代表的英文字符€。
其实我觉得可能很多人会这样写代码,就用char c,>0判断英文字符,其实VC为我们提供了一个良好的接口用来判断多字符编码下某个字节是否为一个多字节字符的前驱(即不是单字节英文字符),IsDBCSLeadByte(),用它就可以很好的解决问题。
如果想看看你的代码里有没有这种问题,输入一个€看看显示是否正常就知道了。