[squid-dev] [PATCH] SBuf Locker friend class

Alex Rousskov rousskov at measurement-factory.com
Thu Oct 29 21:40:18 UTC 2015


On 10/29/2015 01:23 PM, Amos Jeffries wrote:

> Adds the Locker friend class to SBuf to provide safety ref-count locks
> when dealing with dangerous char* or SBuf& inputs.

Thank you for working on this.


> +    Locker prevent_raw_memory_madness(this, S, n);

If you can make it constant, make it const.


> +            // lock if Q intersects the parents buffer area
> +            const MemBlob *P = parent->store_.getRaw();
> +            if ( (Q+len) >= P->mem && Q <= (P->mem + P->capacity) )


I do not think "len" is important here. We are not trying to protect
ourselves against invalid pointers that start somewhere before the blob
but end inside the blob. If I am right, please remove the len argument
and simplify.

I recommend using "min <= x <= max" pattern.

Also, a Q pointing at (P->mem + P->capacity) does not belong to P!

Please avoid single-character names. They may the code more difficult to
understand, search, and refactor.

Please reserve capitalized names for Globals.

In summary, consider:

    if (blob->mem <= mem && mem < blob->mem + blob->capacity)


However, I would actually make it an inlined MemBlob method:

    if (blob->contains(mem))


I like your refcounting Pointer trick. Much better than manual
lock/unlock work!


> I have gone through and added it to all the non-const methods that
> appear to be taking char* directly, or using a char* taken from SBuf&.
> That review added the appendf/printf methods to the set we identified on
> IRC.

What about SBuf::scanf()? Unlikely, but, the format parameter might be
pointing to the same blob that gets deleted when we call c_str()...



>  SBuf &
>  SBuf::append(const char * S, size_type Ssize)
>  {
>      if (S == NULL)
>          return *this;
>      if (Ssize == SBuf::npos)
>          Ssize = strlen(S);
>      debugs(24, 7, "from c-string to id " << id);
> +    Locker prevent_raw_memory_madness(this, S, Ssize);

and

> SBuf::vappendf(const char *fmt, va_list vargs)
>  {
>      Must(fmt != NULL);
>      int sz = 0;
>      //reserve twice the format-string size, it's a likely heuristic
>      size_type requiredSpaceEstimate = strlen(fmt)*2;
>  
> +    // with appendf() an arg might be a dangerous char*
> +    Locker prevent_raw_memory_madness(this, buf(), length());
> +

If possible, let's always start dangerous methods with allocating a
Locker object. This clarifies the lock scope and minimizes the chance
that somebody adds dangerous code _above_ the lock.


> +    // with printf() an arg might be a dangerous char*

> +    // with appendf() an arg might be a dangerous char*


s/an arg/fmt or arg/ or s/an arg/any parameter/

That is, the "fmt" parameter itself is not excluded from danger.


> IMO the trim() method mentioned on IRC does not need it since the scope
> lifetime of the pointer taken by toRemove.buf() does not cross any
> alterations of the this objects members.

Agreed.


I also suggest renaming "prevent_raw_memory_madness" to "blobKeeper" to
clarify and for consistency with other camelCase names.



> I've not added documentation for the Locker class. Alex could you
> provide a blurb to describe the memory issue and requirements this solves ?


How about something like the following?

/// Keeps SBuf's MemBlob alive in a blob-destroying context where
/// a seemingly unrelated memory pointer may belong to the same blob.
/// For [an extreme] example, consider: a.append(a).
/// Compared to an SBuf temporary, this class is optimized to
/// preserve blobs only if needed and to reduce debugging noise.
class Locker ...


HTH,

Alex.



More information about the squid-dev mailing list