On 07.12.2015 19:11, Denis V. Lunev wrote: > On 12/07/2015 08:54 PM, Eric Blake wrote: >> On 12/07/2015 10:51 AM, Eric Blake wrote: >>> [adding qemu-devel - ALL patches should go to qemu-devel, even if they >>> are also going to a sub-list like qemu-block] >>> >>> On 12/07/2015 10:07 AM, Roman Kagan wrote: >>>> qcow2_get_specific_info() used to have a code path which would leave >>>> pointer to ImageInfoSpecificQCow2 uninitialized. >>>> >>>> We guess that it caused sporadic crashes on freeing an invalid pointer >>>> in response to "query-block" QMP command in >>>> visit_type_ImageInfoSpecificQCow2 with QapiDeallocVisitor. >>>> >>>> Although we have neither a solid proof nor a reproduction scenario, >>>> making sure the field is initialized appears a reasonable thing to do. >>>> >>>> Signed-off-by: Roman Kagan <rka...@virtuozzo.com> >>>> --- >>>> block/qcow2.c | 2 +- >>>> 1 file changed, 1 insertion(+), 1 deletion(-) >> Oops; hit send too soon. I added for-2.5? to the subject line, >> because... >> >>>> diff --git a/block/qcow2.c b/block/qcow2.c >>>> index 88f56c8..67c9d3d 100644 >>>> --- a/block/qcow2.c >>>> +++ b/block/qcow2.c >>>> @@ -2739,7 +2739,7 @@ static ImageInfoSpecific >>>> *qcow2_get_specific_info(BlockDriverState *bs) >>>> *spec_info = (ImageInfoSpecific){ >>>> .type = IMAGE_INFO_SPECIFIC_KIND_QCOW2, >>>> - .u.qcow2 = g_new(ImageInfoSpecificQCow2, 1), >>>> + .u.qcow2 = g_new0(ImageInfoSpecificQCow2, 1), >>> NACK. This makes no difference, except when s->qcow_version is out >>> of spec. >>> >>>> }; >>>> if (s->qcow_version == 2) { >>>> *spec_info->u.qcow2 = (ImageInfoSpecificQCow2){ >>>> >>> If s->qcow_version is exactly 2, then we end up initializing all fields >>> due to the assignment here; same if qcow_version is exactly 3. The only >>> time qcow2 remains uninitialized is if qcow_version is 0, 1, or > 3; but >>> we refuse to handle qcow files with out-of-range versions. So I don't >>> see how you are plugging any uninitialized values; and therefore, I >>> don't see how this is patching any crashes. >> ...if you can prove that we aren't gracefully handling an out-of-spec >> qcow_version, such that the uninitialized memory in that scenario is >> indeed causing a crash, then it is worth respinning a v2 of this patch >> with that proof, and worth considering it for 2.5 if it really is a >> crash fixer.
More or less unfortunately, Eric is right. I chose a g_new() over g_new0() because I was using compound literals anyway (and members not explicitly initialized in the initializer list given for a compound literal are initialized implicitly like object with static storage duration, i.e. 0, generally). s->qcow_version is always set to 2 or 3. It is only set in: (1) qcow2_open(): Directly before it is set, we check that the version is either 2 or 3. (2) qcow2_downgrade(): We make sure that target_version (the value s->qcow_version is set to) is equal to 2. (3) qcow2_downgrade(): On error, s->qcow_version may be reset to current_version, which is the old value of s->qcow_version which we can inductively assume to be either 2 or 3. (4) qcow2_amend_options(): On version upgrade, s->qcow_version is overwritten by new_version, which is either 2, 3, or the old value of s->qcow_version (in practice it is always 3 because it needs to be greater than s->qcow_version in order to get here). (5) qcow2_amend_options(): On version upgrade error, s->qcow_version is reset to the old value of s->qcow_version, which we can again assume to be 2 or 3. I'd be completely fine with adding an "else { abort(); }" branch to qcow2_get_specific_info(). But I fear that the issue you encountered is caused by something different than the ImageInfoSpecificQCow2 object not being fully initialized, and therefore I'm against this patch even if it should not change anything (because it might make as feel as if we found the issue even though there (most probably) is none here). Also... > Here is an info about our crash. > > we have this crash under unknown conditions on RHEV version of QEMU. > > Sorry, there is no much additional info. For the [...] > which looks like > > More specifically (expanding inlines along the stack trace): > > (gdb) l *(visit_type_ImageInfoSpecificQCow2+169) > 0x1a71e9 is in visit_type_ImageInfoSpecificQCow2 (qapi-visit.c:552). > 548 static void visit_type_ImageInfoSpecificQCow2_fields(Visitor *m, > ImageInfoSpecificQCow2 **obj, Error **errp) > 549 { > 550 Error *err = NULL; > 551 ==> visit_type_str(m, &(*obj)->compat, "compat", &err); ...the compat field is always set, in either code path (both for version 2 and 3). Therefore, if this pointer is wrong, it definitely is not due to the field not being initialized. Without any way of reproducing, it is difficult to find the true cause of the issue, though. valgrind would probably tell us something, but for that we'd need something it could find first. Max > 552 if (err) { > 553 goto out; > 554 } > > > (gdb) l visit_type_str > 238 void visit_type_str(Visitor *v, char **obj, const char *name, > Error **errp) > 239 { > 240 ==> v->type_str(v, obj, name, errp); > 241 } > > > (gdb) l qapi_dealloc_visitor_new > 175 QapiDeallocVisitor *qapi_dealloc_visitor_new(void) > 176 { > 177 QapiDeallocVisitor *v; > 178 > 179 v = g_malloc0(sizeof(*v)); > [...] > 191 v->visitor.type_str = qapi_dealloc_type_str; > 192 v->visitor.type_number = qapi_dealloc_type_number; > 193 v->visitor.type_size = qapi_dealloc_type_size; > > > (gdb) l qapi_dealloc_type_str > 131 static void qapi_dealloc_type_str(Visitor *v, char **obj, const > char *name, > 132 Error **errp) > 133 { > 134 if (obj) { > 135 ==> g_free(*obj); > 136 } > 137 } > > Den >
signature.asc
Description: OpenPGP digital signature