Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

[RFC] Add pure fail-fast assertMalloc, assertCalloc, assertRealloc #2276

Closed
wants to merge 1 commit into from

Conversation

n8sh
Copy link
Member

@n8sh n8sh commented Aug 16, 2018

These functions achieve purity by aborting the program on failure so errno is never observed to change. This PR also changes pureMalloc etc. to templates so they work in betterC.

The idea was suggested by @ZombineDev at dlang/phobos#6660 (comment) and #2268 (comment). The sole difference is that instead of adding a boolean template parameter to pureMalloc I instead named the new variant differently. I felt that assertMalloc(100) has a more obvious meaning than pureMalloc!true(100) which gives no hint as to whether it's the one that aborts on failure or the one that saves and restores errno.

@dlang-bot
Copy link
Contributor

Thanks for your pull request, @n8sh!

Bugzilla references

Your PR doesn't reference any Bugzilla issue.

If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.

Testing this PR locally

If 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 + druntime#2276"

@n8sh n8sh force-pushed the failfast-malloc branch 2 times, most recently from 9ee729c to fc9c777 Compare August 16, 2018 09:19
void* ret = fakePureMalloc(size);
if (!ret && size)
{
version (D_BetterC) assert(0, "Memory allocation failed");
Copy link
Contributor

Choose a reason for hiding this comment

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

@WalterBright has made the decision that we should be using assert(0) (preferably assert(false)) for both -betterC and non-betterC builds.

Copy link
Member Author

Choose a reason for hiding this comment

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

Got it.

Copy link
Member

Choose a reason for hiding this comment

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

Also it would be better to use version (D_Exceptions) to check whether exceptions can be thrown as LDC/GDC allow to disable them selectively (and e.g. WebAssembly might not defined -betterC, but still not support exceptions.)


@nogc nothrow pure @system unittest
{
const int errno = fakePureErrno();
Copy link
Contributor

@JinShil JinShil Aug 16, 2018

Choose a reason for hiding this comment

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

fakePureErrno is mangled to fakePureErrnoImpl which is not a template. Therefore this won't work until fakePureErrnoImpl is made into a template, or some other solution is devised.

Edit: I mean it won't work in -betterC until fakePureErrnoImpl is made into a template, or some other solution is devised

Copy link
Member Author

Choose a reason for hiding this comment

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

Should be fixed now.

* The functions may terminate the program using `onOutOfMemoryError` or
* `assert(0)`. These functions' purity guarantees no longer hold if
* the program continues execution after catching AssertError or
* OutOfMemoryError.
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this comment needs updating.

Copy link
Member Author

Choose a reason for hiding this comment

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

I kept the mention of the possibility so if we later change to using onOutOfMemoryError no one will be blindsided. Do you think it's better to remove it because that's too unlikely?

Copy link
Contributor

Choose a reason for hiding this comment

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

No need to change anything immediately, IMO. We can wait to see how the review goes. It just eventually needs to reflect the final implementation.

@n8sh n8sh force-pushed the failfast-malloc branch 9 times, most recently from 45fa62e to fe1119f Compare August 16, 2018 12:47

version (D_BetterC) @nogc nothrow private @system
Copy link
Contributor

Choose a reason for hiding this comment

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

Will this implementation work in non-betterC builds? Can't we use this implementation for both -betterC and non-betterC builds?

Copy link
Member Author

Choose a reason for hiding this comment

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

It would work. The purpose of the version branch is so outside code that assumes fakePureErroImpl exists and tries to link to it will not break.

@PetarKirov
Copy link
Member

PetarKirov commented Aug 17, 2018

I would argue that OOM is not a logical error on the programmer side, rather it is an exception from the program environment, albeit a non-recoverable from one. IMO, we should continue calling onOutOfMemoryError as it is provides for a bit more systematic way of handling this type of exception, just make sure it has a fallback for version (D_Exceptions) { } { /* ... */ } .

P.S. Thanks a lot for working on this guys, I would prefer to do the work myself instead of just talking, but sadly I have very limited free time these days.

@n8sh
Copy link
Member Author

n8sh commented Aug 17, 2018

@ZombineDev That makes sense.

Also change pureMalloc etc. to templates so they work in betterC.
@JinShil
Copy link
Contributor

JinShil commented Aug 17, 2018

I would argue that OOM is not a logical error on the programmer side, rather it is an exception from the program environment, albeit a non-recoverable from one. IMO, we should continue calling onOutOfMemoryError as it is provides for a bit more systematic way of handling this type of exception

I'm not terribly partial to either one, but @WalterBright has spoken. We need to come to some consensus about this and apply it consistently.

Edit: I will add that it'd be kind of nice if both -betterC and non-betterC behaved the same whenever possible.

@JinShil JinShil closed this Aug 17, 2018
@JinShil JinShil reopened this Aug 17, 2018
@JinShil
Copy link
Contributor

JinShil commented Aug 17, 2018

Sorry! Wrong button.

@n8sh
Copy link
Member Author

n8sh commented Aug 17, 2018

I'm not terribly partial to either one, but @WalterBright has spoken.

I took your summary to mean that he was okay with using assert but not that he was mandating it. Did I get the wrong idea?

@WalterBright has already affirmed to me (twice actually) in private e-mail exchange that he is OK replacing Errors with asserts even in non-betterC code.

@JinShil
Copy link
Contributor

JinShil commented Aug 17, 2018

I took your summary to mean that he was okay with using assert but not that he was mandating it. Did I get the wrong idea?

@WalterBright will have to speak for himself, but my interpretation is that he preferred us to use asserts. It's very unlike him to mandate anything, from my experience.

Copy link
Contributor

@JinShil JinShil left a comment

Choose a reason for hiding this comment

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

I'm OK with this, but the DDoc comments still need updating.

@JinShil
Copy link
Contributor

JinShil commented Aug 19, 2018

We still need to come to some consensus about Errors vs asserts. Once that decision is made, this should be updated to reflect it.

return ret;
}
/// ditto
void* assertRealloc()(void* ptr, size_t size) @nogc nothrow pure @system
Copy link
Member

Choose a reason for hiding this comment

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

Since realloc() free's memory, it cannot ever be considered pure.

Copy link
Contributor

Choose a reason for hiding this comment

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

Since realloc() free's memory, it cannot ever be considered pure.

We have a pureFree, and GC.free is also marked as pure.

pure functions are allowed to modify their parameters. Freeing is never @safe, but in what way is it less pure than other forms of mutation?

Copy link
Member Author

Choose a reason for hiding this comment

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

There is also already a pureRealloc.

druntime/src/core/memory.d

Lines 840 to 847 in db2910e

/// ditto
void* pureRealloc(void* ptr, size_t size) @system pure @nogc nothrow
{
const errnosave = fakePureErrno();
void* ret = fakePureRealloc(ptr, size);
fakePureErrno() = errnosave;
return ret;
}

@n8sh n8sh closed this Nov 18, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants