Completed
Details
Assignee
UnassignedUnassignedReporter
gfredericksgfredericksApproval
OkPatch
Code and TestPriority
MajorAffects versions
Fix versions
Details
Details
Assignee
Unassigned
UnassignedReporter
gfredericks
gfredericksApproval
Ok
Patch
Code and Test
Priority

Affects versions
Fix versions
Created July 27, 2013 at 11:31 PM
Updated June 17, 2015 at 5:18 PM
Resolved June 17, 2015 at 5:18 PM
reduce
gives aStackOverflowError
on long sequences that contain many transitions between chunked and unchunked:Such a sequence is well behaved under most other sequence operations, and its underlying structure can even be masked such that
reduce
succeeds:I don't think Clojure developers normally worry about mixing chunked and unchunked seqs, so the existence of such a sequence is not at all unreasonable (and indeed this happened to me at work and was very difficult to debug).
Cause: The implementation of reduce can bounce back and forth between CollReduce and InternalReduce, consuming a stack frame in every transition. Given enough transitions, the stack will overflow.
Approach: Degrade to naive impl after first chunk
In the
IChunkedSeq
implementation, instead of callinginternal-reduce
when thesequence stops being chunked, it could have an (inlined?) unoptimized implementation,
ensuring that no further stack space is taken up. This retains the behavior that a
generic seq with a chunked tail will still run in an optimized fashion, but a seq with
two chunked portions would only be optimized the first time.
Rejected alternatives:
1) Use clojure.core/trampoline - This would presumably work, but requires wrapping the normal return values from all implementations of
internal-reduce
.2) Create a special type (
Unreduced
) that signalsan implementation change. The two implementation-change points in
internal-reduce
(in the
IChunkedSeq
impl and theObject
impl) are converted to return an instanceof
Unreduced
instead of a direct call tointernal-reduce
. Thenseq-reduce
is converted to check for instances ofUnreduced
before returning,and recurs if it finds one.
Patch: CLJ-1237f.patch
Screened by: Alex Miller