TranslateDescID with FieldsList
-
Hello everyone!
I found a critical memory leaking bug with TranslateDescID and FieldsList.
I have a ObjectData plugin and TagData plugin. Object plugin translates some DescId with tags one of them is a fieldlist. When i add to Objects fieldlist regular field layer like Linear, Formula etc. it works fine, but some layers makes crash: Time, Delay... When i add Time, Delay to tags fieldslists directly it works with no issue. Crush happens only with ObjectData fieldslist connected by TranslateDescID with tags. -
Hey @mikeudin,
Thank you for reaching out to us and reporting the bug. Without a more precise bug description we unfortunately can only do little. We will need your plugin code here and an example scene. You can share them confidentially as lined out in our forum guidleines under Confidential Data.
And I am a bit curious how you conclude that this is a memory leak? A memory leak means that code compiled by a language that does not offer a managed memory environment, e.g., C++, does not free its allocated memory correctly. The result is then that the application/the system is getting slower and slower, as the application keeps allocating memory without freeing it.
Later on, you talk about a crush happening. I assume, you mean that Cinema 4D terminates irregularly, i.e., crashes. If that is the case, please send your crash report(s) or provide them manually. You can find them under
/{C4D_INSTALL_PREFS}/_bugreports
. When Cinema 4D does crash from Python, it usually means an access violation happend, i.e., the state of memory was not what our/your code assumed it to be.I cannot say much else, as your posting is otherwise unfortunately very vague. The only thing that stands out for me is that I do not really understand what you are trying to do with your field list, and that it sounds a bit dangerous due to the lack of ownership you have there. Things like Time and Delay field layers are
GeListNode
owned by aFieldList
orFieldLayer
; opposed to for example aFfield
layer (the field layer type that refrences an object in the OM) referencing anOfield
in the Object Manager. So, when you then pass out such FieldLayer plus some DescID in it, I am not too surprised that Cinema 4D does crash on you.Cheers,
Ferdinand -
Hello @ferdinand! Thank you for quick response!
Here you have sample ObjectData plugin based on this SDK example.Fieldlist ObjectData plugin is connected with VertexTag fieldlist by TranslateDescID. When adding Time field to Object plugin it freezes Cinema 4D. Tested on MB Air M1 MacOs 12.6.6
-
Hey @mikeudin,
just as an FYI, I am working myself through my backlog, and your case has not been forgotten. I will have a look at it next
Cheers,
Ferdinand -
Hello @mikeudin,
So, I gave this a spin and there is nothing one can do from the user side to prevent this. Cinema 4D freezes and when you attach a debugger, you end up in an access violation for a string trying to construct a
BaseRef
on another string, although that is certainly not the core of the bug and more its final symptom.The crux is here the Time field which then indeed leads to sort of a memory leak in that Cinema 4D keeps looping between your and the variable tag, trying to copy that string and in the process allocating more and more memory. But that is not because memory is not correctly freed but because this TranslateDescID Time field setup creates an infinite recursion more or less.
I filed a bug report for this but have flagged it as low priority due to the foreseeable problems that arise from mapping one fieldlist to another in this manner via
TranslateDescId
. But maybe the responsible dev will see it differently and raise the priority. I have also flagged this topic asto_fix
.Cheers,
FerdinandThe minimal code to induce the problem:
""" """ import c4d PLUGIN_ID = 1037871 class DynamicParametersObjectData(c4d.plugins.ObjectData): """ """ def Init(self, node): """ """ self.parameters = [] self.InitAttr(node, c4d.FieldList, c4d.TEXT_ANIMATOR_FIELDS) node[c4d.TEXT_ANIMATOR_FIELDS] = c4d.FieldList() return True def Message(self, node, mid, _): """ """ if mid == c4d.MSG_MENUPREPARE: pTag = node.MakeTag(c4d.Tvertexmap) if pTag is None: raise MemoryError() pTag[c4d.ID_TAGFIELD_ENABLE] = True return True def TranslateDescID(self, node, id): """ """ if id[0].id == c4d.TEXT_ANIMATOR_FIELDS: tag = node.GetTag(c4d.Tvertexmap) if not tag: return False desc = tag.GetDescription(c4d.DESCFLAGS_DESC_NONE) if not desc: return False return True, desc.CheckDescID(c4d.DescID(c4d.ID_TAGFIELDS), None), tag return False def GetVirtualObjects(self, op, hh): """ """ return c4d.BaseObject(c4d.Onull) if __name__ == "__main__": c4d.plugins.RegisterObjectPlugin(id=PLUGIN_ID, str="Py-DynamicParametersObject", g=DynamicParametersObjectData, description="opydynamicparametersobject", icon=c4d.bitmaps.InitResourceBitmap(c4d.Onull), info=c4d.OBJECT_GENERATOR)
-
Thank you @ferdinand!
Will try to found out the workaround. -
Hey @mikeudin,
just as an FYI, one of our engineers pointed out that Description.CheckDescID is the likely culprit for the problem and that this method should be avoided when possible due to its resource hungry nature. Instead, you would just manually define the parameter ID you mean, e.g.,
c4d.DescID(c4d.ID_TAGFIELDS)
. The problem with this is of course that this statement has been made disjunct from the dynamic parameters example because I stripped that aspect away in my minimized code.The original code example says:
# Fills DescLever type and creator completeId = desc.CheckDescID(descId, None) return True, completeId, tag
So, they seem to be only after filling in the data type and creator ID and not resolving multi-level IDs. Which you could also do manually when you know the parameters you want to wrap, e.g.,:
descId: c4d.DescID = c4d.DescID(c4d.DescLevel(c4d.ID_TAGFIELDS, c4d.CUSTOMDATATYPE_FIELDLIST, c4d.MAXON_CREATOR_ID)) return True, descId, tag
Cheers,
Ferdinand -