概述
编程语言中的数字数据类型都预设了大小,也就是说,一个数字数据类型的变量,总会有能表达的上限,有上限就会有溢出。本篇从二进制的底层,分析解释一下数值溢出问题。以byte为例。
0x01.问题引入
- 看如下一段Java代码,你能立马说出输出结果吗?
public class Main {
public static void main(String[] args) {
int a=1888;
byte b=(byte) a;
System.out.println(b);
}
}
- 或许你只能意识到:反正不是1888,反正不会超过byte能表示的数据范围。
- 赶紧把代码复制下来编译运行一下,一看输出结果:
96
。 - 为什么会是96呢?
- 清楚这个之前,我们不妨去探究一下,底层都干了些什么。
0x02.byte能表示的数据范围
-
我们都知道,byte能表示的数据范围是:
-128-127
,但是,为什么是这个范围呢? -
原因:在Java中,对于byte类型的变量,JVM会为其分配一个字节的内存,一个字节也就是8位,但是由于最高位是符号位,所以能够表示的数据范围就是
-2^7 --2^7-1
。原码,反码,补码知识补充:- 原码:最高位为符号位,“0”表示正,“1”表示负,其余位表示数值的大小。
- 反码:正数的反码与其原码相同;负数的反码是对其原码逐位取反,符号位除外。
- 补码:正数的补码与其原码相同;负数的补码是在其反码的末位加1(负数的补码是其绝对值取反)。
- 在计算机中,用补码表示二进制数。
-
范围可视化:
- 其它数值数据类型的范围,跟byte范围的计算,一模一样。
0x03.byte的溢出原理
- 回到最初的例子,我们看一下那个转换的过程都发生了什么。
- int类型变量占4个字节的内存,也就是32位,所以它能表示的数据范围是:
-2^31--2^31-1
。 - 那么a变量在内存中的表示,是这样吗?
- 必然不是,因为上面说到,一个int类型的变量,占了32位,那么完整的形式应该是:
- 而此时一个未初始化的byte变量b在内存中应该是:
- 此时如果进行强制类型转换
b=(byte)a
,int类型变量的低8位会给byte,然后int其它位的数据就会丢失。如下:
- 这也正好解释了最初b的输出问题。
0x04.快速计算溢出后的值
- 使用二进制去理解原理固然清晰,但是如果都转到二进制计算的话,肯定是会比较复杂的。
- 我们不如看下它的转换规律:
int a=128;
byte b=(byte) a;
System.out.println(b);
//上述代码输出-128
int a=129;
byte b=(byte) a;
System.out.println(b);
//上述代码输出-127
int a=383;
byte b=(byte) a;
System.out.println(b);
//上述代码输出127
int a=384;
byte b=(byte) a;
System.out.println(b);
//上述代码输出-128
int a=-129;
byte b=(byte) a;
System.out.println(b);
//上述代码输出127
- 不难发现,随着int的增大,byte转换后的值都在一个循环内。如下:
-
可以这样看这个图,在byte范围内
127+1=-128
,-128-1=127
。 -
那么整个的计算可以总结为:
-
若a>127,上界溢出,顺时针循环,那么强转成byte后,若以0为起点,对256取余得到的值,就是在这个圈中从0开始往右走了多少。例如:1888,对256取余得96,相当于从0向右走了96,所以最后的值就是96。1920,对256取余得128,相当于从0向右走了128,所以最后的值就是-128。
-
若a<-128,下界溢出,逆时针循环,那么强转成byte后,若以0为起点,对256取余得到的值,就是在这个圈中从0开始往左走了多少。例如:-385,对256取余得129,相当于从0开始向左走了129,所以最后的值就是127。依次类推。
-
-
只要记住循环圆,计算还是比较简单的。
0x05.推广到所有数值类型的溢出
- byte的溢出是一个数值溢出的典型例子,其它数值类型因为表示的范围比较大,发生溢出的情况比较少,不过其所有溢出的原理和byte类型一模一样。
- int类型溢出的例子:
public class Main {
public static void main(String[] args) {
System.out.println(Integer.MAX_VALUE+1==Integer.MIN_VALUE);
//输出true
}
}
- 数值溢出也算是一个很经典的漏洞,如果有数值溢出点,经过攻击者精心的构造利用,可能会造成巨大的损失。具体数值溢出漏洞利用,可以参考:整型溢出漏洞
随时注意数据类型范围很重要哦~~~
最后
以上就是傻傻皮皮虾为你收集整理的【数值溢出】从二进制的角度看数值溢出0x01.问题引入0x02.byte能表示的数据范围0x03.byte的溢出原理0x04.快速计算溢出后的值0x05.推广到所有数值类型的溢出的全部内容,希望文章能够帮你解决【数值溢出】从二进制的角度看数值溢出0x01.问题引入0x02.byte能表示的数据范围0x03.byte的溢出原理0x04.快速计算溢出后的值0x05.推广到所有数值类型的溢出所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复