C语言类型转换(type conversions in C)

java/C++这类语言对类型的要求非常严格,但是C语言对类型几乎没什么限制.

它可以非常灵活的处理不同类型之间的转换.

正因为它的这种灵活性,也导致了程序员在使用各种混合的数据类型时,并不关心这些类型混用带来的危害.

往往这些细节引起大量软件漏洞.降低了软件的安全性,而且使维护成本增高.

这也是C语言编写的程序饱受诟病的原因之一吧.


先说说整数类型转换情况:

0.从一个窄的无符号类型,转换到一个宽的有符号类型.值保留不会改变.( 比如 unsigned short --> int )

      这个很简单,因为更宽的有符号类型总能容纳下比它窄的类型.哪怕是无符号数.

1.从一个窄的有符号类型,转换到一个宽的无符号类型.编译器进行符号拓展(movsx).有可能发生值改变.( 比如char -->unsigned short)

C语言类型转换(type conversions in C)_第1张图片

2.从一个窄的有符号类型,转换到一个宽的有符号类型.编译器进行符号拓展(movsx).转换后的值保留,不会改变.(比如short -->int)

           C语言类型转换(type conversions in C)_第2张图片

3.从一个窄的无符号类型,转换到一个宽的无符号类型.编译器进行零拓展(movzx).转换后的值保留,不会改变.( 比如unsigned short -->unsigned int )

        这个学过汇编的都知道.一条movzx指令就搞定了.

4.从一个宽类型,转换到一个窄类型.编译器进行截断.有可能发生值改变.( 比如unsigned short -->unsigned char )

C语言类型转换(type conversions in C)_第3张图片

5.在无符号类型无符号类型之间转换时.他们的bit位的模式是一致的.但是有可能发生值改变.( 比如unsigned short -->short )

                   C语言类型转换(type conversions in C)_第4张图片


下面看一段有脆弱点的代码:

int read_user_data(int sockfd)
{
    int length, sockfd, n;
    char buffer[1024];

    length = get_user_length(sockfd);

    if(length > 1024){
        error("illegal input, not enough room in buffer\n");
        return 1;
    }

    if(read(sockfd, buffer, length) < 0){
        error("read: %m");
        return 1;
    }

    return 0;
}

首先get_user_length()函数从用户指定的socket取得用户数据的大小并且返回一个int类型的length.

然后根据返回的length调用read函数.读取用户数据.

注意,这里发生了一次类型转换.

length是int型.read函数原型是#include ssize_t read(int fd, void *buf, size_t count).(size_t在32位机器上定义为unsigned int)

所以这里length由singed int 转换到了 unsigned int.

但是如果用户给了一个为负值的长度.

那么read函数将读取一块很大的内存.也就产生了任意读取的bug.




你可能感兴趣的:(c,socket,user,buffer,语言,编译器)