
On 06/07/2018 08:17 AM, Marc Hartmayer wrote:
On Wed, May 09, 2018 at 09:51 PM +0200, John Ferlan <jferlan@redhat.com> wrote:
On 05/07/2018 11:24 AM, Marc Hartmayer wrote:
On Mon, Apr 30, 2018 at 03:20 PM +0200, John Ferlan <jferlan@redhat.com> wrote:
On 04/25/2018 11:55 AM, Marc Hartmayer wrote:
1. Don't allocate if there is nothing that needs to be allocated. Especially as the result of calling calloc(0, ...) is implementation-defined.
uh oh - another memory recollection challenge ;-)
Following VIR_ALLOC_N one finds :
VIR_ALLOC_N(params_val, nparams)
which equates to
# define VIR_ALLOC_N(ptr, count) \ virAllocN(&(ptr), sizeof(*(ptr)), (count), true, \ VIR_FROM_THIS, __FILE__, __FUNCTION__, __LINE__)
or
virAllocN(¶ms_val, sizeof(params_val), nparams, true, ...)
and eventually/essentially
*params_val = calloc(sizeof(params_val), nparams)
If the returned value is NULL then we error w/ OOM (4th param=true).
So, unless @params_val had no elements, it won't be calloc(0,...) and
I'm talking about the case that nparams == 0 => calloc(sizeof(…), 0).
And I was thinking is there a specific consumer/caller of virTypedParamsSerialize that was passing something incorrectly.
thus the question becomes is there a more specific path you are referencing here?
It’s a “generic” serializer so it should work for every (valid) case. What happens, for example, if params == NULL and nparams == 0? In that case I would expect *remote_params_val = NULL and *remote_params_len = 0.
Going through the callers to virTypedParamsSerialize can/does anyone pass params == NULL and nparams == 0? Would that be reasonable and/or expected?
My look didn't find any - either some caller checks that the passed @params != NULL (usually via virCheckNonNullArgGoto in the external API call) or @params is built up on the fly and wouldn't be NULL because there'd be an error causing failure beforehand. Although I'll admit the migration ones are also crazy to look at.
I could have made a mistake too; hence, the is there a specific instance that I missed? Or perhaps this is a result of some branched/private code that had that error which I don't have access to?
It was the result of private code but actually it was intended and no error :)
To answer your "What happens, for example, if params == NULL and nparams == 0?", well supposedly "VIR_ALLOC_N(params_val, 0)" should return NULL, so params_val and thus *remote_params_val == NULL.
Did you try what 'VIR_ALLOC_N(params_val, 0)' actually returns? At least for me, it doesn’t return a NULL pointer.
I think I already determined that NULL isn't returned; otherwise, we would have failed w/ OOM. I do recall trying this and seeing a non NULL value returned. IIRC: I found no way into [de]serialize w/ a 0 parameter, so having that guard didn't seem necessary, but it's been 2 months since I looked at this and that level of detail has long been flushed out of main memory cache. ;-)
The man page for calloc-posix reads:
“If either nelem or elsize is 0, then either a null pointer or a unique pointer value that can be successfully passed to free() shall be returned.” [1]
perhaps then we avoid this conundrum and take Daniel's advice in his response: "If there is any problem with this, then we should just change bootstrap.conf to use calloc-gnu instead of calloc-posix, which basically turns calloc(0) into calloc(1) for compat with glibc behaviour." John
Unless of course as Daniel points out needing a patch for bootstrap.conf to use calloc-gnu instead of calloc-posix.
John
FWIW: My f26 man page for calloc says:
"The calloc() function allocates memory for an array of nmemb elements of size bytes each and returns a pointer to the allocated memory. The memory is set to zero. If nmemb or size is 0, then calloc() returns either NULL, or a unique pointer value that can later be successfully passed to free()"
We have so many places in the code that use VIR_ALLOC_N and do not check if the sizeof() or count is 0 - which makes me wonder even more about the specific case in which you are referencing.
It is not about the general use of VIR_ALLOC_N, but about the result of the serializer and deserializer.
I looked through the various remote_protocol.x structures that would use this and it seems they all use remote_typed_param for the structure being returned, so it's not clear how any of them could have a sizeof() returning 0.
2. Update the length @remote_params_len only if the related @remote_params_val has also been set.
This one changes the error case as the returned @remote_params_len changes from being set to @params_len on input to be undefined.
Hmm, that’s already the case for 'remote_params_val'? But indeed, we can either initialize both of them to 0 and NULL or add an error label for this.
“@remote_params_len: the final number of elements in @remote_params_val.”
[…snip…]
-- Beste Grüße / Kind regards Marc Hartmayer
IBM Deutschland Research & Development GmbH Vorsitzende des Aufsichtsrats: Martina Koederitz Geschäftsführung: Dirk Wittkopp Sitz der Gesellschaft: Böblingen Registergericht: Amtsgericht Stuttgart, HRB 243294
-- Beste Grüße / Kind regards Marc Hartmayer
IBM Deutschland Research & Development GmbH Vorsitzende des Aufsichtsrats: Martina Koederitz Geschäftsführung: Dirk Wittkopp Sitz der Gesellschaft: Böblingen Registergericht: Amtsgericht Stuttgart, HRB 243294