Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.
/ druntime Public archive
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 17 additions & 10 deletions src/core/memory.d
Original file line number Diff line number Diff line change
Expand Up @@ -811,9 +811,11 @@ struct GC
}

/**
* Pure variants of C's memory allocation functions `malloc`, `calloc` and
* `realloc`. Purity is achieved via resetting the `errno` to it's value prior
* to being called, removing the function's global state mutation.
* Pure variants of C's memory allocation functions `malloc`, `calloc`, and
* `realloc` and deallocation function `free`.
*
* Purity is achieved by saving and restoring the value of `errno`, thus
* behaving as if it were never changed.
*
* See_Also:
* $(LINK2 https://dlang.org/spec/function.html#pure-functions, D's rules for purity),
Expand Down Expand Up @@ -841,7 +843,7 @@ void* pureCalloc(size_t nmemb, size_t size) @trusted pure @nogc nothrow
return ret;
}
/// ditto
void* pureRealloc(void* ptr, size_t size) pure @nogc nothrow
void* pureRealloc(void* ptr, size_t size) @system pure @nogc nothrow
{
const errno = fakePureGetErrno();
void* ret = fakePureRealloc(ptr, size);
Expand All @@ -851,12 +853,17 @@ void* pureRealloc(void* ptr, size_t size) pure @nogc nothrow
}
return ret;
}
/// ditto
void pureFree(void* ptr) @system pure @nogc nothrow
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

free is not guaranteed not to set errno by current standards; libc implementations may choose to set errno for both valid and invalid pointers.
POSIX.1 Issue 8 (still WIP), is going to forbid free to set errno for valid pointers, but explicitly allows setting it for an invalid pointers.
AFAIK there's no way for us to know whether the used libc will be linked to statically or dynamically and in the latter case there's no way AFAIK to know if the libc does or does not set errno.
It follows that pureFree must save&restore the errno value the same way that the allocation functions do:

const errno = fakePureGetErrno();
fakePureFree(ptr);
if (errno != 0) fakePureSetErrno(errno);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yah, let's set and restore it for now regardless. We may change that later as an optimization. Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

{
const errno = fakePureGetErrno();
fakePureFree(ptr);
cast(void)fakePureSetErrno(errno);
}

///
nothrow @nogc unittest
@system pure nothrow @nogc unittest
{
import core.stdc.stdlib : free;

ubyte[] fun(size_t n) pure
{
void* p = pureMalloc(n);
Expand All @@ -869,10 +876,10 @@ nothrow @nogc unittest

auto buf = fun(100);
assert(buf.length == 200);
free(buf.ptr);
pureFree(buf.ptr);
}

pure @nogc nothrow unittest
@system pure nothrow @nogc unittest
{
const int errno = fakePureGetErrno();

Expand Down Expand Up @@ -909,5 +916,5 @@ extern (C) private pure @system @nogc nothrow
pragma(mangle, "calloc") void* fakePureCalloc(size_t nmemb, size_t size);
pragma(mangle, "realloc") void* fakePureRealloc(void* ptr, size_t size);

pragma(mangle, "free") void fakePureFree(void* ptr); // needed by unittests
pragma(mangle, "free") void fakePureFree(void* ptr);
}