-
-
Notifications
You must be signed in to change notification settings - Fork 700
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
Fix Issue 18848 - std.allocator: Regions are non-copyable, yet are pa… #6509
base: master
Are you sure you want to change the base?
Conversation
…ssed around in examples This doesn't fix that non-copyable regions are still passed around in examples, so we still rely on NRVO to do its thing and elide the copy, but at least this will now catch wrong code that mistakenly copied Regions around.
Thanks for your pull request, @CyberShadow! Bugzilla references
Testing this PR locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub fetch digger
dub run digger -- build "master + phobos#6509" |
OK, so, this is bad. The test failures indicate actual bugs in std.allocator code and unit tests. For example, in the case of FreeList failure, I wrote this program to verify: import std.experimental.allocator.building_blocks.free_list;
import std.experimental.allocator.common;
import std.stdio;
void logArg(A)(A arg)
{
static if (is(typeof(arg) : T[], T))
writef("%s..%s", arg.ptr, arg.ptr + arg.length);
else
write(arg);
}
struct LoggingAllocator(ParentAllocator)
{
static if (stateSize!ParentAllocator)
ParentAllocator parent;
else
{
alias ParentAllocator.instance parent;
enum instance = typeof(this).init;
}
enum alignment = ParentAllocator.alignment;
auto opDispatch(string fun, Args...)(auto ref Args args)
if (is(typeof(mixin(`parent.`~fun~`(args)`))))
{
write(fun, "(");
foreach (i, arg; args)
{
if (i) write(", ");
logArg(arg);
}
write(")");
static if (is(typeof(mixin(`parent.`~fun~`(args)`)) == void))
{
mixin(`parent.`~fun~`(args)`);
writeln;
}
else
{
auto res = mixin(`parent.`~fun~`(args)`);
write(" => ");
logArg(res);
writeln;
return res;
}
}
alias parent this;
}
void main()
{
// Fragment of a FreeList unittest
import std.experimental.allocator.building_blocks.region : Region;
import std.experimental.allocator.gc_allocator : GCAllocator;
import std.typecons : Ternary;
alias R = Region!(LoggingAllocator!GCAllocator);
alias A = ContiguousFreeList!(R, 0, 64);
auto a = A(R(1024 * 4), 1024);
auto b = a.allocate(100);
write("Allocated: "); logArg(b); writeln;
} Currently, the output is:
Meaning, not only do we "allocate" and return a block inside already-deallocated memory, but there is also a double-free bug (which for some reason GCAllocator ignores). This indicates that there is a systemic problem in how std.allocator is tested, and there are likely to be more similar bugs lurking around. I suggest to introduce something like a
Then, we should make all unit tests use The failing unit tests themselves should be easy enough to fix, just replace |
This is bad. Good catch!
We have For the current issue, I think that passing a pointer to the Regardless of what we decide the approach should be, I think it would be good to disable the postblit for |
CC @jercaianu |
Fix compilation error (previously, silent dangling pointer and double-free).
Ah, okay, I guess we can check for double-frees just by making sure we don't deallocate more than we allocated. A double free plus a memory leak shouldn't sum to "all OK", but I guess it doesn't make sense to put the carriage before the horse and overcomplicate things until we run into a bug that requires that level of thoroughness.
Alright, I fixed that instance by making it pass a pointer, and it looks like that was the only instance in the test suite so far, so CI is green.
Looks like that currently doesn't work, as
Agreed, so I think this PR is good for merge. |
Looks like that wasn't trivial either, started a discussion here: |
Speaking of StatsCollector, we should probably fix this before using it for such purposes: |
Thanks for looking into this! |
You mean, whenever a pointer would be used, make RCIAllocator the recommended choice? I think that would be fine, though perhaps ideally we'd have better move construction semantics in the language. I think modern C++ doesn't have this problem. |
@thewilsonator this would be a good merge with a resolution. |
…ssed around in examples
This doesn't fix that non-copyable regions are still passed around in
examples, so we still rely on NRVO to do its thing and elide the
copy, but at least this will now catch wrong code that mistakenly
copied Regions around.