String::drain leaking concerns

String::drain's description says:

Leaking
If the returned iterator goes out of scope without being dropped (due to core::mem::forget, for example), the string may still contain a copy of any drained characters, or may have lost characters arbitrarily, including characters outside the range.

Why is that? The only thing Drain::drop does is removing char range from String. How can the String (from which I created draining iterator) lose characters then? Or maybe it means I shouldn't ever try to re-use the forgotten Drain, because the state of String may have changed, so the iterator would not be up-to-date?

You can't. mem::forget() assumes ownership of its argument.

I'm not sure you are understanding correctly what this clause is about. It describes situations when you (presumably intentionally) leak the iterator. You shouldn't do that, and it doesn't happen under normal circumstamces. This paragraph is not something you should worry about in all but the most degenerate cases.

Due to the implementation details of the removal. Maybe drain() doesn't remove everything at once (to spare an additional allocation), and moves characters to the left
one-by one, or something like this.

1 Like

Relevant article if you want to learn more on the background (at least for Vec::drain, but some of the considerations should transfer)

6 Likes

You can't. mem::forget() assumes ownership of its argument.

I rather thought about unsafe ways of doing so, but as I see now, pointer may not be valid after forget(), so let's forget :slight_smile: about that.

I'm not sure you are understanding correctly what this clause is about

I understand memory leaking, but I was just wondering why this

may have lost characters arbitrarily, including characters outside the range

could happen. Removal of the string slice happens in Drain's drop implementation, but we're talking about situation where we leak iterator, so drop isn't executed, drained part isn't removed from string and basically nothing happens to String itself. In this case String just shoudn't lose any characters. Am I wrong?

No, this is indeed very reasonable, and - without having looked at the implementation - that's likely what will actually be happening. The wording of the documentation is probably, as I mentioned above, just an insurance that standard library authors don't unnecessarily paint themselves into a corner by overspecifying implementation details (for corner cases you're not supposed to get yourself into in the first place) and possibly limiting future changes / improvements to the implementation strategy.

Maybe it's unnecessarily cautious in this particular case, but it's a good general approach to standard library documentation. Also, among all the drain methods, and particularly compared to Vec's one, the String::drain method is the only one that could even guarantee in the first place that the drained range would stay unmodified in case of leakage; documenting this could create false expectations that Vec::drain does (or ought to) operate the same way, since for many other methods, Vec and String do operate the same, or operations on String are even implemented in terms of the corresponding one for Vec.

6 Likes

That would be 100% UB.

The Drop impl isn't guaranteed to work like that. It may change any day. The documentation says "may", not that it does happen.

1 Like