Closed Bug 1472113 Opened 6 years ago Closed 6 years ago

[meta] Audit callers of SetCapacity for writing past mLength

Categories

(Core :: XPCOM, enhancement)

enhancement
Not set
normal

Tracking

()

RESOLVED FIXED

People

(Reporter: hsivonen, Assigned: hsivonen)

References

Details

(Keywords: meta)

Currently, we have callers that assume that it's valid to do this:
 1) Call SetCapacity()
 2) Obtain a raw pointer to the start of the string and write past mLength of the string.
 3) Call SetLength() with a new length assuming that even a reallocation happens, the data written past mLength is preserved.

This is bad, because it causes excessive memcpy in the case of reasonable callers.

We should audit callers of SetCapacity() to make sure that callers that wish to write stuff to the raw buffer use SetLength() instead. Then we should make SetCapacity() preserve buffer data only up to mLength.

It doesn't make sense to start this until bug 1402247 has landed.
Base64Decode is one of the bad callers.
(In reply to Henri Sivonen (:hsivonen) from comment #0)
> Currently, we have callers that assume that it's valid to do this:
>  1) Call SetCapacity()
>  2) Obtain a raw pointer to the start of the string and write past mLength
> of the string.
>  3) Call SetLength() with a new length assuming that even a reallocation
> happens, the data written past mLength is preserved.

Is it really common for callers to pass different lengths to SetCapacity/SetLength, or even a *larger* SetLength than SetCapacity?

> This is bad, because it causes excessive memcpy in the case of reasonable
> callers.

I agree this is a gnarly pattern, but where does the excessive memcpy'ing come from?
(In reply to Nathan Froyd [:froydnj] from comment #2)
> (In reply to Henri Sivonen (:hsivonen) from comment #0)
> > Currently, we have callers that assume that it's valid to do this:
> >  1) Call SetCapacity()
> >  2) Obtain a raw pointer to the start of the string and write past mLength
> > of the string.
> >  3) Call SetLength() with a new length assuming that even a reallocation
> > happens, the data written past mLength is preserved.
> 
> Is it really common for callers to pass different lengths to
> SetCapacity/SetLength, or even a *larger* SetLength than SetCapacity?

In addition to the Base64 code, I found another offender:
https://searchfox.org/mozilla-central/source/gfx/layers/opengl/GLBlitTextureImageHelper.cpp#243

So far not common.

> > This is bad, because it causes excessive memcpy in the case of reasonable
> > callers.
> 
> I agree this is a gnarly pattern, but where does the excessive memcpy'ing
> come from?

Having to memcpy not only the number of code units indicated by the old mLength but the whole buffer--even the part that's logically supposed to be unused.
Assignee: nobody → hsivonen
Status: NEW → ASSIGNED
(In reply to Henri Sivonen (:hsivonen) from comment #4)
> Bogus in yet another way:
> https://searchfox.org/mozilla-central/source/netwerk/protocol/http/
> Http2Compression.cpp#1095

The use of BeginWriting() in this file is at the very least weird, though perhaps not wrong.
Depends on: 1484668
XHR's responseText building has this issue, too.
Depends on: 1484984
Depends on: 1484985
Depends on: 1484987
Depends on: 1484988
Actual patches in the dependencies. Marking this one as meta.
Keywords: meta
(In reply to Henri Sivonen (:hsivonen) from comment #0)
> Currently, we have callers that assume that it's valid to do this:
>  1) Call SetCapacity()
>  2) Obtain a raw pointer to the start of the string and write past mLength
> of the string.
>  3) Call SetLength() with a new length assuming that even a reallocation
> happens, the data written past mLength is preserved.

Would poisoning the truncated bytes of the buffer catch these bad callers? Trying to read beyond mLength would then return garbage data.
(In reply to Chris Peterson [:cpeterson] from comment #8)
> (In reply to Henri Sivonen (:hsivonen) from comment #0)
> > Currently, we have callers that assume that it's valid to do this:
> >  1) Call SetCapacity()
> >  2) Obtain a raw pointer to the start of the string and write past mLength
> > of the string.
> >  3) Call SetLength() with a new length assuming that even a reallocation
> > happens, the data written past mLength is preserved.
> 
> Would poisoning the truncated bytes of the buffer catch these bad callers?
> Trying to read beyond mLength would then return garbage data.

Yeah, that would make sense to do here once the dependencies have been fixed.
Depends on: 1484990
Depends on: 1485943
Depends on: 1485945
See Also: → 1486706
Blocks: 1486711
All the dependencies have landed.
Status: ASSIGNED → RESOLVED
Closed: 6 years ago
Resolution: --- → FIXED
Status: RESOLVED → REOPENED
Resolution: FIXED → ---
Depends on: 1488186
Depends on: 1488452
Depends on: 1489462
Status: REOPENED → RESOLVED
Closed: 6 years ago6 years ago
Resolution: --- → FIXED
Component: String → XPCOM
Summary: Audit callers of SetCapacity for writing past mLength → [meta] Audit callers of SetCapacity for writing past mLength
You need to log in before you can comment on or make changes to this bug.