关注潜在的整数越界问题

这篇具有很好参考价值的文章主要介绍了关注潜在的整数越界问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在平时的开发过程中,整数越界是一个容易被忽视的问题,关注潜在的整数越界问题可使我们编写的代码更加健壮,规避因整数越界导致的 bug。

比较器

以下是在 Code Review 中发现的比较器实现:

乍一看该比较器实现不存在问题,但是如果 tag1 = Integer.MIN_VALUE = -2147483648, tag2 为大于 0 的数字如 1,则此时 tag1 - tag2 = 2147483647,但是按照 java.util.Comparator#compare 的定义,tag1 小于 tag2 时,应该返回一个负数,以上写法在遇到这样的示例数据时将导致排序结果错乱,引发相关 bug。

下面看看 Spring 中比较器的实现,在 Spring 中,提供了 @Order 注解用于指定 bean 的顺序,默认值为 Ordered.LOWEST_PRECEDENCE = Integer.MAX_VALUE,即在排序时排在最后,相关源码如下:

对应的比较器实现如下:

可知其采用的 Integer.compare 方法对两个整数进行比较操作,查看 Integer#compare 方法的源码:

/**
 * Compares two {@code int} values numerically.
 * The value returned is identical to what would be returned by:
 * <pre>
 *    Integer.valueOf(x).compareTo(Integer.valueOf(y))
 * </pre>
 *
 * @param  x the first {@code int} to compare
 * @param  y the second {@code int} to compare
 * @return the value {@code 0} if {@code x == y};
 *         a value less than {@code 0} if {@code x < y}; and
 *         a value greater than {@code 0} if {@code x > y}
 * @since 1.7
 */
public static int compare(int x, int y) {
    return (x < y) ? -1 : ((x == y) ? 0 : 1);
}

可知 java.lang.Integer#compare 并未采取 x - y 的方式进行比较,而是使用小于等于运算符直接进行比较,规避了潜在的整数越界问题。 那么文首代码正确的实现方式应为 return Integer.compare(tag1, tag2)。如果查看 JDK 中常见数值类的源码,可知均提供了静态的 compare 方法,如:java.lang.Long#compare,java.lang.Double#compare,此处不再赘述。

切量比例

以上代码是某段业务逻辑中初始切量比例实现,取余 100 的模式常用于按比例切量、按比例降级等业务场景。以上代码使用 userPin 的哈希值取余 100 判断是否小于切量比例以决定是否执行新业务逻辑,如果我们查看 java.lang.String#hashCode 的源码实现:

/**
 * Returns a hash code for this string. The hash code for a
 * {@code String} object is computed as
 * <blockquote><pre>
 * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
 * </pre></blockquote>
 * using {@code int} arithmetic, where {@code s[i]} is the
 * <i>i</i>th character of the string, {@code n} is the length of
 * the string, and {@code ^} indicates exponentiation.
 * (The hash value of the empty string is zero.)
 *
 * @return  a hash code value for this object.
 */
public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}

可知 java.lang.String#hashCode 本质上是对字符串进行 s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] 多项式求值,此处潜在的风险在于计算出的 hash 值可能越界,导致 userPin.hashCode() 返回值为负数,如:"jd_xxxxxxxxxxxx".hashCode() = -1406647067,且在 Java 语言中,使用负数对正数取余,是可能得到负数的。以上代码的风险在于潜在的放大了期望的切量比例,如使用以上的代码进行上线,那么当我们设定 1% 的切量比例时,会导致远超 1%的用户执行新的业务逻辑(通过采样日志发现用户 pin 集合 hashCode 值负数占比并不低),导致非预期的切量结果。

基于以上的背景,容易想到的一种修复方案为在 userPin.hashCode 外层使用 Math.abs 保证取余前的数字为正数:

以上修复方案看似不再存在问题,但是并不能保证完全正确,我们查看 Math.abs 的源码实现:

/**
 * Returns the absolute value of an {@code int} value.
 * If the argument is not negative, the argument is returned.
 * If the argument is negative, the negation of the argument is returned.
 *
 * <p>Note that if the argument is equal to the value of
 * {@link Integer#MIN_VALUE}, the most negative representable
 * {@code int} value, the result is that same value, which is
 * negative.
 *
 * @param   a   the argument whose absolute value is to be determined
 * @return  the absolute value of the argument.
 */
public static int abs(int a) {
    return (a < 0) ? -a : a;
}

可知在注释中特意提到,如果入参是 Integer.MIN_VALUE,即 int 域中最小的值时,返回值依然为 Integer.MIN_VALUE,因为 int 域的范围为 [-2147483648, 2147483647]。如果按照 JLS 中的解释,-x equals (~x)+1。那么可知:

x = Integer.MIN_VALUE:
10000000_00000000_00000000_00000000

~x:
01111111_11111111_11111111_11111111

(~x) + 1:
10000000_00000000_00000000_00000000

如果在神灯上搜索 Math.abs,可以发现有三篇文章与该函数有关,均与 Math.abs(Integer.MIN_VALUE) 依然为 Integer.MIN_VALUE 有关。而我们在 Code Review 阶段发现该问题即从根本上规避了该问题,不会使存在 bug 的代码上线。最后切量比例修改后的实现如下:

总结

  • java.lang.String#hashCode 在计算过程中可能因为整数越界导致返回值为负数
  • Java 语言中的 % 是取余而不是取模,如:(-21) % 4 = (-21) - (-21) / 4 *4 = -1
  • Math.abs(int a) 当入参是 Integer.MIN_VALUE 时返回值依然是负数 Integer.MIN_VALUE

参考

15.15.4. Unary Minus Operator -

What's the difference between “mod” and “remainder”? - Stack Overflow

Best way to make Java's modulus behave like it should with negative numbers? - Stack Overflow

OrderComparator.java · spring-projects/spring-framework

作者:京东物流 刘建设 张九龙 田爽

来源:京东云开发者社区 自猿其说Tech 转载请注明来源文章来源地址https://www.toymoban.com/news/detail-746747.html

到了这里,关于关注潜在的整数越界问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 需求管理全过程流程图及各阶段核心关注点详解

    分析报告指出,多达76%的项目失败是因为差劲的需求管理,这个是项目失败的最主要原因,比落后的技术、进度失控或者混乱的变更管理还要关键。 很多项目往往在开始的时候已经决定了失败,谜底就在谜面上,开始就注定的失败,你后面多努力都很难,注定背锅! 很多P

    2024年02月15日
    浏览(39)
  • 软件工程:墨菲定律,潜在问题管理的艺术

    hi,我是熵减,见字如面。 在软件开发中,你是否遇到过这种情况: 你正在开发一个新的软件,你已经完成了测试并发布了软件。然而,在用户开始使用软件之后,你开始接到了大量的错误报告。你发现用户遇到的问题并不是你测试过程中遇到的问题,这些问题可能是因为用

    2023年04月18日
    浏览(76)
  • 关于mysql数据库模糊查询的潜在问题

    初学者在学习的时候经常会写下面的模糊查询语句: 有两方面的问题,第一,我们从结果分析入手: 我们想看到的是什么,我们想看到的是蔡徐坤这个字符串能出现在我搜索的第一个位置,而不是我明明搜的蔡徐坤,蔡徐坤却出现在了最后面,前面一堆不太相干的。而之所

    2024年02月13日
    浏览(38)
  • AgentBench::AI智能体发展的潜在问题一

    从历史上看,几乎每一种新技术的广泛应用都会在带来新机遇的同时引发很多新问题,AI智能体也不例外。从目前的发展看,AI智能体的发展可能带来的新问题可能包括如下方面: 第一是它可能带来涉及个人数据、隐私,以及知识产权的法律纠纷的大幅增长。要产生一个优秀

    2024年02月12日
    浏览(37)
  • 未连接:有潜在的安全问题Firefox 检测到潜在的安全威胁,并因 github.com 要求安全连接而没有继续。

    未连接:有潜在的安全问题 Firefox 检测到潜在的安全威胁,并因 github.com 要求安全连接而没有继续。 出现这个报错,是我在弄dev-sidecad项目 是安装了根证书后出现的,应该是该项目安装的证书有些问题过不了Firefox的检测 在地址栏输入:about:config 接受风险并继续   在搜索框

    2024年02月11日
    浏览(38)
  • 历史本质是就是新生事物替代旧事物的过程,要保持对新生事物的关注,伺机拥抱

    当今这瞬息万变,时代变迁的洪流中,每一天都在诞生新生事物,每一天都在产生新的可能性,未来的某一天这些新事物就会取代旧事物立在时代的潮头。 从哲学角度来看,万事万物都是不断处于运动和发展中的,一个事物终将被另一个新生事物取代是宿命,这就要求人在享

    2024年02月08日
    浏览(38)
  • Day26: Redis入门、开发点赞功能、开发我收到的赞的功能、重构点赞功能、开发关注、取消关注、开发关注列表、粉丝列表、重构登录功能

    Redis是NoSQL数据库(Not only SQL) 值支持多种数据结构(key都是string): 字符串、哈希、列表、集合、有序集合 把数据存在内存中,速度惊人; 同时也可以讲数据快照(数据备份,定时跑一次)/日志**(AOF,实时存命令)**存在硬盘上,保证数据安全性; Redis典型的应用场景包

    2024年04月27日
    浏览(42)
  • 如何使用PMD插件检测Java代码中的潜在问题?

    当今的软件开发需要使用许多不同的工具和技术来确保代码质量和稳定性。PMD是一个流行的静态代码分析工具,可以帮助开发者在编译代码之前发现潜在的问题。在本文中,我们将讨论如何在Gradle中使用PMD,并介绍一些最佳实践。 PMD是一个用于Java代码的静态代码分析工具。

    2023年04月10日
    浏览(85)
  • AR工业远程巡查系统:实时监控设备状态,及时发现潜在问题

    随着工业4.0的到来,先进的技术和创新的解决方案正在改变着工业生产的方式。其中,增强现实(AR)技术带来的工业巡检系统就是一个典型的例子。这种系统通过在现实世界中添加虚拟信息,使得操作人员能够更有效地进行检查和维护工作,从而提高生产效率,降低运营成

    2024年02月09日
    浏览(43)
  • 开发过程中遇到的问题以及解决方法

    巩固基础,砥砺前行 。 只有不断重复,才能做到超越自己。 能坚持把简单的事情做到极致,也是不容易的。 简单易用的git命令 git命令: 查看有几个分支:git branch -a 切换分支:git checkout 分支名称 下载项目:git clone url 拉取项目:每次提交代码之前都需要,相当于更新代码

    2024年02月13日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包