Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kibit 0.0.8 fails with Stack Overflow error when reading #{} set literals #78

Closed
jasonab opened this issue Mar 11, 2013 · 25 comments
Closed
Labels

Comments

@jasonab
Copy link

jasonab commented Mar 11, 2013

Exception in thread "main" java.lang.StackOverflowError
at clojure.core.logic$tree_term_QMARK_.invoke(logic.clj:972)
at clojure.core.logic$walk_STAR_$fn__1462.invoke(logic.clj:419)
at clojure.core.logic$eval1645$fn__1646.invoke(logic.clj:1068)
at clojure.core.logic$eval375$fn__376$G__366__383.invoke(logic.clj:85)
at clojure.core.logic$walk_STAR_.invoke(logic.clj:416)
at clojure.core.logic$walk_STAR_$fn__1462.invoke(logic.clj:420)
at clojure.core.logic$eval1645$fn__1646.invoke(logic.clj:1068)
at clojure.core.logic$eval375$fn__376$G__366__383.invoke(logic.clj:85)
at clojure.core.logic$walk_STAR_.invoke(logic.clj:416)
at clojure.core.logic$walk_STAR_$fn__1462.invoke(logic.clj:420)
at clojure.core.logic$eval1645$fn__1646.invoke(logic.clj:1068)
at clojure.core.logic$eval375$fn__376$G__366__383.invoke(logic.clj:85)

@jonase
Copy link
Collaborator

jonase commented Mar 11, 2013

Did you run kibit on a codebase that is publicly available?

@jasonab
Copy link
Author

jasonab commented Mar 11, 2013

Sorry, no, it ran on my company's codebase. I can completely believe that there's something weird inside it, but unfortunately I don't have any more information to go on.

Maybe an option to report what file kibit is processing?

@nbeloglazov
Copy link

Try run it on incanter's core.clj: https://github.com/liebke/incanter/blob/master/modules/incanter-core/src/incanter/core.clj
It fails with stackoverflow on my computer.

@nbeloglazov
Copy link

It fails on following function:

(defn- except-for-cols
"
"
  ([data except-cols]
     (let [colnames (:column-names data)
           _except-cols (if (coll? except-cols)
                          (map #(get-column-id data %) except-cols)
                          [(get-column-id data except-cols)])
           except-names  (if (some number? _except-cols)
                           (map #(nth colnames %) _except-cols)
                           _except-cols)]
       (for [name colnames :when (not (some #{name} except-names))]
         name))))

Actually on this part:

(not (some #{name} except-names))

@clyce
Copy link

clyce commented Dec 28, 2013

on my project, stack over flows too

@aspasia
Copy link

aspasia commented Feb 20, 2014

same here

@willgorman
Copy link

I can trigger a stack overflow running kibit on a file containing the form (->> [[1 2]] (into #{})) It looks like it may have something to do with the combination of the ->> macro and the set reader macro. The form (->> [[1 2]] (into {})) does not cause a stack overflow. I'm using kibit 0.0.8, leiningen 2.3.4, clojure 1.5.1, and java 1.7.0_45.

@dustinconrad
Copy link

This is happening for me. Codebase is publicly available.

@willgorman
Copy link

I think the problem is that core.logic doesn't support sets (Also: LOGIC-154)

@dustinconrad
Copy link

Will, I'm not sure that is it, as I replaced instances of #{...} with (hash-set ...) and now the stackoverflow isn't happening.

@danielcompton danielcompton modified the milestone: 0.1.0 release Nov 10, 2014
@danielcompton
Copy link
Member

This is still happening on core.logic 0.8.8. It looks possible (though maybe not advisable) to extend core.logic to be able to handle sets in kibit. - http://stackoverflow.com/questions/18017924/core-logic-stackoverflow-when-using-sets. Another way would be to modify core.logic.core/tree-term? from inside kibit, but that would be an even dirtier hack. Modifying tree-term? will let us read Clojure code, without throwing exceptions when we run across a set.

(defn tree-term? [x]
  (and (or (coll? x)
           (instance? ITreeTerm x))
       (not (instance? IPersistentSet x))))

@eigenhombre
Copy link

This failed for us recently too and cost us an hour or so. Here's what it barfs on:

(defn killit [coll]
  (not (some #{"string1" "string2"} (map ffirst coll))))

@danielcompton danielcompton changed the title Kibit 0.0.8 fails with Stack Overflow error Kibit 0.0.8 fails with Stack Overflow error when reading #{} set literals Nov 25, 2014
@danielcompton danielcompton removed this from the 0.1.0 release milestone Nov 25, 2014
@replomancer
Copy link
Contributor

Hey, same problem here (Kibit 0.0.8, Leiningen 2.5.1, Clojure both 1.7.0-alpha6 and 1.6.0). In my case it's this:
(defn f [x] (when (some #{x} [1]) (do (println "hello") 0)))
Kibit runs OK when I replace (some #{x} [1]) with true or if I remove the redundant do (either of these simplifications prevents StackOverflowError).

gshakhn added a commit to gshakhn/freefrog that referenced this issue May 4, 2015
A bit ugly, but it's a workaround until clj-commons/kibit#78 gets fixed.

Re-enable kibit for Travis CI builds since it should work now.
@schmir
Copy link

schmir commented Jun 26, 2015

Can we catch the error and go on with checking expressions until a proper fix is in place?

@a613
Copy link

a613 commented Oct 20, 2016

Still happening

@torbjornvatn
Copy link

Any hope for this beeing fixed? It's really annoying to get that looooong stacktrace in the output

@arrdem
Copy link
Collaborator

arrdem commented Oct 26, 2016

The "quick fix" which for the record I fully support would be to modify tree-term? as described by @danielcompton above. It's a dirty hack, but I think that influencing core.logic in this matter is either unlikely or at least likely to be slow. See how this issue has sat around for three years, and how the comments above about core.logic support for sets are in the same vintage.

Unless someone here wants to make the effort to enable core.logic to support sets properly.

@Rovanion
Copy link

Rovanion commented Nov 9, 2016

Another example of crash causing code:

(-> 1 (into #{}))

Rovanion added a commit to WeatherMagic/weather-front that referenced this issue Nov 9, 2016
@arrdem
Copy link
Collaborator

arrdem commented Nov 9, 2016

After talking with @danielcompton about this, the consensus seems to be that kibit will take the low road here. I'll drop a patch tonight which will run the kibit linter with a monkeypatch of the relevant part(s) of core.logic.

@arrdem
Copy link
Collaborator

arrdem commented Nov 10, 2016

Patch:

commit 07292e392c6b8adb44f4a37ba3dd952d78beffa3
Author: Reid 'arrdem' McKenzie <me@arrdem.com>
Date:   Thu Nov 10 00:10:56 2016 -0800

    WIP

diff --git a/src/kibit/driver.clj b/src/kibit/driver.clj
index caab14e..02bc091 100644
--- a/src/kibit/driver.clj
+++ b/src/kibit/driver.clj
@@ -3,9 +3,17 @@
             [kibit.rules :refer [all-rules]]
             [kibit.check :refer [check-file]]
             [kibit.reporters :refer :all]
-            [clojure.tools.cli :refer [cli]])
+            [clojure.tools.cli :refer [cli]]
+            [clojure.core.logic :refer [tree-term?]])
   (:import [java.io File]))

+(.setDynamic ^clojure.lang.Var #'tree-term?)
+
+(defn our-tree-term? [x]
+  (and (or (coll? x)
+           (instance? clojure.core.logic.protocols.ITreeTerm x))
+       (not (instance? clojure.lang.IPersistentSet x))))
+
 (def cli-specs [["-r" "--reporter"
                  "The reporter used when rendering suggestions"
                  :default "text"]])
@@ -33,16 +41,19 @@

 (defn run [source-paths rules & args]
   (let [[options file-args usage-text] (apply (partial cli args) cli-specs)
-        source-files (mapcat #(-> % io/file find-clojure-sources-in-dir)
-                             (if (empty? file-args) source-paths file-args))]
-    (mapcat (fn [file] (try (check-file file
-                                        :reporter (name-to-reporter (:reporter options)
-                                                                    cli-reporter)
-                                        :rules (or rules all-rules))
-                            (catch Exception e
-                              (binding [*out* *err*]
-                                (println "Check failed -- skipping rest of file")
-                                (println (.getMessage e))))))
+        source-files                   (mapcat #(-> % io/file find-clojure-sources-in-dir)
+                                               (if (empty? file-args) source-paths file-args))]
+    (mapcat (fn [file]
+              (try
+                (with-bindings {}
+                  (check-file file
+                              :reporter (name-to-reporter (:reporter options)
+                                                          cli-reporter)
+                              :rules (or rules all-rules)))
+                (catch Exception e
+                  (binding [*out* *err*]
+                    (println "Check failed -- skipping rest of file")
+                    (println (.getMessage e))))))
             source-files)))

 (defn external-run
diff --git a/test/kibit/test/collections.clj b/test/kibit/test/collections.clj
index e219f86..a81a1ea 100644
--- a/test/kibit/test/collections.clj
+++ b/test/kibit/test/collections.clj
@@ -4,24 +4,30 @@

 (deftest collections-are
   (are [expected-alt-form test-form]
-       (= expected-alt-form (:alt (kibit/check-expr test-form)))
-    '(seq a) '(not (empty? a))
+      (= expected-alt-form (:alt (kibit/check-expr test-form)))
+    '(seq a)          '(not (empty? a))
     '(when (seq a) b) '(when-not (empty? a) b)
     '(when (seq a) b) '(when (not (empty? a)) b)
-    '(vector a) '(conj [] a)
+
+    '(vector a)   '(conj [] a)
     '(vector a b) '(conj [] a b)
-    '(vec coll) '(into [] coll)
+    '(vec coll)   '(into [] coll)
+
     '(set coll) '(into #{} coll)
+
     '(update-in coll [k] f) '(assoc coll k (f (k coll)))
     '(update-in coll [k] f) '(assoc coll k (f (coll k)))
     '(update-in coll [k] f) '(assoc coll k (f (get coll k)))
+
     '(assoc-in coll [k0 k1] a) '(assoc coll k0 (assoc (k0 coll) k1 a))
     '(assoc-in coll [k0 k1] a) '(assoc coll k0 (assoc (coll k0) k1 a))
     '(assoc-in coll [k0 k1] a) '(assoc coll k0 (assoc (get coll k0) k1 a))
+    '(assoc-in coll [k1 k2] v) '(update-in coll [k1 k2] assoc v)
+
     '(update-in coll [k] f a b c) '(assoc coll k (f (k coll) a b c))
     '(update-in coll [k] f a b c) '(assoc coll k (f (coll k) a b c))
     '(update-in coll [k] f a b c) '(assoc coll k (f (get coll k) a b c))
-    '(assoc-in coll [k1 k2] v) '(update-in coll [k1 k2] assoc v)
+
     '(repeatedly 10 (constantly :foo)) '(take 10 (repeatedly (constantly :foo)))

     ;; some wrong simplifications happened in the past:
diff --git a/test/kibit/test/driver.clj b/test/kibit/test/driver.clj
index 2cd3534..ed93f4d 100644
--- a/test/kibit/test/driver.clj
+++ b/test/kibit/test/driver.clj
@@ -13,5 +13,9 @@
 (deftest find-clojure-sources-are
   (is (= [(io/file "test/resources/first.clj")
           (io/file "test/resources/second.cljx")
+          (io/file "test/resources/sets.clj")
           (io/file "test/resources/third.cljs")]
          (driver/find-clojure-sources-in-dir (io/file "test/resources")))))
+
+(deftest test-set-file
+  (is (driver/run ["test/resources/sets.clj"] nil)))
diff --git a/test/resources/sets.clj b/test/resources/sets.clj
new file mode 100644
index 0000000..f9025cd
--- /dev/null
+++ b/test/resources/sets.clj
@@ -0,0 +1,5 @@
+(ns resources.sets)
+
+(defn killit [coll]
+  (not (some #{"string1" "string2"}
+             (map ffirst coll))))

Test output:


lein test kibit.test.arithmetic

lein test kibit.test.check

lein test kibit.test.collections

lein test kibit.test.control-structures

lein test kibit.test.core

lein test kibit.test.driver

lein test :only kibit.test.driver/test-set-file

ERROR in (test-set-file) (logic.clj:359)
expected: (driver/run ["test/resources/sets.clj"] nil)
  actual: java.lang.StackOverflowError: null
 at clojure.core.logic.Substitutions.walk (logic.clj:359)
    clojure.core.logic$walk_STAR_$fn__1798.invoke (logic.clj:231)
    clojure.core.logic$eval1980$fn__1981.invoke (logic.clj:984)
    clojure.core.logic.protocols$eval456$fn__457$G__447__464.invoke (protocols.clj:55)
    clojure.core.logic$walk_STAR_.invokeStatic (logic.clj:229)
    clojure.core.logic$walk_STAR_.invoke (logic.clj:227)
    clojure.core.logic$walk_STAR_$fn__1798.invoke (logic.clj:233)
    clojure.core.logic$eval1980$fn__1981.invoke (logic.clj:984)
    [[ repeating frames elided ]]

lein test kibit.test.equality

lein test kibit.test.misc

lein test kibit.test.reporters

lein test resources.sets

Ran 15 tests containing 121 assertions.
0 failures, 1 errors.

@michael-cenx
Copy link

I seemingly reproduced this stack overflow bug with nested #{}

(def data {"a" #{"b" "c"}, "d" #{"f" "e"}}) => #'user/data (->> (for [[k v] data] (assoc {} :entity-id k :contents (into #{} v))) (into #{}))

Workaround: Replace all #{} with (hash-set). We may want to re-open this bug

@danielcompton
Copy link
Member

Can you try again with 0.1.4? I think that should work.

@michael-cenx
Copy link

michael-cenx commented May 8, 2017

Sorry I just tried it and it failed.

lein kibit Exception in thread "main" java.lang.StackOverflowError, compiling:(/private/var/folders/ch/lwy55whj30xc297m70qqhpfw0000gp/T/form-init8711051728291748004.clj:1:124) at clojure.lang.Compiler.load(Compiler.java:7142) at clojure.lang.Compiler.loadFile(Compiler.java:7086) at clojure.main$load_script.invoke(main.clj:274) at clojure.main$init_opt.invoke(main.clj:279) at clojure.main$initialize.invoke(main.clj:307) at clojure.main$null_opt.invoke(main.clj:342) at clojure.main$main.doInvoke(main.clj:420) at clojure.lang.RestFn.invoke(RestFn.java:421) at clojure.lang.Var.invoke(Var.java:383) at clojure.lang.AFn.applyToHelper(AFn.java:156) at clojure.lang.Var.applyTo(Var.java:700) at clojure.main.main(main.java:37) Caused by: java.lang.StackOverflowError at clojure.core.logic$eval1821$fn__1822.invoke(logic.clj:979) at clojure.core.logic.protocols$eval277$fn__278$G__268__285.invoke(protocols.clj:55) at clojure.core.logic$walk_STAR_.invoke(logic.clj:229) at clojure.core.logic$walk_STAR_$fn__1620.invoke(logic.clj:233) at clojure.core.logic$eval1821$fn__1822.invoke(logic.clj:984) at clojure.core.logic.protocols$eval277$fn__278$G__268__285.invoke(protocols.clj:55) at clojure.core.logic$walk_STAR_.invoke(logic.clj:229) at clojure.core.logic$walk_STAR_$fn__1620.invoke(logic.clj:233) at clojure.core.logic$eval1821$fn__1822.invoke(logic.clj:984) at clojure.core.logic.protocols$eval277$fn__278$G__268__285.invoke(protocols.clj:55) ...

@danielcompton
Copy link
Member

@arrdem thoughts?

@arrdem
Copy link
Collaborator

arrdem commented May 9, 2017

Investigating.

arrdem added a commit to arrdem/kibit that referenced this issue May 9, 2017
The monkeypatching code was totally appropriate we just weren't using
it.

Fixes clj-commons#78
arrdem added a commit to arrdem/kibit that referenced this issue May 9, 2017
arrdem added a commit to arrdem/kibit that referenced this issue May 9, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests