文档章节

忽视数值类型的长度范围而造成的问题代码

yhchinabest
 yhchinabest
发布于 2019/10/23 23:34
字数 893
阅读 459
收藏 2

在日常编程中,我们可能经常简单的处理不同数值类型,而忽视其能表示的长度范围,比如int和long,我们可能经常将这两种类型混用,然后遇到编译报错,就用强制转换来应付。但通过我最近遇到的两个代码所暴露出的问题,发现这种做法是不严谨的。

首先看代码1(java代码),某广泛使用的即时通讯SDK所声明的接口

    // 返回第i个元素
	public TIMElem getElement(int i) {
	   // 实现代码省略
    }

	// 返回元素的个数
    public long getElementCount() {
	   // 实现代码省略
    }



这段代码的问题在于:取元素时下标的数值范围和元素数组的长度不一致,我们知道在java中,int表示的范围是-2^31~2^31-1,long的范围式-2^63~2^63-1,那么如果元素个数大于int能表示的最大值,则 getElement是无法取到所有的元素的。那么sdk的demo是怎么使用这个接口的呢?

       List<MessageInfo> list = new ArrayList<>();
        for (int i = 0; i < timMessage.getElementCount(); i++) {
            final MessageInfo msgInfo = new MessageInfo();
            if (ele2MessageInfo(msgInfo, timMessage, timMessage.getElement(i), isGroup) != null) {
                list.add(msgInfo);
            }
        }




这段代码的问题在于,如果getElementCount()的值大于int的最大值,即2^31-1(虽然实际情况不可能出现这样的场景),则getElement的参数会为负数,很可能造成异常。

再看看第二个问题的代码,也是java代码

   class XXXItem implements Comparable{
    // 成员变量,long类型
    private long mTime;
	
	public long getTime() {
        return mTime;
    }
	
    // 实现了一个用于比较大小的接口
	@Override
    public int compareTo(@NonNull XXXItem item) {
        return (int) (item.getTime() - this.getTime());
    }
   }




Comparable的用法,熟悉java的人应该都比较清楚。这里的问题就是出在compareTo上,getTime()返回值是long类型,两个long类型相减,并将结果强制转换为int,可能会造成溢出,从而违背该代码的本来初衷。其实java标准库中的Long类已经给出了比较long的方法,,可以直接调用,它实现的也很简洁。

    public final class Long extends Number implements Comparable<Long> {
	    public static int compare(long x, long y) {
        	return (x < y) ? -1 : ((x == y) ? 0 : 1);
    	}
	}




思考

关于溢出造成的不安全代码并不罕见,在《深入理解计算机系统》这本书中的2.3节就有介绍,里面还举例了FreeBSD的代码库中就曾经存在这种存在安全隐患的代码。我觉得出现这种问题的本质还是因为:计算机科学家在设计补码这种数值表示方式时,是允许溢出这种现象存在的,有些程序逻辑甚至需要溢出来实现,但程序员在开发时,忽略了溢出的存在,而仅凭直觉去写代码,从而造成了这种隐患。因此我觉得我们在日常写代码时要注意:

  1. 设计接口时,相同事物返回值的类型要一致。
  2. 不同类型数值进行比较操作或者进行强制转换赋值时,要格外小心,思考是否会有溢出的情况出现。

© 著作权归作者所有

yhchinabest
粉丝 3
博文 50
码字总数 13606
作品 0
武汉
高级程序员
私信 提问
加载中

评论(0)

智能合约bug是以太坊的缺陷?不用SafeMath就会溢出?别闹!

关于智能合约的溢出攻击,我遇到了多次这样的诘问:没有用SafeMath,难道你不怕溢出攻击吗?每次面对这样的问题,我的内心是这样的: 先来看一下以太坊官方文档是如何介绍TOKEN的智能合约: 地...

李万胜
2018/05/16
0
0
2Python全栈之路系列之MysQl基本数据类型

Python全栈之路系列之MySQL基本数据类型 MySQL中定义数据字段的类型对你数据库的优化是非常重要的。 MySQL支持多种类型,大致可以分为三类: 数字类型 日期和时间类型 字符串类型 数字类型 ...

Edenwy
2017/05/15
0
0
Hadoop序列化与Writable接口(二)

上一篇文章Hadoop序列化与Writable接口(一)介绍了Hadoop序列化,Hadoop Writable接口以及如何定制自己的Writable类,在本文中我们继续Hadoop Writable类的介绍,这一次我们关注的是Writabl...

pczhangtl
2013/11/21
1.7K
0
Mysql学习笔记之常用数据类型

数据类型是定义列中可以存储什么数据以及该数据实际怎么存储的基本规则。Mysql的常用数据类型主要有: 串数据类型:最常用的数据类型,有两种基本的串类型:分别为定长串和不定长串。定长串结...

Sem怪怪
2015/07/23
69
0
MySQL数据类型介绍

MySQL数据类型介绍 一、数据类型 MySQL支持多种数据类型,主要有数值类型、日期/时间类型和字符串类型。 数值数据类型 整数类型: TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT 浮点数类型:F...

持续高温
2018/01/07
0
0

没有更多内容

加载失败,请刷新页面

加载更多

00-Java 面试准备

面试之前 面试前准备简历需要注意的几个方面: 写简历、改简历,这个一定要干的。简历有两个作用,一个是吸引别人,能让别人邀请你去面试,这是前提;另一个是引导面试的人,让面试的人问你所...

源程序
今天
54
0
OSChina 周二乱弹 —— 大王(@罗马的王)颜值制霸Osc社区

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 @巴拉迪维 :Lunik的单曲《Seeing You Soar》 I hope you’re smiling,When seeing me soar. #今日歌曲推荐# 《Seeing You Soar》- Lunik 手...

小小编辑
今天
75
0
wordcount代码

1.写出map类 public class WCMapper extends Mapper<LongWritable,Text,Text,LongWritable>{ @Override protected void map(LongWritable key,Text value,Context context)throws IOExcepti......

七宝1
今天
59
0
Spring Batch 小任务(Tasklet)步骤

Chunk-Oriented Processing不是处理 step 的唯一方法。 考虑下面的一个场景,如果你仅仅需要调用一个存储过程,你可以在 ItemReader 中实现这个调用,然后在存储过程完成调用后返回 null。这...

honeymoose
今天
67
0
Linux日志分析

1. Linux日志文件的类型 2. 系统服务日志 2.1 syslogd的简介 2.2 syslogd的配置和使用 2.3 日志的安全性设置 2.4 远程日志记录服务 3. 日志的轮替 3.1 logrotate简介 3.2 logrotate的配置 3....

JiaMing
昨天
67
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部