[libvirt] [PATCH] cgroup: Free line even if no characters were read
Ján Tomko
jtomko at redhat.com
Wed Jul 17 10:00:42 UTC 2013
On 07/17/2013 04:03 AM, Eric Blake wrote:
> On 07/16/2013 06:14 AM, Ján Tomko wrote:
>> Even if getline doesn't read any characters it allocates a buffer.
>>
>> ==404== 120 bytes in 1 blocks are definitely lost in loss record 1,344 of 1,671
>> ==404== at 0x4C2C71B: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
>> ==404== by 0x906F862: getdelim (iogetdelim.c:68)
>> ==404== by 0x52A48FB: virCgroupPartitionNeedsEscaping (vircgroup.c:1136)
>> ==404== by 0x52A0FB4: virCgroupPartitionEscape (vircgroup.c:1171)
>> ==404== by 0x52A0EA4: virCgroupNewDomainPartition (vircgroup.c:1450)
>>
>> Introduced by f366273.
>> ---
>>
>> Can STRPREFIX(path, line) be possibly true if tmp is NULL?
>> path[NULL - line] would be accessed in that case.
>
> [1] good question; answer below (you didn't ask quite the right
> question, but it made me read the code - both the original code and this
> patch are broken; we need a v2).
>
>>
>> src/util/vircgroup.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c
>> index 5a98393..2419d80 100644
>> --- a/src/util/vircgroup.c
>> +++ b/src/util/vircgroup.c
>> @@ -1136,38 +1136,38 @@ static int virCgroupPartitionNeedsEscaping(const char *path)
>> while (getline(&line, &len, fp) > 0) {
>> if (STRPREFIX(line, "#subsys_name")) {
>> VIR_FREE(line);
>
> This VIR_FREE(line) is spurious, and should be deleted. The whole point
> of getline() is that it reuses a malloc'd buffer, possibly realloc()ing
> it to be larger, to minimize the malloc overhead. But by freeing every
> iteration of the loop, we've lost that advantage.
>
>> continue;
>> }
>> char *tmp = strchr(line, ' ');
>> if (tmp)
>> *tmp = '\0';
>> len = tmp - line;
>
> This is bogus. If tmp is NULL, then len is extremely large, and will
> mess up the next iteration call to getline(). However, I could live with:
It doesn't mess it up right now, since we set line to NULL every time.
>
> if (tmp) {
> *tmp = '\0';
> len = tmp - line;
> }
>
> which is slightly sub-optimal (it makes the next getline() call think it
> needs to call realloc(), when it really might already be large enough),
> but otherwise harmless (realloc() doesn't pay attention to *len, and is
> smart enough to be a no-op if the new size is no bigger than the
> existing real size).
This would leave len untouched if no space was found and tmp is NULL..
>
>>
>> if (STRPREFIX(path, line) &&
>
> [1] To answer your question, STRPREFIX() is unsafe to call on NULL (it
> is a macro that boils down to strncmp, which must NOT have null
> arguments). But we are guaranteed that path and line are non-null here.
>
>> path[len] == '.') {
.. and path[len] would off by one instead of ~2^64.
>> ret = 1;
>> - VIR_FREE(line);
>> goto cleanup;
>> }
>> VIR_FREE(line);
>
> This is another VIR_FREE that could be safely nuked, given the semantics
> of readline().
>
>> }
>>
>> if (ferror(fp)) {
>> ret = -EIO;
>> goto cleanup;
>> }
>>
>> cleanup:
>> + VIR_FREE(line);
>
> Yes, I agree that we need this, but we also need to fix the other bugs
> in the area. Looking forward to v2.
>
I've sent v2 as 'cgroup: reuse buffer for getline'
Jan
More information about the libvir-list
mailing list