如何审核我的 Windows 应用程序以进行正确的 Unicode 处理?

Posted

技术标签:

【中文标题】如何审核我的 Windows 应用程序以进行正确的 Unicode 处理?【英文标题】:How can I audit my Windows application for correct Unicode handling? 【发布时间】:2011-06-20 15:42:08 【问题描述】:

我不能使用预打包的 Unicode 字符串库,例如 ICU,因为它们会将二进制文件的大小扩大到疯狂的程度(这是一个 200k 的程序;ICU 是 16MB+!)。

我已经对所有内容使用了内置的 wchar_t 字符串类型,但我想确保在对字符串进行迭代或类似的事情方面我不会做任何愚蠢的事情。

是否有像 Fuzzers 这样的工具用于安全性但用于 Unicode?也就是说,在我的代码中抛出基本多语言平面之外的字符,并确保将事情正确处理为 UTF-16?

(哦,显然跨平台解决方案是可行的,尽管大多数跨平台的东西必须同时支持 UTF-8 和 UTF-16)

编辑:还要注意比 UTF-16 代理对不太明显的东西——比如重音符号!

【问题讨论】:

+1 好问题。请注意:wchar_t 根本不暗示您正在使用 Unicode。 wprintf 之类的函数并不能真正正确地处理 Unicode,您实际上必须确保您的字符串操作考虑到具有多个代码点的字符。事实上,我认为(虽然我不是 100% 确定)像 wcsstr 这样的函数 正确处理 U+0000FFFF 以上的字符,因为它们只是处理字符串就像使用固定长度编码一样。 @Mehrdad:在几乎每个 Windows 编译器上,wchar_t 表示 UTF-16。标准没有要求,但是所有的 windows API 函数都是这样写的。 @Mehrdad:wcsstr 不需要更新以处理大于 U+FFFF 的字符。简单的按字节比较就可以了(这是 UTF-8 和 UTF-16 的优点之一)。当您想要进行排序等操作时,事情会变得更加复杂。 @DeadMG: 1. 因为我的很多用户都在拨号。 2. 因为这个东西每月被下载(作为 ComboFix 的一部分)大约 400 万次,而我(嗯,我的朋友们)正在为带宽付费。 @Kerrek: 1. wcslen 不是 Windows API 函数。 2. wcslen 从未声称要进行代码点解码。正如strlenUTF-8 的打印字符数毫无价值一样,wcslen 对于 UTF-16 而言毫无价值。即使你让它足够聪明地处理代理对,你仍然不会有一个真正的字符数,因为像重音符号这样的东西是完整的代码点,但对单个字符有贡献。 3. 除了wcslenwcschr,我不知道UTF-16 会破坏任何wcsXxx 函数的问题。 【参考方案1】:

错误的答案

使用WM_UNICHAR,它处理UTF-32并且可以处理Unicode Supplementary Plane字符。

虽然这几乎是真的,但完整的事实看起来像这样:

    WM_UNICHAR 是为 ANSI Windows 设计的用于接收 Unicode 字符的 hack。创建一个 Unicode 窗口,您将永远不会收到它。 创建一个 ANSI 窗口,您会惊讶地发现它仍然不能按预期工作。需要注意的是,当创建窗口时,您会收到带有0xffffWM_UNICHAR,您必须通过返回1 做出反应(默认窗口过程将返回0)。如果不这样做,您将永远不会再看到WM_UNICHAR。干得好,官方文档没有告诉你。 在一个出于神秘原因不支持WM_UNICHAR 的系统(例如我的 Windows 7 64 系统)上运行您的程序,即使您正确执行所有操作,它仍然无法运行。

理论上正确答案

没有什么需要审计或注意的。

在定义UNICODE 的情况下编译,或使用“W”函数显式创建窗口类和窗口,并使用WM_CHAR,就好像这是最自然的事情一样。就是这样。这确实是最自然的事情。

WM_CHAR 使用 UTF-16(除非它不使用,例如在 Windows 2000 下)。当然,单个 UTF-16 字符不能表示 BMP 之外的代码点,但这不是问题,因为您只需得到 两个 WM_CHAR 包含代理对的消息。它对您的应用程序完全透明,您不需要做任何特别的事情。任何接受宽字符串的 Windows API 函数也很乐意接受这些代理项。 唯一需要注意的是,现在字符串的字符长度(显然)不再只是 16 位字的数量。但无论如何,这是一个错误的假设。

悲伤的真相

实际上,在许多(大多数?全部?)系统上,您只会收到一条带有wParamWM_CHAR 消息,其中包含密钥代码的低16 位。这对于 BMP 中的任何东西都很好,但在其他方面很糟糕。

我已经通过使用 Alt 键盘代码和创建自定义键盘布局来验证这一点,该布局在 BMP 之外生成代码点。无论哪种情况,都只会收到一个WM_CHAR,其中包含字符的低16 位。高 16 位被简单地丢弃。

为了让您的程序在 Unicode 上 100% 正确运行,您显然必须使用输入法管理器 (ImmGetCompositionStringW),这很麻烦,而且文档记录不充分。就我个人而言,这只是意味着:“好吧,搞砸了”。但是,如果您对 100% 正确感兴趣,请查看使用 Scintilla (link to line) 的任何编辑器的源代码,它可以完美地做到这一点。

【讨论】:

【参考方案2】:

需要检查的一些事项:

确保您处理的是WM_UNICHAR,而不是WM_CHAR

WM_UNICHAR 消息与WM_CHAR 相同,但它使用 UTF-32。它旨在将 Unicode 字符发送或发布到 ANSI 窗口,它可以处理 Unicode 补充平面字符

不要假设第 ith 字符位于索引 i。显然不是,如果你碰巧使用这个事实,比如说,把一根绳子分成两半,那么你可能会把它搞砸了。

不要仅仅因为字符数组的长度为 N,就告诉用户(在状态栏或其他地方)用户有 N 个字符。

【讨论】:

@Billy:查看我的编辑。 (有些东西告诉我,当 Windows 说“UTF-16”时,它并不总是意味着“UTF-16”......) @Mehrdad:啊——我现在明白了。 WM_CHAR 传递了一个 wchar_t,因此无法传递代理对。 (我在考虑字符串,但如果你传递单个代码点是有道理的) @Billy:是的,但问题是如果它只通过一个wchar_t,那么它就不是真正的UTF-16,不是吗?... @Mehrdad:它仍然可以是 UTF-16 并且是单个字符。它只是装箱到一个字符。我想这也和UCS-2一样,但不一定是系统本身的限制,只是他们只为返回结构中的字符分配了2个字节。 @Billy:我明白你的意思,但是对于最终用户(和开发人员)来说,这系统的限制,不是吗?跨度>

以上是关于如何审核我的 Windows 应用程序以进行正确的 Unicode 处理?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Facebook sdk 开发/测试 android 应用程序 - 而我的应用程序尚未完成且尚未准备好进行审核?

如何模拟 Windows 关机以进行调试?

如何使用 WordPress 配置 Windows Azure 以进行 URL 重写?

问题:需要登录凭据以进行应用审核

需要有关 SQL 查询以进行评论审核的帮助

如何操纵我的审计项目以在 Spring Boot 中持续存在