summaryrefslogtreecommitdiff
path: root/bincompat-backward.whitelist.conf
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2017-01-24 19:48:43 +1000
committerJason Zaugg <jzaugg@gmail.com>2017-02-19 15:18:27 +1000
commit777a0e5ae35e174cc79e786d0333183041baf123 (patch)
treea5d8022b3fe7173b4ac922d6d882b5bb7afbcb77 /bincompat-backward.whitelist.conf
parent147e5dd1b88a690b851e57a1783f099cb0dad091 (diff)
downloadscala-777a0e5ae35e174cc79e786d0333183041baf123.tar.gz
scala-777a0e5ae35e174cc79e786d0333183041baf123.tar.bz2
scala-777a0e5ae35e174cc79e786d0333183041baf123.zip
SI-10026 Fix endless cycle in runtime reflection
56f23af introduced a call to `baseTypeSeq` of `scala.collection.mutable.ArrayOps.ofRef[?T]{}` in `findMember`. This exposed a latent bug in the synchronized wrapper of `BaseTypeSeq`, demonstrated below with an older version of Scala: ``` Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_112). Type in expressions for evaluation. Or try :help. scala> val symtab = reflect.runtime.universe.asInstanceOf[scala.reflect.internal.SymbolTable] symtab: scala.reflect.internal.SymbolTable = scala.reflect.runtime.JavaUniverse@458544e0 scala> import symtab._ import symtab._ scala> val ArrayOps_ofRef_Class = symtab.symbolOf[scala.collection.mutable.ArrayOps.ofRef[AnyRef]] ArrayOps_ofRef_Class: symtab.TypeSymbol = class ofRef scala> appliedType(symbolOf[Set[Any]], symbolOf[Set[Any]].typeParams.map(TypeVar(_))) res2: symtab.Type = Set[?A] scala> .narrow res3: symtab.Type = <none>.<refinement>.type scala> .baseTypeSeq java.lang.StackOverflowError at scala.reflect.runtime.Gil$class.gilSynchronized(Gil.scala:21) at scala.reflect.runtime.JavaUniverse.gilSynchronized(JavaUniverse.scala:16) at scala.reflect.runtime.SynchronizedOps$SynchronizedBaseTypeSeq$class.map(SynchronizedOps.scala:27) at scala.reflect.runtime.SynchronizedOps$SynchronizedBaseTypeSeq$$anon$2.map(SynchronizedOps.scala:34) at scala.reflect.runtime.SynchronizedOps$SynchronizedBaseTypeSeq$class.lateMap(SynchronizedOps.scala:34) at scala.reflect.runtime.SynchronizedOps$SynchronizedBaseTypeSeq$$anon$2.lateMap(SynchronizedOps.scala:34) at scala.reflect.internal.BaseTypeSeqs$MappedBaseTypeSeq.map(BaseTypeSeqs.scala:235) at scala.reflect.runtime.SynchronizedOps$SynchronizedBaseTypeSeq$$anon$2.scala$reflect$runtime$SynchronizedOps$SynchronizedBaseTypeSeq$$super$map(SynchronizedOps.scala:34) at scala.reflect.runtime.SynchronizedOps$SynchronizedBaseTypeSeq$$anonfun$map$1.apply(SynchronizedOps.scala:27) at scala.reflect.runtime.SynchronizedOps$SynchronizedBaseTypeSeq$$anonfun$map$1.apply(SynchronizedOps.scala:27) at scala.reflect.runtime.Gil$class.gilSynchronized(Gil.scala:19) at scala.reflect.runtime.JavaUniverse.gilSynchronized(JavaUniverse.scala:16) at scala.reflect.runtime.SynchronizedOps$SynchronizedBaseTypeSeq$class.map(SynchronizedOps.scala:27) at scala.reflect.runtime.SynchronizedOps$SynchronizedBaseTypeSeq$$anon$2.map(SynchronizedOps.scala:34) at scala.reflect.runtime.SynchronizedOps$SynchronizedBaseTypeSeq$class.lateMap(SynchronizedOps.scala:34) at scala.reflect.runtime.SynchronizedOps$SynchronizedBaseTypeSeq$$anon$2.lateMap(SynchronizedOps.scala:34) at scala.reflect.internal.BaseTypeSeqs$MappedBaseTypeSeq.map(BaseTypeSeqs.scala:235) ``` The infinite cycle involves: ``` class MappedBaseTypeSeq(orig: BaseTypeSeq, f: Type => Type) extends BaseTypeSeq(orig.parents map f, orig.elems) { ... override def map(g: Type => Type) = lateMap(g) override def lateMap(g: Type => Type) = orig.lateMap(x => g(f(x))) } trait SynchronizedBaseTypeSeq extends BaseTypeSeq { ... override def map(f: Type => Type): BaseTypeSeq = gilSynchronized { super.map(f) } override def lateMap(f: Type => Type): BaseTypeSeq = // only need to synchronize BaseTypeSeqs if they contain refined types if (map(f).toList.exists(_.isInstanceOf[RefinedType])) new MappedBaseTypeSeq(this, f) with SynchronizedBaseTypeSeq else new MappedBaseTypeSeq(this, f) } ``` This commit creates a new factory method for `MappedBaseTypeSeq`-s to break the cycle. As an independent change, I have also removed the attempt to conditionally synchronize them, as the condition was eagerly applying the map function (and throwing away the result!). I've appeased MiMa with new whitelist entries, but I'm confident that this is deep enough in the bowels of our runtime reflection implementation that there is no way that user code will be calling these methods directly.
Diffstat (limited to 'bincompat-backward.whitelist.conf')
-rw-r--r--bincompat-backward.whitelist.conf8
1 files changed, 8 insertions, 0 deletions
diff --git a/bincompat-backward.whitelist.conf b/bincompat-backward.whitelist.conf
index 57dc564e8a..9ea78a2977 100644
--- a/bincompat-backward.whitelist.conf
+++ b/bincompat-backward.whitelist.conf
@@ -34,6 +34,14 @@ filter {
problemName=DirectMissingMethodProblem
},
{
+ matchName="scala.reflect.runtime.SynchronizedOps.scala$reflect$runtime$SynchronizedOps$$super$newMappedBaseTypeSeq"
+ problemName=ReversedMissingMethodProblem
+ },
+ {
+ matchName="scala.reflect.runtime.SynchronizedOps#SynchronizedBaseTypeSeq.lateMap"
+ problemName=DirectMissingMethodProblem
+ },
+ {
matchName="scala.collection.immutable.HashMap.contains0"
problemName=DirectMissingMethodProblem
},