digitalmars.D.learn - SegFault trying to chunk lazily joined ranges
- Keivan Shah (48/48) Jul 01 2021 Hello,
- Steven Schveighoffer (21/27) Jul 01 2021 Thanks for the detailed instructions, very easy to reproduce.
Hello, I am trying to create a lazy range that iterates and chunks data over an array of lazy ranges but the code seems to lead to segFaults. I have tried to reduce the issue to minimum possible code that reproduces the error. My hypothesis is I am doing something wrong leading to the `joiner` and `chunkBy` code to not play well with each other, when trying to create a lazy range. But the code does work when I load all the data into memory i.e skip doing it lazily. Here is the reduced code example, running the code on [run.dlang.io](https://run.dlang.io/is/wfhNrn) also reproduces the error: ```D void main() { import std.range; import std.stdio; import std.algorithm; import etc.linux.memoryerror; static if (is(typeof(registerMemoryErrorHandler))) registerMemoryErrorHandler(); ForwardRange!(int)[] listOfRanges; listOfRanges ~= iota(1).map!(a => a).inputRangeObject; listOfRanges ~= iota(2).map!(a => a).inputRangeObject; auto lazyFlattenedRange = joiner(listOfRanges); auto d1 = lazyFlattenedRange .array // Everything is loaded, no longer lazy .chunkBy!(a => a).map!(a => a[0]) .inputRangeObject; writeln("Non Lazy Chunked Data length: ", d1.walkLength); // The NEXT part will cause a SEGFAULT. lazyFlattenedRange = joiner(listOfRanges); // Reinitializing, since we already iterated it once auto d2 = lazyFlattenedRange .chunkBy!(a => a).map!(a => a[0]) .inputRangeObject; writeln("Lazy Chunked Data length: ", d2.walkLength); // <--- SegFault } ``` Using the handler I was able to get the stack trace and it seems that the segFault is caused by `joiner` trying to call `.save` on a null object leading to a `NullPointerError`. But I have not been able to debug it further. Mostly it seems that there is something wrong with my understanding of ranges or it could be a genuine bug in std.range. Can anyone help me debug this piece of code? Thanks, Keivan Shah
Jul 01 2021
On 7/1/21 10:56 AM, Keivan Shah wrote:Using the handler I was able to get the stack trace and it seems that the segFault is caused by `joiner` trying to call `.save` on a null object leading to a `NullPointerError`. But I have not been able to debug it further. Mostly it seems that there is something wrong with my understanding of ranges or it could be a genuine bug in std.range. Can anyone help me debug this piece of code?Thanks for the detailed instructions, very easy to reproduce. However, chunkBy is a hot mess, which probably has a bug in it somewhere. I don't exactly know where this is, but know that using objects for forward ranges is bound to result in some failures, simply because they are one of the only forward ranges that *requires* calling `.save`, and much code exists that forgets to do that. I spent about 20 minutes trying to find this and can't see how `chunkBy` actually works in this case. I don't have any more time to spend on it, sorry. I narrowed your code down to the minimal case that I could find that segfaults: ```d ForwardRange!int[] listOfRanges = [iota(1).inputRangeObject]; auto lazyFlattenedRange = joiner(listOfRanges); auto d2 = lazyFlattenedRange.chunkBy!(a => a); while(!d2.empty) d2.popFront; ``` I hope this helps someone narrow it down. -Steve
Jul 01 2021