This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch GROOVY-7722
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit cca6da1f94c3d78d6d9cc1f722b2a5bfaecd6733
Author: Eric Milles <eric.mil...@thomsonreuters.com>
AuthorDate: Sat Nov 9 10:16:10 2019 -0600

    GROOVY-7722: prevent stack overflow resolving generics placeholders
    
    GROOVY-7864
---
 .../codehaus/groovy/ast/tools/GenericsUtils.java   |  2 +
 src/test/groovy/bugs/Groovy7722.groovy             | 83 ++++++++++++++++++++++
 2 files changed, 85 insertions(+)

diff --git a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java 
b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
index 0ff33de..bc22176 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -50,6 +50,7 @@ import java.util.function.Predicate;
 
 import static groovy.lang.Tuple.tuple;
 import static org.apache.groovy.util.SystemUtil.getSystemPropertySafe;
+import static org.codehaus.groovy.runtime.DefaultGroovyMethods.plus;
 import static 
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.getCorrectedClassNode;
 import static 
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf;
 
@@ -352,6 +353,7 @@ public class GenericsUtils {
         }
         if (type.isGenericsPlaceHolder() && 
!exclusions.contains(type.getUnresolvedName())) {
             String name = type.getGenericsTypes()[0].getName();
+            exclusions = plus(exclusions, name); // GROOVY-7722
             type = genericsSpec.get(name);
             if (type != null && type.isGenericsPlaceHolder()) {
                 if (type.getGenericsTypes() == null) {
diff --git a/src/test/groovy/bugs/Groovy7722.groovy 
b/src/test/groovy/bugs/Groovy7722.groovy
new file mode 100644
index 0000000..1fd017c
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy7722.groovy
@@ -0,0 +1,83 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package groovy.bugs
+
+import groovy.transform.CompileStatic
+import org.junit.Test
+
+import static groovy.test.GroovyAssert.assertScript
+
+@CompileStatic
+final class Groovy7722 {
+
+    @Test
+    void testGenericsStackOverflow1() {
+        assertScript '''
+            interface Action1<T> {
+                void call(T t)
+            }
+            abstract class Subscriber<T> {
+            }
+            interface OnSubscribe<T> extends Action1<Subscriber<? super T>> {
+            }
+
+            new OnSubscribe<List>() {
+                @Override
+                void call(Subscriber<? super List> o) {
+                    println 'called'
+                }
+            }.call(null)
+        '''
+    }
+
+    @Test // GROOVY-7864
+    void testGenericsStackOverflow2() {
+        assertScript '''
+            // from RxJava 1.x
+            class Observable<T> {
+                interface OnSubscribe<T> extends Action1<Subscriber<? super 
T>> {
+                }
+                static <T> Observable<T> create(OnSubscribe<T> f) {
+                    return new Observable<T>(/*RxJavaHooks.onCreate(f)*/);
+                }
+            }
+            abstract class Subscriber<T> implements Observer<T>, Subscription {
+            }
+            interface Action1<T> /*extends Action*/ {
+                void call(T t)
+            }
+            interface Observer<T> {
+                void onNext(T t)
+                void onCompleted()
+                void onError(Throwable t)
+            }
+            public interface Subscription {
+                void unsubscribe()
+                boolean isUnsubscribed()
+            }
+
+            Observable.create(new Observable.OnSubscribe() {
+                @Override
+                void call(Subscriber subscriber) {
+                    //...
+                }
+            })
+        '''
+    }
+}

Reply via email to