<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Dec 12, 2014 at 2:37 PM, Carl Worth <span dir="ltr"><<a href="mailto:cworth@cworth.org" target="_blank">cworth@cworth.org</a>></span> wrote:<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On Thu, Dec 11 2014, Jason Ekstrand wrote:<br>
> Yeah, this looks nifty.<br>
<br>
Thanks!<br>
<span class=""><br>
> I've got some comments on the implementation though.<br>
<br>
</span>I really appreciate the careful review. I obviously didn't pay quite as<br>
much attention to detail as I would like to when writing this patch. I'm<br>
glad I didn't bury this code in a giant "here's the shader cache" series<br>
where this review wouldn't have happened.<br></blockquote><div><br></div><div>No problem.  It was a fun little review.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<span class=""><br>
>> + * Permission is hereby granted, free of charge, to any person obtaining<br>
> a<br>
<br>
</span>[Incidentally, your email to me appears to have been word-wrapped after<br>
the quote prefixes were added, (and those prefixes pushing some lines<br>
past 80 columns). That made it a bit harder to read. I haven't seen this<br>
failure mode commonly before. Part of that may be due to the<br>
mesa/.dir-locals.el file which is making my emacs wrap my code at 78<br>
columns rather than its default of 70. Maybe that should be toned down a<br>
bit.]<br></blockquote><div><br></div><div>You can probably blame it on G-Mail<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<span class=""><br>
>> +   if (blob->allocated == 0)<br>
>> +      to_allocate = BLOB_INITIAL_SIZE;<br>
>> +   else<br>
>> +      to_allocate = blob->allocated * 2;<br>
><br>
> What happens if additional is bigger than blob->size?  Maybe iterate (if<br>
> you want to keep power-of-two) or take a max here.<br>
<br>
</span>Good catch. I'm not particularly concerned about a power-of-two size. So<br>
I've changed the code to take a max here.<br>
<span class=""><br>
>> +static bool<br>
>> +align_blob (struct blob *blob, size_t alignment)<br>
>> +{<br>
>> +   size_t new_size;<br>
>> +<br>
>> +   new_size = ALIGN(blob->size, alignment);<br>
><br>
> Do we what to align the pointer or the size?  Aligning the size only makes<br>
> sense if the pointer is already aligned.<br>
<br>
</span>Note that the size we're aligning here (blob->size) is the size of all<br>
data that's already written to the blob, (not the size of the object<br>
about to be written that is imposing an alignment constraint).<br>
<br>
It's not clear to me if your question was based on a misreading of that.<br></blockquote><div><br></div><div>Right, I think I misread something.  We don't really have a pointer to align here.  My point was that if the pointer is only 16-aligned then it's no good to 32-align the size because ptr + size will still only be 16-aligned.  However, given that it's coming out of malloc and we only care about 64bit things, it should be fine.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<span class=""><br>
> At the very least, we should assert that the requested alignment is<br>
> less than or equal to the known pointer alignment for the start of the<br>
> blob.<br>
<br>
</span>The start of the blob's data is a pointer returned by malloc(), (or<br>
realloc()), so the known pointer alignment there should be adequate for<br>
anything we're writing to it.<br></blockquote><div><br></div><div>Sure.  It's probably fine then.<br></div><div>--Jason<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<span class=""><br>
>> +static void<br>
>> +align_blob_reader (struct blob_reader *blob, size_t alignment)<br>
>> +{<br>
>> +   blob->current = blob->data + ALIGN(blob->current - blob->data,<br>
> alignment);<br>
><br>
> Again, pointer or size?  Also, why is this way up here when the other<br>
> reader stuff comes later.<br>
<br>
</span>I guess I was putting all of the allocation and alignment code in one<br>
place, (which wasn't obvious since the blob_reader code doesn't have any<br>
allocation). Obviously, that's easy to move. I'll do that.<br>
<span class=""><br>
>> +void<br>
>> +blob_reader_init (struct blob_reader *blob, uint8_t *data, size_t size)<br>
><br>
> Calling it blob is a bit disconcerting, but probably not a big deal.<br>
<br>
</span>Yes. I hesitated a bit when doing that. This came about probably because<br>
I had earlier toyed with having a single, shared data structure for both<br>
purposes, but I decided that they really are different. At the very<br>
least this "struct blob_reader as 'blob'" naming is contained to just<br>
this file and obviously doesn't leak into any callers or anything.<br>
<span class=""><br>
>> +void *<br>
>> +blob_read_bytes (struct blob_reader *blob, size_t size)<br>
>> +{<br>
>> +   void *ret;<br>
>> +<br>
>> +   if (blob->current > blob->end || blob->end - blob->current < size)<br>
>> +      return NULL;<br>
><br>
> Why isn't this a call to ensure_can_read?  Without this, the overrun flag<br>
> never gets set.<br>
<br>
</span>Thanks for the catch.<br>
<span class=""><br>
> We also don't get overrun set for out-of-bounds copies and<br>
> string reads.  If that's intentional, it should be documented.<br>
<br>
</span>That was not intentional. Fixing blob_read_bytes() above takes care of<br>
out-of-bounds copies. For blob_read_string I've just added:<br>
<br>
        blob->overrun = true;<br>
<br>
to the case that handles "no 0 byte appears in the remainder of the<br>
blob's data".<br>
<span class=""><br>
> Also, you reversed the logic wrong.  It should be current >= end.<br>
<br>
</span>I don't think so. Checking for "current >= end" is a check to see<br>
whether a previous operation has overrun. But what we want to check here<br>
is whether the current operation would overrun, (whether or not the<br>
previous one had).<br>
<br>
But it doesn't matter since I just deleted that code and replaced it<br>
with a call to ensure_can_read().<br>
<span class=""><br>
>> +blob_read_string (struct blob_reader *blob)<br>
>> +{<br>
>> +   int size;<br>
>> +   char *ret;<br>
>> +   uint8_t *nul;<br>
>> +<br>
>> +   /* If there is no NULL terminator, the reader gets nothing. */<br>
>> +   nul = memchr (blob->current, 0, blob->end - blob->current);<br>
><br>
> Should we check for current >= end first?...<br>
<br>
</span>Yes. That's another good fix, (for the case of trying to read a string<br>
immediately after having read the entire blob's data).<br>
<span class=""><br>
<br>
>> +   if (! ensure_can_read(blob, size))<br>
>> +      return 0;<br>
><br>
> ...If we do, this does nothing.<br>
<br>
</span>How about for my own comfort, I leave that in as:<br>
<br>
        assert(ensure_can_read(blob, size));<br>
<span class=""><br>
> We may want to set the overrun flag if there is no null.<br>
<br>
</span>As I mentioned above, I did add this.<br>
<span class=""><br>
>> +bool<br>
>> +blob_overwrite_bytes (struct blob *blob,<br>
>> +                      size_t offset,<br>
>> +                      const void *bytes,<br>
>> +                      size_t to_write);<br>
><br>
> This function isn't implemented.<br>
<br>
</span>Thanks. As you mentioned in your other email, I moved this chunk to the<br>
second patch.<br>
<br>
I'll follow up with a second revision of this patch incorporating all of<br>
the changes described here.<br>
<span class="HOEnZb"><font color="#888888"><br>
-Carl<br>
<br>
</font></span></blockquote></div></div></div>