C神秘溢出

时间:2016-11-21 03:57:17

标签: c buffer-overflow

为什么这段代码输出-32768而不是32768?看起来像溢出但我无法弄清楚在哪里。

#include <stdio.h>
#include <stdlib.h>
int main()
{
    char *buffer = (char*)malloc(sizeof(char)*2);
    buffer[0] = 0x80;
    buffer[1] = 0x00;
    int address = (buffer[0]<<8) | (buffer[1]);
    printf("%d\n", address); //outputs -32768
    return 0;
}

2 个答案:

答案 0 :(得分:1)

在您的编译器上char已签名。

在您的编译器上,0x80已转换为-0x80以适合签名的char

因此buffer[0]保留-128,((-128)<<8) | (0)评估为-32768。

答案 1 :(得分:0)

此代码可以通过多种方式执行。

  • 编译器上的char都是无符号的。然后表达式将被评估为0x80<<8 | 0x00,其中0x8000。如果这适合您系统中的int,则结果将为32768.否则,它将以某种实现定义的方式转换为签名格式。在二进制补码计算机上,您可能会得到结果-32768。

  • char已在您的编译器上签名。然后0x80不适合它,但是以某种实现定义的方式转换为负数。在二进制补码计算机上,它可能会得到-128的值。然后你左移这个负值 - 这会调用未定义的行为(来源:C11 6.5.7 / 4)。这反过来可能导致任何事情发生:您的程序可能崩溃或打印废话,或者您的编译器可能存在某些特定的非标准行为,例如将结果视为-32768。

这里的关键是你不应该写这样的代码,它依赖于许多形式的指定不当的行为。这是不好的做法。之所以你最终得到这个,是因为你使用的是charint之类的原生数据类型,这些数据类型指定不当,因此很难用于位操作。

您的代码应该被修复为安全的东西,无论系统或编译器如何,都会给出确定的结果:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>

int main()
{
    uint8_t *buffer = malloc( sizeof(uint8_t[2]) );
    buffer[0] = 0x80;
    buffer[1] = 0x00;
    uint16_t address = ((uint16_t)buffer[0]<<8) | (buffer[1]);
    printf("%" PRIu16 "\n", address);
    free(buffer);
    return 0;
}