Bug 22359 – joiner over an empty forward range object liable to segfault

Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P1
Component
phobos
Product
D
Version
D2
Platform
x86_64
OS
Linux
Creation time
2021-10-06T01:51:05Z
Last change time
2021-10-09T09:17:59Z
Keywords
pull
Assigned to
No Owner
Creator
Adam D. Ruppe

Comments

Comment #0 by destructionator — 2021-10-06T01:51:05Z
There's some old bugs from a decade ago that are apparently related but not quite the same as their test case is one item deep and this requires something two items deep. Behold: ------ import std.range; ForwardRange!int fnFlatten(int[][] r) { import std.range : inputRangeObject; import std.algorithm : map, joiner; auto range = inputRangeObject(r); return range.map!(a =>inputRangeObject(a)).joiner.inputRangeObject; } void main() { auto f = fnFlatten([[]]); f.save(); } ------ In the `private enum popFrontEmptyElement` of joiner, there's a `_current = typeof(_current).init;` If _current is some kind of class, that's null. Then when you call `save` on it, it is a null this deref.
Comment #1 by destructionator — 2021-10-06T01:53:16Z
There's also a static if (isBidirectional && hasNested!Result) _currentBack = typeof(_currentBack).init; Same problem.
Comment #2 by destructionator — 2021-10-06T01:55:38Z
A patched function that can fix the issue: static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR)) { @property auto save() { static if(is(typeof(null) : typeof(_current))) { auto r = Result(_items.save, _current is null ? null : _current.save); } else auto r = Result(_items.save, _current.save); static if (isBidirectional) { static if(is(typeof(null) : typeof(_currentBack))) { r._currentBack = _currentBack is null ? null : _currentBack.save; } else { r._currentBack = _currentBack.save; } r.reachedFinalElement = reachedFinalElement; } return r; } }
Comment #3 by dlang-bot — 2021-10-06T02:14:25Z
@adamdruppe created dlang/phobos pull request #8263 "Fix issue #22359." fixing this issue: - Fix issue #22359. If you pass it a range of class-based ranges, the initialization to `typeof(_current).init` will be `null`. Calling the `save` method on `null` will naturally be a memory violation. This generic check will handle null without harming any other type since save of any init value will be another init value. https://github.com/dlang/phobos/pull/8263
Comment #4 by dlang-bot — 2021-10-09T09:17:59Z
dlang/phobos pull request #8263 "Fix issue #22359 - joiner over an empty class range liable to segfault" was merged into master: - ff6920bd8a461393dcdb7d01edb9b62bcb9bf4d1 by Adam D. Ruppe: Fix issue #22359 - joiner over an empty forward range object liable to segfault If you pass it a range of class-based ranges, the initialization to `typeof(_current).init` will be `null`. Calling the `save` method on `null` will naturally be a memory violation. This generic check will handle null without harming any other type since save of any init value will be another init value. https://github.com/dlang/phobos/pull/8263