【数值溢出】从二进制的角度看数值溢出
编程语言中的数字数据类型都预设了大小,也就是说,一个数字数据类型的变量,总会有能表达的上限,有上限就会有溢出。本篇从二进制的底层,分析解释一下数值溢出问题。以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);
//上述代码输出-128int a=129;
byte b=(byte) a;
System.out.println(b);
//上述代码输出-127int a=383;
byte b=(byte) a;
System.out.println(b);
//上述代码输出127int a=384;
byte b=(byte) a;
System.out.println(b);
//上述代码输出-128int 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}
}
- 数值溢出也算是一个很经典的漏洞,如果有数值溢出点,经过攻击者精心的构造利用,可能会造成巨大的损失。具体数值溢出漏洞利用,可以参考:整型溢出漏洞
随时注意数据类型范围很重要哦~~~
【数值溢出】从二进制的角度看数值溢出相关推荐
- ES6-11数值扩展:二进制和八进制、数值分隔符、Number.isFinite()、Number.isNaN()等
1. 二进制和八进制 用前缀0b(或0B)和0o(或0O)表示. 0b111110111 === 503 // true 0o767 === 503 // true// 非严格模式 (function ...
- 汇川plc可以用C语言吗,汇川小型PLC梯形图编程系列教程(七):数值存储与二进制数据知识详解...
PLC数据存储原理简介 H123U小型PLC内部采用的是32位的处理器,PLC中的数据处理和电脑中的数据处理基本是一致的.所有的CPU进行数据处理时,都是将其他进制的数据转换成二进制数进行加减乘除运算 ...
- 汇川小型PLC梯形图编程系列教程(七):数值存储与二进制数据知识详解
原文链接:汇川小型PLC梯形图编程系列教程(七):数值存储与二进制数据知识详解 PLC数据存储原理简介 H123U小型PLC内部采用的是32位的处理器,PLC中的数据处理和电脑中的数据处理基本是一致的 ...
- 运行时错误7内存溢出_分别从运行时和GC的角度看JAVA8内存管理
运行时区域 1.程序计数器 程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器.在虚拟机概念模型里(概念模型,各种虚拟机 ...
- 一个数值转化为二进制 位运算和位域
在嵌入式系统和单片机开发中,数值转化为二进制是非常常用的,对与位域可能很多上层开发人员都 不曾见到,位域在MCU开发中常用的使用的,例如一个开关量和高低电平信号,只用0和1两种状态. 下面是我做项目时 ...
- 从JDK源码角度看Long
概况 Java的Long类主要的作用就是对基本类型long进行封装,提供了一些处理long类型的方法,比如long到String类型的转换方法或String类型到long类型的转换方法,当然也包含与其 ...
- go conn 读取byte数组后是否要_【技术推荐】正向角度看Go逆向
Go语言具有开发效率高,运行速度快,跨平台等优点,因此正越来越多的被攻击者所使用,其生成的是可直接运行的二进制文件,因此对它的分析类似于普通C语言可执行文件分析,但是又有所不同,本文将会使用正向与逆向 ...
- 【技术推荐】正向角度看Go逆向
Go语言具有开发效率高,运行速度快,跨平台等优点,因此正越来越多的被攻击者所使用,其生成的是可直接运行的二进制文件,因此对它的分析类似于普通C语言可执行文件分析,但是又有所不同,本文将会使用正向与逆向 ...
- 一般向量空间的基变换_从希尔伯特空间的角度看线性变换的一般思想和问题
一般线性变换以及傅里叶变换,欧氏变换,仿射变换,余弦变换,小波变换,拉普拉斯变换,Z变换,希尔伯特变换等等这些所谓的变换太多了,这些到底搞得是什么?怎么像云像雾又像风呢?怎么才能彻底理解它们?它们究竟 ...
最新文章
- Express2.X迁移至3.X注意事项
- Django框架之DRF get post put delete 使用简单示例 (利用序列化反序列化)
- 算法题007 计算n的阶乘
- 批量部署虚拟机实战解析
- java依赖注入_Java依赖注入选项
- Java Swing/AWT和GTK混合GUI编程
- java处理json的工具类(list,map和json的之间的转换)
- R和Tableau平行坐标图
- python:查看函数方法的具体信息、参数等
- SpringBoot整合调用微信模板方法实现微信公众号消息通知推送,Java实现微信公众号给关注用户推送自定义消息通知(手把手从0到1)
- 电信 dns服务器 不稳定,网速不稳定的解决方法:修改本地DNS
- 于歆杰pdf 电路原理_buck电路原理(于歆杰 电路原理pdf)
- iOS仿苹果原生天气app总结
- 微信开发工具出现 [渲染层网络层错误]
- ListNode的理解
- Tomcat输出框乱码(鏈嶅姟鍣ㄥ湪[463]姣鍐呭垵濮嬪寲)
- android 仿小米相机,android-自定义相机遇小米3生成图片花屏
- 通过adb模拟快速的屏幕点击,小米手机亲测有效
- [C++]char转换为string ,固定长度的char数组转换为string
- ubuntu护眼第二大神器 Redshift