comtypes icon indicating copy to clipboard operation
comtypes copied to clipboard

Variant pointers to BSRT marked as free before being passed to c++ side

Open Antonm5012 opened this issue 7 years ago • 1 comments

I am passing a 2d array of strings to c++ library. 2d arrays are converted to ndarrays before being placed in safearrays.

Temporary VARIANT objects are created to be put in ndarray:

def _ndarray_to_variant_array(value): varr = numpy.zeros(value.shape, npsupport.VARIANT_dtype, order='F') varr.flat = [VARIANT(v) for v in value.flat] <--------------- here

..this temporary variants are then destroyed (confirmed by print statements in tagVARIANT.del). You would assume that the copies placed in varr are intact, however it looks like their string pointers (BSTR fields) are marked as free as a result.

On the c++ side all data is visible fine until one tries to create any BSTR using SysAllocString: BSTRs in the input are overridden.

e.g. I pass A = [[A00],[A10],[A20],[A30]] (a 2d array of 4x1). On c++ side I make a copy of it, B = A, B_ij = A_ij; however as I copy B00 = A00, B00 (expectedly) becomes A00 and also A30 incidentally becomes A00, because B00 uses the same address as A30; then B10 = A10, and incidentally A20 becomes A10. B_ij is obtained by ::SysAllocStringLen(A_ij, SysStringLen(A_ij)), so should be legitimate allocation of memory for new BSTR. My guess is SysAllocString picks memory allocated for A30 and assumes it is free.

..Back to Py side:

If I comment out _VariantClear in the comptypes/automation.py: class tagVARIANT(Structure): class U_VARIANT1(Union): .. .. def del(self): if self.b_needsfree: #_VariantClear(self) <------------------------

..then everything works fine.

Which confirms that memory allocated for strings on the Pythons side is marked as free and reused any time one wants to create BSTR object.

Suprisingly, no problems were noticed when using 1d array. My guess is memory is still marked as free, but the allocation order is such, that this memory is not overridden.

Also, no problems when passing list or tuple. (however, if I pass a nested list, it creates a safearray of safearrays instead of 2d safearray of non-safearray variants)

Any thoughts?

Antonm5012 avatar Aug 24 '18 09:08 Antonm5012

Solved by creating a storage for variants: input values converted to variants are saved in the storage and destroyed only after the function call

Antonm5012 avatar Sep 05 '18 08:09 Antonm5012

@Antonm5012

If the issue remains, please re-open.

—- This may be a clue to resolving #80 and #347.

junkmd avatar Dec 06 '22 03:12 junkmd