Skip to content

Conversation

@WalterBright
Copy link
Member

No description provided.

@9il 9il added the overflow label Aug 5, 2016
std/file.d Outdated
immutable newAlloc = addu(size, sizeIncrement, overflow);
if (overflow) assert(0);

result = GC.realloc(result.ptr, newAlloc, GC.BlkAttr.NO_SCAN)[0 .. newAlloc];
Copy link
Member

Choose a reason for hiding this comment

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

Why?
You'll always crash before reaching that overflow. It's a size_t, so your address space is gone before it overflows.
That's too much ugly code for it's uselessness.

Copy link
Member Author

Choose a reason for hiding this comment

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

You'll always crash before reaching that overflow.

Famous last words :-)

All assert's are guaranteed to never be tripped. Of course, we're often wrong about that, and they get tripped. Hence adding this here.

@MartinNowak
Copy link
Member

See, this is the mess w/ all those crappy tiny PRs.
Now we having plenty of separate discussions #4712, #4713, #4714, #4715, #4716, #4717, #4718 about the same thing. This literally feels like sneaking in changes to me.

@MartinNowak
Copy link
Member

Where does the sudden interest in size_t overflows come from? In particular when used in buffer resizing there seems to be no practical use, b/c as pointed out above, you'll always end up w/o address space long before the overflow.

@MartinNowak
Copy link
Member

Before flooding phobos w/ even more of this ugly code, please write a small SafeInt helper in std/internal that does those checks.

@schveiguy
Copy link
Member

schveiguy commented Aug 9, 2016

you'll always end up w/o address space long before the overflow.

Not necessarily. In many cases, you request a malloc for the result of a multiplication. If it overflows, the size actually granted could succeed and be quite small. But because malloc only tells you that you succeeded and here's your pointer, it's up to you to make that into a safe D array. In other words, your code thinks you requested space for 2 billion int, but instead you got space for 50 million. However, you just happily slice the pointer for 2 billion having a large unsafe access to all address space. In 64 bits, the overflow case is much less likely.

For the addition overflows, I agree the benefit is debatable. But if you are going to check for one case, you may as well check for all.

I do agree that a SafeInt type would look MUCH better than all these calls. It's easy to miss some operations too without such a nice wrapper type.

@JackStouffer
Copy link
Contributor

I do agree that a SafeInt type would look MUCH better than all these calls. It's easy to miss some operations too without such a nice wrapper type.

Then review #4613

Copy link
Member

@andralex andralex left a comment

Choose a reason for hiding this comment

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

This is getting to the point where Checked is justified. Simply replacing size_t size = 0; with auto size = checked!size_t(0); and leaving all other code unchanged takes care of it.

@JackStouffer
Copy link
Contributor

@andralex I thought the current rule was "no std.experimental use in std".

@andralex
Copy link
Member

@JackStouffer on the contrary, use of experimental facilities in phobos is good dogfooding.

@dnadlinger
Copy link
Contributor

@andralex @JackStouffer: Agreed. std.experimental shouldn't leak into the interface, but use in the implementation is fine. If the worst comes to the worst, we could always keep a private copy of the necessary parts in std.internal.

@WalterBright
Copy link
Member Author

Simply replacing size_t size = 0; with auto size = checked!size_t(0); and leaving all other code unchanged takes care of it.

Turns out it's more than that, as the diffs show.

@WalterBright
Copy link
Member Author

Hmm, now I get:

object.Error@src/rt/minfo.d(371): Cyclic dependency between module std.experimental.allocator and std.concurrency
std.experimental.allocator* ->
std.conv ->
std.datetime ->
std.datetime.timezone ->
std.concurrency* ->
std.stdio ->
std.file ->
std.experimental.checkedint ->
std.experimental.allocator.common ->
std.experimental.allocator*

checkedint should not be having cycles

@andralex
Copy link
Member

Time to get rid of them static shared this(). #5421

@andralex
Copy link
Member

#5423, too

Copy link
Member

@andralex andralex left a comment

Choose a reason for hiding this comment

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

Couple of things that make the code a tad simpler. In fact I'll try to make the changes myself.

size_t size = 0;

import std.experimental.checkedint;
auto size = checked!Abort(cast(size_t)0);
Copy link
Member

Choose a reason for hiding this comment

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

Abort is the default, please use checked(size_t(0))

version (unittest)
enum BUF_SIZE = 10; // trigger reallocation code
else
enum BUF_SIZE = 4096; // enough for most common case
Copy link
Member

Choose a reason for hiding this comment

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

neat idea

{
auto ptr = cast(wchar*) malloc(wchar.sizeof * n);
import std.experimental.checkedint;
auto cn = checked!Abort(n);
Copy link
Member

Choose a reason for hiding this comment

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

checked(n)

@andralex
Copy link
Member

@WalterBright I couldn't edit this PR. Please rebase and mind the review - thx!

@JackStouffer
Copy link
Contributor

As this is dead in the water, I've revived the changes here: #5990

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants