001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.bcel.verifier; 020 021import java.util.LinkedHashMap; 022import java.util.List; 023import java.util.Map; 024import java.util.Vector; 025 026/** 027 * This class produces instances of the Verifier class. Its purpose is to make sure that they are singleton instances with respect to the class name they 028 * operate on. That means, for every class (represented by a unique fully qualified class name) there is at most one cached Verifier. The cache is bounded (see 029 * {@link #MAX_CACHE_SIZE_PROPERTY}); after eviction, a new Verifier is transparently created on the next request for that class name. 030 * <p> 031 * The system property {@code org.apache.bcel.verifier.VerifierFactory.maxCacheSize} controls how many Verifier instances this factory caches; 032 * least-recently-used entries are evicted first. Verifier names are taken from the constant pools of the (possibly untrusted) classes being verified, so an 033 * unbounded cache would let a single hostile class file referencing many distinct bogus type names grow the heap without limit in a long-running process. Set 034 * the property to {@code 0} or a negative value to opt out and restore the historical unbounded behavior. 035 * </p> 036 * 037 * @see Verifier 038 */ 039public class VerifierFactory { 040 041 /** 042 * Name of the system property controlling how many Verifier instances this factory caches; least-recently-used entries are evicted first. Verifier names 043 * are taken from the constant pools of the (possibly untrusted) classes being verified, so an unbounded cache would let a single hostile class file 044 * referencing many distinct bogus type names grow the heap without limit in a long-running process. Set the property to {@code 0} or a negative value to 045 * opt out and restore the historical unbounded behavior. 046 */ 047 static final String MAX_CACHE_SIZE_PROPERTY = "org.apache.bcel.verifier.VerifierFactory.maxCacheSize"; 048 049 /** 050 * Default value used when {@link #MAX_CACHE_SIZE_PROPERTY} is not set. 051 */ 052 private static final int DEFAULT_MAX_CACHE_SIZE = 10_000; 053 054 /** 055 * The map that holds the data about the already-constructed Verifier instances, in least-recently-used order, 056 * bounded by {@link #MAX_CACHE_SIZE_PROPERTY}. 057 */ 058 private static final Map<String, Verifier> MAP = new LinkedHashMap<String, Verifier>(16, 0.75f, true) { 059 060 private static final long serialVersionUID = 1L; 061 062 @Override 063 protected boolean removeEldestEntry(final Map.Entry<String, Verifier> eldest) { 064 final int maxCacheSize = Integer.getInteger(MAX_CACHE_SIZE_PROPERTY, DEFAULT_MAX_CACHE_SIZE).intValue(); 065 return maxCacheSize > 0 && size() > maxCacheSize; 066 } 067 }; 068 069 /** 070 * The VerifierFactoryObserver instances that observe the VerifierFactory. 071 */ 072 private static final List<VerifierFactoryObserver> OBSVERVERS = new Vector<>(); 073 074 /** 075 * Adds the VerifierFactoryObserver o to the list of observers. 076 * 077 * @param o The observer to add. 078 */ 079 public static void attach(final VerifierFactoryObserver o) { 080 OBSVERVERS.add(o); 081 } 082 083 /** 084 * Clears the factory. 085 * 086 * @since 6.6.2 087 */ 088 public static void clear() { 089 MAP.clear(); 090 OBSVERVERS.clear(); 091 } 092 093 /** 094 * Removes the VerifierFactoryObserver o from the list of observers. 095 * 096 * @param o The observer to remove. 097 */ 098 public static void detach(final VerifierFactoryObserver o) { 099 OBSVERVERS.remove(o); 100 } 101 102 /** 103 * Returns the verifier responsible for the class with the given name. Possibly a new Verifier object is 104 * transparently created; if the cache bound ({@link #MAX_CACHE_SIZE_PROPERTY}) has been reached, the 105 * least-recently-used cached Verifier is evicted first. 106 * 107 * @param fullyQualifiedClassName The fully qualified class name. 108 * @return The verifier responsible for the class with the given name. 109 */ 110 public static Verifier getVerifier(final String fullyQualifiedClassName) { 111 return MAP.computeIfAbsent(fullyQualifiedClassName, k -> { 112 final Verifier v = new Verifier(k); 113 notify(k); 114 return v; 115 }); 116 } 117 118 /** 119 * Returns all Verifier instances created so far. This is useful when a Verifier recursively lets the VerifierFactory 120 * create other Verifier instances and if you want to verify the transitive hull of referenced class files. 121 * 122 * @return array of all Verifier instances. 123 */ 124 public static Verifier[] getVerifiers() { 125 return MAP.values().toArray(Verifier.EMPTY_ARRAY); 126 } 127 128 /** 129 * Notifies the observers of a newly generated Verifier. 130 */ 131 private static void notify(final String fullyQualifiedClassName) { 132 // notify the observers 133 OBSVERVERS.forEach(vfo -> vfo.update(fullyQualifiedClassName)); 134 } 135 136 /** 137 * The VerifierFactory is not instantiable. 138 */ 139 private VerifierFactory() { 140 } 141}