6586091: javac crashes with StackOverflowError

Thu, 09 Oct 2008 16:21:04 +0100

author
mcimadamore
date
Thu, 09 Oct 2008 16:21:04 +0100
changeset 138
d766e40e49d6
parent 137
e4eaddca54b7
child 139
e03459165ec4

6586091: javac crashes with StackOverflowError
Summary: Types.adapt should avoid infinite loops by exploiting a local cache
Reviewed-by: jjg

src/share/classes/com/sun/tools/javac/code/Types.java file | annotate | diff | comparison | revisions
test/tools/javac/cast/6586091/T6586091.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/classes/com/sun/tools/javac/code/Types.java	Thu Oct 09 16:19:13 2008 +0100
     1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Types.java	Thu Oct 09 16:21:04 2008 +0100
     1.3 @@ -3213,6 +3213,7 @@
     1.4              containsType(t, s) && containsType(s, t);
     1.5      }
     1.6  
     1.7 +    // <editor-fold defaultstate="collapsed" desc="adapt">
     1.8      /**
     1.9       * Adapt a type by computing a substitution which maps a source
    1.10       * type to a target type.
    1.11 @@ -3226,94 +3227,115 @@
    1.12                         Type target,
    1.13                         ListBuffer<Type> from,
    1.14                         ListBuffer<Type> to) throws AdaptFailure {
    1.15 -        Map<Symbol,Type> mapping = new HashMap<Symbol,Type>();
    1.16 -        adaptRecursive(source, target, from, to, mapping);
    1.17 -        List<Type> fromList = from.toList();
    1.18 -        List<Type> toList = to.toList();
    1.19 -        while (!fromList.isEmpty()) {
    1.20 -            Type val = mapping.get(fromList.head.tsym);
    1.21 -            if (toList.head != val)
    1.22 -                toList.head = val;
    1.23 -            fromList = fromList.tail;
    1.24 -            toList = toList.tail;
    1.25 +        new Adapter(from, to).adapt(source, target);
    1.26 +    }
    1.27 +
    1.28 +    class Adapter extends SimpleVisitor<Void, Type> {
    1.29 +
    1.30 +        ListBuffer<Type> from;
    1.31 +        ListBuffer<Type> to;
    1.32 +        Map<Symbol,Type> mapping;
    1.33 +
    1.34 +        Adapter(ListBuffer<Type> from, ListBuffer<Type> to) {
    1.35 +            this.from = from;
    1.36 +            this.to = to;
    1.37 +            mapping = new HashMap<Symbol,Type>();
    1.38          }
    1.39 -    }
    1.40 -    // where
    1.41 -        private void adaptRecursive(Type source,
    1.42 -                                    Type target,
    1.43 -                                    ListBuffer<Type> from,
    1.44 -                                    ListBuffer<Type> to,
    1.45 -                                    Map<Symbol,Type> mapping) throws AdaptFailure {
    1.46 -            if (source.tag == TYPEVAR) {
    1.47 -                // Check to see if there is
    1.48 -                // already a mapping for $source$, in which case
    1.49 -                // the old mapping will be merged with the new
    1.50 -                Type val = mapping.get(source.tsym);
    1.51 -                if (val != null) {
    1.52 -                    if (val.isSuperBound() && target.isSuperBound()) {
    1.53 -                        val = isSubtype(lowerBound(val), lowerBound(target))
    1.54 -                            ? target : val;
    1.55 -                    } else if (val.isExtendsBound() && target.isExtendsBound()) {
    1.56 -                        val = isSubtype(upperBound(val), upperBound(target))
    1.57 -                            ? val : target;
    1.58 -                    } else if (!isSameType(val, target)) {
    1.59 -                        throw new AdaptFailure();
    1.60 -                    }
    1.61 -                } else {
    1.62 -                    val = target;
    1.63 -                    from.append(source);
    1.64 -                    to.append(target);
    1.65 +
    1.66 +        public void adapt(Type source, Type target) throws AdaptFailure {
    1.67 +            visit(source, target);
    1.68 +            List<Type> fromList = from.toList();
    1.69 +            List<Type> toList = to.toList();
    1.70 +            while (!fromList.isEmpty()) {
    1.71 +                Type val = mapping.get(fromList.head.tsym);
    1.72 +                if (toList.head != val)
    1.73 +                    toList.head = val;
    1.74 +                fromList = fromList.tail;
    1.75 +                toList = toList.tail;
    1.76 +            }
    1.77 +        }
    1.78 +
    1.79 +        @Override
    1.80 +        public Void visitClassType(ClassType source, Type target) throws AdaptFailure {
    1.81 +            if (target.tag == CLASS)
    1.82 +                adaptRecursive(source.allparams(), target.allparams());
    1.83 +            return null;
    1.84 +        }
    1.85 +
    1.86 +        @Override
    1.87 +        public Void visitArrayType(ArrayType source, Type target) throws AdaptFailure {
    1.88 +            if (target.tag == ARRAY)
    1.89 +                adaptRecursive(elemtype(source), elemtype(target));
    1.90 +            return null;
    1.91 +        }
    1.92 +
    1.93 +        @Override
    1.94 +        public Void visitWildcardType(WildcardType source, Type target) throws AdaptFailure {
    1.95 +            if (source.isExtendsBound())
    1.96 +                adaptRecursive(upperBound(source), upperBound(target));
    1.97 +            else if (source.isSuperBound())
    1.98 +                adaptRecursive(lowerBound(source), lowerBound(target));
    1.99 +            return null;
   1.100 +        }
   1.101 +
   1.102 +        @Override
   1.103 +        public Void visitTypeVar(TypeVar source, Type target) throws AdaptFailure {
   1.104 +            // Check to see if there is
   1.105 +            // already a mapping for $source$, in which case
   1.106 +            // the old mapping will be merged with the new
   1.107 +            Type val = mapping.get(source.tsym);
   1.108 +            if (val != null) {
   1.109 +                if (val.isSuperBound() && target.isSuperBound()) {
   1.110 +                    val = isSubtype(lowerBound(val), lowerBound(target))
   1.111 +                        ? target : val;
   1.112 +                } else if (val.isExtendsBound() && target.isExtendsBound()) {
   1.113 +                    val = isSubtype(upperBound(val), upperBound(target))
   1.114 +                        ? val : target;
   1.115 +                } else if (!isSameType(val, target)) {
   1.116 +                    throw new AdaptFailure();
   1.117                  }
   1.118 -                mapping.put(source.tsym, val);
   1.119 -            } else if (source.tag == target.tag) {
   1.120 -                switch (source.tag) {
   1.121 -                    case CLASS:
   1.122 -                        adapt(source.allparams(), target.allparams(),
   1.123 -                              from, to, mapping);
   1.124 -                        break;
   1.125 -                    case ARRAY:
   1.126 -                        adaptRecursive(elemtype(source), elemtype(target),
   1.127 -                                       from, to, mapping);
   1.128 -                        break;
   1.129 -                    case WILDCARD:
   1.130 -                        if (source.isExtendsBound()) {
   1.131 -                            adaptRecursive(upperBound(source), upperBound(target),
   1.132 -                                           from, to, mapping);
   1.133 -                        } else if (source.isSuperBound()) {
   1.134 -                            adaptRecursive(lowerBound(source), lowerBound(target),
   1.135 -                                           from, to, mapping);
   1.136 -                        }
   1.137 -                        break;
   1.138 +            } else {
   1.139 +                val = target;
   1.140 +                from.append(source);
   1.141 +                to.append(target);
   1.142 +            }
   1.143 +            mapping.put(source.tsym, val);
   1.144 +            return null;
   1.145 +        }
   1.146 +
   1.147 +        @Override
   1.148 +        public Void visitType(Type source, Type target) {
   1.149 +            return null;
   1.150 +        }
   1.151 +
   1.152 +        private Set<TypePair> cache = new HashSet<TypePair>();
   1.153 +
   1.154 +        private void adaptRecursive(Type source, Type target) {
   1.155 +            TypePair pair = new TypePair(source, target);
   1.156 +            if (cache.add(pair)) {
   1.157 +                try {
   1.158 +                    visit(source, target);
   1.159 +                } finally {
   1.160 +                    cache.remove(pair);
   1.161                  }
   1.162              }
   1.163          }
   1.164 -        public static class AdaptFailure extends Exception {
   1.165 -            static final long serialVersionUID = -7490231548272701566L;
   1.166 -        }
   1.167 -
   1.168 -    /**
   1.169 -     * Adapt a type by computing a substitution which maps a list of
   1.170 -     * source types to a list of target types.
   1.171 -     *
   1.172 -     * @param source    the source type
   1.173 -     * @param target    the target type
   1.174 -     * @param from      the type variables of the computed substitution
   1.175 -     * @param to        the types of the computed substitution.
   1.176 -     */
   1.177 -    private void adapt(List<Type> source,
   1.178 -                       List<Type> target,
   1.179 -                       ListBuffer<Type> from,
   1.180 -                       ListBuffer<Type> to,
   1.181 -                       Map<Symbol,Type> mapping) throws AdaptFailure {
   1.182 -        if (source.length() == target.length()) {
   1.183 -            while (source.nonEmpty()) {
   1.184 -                adaptRecursive(source.head, target.head, from, to, mapping);
   1.185 -                source = source.tail;
   1.186 -                target = target.tail;
   1.187 +
   1.188 +        private void adaptRecursive(List<Type> source, List<Type> target) {
   1.189 +            if (source.length() == target.length()) {
   1.190 +                while (source.nonEmpty()) {
   1.191 +                    adaptRecursive(source.head, target.head);
   1.192 +                    source = source.tail;
   1.193 +                    target = target.tail;
   1.194 +                }
   1.195              }
   1.196          }
   1.197      }
   1.198  
   1.199 +    public static class AdaptFailure extends RuntimeException {
   1.200 +        static final long serialVersionUID = -7490231548272701566L;
   1.201 +    }
   1.202 +
   1.203      private void adaptSelf(Type t,
   1.204                             ListBuffer<Type> from,
   1.205                             ListBuffer<Type> to) {
   1.206 @@ -3326,6 +3348,7 @@
   1.207              throw new AssertionError(ex);
   1.208          }
   1.209      }
   1.210 +    // </editor-fold>
   1.211  
   1.212      /**
   1.213       * Rewrite all type variables (universal quantifiers) in the given
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/test/tools/javac/cast/6586091/T6586091.java	Thu Oct 09 16:21:04 2008 +0100
     2.3 @@ -0,0 +1,38 @@
     2.4 +/*
     2.5 + * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
     2.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     2.7 + *
     2.8 + * This code is free software; you can redistribute it and/or modify it
     2.9 + * under the terms of the GNU General Public License version 2 only, as
    2.10 + * published by the Free Software Foundation.
    2.11 + *
    2.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    2.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    2.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    2.15 + * version 2 for more details (a copy is included in the LICENSE file that
    2.16 + * accompanied this code).
    2.17 + *
    2.18 + * You should have received a copy of the GNU General Public License version
    2.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    2.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    2.21 + *
    2.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    2.23 + * CA 95054 USA or visit www.sun.com if you need additional information or
    2.24 + * have any questions.
    2.25 + */
    2.26 +
    2.27 +/*
    2.28 + * @test
    2.29 + * @author Maurizio Cimadamore
    2.30 + * @bug     6586091
    2.31 + * @summary javac crashes with StackOverflowError
    2.32 + * @compile T6586091.java
    2.33 + */
    2.34 +
    2.35 +class T6586091 {
    2.36 +    static class A<T extends A<?>> {}
    2.37 +    static class B extends A<A<?>> {}
    2.38 +
    2.39 +    A<A<?>> t = null;
    2.40 +    B c = (B)t;
    2.41 +}
    2.42 \ No newline at end of file

mercurial