多字节语言环境中glibc的printf截断错误的解决方法?

时间:2014-08-18 22:56:57

标签: c utf-8 printf glibc

某些基于GNU的操作系统发行版(Debian)仍然受到GNU libc中的错误的影响,该错误会导致printf系列函数在指定的精度级别截断时导致伪造-1多字节字符。此错误已在2.17中修复,并向后移植到2.16。 Debian has an archived bug为此,但维护者似乎无意将修复程序向后移植到Wheezy使用的2.13。

以下文字引自https://sourceware.org/bugzilla/show_bug.cgi?id=6530。 (请不要再编辑内联引用的块。)

  

这是Jonathan Nieder提供的更简单的测试用例:

#include <stdio.h>
#include <locale.h>

int main(void)
{
    int n;

    setlocale(LC_CTYPE, "");
    n = printf("%.11s\n", "Author: \277");
    perror("printf");
    fprintf(stderr, "return value: %d\n", n);
    return 0;
}
  

在C语言环境下,做正确的事情:

$ LANG=C ./test
Author: &#65533;
printf: Success
return value: 10
  

但不是在UTF-8语言环境下,因为\277不是有效的UTF-8序列:

$ LANG=en_US.utf8 ./test
printf: Invalid or incomplete multibyte or wide character

值得注意的是,printf也会在此上下文中用\0覆盖输出数组的第一个字符。

我目前正在尝试改造MUD代码库以支持UTF-8,不幸的是,代码中充斥着使用任意sprintf精度来限制将多少文本发送到输出缓冲区的情况。大多数程序员都不希望在此上下文中发生-1返回,这可能会导致未初始化的内存读取和从内存中流失的错误,从而使问题更加严重。 。 (已经在 valgrind 中发现了一些案例)

有没有人在他们的代码中为这个错误提出了一个简明的解决方法,它不涉及重写每个调用任意长度精度的格式化字符串?我很好地将截断的UTF-8字符写入我的输出缓冲区,因为在套接字写入之前在输出处理中清除它是相当微不足道的,并且将这么多努力付诸实践似乎有点过头了。这个问题最终会在几年后消失。

1 个答案:

答案 0 :(得分:1)

我猜测,这个问题的评论似乎证实了你没有充分利用C库的语言环境特定功能。在这种情况下,最好不要将语言环境更改为基于UTF-8的语言环境,并将其保留在代码假定的单字节语言环境中。

当您需要将UTF-8字符串作为UTF-8字符串处理时,您可以使用专门的代码。编写自己的UTF-8处理例程并不难。您甚至可以下载Unicode Character Database并进行一些相当复杂的字符分类。如果您更喜欢使用第三方库来处理UTF-8字符串,那么就像您在评论中提到的那样ICU。它是一个相当重量级的图书馆,之前的问题推荐了一些lighter weight alternatives

也可以根据需要来回切换C语言环境,以便您可以使用C库的功能。但是,您要检查这对性能的影响,因为切换区域设置可能是一项昂贵的操作。