Skip to content

Latest commit

 

History

History
52 lines (42 loc) · 3.67 KB

File metadata and controls

52 lines (42 loc) · 3.67 KB

ConcurrentHashMap equals 跳板(ConcurrentHashMapEquals)

注解全名(annotation.name):HashMap#readObject()调用equals()方法,注意在调用equals方法之前会调用到包装对象hashCode方法,所以需要保证对象调用hashCode不能出现问题

  • 类别:common 别名:— 优先级:—
  • 作者:—
  • 依赖:无(纯 JDK)
  • 状态@Deprecated(已弃用,见下)

作用

构造一个在 Java 原生反序列化(HashMap/ConcurrentHashMapreadObject)过程中,会对两个被包装对象触发 equals() 调用的 Map。属于「原生反序列化 → equals sink」的跳板入口:为那些以 equals() 为触发点的下游 gadget(nextTags=Equals)提供反序列化入口。

链接标签

  • 入口 tagsJavaNativeDeserialize —— 承接 Java 原生反序列化入口,是链的最外层跳板之一。
  • 衔接 nextTagsEquals —— 其内层必须是一个「以 equals() 为触发点」的 gadget,且该 gadget 需产出一对对象 Object[2](在 map 中相互 equals)。
  • excludes:无。

源码剖析

public Object getObject(Object obj1, Object obj2) throws Exception {
    return PayloadHelper.concurrentmap2equals(obj1, obj2);   // 把两对象放入会触发 equals 的 map
}

@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
    Object[] objects = (Object[]) chain.doCreate(context);   // 内层产出一对对象
    Object getterObject = context.get(ContextTag.FASTJSON_HANDLE_BYPASS_KEY);
    Object resultObject = this.getObject(objects[0], objects[1]);
    if (getterObject != null) {
        return CommonMethod.listWrap(getterObject, resultObject);  // Fastjson 绕过时再包一层 List
    }
    return resultObject;
}
  • 内层需产出 Object[2]chain.doCreate 被强转为 Object[],取 objects[0]/objects[1] 交给 PayloadHelper.concurrentmap2equals。该 helper 把两个对象填入 ConcurrentHashMap/HashMap 的桶结构,使得反序列化时因哈希落到同一桶而触发 key.equals(otherKey)
  • 注解中的关键坑(务必满足)HashMap.readObject 在把 entry 放回散列表前会先调用键对象的 hashCode(),之后同桶冲突时才调用 equals()。因此被包装对象的 hashCode() 必须能正常返回、不得抛异常,否则反序列化在 equals 之前就中断。这也是很多 equals 型链需要精心选择包装对象的原因。
  • FASTJSON_HANDLE_BYPASS_KEY 分支:当上下文标记了 Fastjson 绕过场景时,用 CommonMethod.listWrap 把一个额外的 getter 对象与结果再包成 List,兼容二次处理。常规链此分支为 null,直接返回该 map。

参数(@Param)

本类无 @Param。行为完全由内层产出的对象对与上下文决定。

适用版本与原理要点

  • 依赖 JDK 内置 HashMap/ConcurrentHashMapreadObject 逻辑,无第三方依赖。
  • @Deprecated:该实现被更通用/稳定的 equals 跳板取代(参见 HashMapEqualsHashTableEquals)。在选链时优先使用未弃用的替代品。
  • 成功前提:被包装对象的 hashCode() 不抛异常,且能命中同桶以触发 equals

所属预设链

自由构件,未直接出现在预设链(usedInChains 为空)。

关联

  • 下游(nextTags=Equals):以 equals() 为触发点、产出对象对的 gadget(如各类 *Equals/XString 型 sink)。
  • 同族替代:HashMapEqualsHashTableEquals(同为 JavaNativeDeserialize → Equals 跳板,未弃用)。