sscanf linux内核不同于sscanf glibc

sscanf linux内核不同于sscanf glibc,c,linux-kernel,glibc,scanf,format-string,C,Linux Kernel,Glibc,Scanf,Format String,在我的计算机上运行以下代码(make runtest)(4.6.4-1-ARCH) 基本上,使用sscanf和一系列%2hhx格式说明符将ffffffffffffffffffffffffff读取到fp。之后,它使用printf/printk和一系列%2.2hhx格式说明符打印fp 有人能解释一下为什么用和阅读时,fp不一样吗。此外,为什么aabb-测试工作正常 我已经检查了激励,从我所能看到的来看,它应该类似于 我确实觉得我忽略了这里显而易见的东西 注: 可以找到包含Makefile的要点

在我的计算机上运行以下代码(
make runtest
)(
4.6.4-1-ARCH

基本上,使用
sscanf
和一系列
%2hhx
格式说明符将
ffffffffffffffffffffffffff
读取到
fp
。之后,它使用
printf
/
printk
和一系列
%2.2hhx
格式说明符打印
fp

有人能解释一下为什么用和阅读时,
fp
不一样吗。此外,为什么
aabb
-测试工作正常

我已经检查了激励,从我所能看到的来看,它应该类似于

我确实觉得我忽略了这里显而易见的东西


注:

  • 可以找到包含Makefile的要点
  • 这只是一个例子,请不要告诉我这是一个丑陋的实现。甚至有24个无效读取!谢谢,我知道

请将代码包括在问题中,而不仅仅是通过Github中的要点。粗略地看一下代码:内核有一种奇怪的扫描字符串的方式。它将尽可能多地转换字符串,忽略字段宽度(即使结果溢出),然后查看字段宽度并备份字符串指针适当数量的字符,同时每次备份指针时将结果除以基数(此处为16)。所以我怀疑那些备份和分区正在将最初的几个结果缩减为0,直到要分析的字符串足够小而不会溢出为止。解决方法:不要给内核sscanf一个会溢出64位数字的数字字符串。@MarkPlotnick我想内核的vsscanf实现真正需要的是一些最大字段宽度感知整数解析函数@IanAbbott,内核中的
vscanf()
对于我们所拥有的任务来说是很小很好的。否则,大多数可能使用大数字操作的代码通常使用
kstrto*()
或类似方法解析输入。
/* scanf userland & kernelspace test */

#if __KERNEL__

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>

MODULE_AUTHOR("Enteee (duckpond.ch) ");
MODULE_DESCRIPTION("scanf test");
MODULE_LICENSE("GPL");
MODULE_ALIAS("scanf_test");

#else

#include <stdio.h>
#include <string.h>
#define printk printf

#endif

void test(void){
    int ret = 0;
    char fp[20] = { 0 };

    memset(fp, 0xaa, sizeof(fp));
    printk("init, ret = %d fp = "
            "%2.2hhx%2.2hhx%2.2hhx%2.2hhx%2.2hhx%2.2hhx"
            "%2.2hhx%2.2hhx%2.2hhx%2.2hhx%2.2hhx%2.2hhx"
            "%2.2hhx%2.2hhx%2.2hhx%2.2hhx%2.2hhx%2.2hhx"
            "%2.2hhx%2.2hhx, "
            // overflow prints (hacky)
            "after fp = "
            "%2.2hhx%2.2hhx%2.2hhx%2.2hhx%2.2hhx%2.2hhx, "
            "before fp = "
            "%2.2hhx%2.2hhx%2.2hhx%2.2hhx%2.2hhx%2.2hhx"
            "\n",
            ret,
            (fp)[0],  (fp)[1],  (fp)[2],  (fp)[3],  (fp)[4],  (fp)[5],
            (fp)[6],  (fp)[7],  (fp)[8],  (fp)[9],  (fp)[10], (fp)[11],
            (fp)[12], (fp)[13], (fp)[14], (fp)[15], (fp)[16], (fp)[17],
            (fp)[18], (fp)[19],
            // overflow
            (fp)[20], (fp)[21], (fp)[22], (fp)[23], (fp)[24], (fp)[25],
            (fp)[-1], (fp)[-2], (fp)[-3], (fp)[-4], (fp)[-5], (fp)[-6]
          );

    ret = sscanf("aabb", "%2hhx%2hhx", &fp[0], &fp[1]);
    printk("ret = %d fp = %2.2hhx%2.2hhx\n", ret, fp[0], fp[1]);

    ret = sscanf(
            "ffffffffffffffffffffffffffffffffffffffff", 
            "%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx"
            "%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx"
            "%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx"
            "%2hhx%2hhx",
            &(fp)[0],  &(fp)[1],  &(fp)[2],  &(fp)[3],  &(fp)[4],  &(fp)[5],
            &(fp)[6],  &(fp)[7],  &(fp)[8],  &(fp)[9],  &(fp)[10], &(fp)[11],
            &(fp)[12], &(fp)[13], &(fp)[14], &(fp)[15], &(fp)[16], &(fp)[17],
            &(fp)[18], &(fp)[19]
            );

    printk("ret = %d fp = "
            "%2.2hhx%2.2hhx%2.2hhx%2.2hhx%2.2hhx%2.2hhx"
            "%2.2hhx%2.2hhx%2.2hhx%2.2hhx%2.2hhx%2.2hhx"
            "%2.2hhx%2.2hhx%2.2hhx%2.2hhx%2.2hhx%2.2hhx"
            "%2.2hhx%2.2hhx, "
            // overflow prints (hacky)
            "after fp = "
            "%2.2hhx%2.2hhx%2.2hhx%2.2hhx%2.2hhx%2.2hhx, "
            "before fp = "
            "%2.2hhx%2.2hhx%2.2hhx%2.2hhx%2.2hhx%2.2hhx"
            "\n",
            ret,
            (fp)[0],  (fp)[1],  (fp)[2],  (fp)[3],  (fp)[4],  (fp)[5],
            (fp)[6],  (fp)[7],  (fp)[8],  (fp)[9],  (fp)[10], (fp)[11],
            (fp)[12], (fp)[13], (fp)[14], (fp)[15], (fp)[16], (fp)[17],
            (fp)[18], (fp)[19],
            (fp)[20], (fp)[21], (fp)[22], (fp)[23], (fp)[24], (fp)[25],
            (fp)[-1], (fp)[-2], (fp)[-3], (fp)[-4], (fp)[-5], (fp)[-6]
          );
}

#ifndef __KERNEL__

int main(void){
    test();
    return 0;
}

#else

static int __init test_init(void) {
    test();
    return 0;
}

static void __exit test_exit(void) {
}

module_init(test_init);
module_exit(test_exit);

#endif
=== user space ===
init, ret = 0 fp = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, after fp = 65005f5f7664, before fp = 000000000000
ret = 2 fp = aabb
ret = 20 fp = ffffffffffffffffffffffffffffffffffffffff, after fp = 65005f5f7664, before fp = 000000000000
=== kernel space ===
[386177.161037] init, ret = 0 fp = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, after fp = baae0dbc0000, before fp = bc0daebaffff
[386177.161044] ret = 2 fp = aabb
[386177.161061] ret = 20 fp = 000000000000000000000000ffffffffffffffff, after fp = baae0dbc0000, before fp = bc0daebaffff