谈谈JDK 漏洞 6260652

JDK 漏洞 6260652

在看ArrayList源码的过程中 发现带参构造里有一个注释:
// c.toArray might (incorrectly) not return Object[] (see 6260652)

 public ArrayList(Collection<? extends E> c) {elementData = c.toArray();if ((size = elementData.length) != 0) {// c.toArray might (incorrectly) not return Object[] (see 6260652)if (elementData.getClass() != Object[].class)elementData = Arrays.copyOf(elementData, size, Object[].class);} else {// replace with empty array.this.elementData = EMPTY_ELEMENTDATA;}}

于是带着下面三个问题去查资料,探究了一下这个问题。

这段代码解决的是什么漏洞?什么情况下会出现这个漏洞呢? 这个漏洞可能会引发哪些问题?

先查官网的bug库
漏洞在官网上的描述:https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6260652
在这里插入图片描述
问题提出时间:2005-04-25 解决时间: 2015-07-09 , 受到影响的版本JDK5.0 和 6
在JDK9中修复了该问题。

在这里插入图片描述
这里的问题描述说的是:

JDK1.5.0_02版本中、 Collection接口的 <T> T[] toArray(T[] a);方法上有这么一段注释

Note that toArray(new Object[0])  is identical in function to toArray() 
意思是   toArray(new Object[0]) 方法和  toArray() 方法在功能上是相同的

我们看下这两个方法在Collection接口中的定义:


Object[] toArray();<T> T[] toArray(T[] a);

我们知道接口是属于比较高层次的抽象,任何实现了某个接口的类都必须遵循这个接口中方法的声明。
也就是说 Collection接口的子类 都必须遵循上面 toArray(new Object[0]) 方法和 toArray() 方法在功能上是相同的这个声明。

但是,但是来了就是问题要来了。县长来了,鹅城就太平了。
Arrays类来了JDK的坑就有了。。。

之前其实已经提过Arrays.asList方法返回的List 实际上是 Arrays类的一个静态内部类 private static class ArrayList<E>
并非 java.util.ArrayList ,所以之前在 **Java API使用避坑合集**这篇文章中介绍过,private static class ArrayList 不支持添加或者修改操作。否则会报java.lang.UnsupportedOperationException。

那么我们现在说的这个漏洞又是Arrays搞得鬼,这真验证了那句话,约80%的程序错误可能源于20%的代码模块(2/8定律,又称为帕累托原则(Pareto Principle))。

我们回到 JDK 漏洞 6260652的讨论,上面说了 private static class ArrayList 坑, 那么 JDK 漏洞 6260652 是具体怎么体现的呢?

实际上就是 private static class ArrayList 这个静态内部类, 没有遵循Collection 接口声明的 这句话Note that toArray(new Object[0]) is identical in function to toArray()
我们看下private static class ArrayList中 toArray的具体实现 下面源码是 JDK8版本

// 无参的toArray 实际上调用的 是clone方法  返回的是Object数组 (但是返回的数组实际的类型 并一定是Object)
@Override
public Object[] toArray() {return a.clone();
}// 有参的toArray 实际上调用的是 Arrays.copyOf  返回的数组类型是根据具体的运行时类型而确定的
// 所以如果该方法返回了 Object[]   上面的toArray()返回了 String[]  那么两个toArray方法返回的数组类型就不一致了  
@Override
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {int size = size();if (a.length < size)return Arrays.copyOf(this.a, size,(Class<? extends T[]>) a.getClass());System.arraycopy(this.a, 0, a, 0, size);if (a.length > size)a[size] = null;return a;
}

这两个方法在某些情况下 返回的结果并不一致。也就不遵循Collection 接口对这两个方法的声明。

看下面的代码:

public class TestA {public static void main(String[] args) {List l = Arrays.asList(args);Object[] objects1 = l.toArray();Object[] objects2 = l.toArray(new Object[0]);System.out.println(objects1.getClass());System.out.println(objects2.getClass());}
}

运行结果:

class [Ljava.lang.String;
class [Ljava.lang.Object;

很明显同一个 private static class ArrayList 对象调用toArray()和toArray(new Object[0])两个方法,返回的数组类型不一致,
这和 Collection 接口声明的 这句话Note that toArray(new Object[0]) is identical in function to toArray() 相悖了。
这就是这个漏洞的具体表现。

这个漏洞可能会造成的问题如下:

public static void main(String[] args) {List<String> list = Arrays.asList("a","b");System.out.println(list.getClass());Object[] o = list.toArray();System.out.println(o.getClass());o[0] = "c";System.out.println(Arrays.toString(o));// ArrayStoreExceptiono[1] = new Object();}

运行结果:

class java.util.Arrays$ArrayList
class [Ljava.lang.String;
[c, b]
Exception in thread "main" java.lang.ArrayStoreException: java.lang.Object

o[1] = new Object();报错了 ArrayStoreException
因为 java.util.Arrays$ArrayList 也就是 Arrays的静态内部类 private static class ArrayList 的toArray()方法返回了 Object数组,但是这个数组实际上的类型是String。
如果这个时候我们给 toArray()方法返回的数组中的元素赋值一个Object类型的变量,显然在编译时期可以正常编译,但是在运行时期就会出现Object对象 向String数组中存储的情况,此时JVM会抛出 ArrayStoreException。

我们再回头看真正的 java.util.ArrayList 集合中 的这段代码的时候就清楚了:
在这里插入图片描述
所以这个判断是为了保证真正存储集合元素的数组类型是 Object类型。

如果没有这段代码 if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class);

我们通过反射做点小手脚,运行下面这段代码:

public static void main(String[] args) throws Exception {// 创建一个普通的 ArrayListArrayList<Object> list = new ArrayList<>(Arrays.asList("1", "2", "3"));// 使用反射获取 ArrayList 类中的 elementData 字段Field elementDataField = ArrayList.class.getDeclaredField("elementData");elementDataField.setAccessible(true);// 将 list对象的elementData 字段设置为一个新的数组  相当于 在ArrayList有参构造中执行了elementData = c.toArray();// 未执行  if (elementData.getClass() != Object[].class)    elementData = Arrays.copyOf(elementData, size, Object[].class);Object[] objects = Arrays.asList("1", "2", "3").toArray();elementDataField.set(list, objects);System.out.println(list);  // 输出: [1, 2, 3]System.out.println(objects.getClass());  // 输出 class [Ljava.lang.String;// 下面这行代码会抛出 ArrayStoreExceptionlist.add(new Object());}

可以看到在 list.add(new Object());时抛了 java.lang.ArrayStoreException 因为在运行时 ArrayList尝试把Object类型的对象添加进 String类型的数组中 这是不被允许的。

那么再回过头来看:

 // c.toArray might (incorrectly) not return Object[] (see 6260652)if (elementData.getClass() != Object[].class)elementData = Arrays.copyOf(elementData, size, Object[].class);

目的就很明确了, 由于运行时 c.toArray返回的可能不是 Object类型的数组 ,为了保证集合运行时的类型安全
通过elementData = Arrays.copyOf(elementData, size, Object[].class); 来保证 elementData 获取的是Object数组类型。

在JDK9版本,对 private static class ArrayList 的toArray()方法也进行了改进:
JDK9之前的版本是这样的:

 @Override
public Object[] toArray() {// clone返回的是 运行时的具体类型return a.clone();}

JDK9及之后的版本是这样的:

 @Overridepublic Object[] toArray() {// 利用Arrays.copyOf 复制一个新的 Object类型数组return Arrays.copyOf(this.a, this.a.length, Object[].class);}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/23262.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

动物收容所

题目链接 动物收容所 题目描述 注意点 若没有可以收养的动物&#xff0c;则返回[-1,-1]收纳所的最大容量为20000编号随着收养动物的增加自增 解答思路 利用队列先进先出的特点将猫和狗分别存进两个队列中&#xff0c;关键是dequeueAny这个方法中如果此时猫和狗的队列中都有…

演讲全文|林涛:MongoDB助力智能制造出海控本增效

5月29日-30日在上海世博中心举办的亚马逊云科技中国峰会圆满结束。本文整理了MongoDB北亚区方案与咨询总监林涛在白金讲堂的演讲全文&#xff0c;就《MongoDB助力智能制造出海控本增效》话题与大家共同探讨。 白金讲堂演讲视频 从全球经济竞争的角度看&#xff0c;中国制造业…

C++标准模板(STL)- 迭代器库-迭代器适配器- 逆序遍历的迭代器适配器 (二)

迭代器库-迭代器原语 迭代器库提供了五种迭代器的定义&#xff0c;同时还提供了迭代器特征、适配器及相关的工具函数。 迭代器分类 迭代器共有五 (C17 前)六 (C17 起)种&#xff1a;遗留输入迭代器 (LegacyInputIterator) 、遗留输出迭代器 (LegacyOutputIterator) 、遗留向前…

网站安全小白也能搞定的SSL证书安装免费方法

大家都知道&#xff0c;部署一个网站&#xff0c;除了购买域名&#xff0c;现在基本标配SSL证书。 我们以aliyun为例 大家看到这个&#xff0c;收费的SSL证书几千-几万1年不等。这时候&#xff0c;你就会想有没有免费的可以搞。linux老鸟都知道&#xff0c; Let’s Encrypt 、…

Megapoly.Art - Mechanic Shop Pack

Megapoly.art很高兴推出“汽车机械师包”。这个模块化包包括创建汽车机械师场景所需的一切,从简单的工具到先进的机器,包括路虎卫士的额外内容。 移动友好型低多边形建模和优化的纹理。 包信息 总计:129个预制件 - 5个独特的机器,21个建筑预制件,98个道具和奖励内容路虎(…

JVM类加载机制和双亲委派

类加载机制 java文件需要编译成字节码文件(.class文件)&#xff0c;jvm是通过类加载机制&#xff0c;将.class文件加载进内存&#xff0c;经过验证连接->初始化直到使用该对象的过程就是类加载机制&#xff0c;当new对象的时候&#xff0c;jvm首先去常量池寻找该类的符号引用…

LabVIEW电路板性能与稳定性测试系统

LabVIEW电路板性能与稳定性测试系统 概述&#xff1a; 开发基于LabVIEW的电路板性能与稳定性测试系统&#xff0c;通过集成多种测试仪器&#xff0c;实现对电路板的电气性能和长期稳定性的全面评估。系统涵盖了电压、电流、温度等多项参数的监测&#xff0c;并具备自动化测试…

Navicat+sqlite操作数据

使用navicat操作数据库&#xff08;比如sqlite数据库&#xff09;可以实现与access&#xff08;参考该文&#xff09;一样的操作&#xff0c;可以导入导出excel等格式的文件&#xff0c;如下图所示。 两种方式的sql语句的语法也基本一样。

C# PaddleOCR 单字识别效果

C# PaddleOCR 单字识别效果 效果 说明 根据《百度办公文档识别C离线SDKV1.2用户接入文档.pdf》&#xff0c;使用C封装DLL&#xff0c;C#调用。 背景 为使客户、第三方开发者等能够更快速、方便的接入使用百度办公文档识别 SDK、促进百度 OCR产品赋能更多客户&#xff0c;特设…

水泵选型指南

在现代暖通空调&#xff08;HVAC&#xff09;系统中&#xff0c;冷冻水泵是关键组件之一&#xff0c;它在提供冷却和空调效果方面起着至关重要的作用。选择合适的冷冻水泵不仅可以提高系统效率&#xff0c;还能节省能源和维护成本。本文将介绍冷冻水泵选型的关键因素和步骤。 …

【遗传算法】【机器学习】【Python】常见交叉方法(二)、多点交叉和均匀交叉

往期遗传算法文章见&#xff1a; 【遗传算法】【机器学习】【Python】常见交叉方法&#xff08;一&#xff09;、单点交叉和两点交叉 一、遗传算法流程图 交叉过程即存在于上图的”交叉“&#xff08;crossover&#xff09;步骤中。 二、多点交叉 多点交叉的原理就是&#x…

金融科技发展报告:移动支付的市场格局、趋势与优缺点

一、引言 随着科技的飞速发展,金融科技已成为推动全球经济发展的重要力量。移动支付作为金融科技的重要分支,其市场格局与趋势日益受到业界的关注。本报告将详细剖析移动支付的市场格局,并深入探讨其发展趋势,同时结合相关案例和数据,为读者呈现移动支付的优缺点,以及国…

LNMP网络架构的搭建

操作准备&#xff1a;准备三台虚拟机 安装 MySQL 服务 &#xff08;1&#xff09;准备好mysql目录上传软件压缩包并解压 cd /opt mkdir mysql tar xf mysql-boost-5.7.44.tar.gz &#xff08;2&#xff09;安装mysql环境依赖包 yum -y install ncurses ncurses-devel bison…

JVM之垃圾回收面试总结

文章目录 1.GC概述1.1 什么是垃圾1.2 为什么需要GC&#xff1f;1.3 早期垃圾回收1.4 Java垃圾回收机制1.5 评估GC的性能指标 2.垃圾回收相关算法2.1 垃圾标记阶段的算法2.1.1 引用计数算法(Java没有使用)2.1.2 可达性分析算法 2.2 垃圾清除阶段的算法2.2.1 标记-清除(Mark-Swee…

RAG 高效应用指南 :Query 理解

前言 构建一个检索增强生成 (Retrieval-Augmented Generation, RAG) 应用的 PoC&#xff08;概念验证&#xff0c;Proof of Concept&#xff09;过程相对简单&#xff0c;但要将其推广到生产环境中则会面临多方面的挑战。这主要是因为 RAG 系统涉及多个不同的组件&#xff0c;…

Termux安装SSH服务与内网穿透工具实现远程SFTP传输文件

文章目录 前言1. 安装openSSH2. 安装cpolar3. 远程SFTP连接配置4. 远程SFTP访问4. 配置固定远程连接地址 前言 本教程主要介绍如何在安卓 Termux 系统中使用 SFTP 文件传输并结合[cpolar内网穿透工具](cpolar - 安全的内网穿透工具)轻松实现无公网IP远程传输&#xff0c;无需购…

ATFX汇市:加拿大央行或启动首次降息,关注加元贬值风险

ATFX汇市&#xff1a;今日21:45&#xff0c;加拿大央行将公布6月份利率决议结果&#xff0c;当前的基准利率为5%&#xff0c;市场普遍预期其将降息25基点&#xff0c;最新基准利率有可能调降至4.75%。市场人士预期降息的主要依据有两点&#xff0c;其一是加拿大央行行长麦克勒姆…

超级详细Spring AI运用Ollama大模型

大模型工具Ollama 官网:https://ollama.com/ Ollama是一个用于部署和运行各种开源大模型的工具; 它能够帮助用户快速在本地运行各种大模型&#xff0c;极大地简化了大模型在本地运行的过程。用户通过执行几条命令就能在本地运行开源大模型&#xff0c;如Lama 2等; 综上&#x…

SpringBoot:SpringBoot中使用Redisson实现分布式锁

一、前言 Redisson是一个在Redis的基础上实现的Java驻内存数据网格&#xff08;In-Memory Data Grid&#xff09;。它不仅提供了一系列的分布式的Java常用对象&#xff0c;还提供了许多分布式服务。 刚好项目中需要使用到分布式锁&#xff0c;记录一下Redisson是如何使用分布式…

(免费领源码)Java#springboot#MySQL书法社团管理系统36200-计算机毕业设计项目选题推荐

目 录 摘要 Abstract 1 绪论 1.1 研究背景 1.2 研究意义 1.3论文结构与章节安排 2 书法社团管理系统系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据增加流程 2.2.2 数据修改流程 2.2.3 数据删除流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析…