Forráskód Böngészése

Fix: rare buffer overflow in custom properties

this buffer overflow only seems to occur for int properties
that are generated from an existing rig.
Further research is required to identify the correct way to avoid
overflowing.
Brandenburg 3 hete
szülő
commit
1781ab8df0
1 módosított fájl, 56 hozzáadás és 63 törlés
  1. 56 63
      xForm_nodes.py

+ 56 - 63
xForm_nodes.py

@@ -3,8 +3,8 @@ from .base_definitions import MantisNode, NodeSocket
 from .xForm_socket_templates import *
 
 def TellClasses():
-             
-    return [ 
+
+    return [
              # xForm
              xFormArmature,
              xFormBone,
@@ -24,7 +24,7 @@ def reset_object_data(ob):
     ob.modifiers.clear() # I would also like a way to copy modifiers and their settings, or bake them down. oh well
 
 def get_parent_node(node_container, type = 'XFORM'):
-    # type variable for selecting whether to get either 
+    # type variable for selecting whether to get either
     #   the parent xForm  or the inheritance node
     node_line, socket = trace_single_line(node_container, "Relationship")
     parent_nc = None
@@ -61,7 +61,7 @@ def set_object_parent(node):
                     prWhite(f"INFO: no parent set for {node}.")
                     return
                 prWhite(f"INFO: setting parent of {node} to {other_node}.")
-                
+
                 if (parent.bObject) is None:
                     raise GraphError(f"Could not get parent object from node {parent} for {node}")
                 if isinstance(parent, xFormBone):
@@ -79,13 +79,13 @@ class xFormNode(MantisNode):
         self.bObject=None
 
     # because new objects are created during prep phase
-    def reset_execution(self): 
+    def reset_execution(self):
         super().reset_execution()
         self.prepared=False
 
 class xFormArmature(xFormNode):
     '''A node representing an armature object'''
-    
+
     def __init__(self, signature, base_tree):
         super().__init__(signature, base_tree, xFormArmatureSockets)
         self.init_parameters()
@@ -97,7 +97,7 @@ class xFormArmature(xFormNode):
 
     def bTransformPass(self, bContext = None,):
         # from .utilities import get_node_prototype
-        
+
         import bpy
         if (not isinstance(bContext, bpy.types.Context)):
             raise RuntimeError("Incorrect context")
@@ -112,8 +112,8 @@ class xFormArmature(xFormNode):
                 while (ob.animation_data.drivers):
                         ob.animation_data.drivers.remove(ob.animation_data.drivers[-1])
             for pb in ob.pose.bones:
-                # clear it, even after deleting the edit bones, 
-                #  if we create them again the pose bones will be reused 
+                # clear it, even after deleting the edit bones,
+                #  if we create them again the pose bones will be reused
                 while (pb.constraints):
                     pb.constraints.remove(pb.constraints[-1])
                 if reset_transforms:
@@ -137,7 +137,7 @@ class xFormArmature(xFormNode):
             ob = bpy.data.objects.new(name, bpy.data.armatures.new(name)) #create ob
             if (ob.name != name):
                 raise RuntimeError("Could not create xForm object", name)
-            
+
         self.bObject = ob.name
         ob.matrix_world = matrix.copy()
         ob.data.pose_position = 'REST'
@@ -256,7 +256,7 @@ class xFormBone(xFormNode):
         # currently it is waiting on BBone and refactoring/cleanup.
         self.init_parameters()
         self.set_traverse([("Relationship", "xForm Out")])
-    
+
     def bGetParentArmature(self):
         if (trace := trace_single_line(self, "Relationship")[0] ) :
             for i in range(len(trace)):
@@ -265,7 +265,7 @@ class xFormBone(xFormNode):
                     return trace[ i ].bGetObject()
         return None
         #should do the trick...
-    
+
     def bSetParent(self, eb):
         # print (self.bObject)
         from bpy.types import EditBone
@@ -279,16 +279,16 @@ class xFormBone(xFormNode):
 
         if isinstance(parent, EditBone):
             eb.parent = parent
-            
+
         eb.use_connect = parent_nc.evaluate_input("Connected")
         eb.use_inherit_rotation = parent_nc.evaluate_input("Inherit Rotation")
         eb.inherit_scale = parent_nc.evaluate_input("Inherit Scale")
         # otherwise, no need to do anything.
-    
+
     def bPrepare(self, bContext=None):
         self.parameters['Matrix'] = get_matrix(self)
         self.prepared = True
-    
+
     def bTransformPass(self, bContext = None,): #possibly will need to pass context?
         import bpy
         from mathutils import Vector
@@ -301,7 +301,7 @@ class xFormBone(xFormNode):
 
         matrix = self.parameters['Matrix']
         length = matrix[3][3]
-        
+
         if (xF):
             if (xF.mode != "EDIT"):
                 raise RuntimeError("Armature Object Not in Edit Mode, exiting...")
@@ -334,7 +334,7 @@ class xFormBone(xFormNode):
                     col.parent = col_parent
                     col_parent = col
                 d.collections_all.get(hierarchy[-1]).assign(eb)
-        
+
         if (eb.name != name):
             prRed(f"Expected bone of name: {name}, got {eb.name} instead.")
             raise RuntimeError("Could not create bone ", name, "; Perhaps there is a duplicate bone name in the node tree?")
@@ -347,12 +347,12 @@ class xFormBone(xFormNode):
         assert (eb.name), "Bone must have a name."
         self.bObject = eb.name
         # The bone should have relationships going in at this point.
-        
+
         self.bSetParent(eb)
 
         if eb.head == eb.tail:
             raise RuntimeError(wrapRed(f"Could not create edit bone: {name} because bone head was located in the same place as bone tail."))
-        
+
         # Setup Deform attributes...
         eb.use_deform            = self.evaluate_input("Deform")
         eb.envelope_distance     = self.evaluate_input("Envelope Distance")
@@ -431,7 +431,7 @@ class xFormBone(xFormNode):
                 b.bbone_handle_type_start = handle_type
             if handle_type := self.evaluate_input("BBone End Handle Type"):
                 b.bbone_handle_type_end = handle_type
-            
+
             try:
                 if (custom_handle := self.evaluate_input("BBone Custom Start Handle")):
                     b.bbone_custom_handle_start = self.bGetParentArmature().data.bones[custom_handle]
@@ -454,7 +454,7 @@ class xFormBone(xFormNode):
             b.bbone_handle_use_scale_start = self.evaluate_input("BBone Start Handle Scale")
             b.bbone_handle_use_scale_end = self.evaluate_input("BBone End Handle Scale")
 
-            
+
         import bpy
         from .drivers import MantisDriver
         # prevAct = bContext.view_layer.objects.active
@@ -468,7 +468,7 @@ class xFormBone(xFormNode):
         #
         #
         # Don't need to bother about whatever that was
-        
+
         pb = self.bGetParentArmature().pose.bones[self.bObject]
         rotation_mode = self.evaluate_input("Rotation Order")
         if rotation_mode == "AUTO": rotation_mode = "XYZ"
@@ -517,42 +517,35 @@ class xFormBone(xFormNode):
             if (value is None):
                 raise RuntimeError("Could not set value of custom parameter")
                 # it creates a more confusing error later sometimes, better to catch it here.
-            
-            # IMPORTANT: Is it possible for more than one driver to
-            #   come through here, and for the variable to be
-            #   overwritten?
-                
+
             #TODO important
             #from rna_prop_ui import rna_idprop_ui_create
             # use this ^
-            
-            # add the custom properties to the **Pose Bone**
+
             pb[name] = value
-            # This is much simpler now.
             ui_data = pb.id_properties_ui(name)
-            description=''
+            description = ''
+            if hasattr(inp, 'description'):
+                description = int.description 
+                # i am assuming there was a reason I was not already taking inp.description
+                # So guard it a little here just to be safe and not change things too much.
             ui_data.update(
-                description=description,#inp.description,
-                default=value,)
-            #if a number
-
-            if type(value) == float:
-                ui_data.update(
-                    min = inp.min,
-                    max = inp.max,
-                    soft_min = inp.soft_min,
-                    soft_max = inp.soft_max,)
-                        
-            elif type(value) == int:
-                ui_data.update(
-                    min = int(inp.min),
-                    max = int(inp.max),
-                    soft_min = int(inp.soft_min),
-                    soft_max = int(inp.soft_max),)
-            elif type(value) == bool:
-                ui_data.update() # TODO I can't figure out what the update function expects because it isn't documented
+                default=value,
+                description=description)
+
+            #if a number, set the min/max values. it may overflow on the C side
+            if type(value) in [float, int]:
+                for prop_name in ['min', 'max', 'soft_min', 'soft_max', ]:
+                    prop_value = getattr(inp, prop_name)
+                    if type(value) == int: prop_value = int(prop_value)
+                    # DO: figure out the right way to prevent an oveflow
+                    try: # we have to do this as a keyword argument like this
+                        ui_data.update( **{prop_name:prop_value} )
+                    except OverflowError: #this occurs when the value is inf
+                        prRed(f"invalid value {prop_value} for custom prop {prop_name}"
+                             f" of type {type(value)} in {self}. It will remain unset.")
             pb.property_overridable_library_set(f"[\"{name}\"]", True)
-        
+
         if (pb.is_in_ik_chain):
             # this  props_socket thing wasn't really meant to work here but it does, neat
             props_sockets = {
@@ -619,7 +612,7 @@ class xFormBone(xFormNode):
         }
         evaluate_sockets(self, pb.bone, props_sockets)
 
-        
+
         if (driver):
             pass
         # whatever I was doing there.... was stupid. CLEAN UP TODO
@@ -634,14 +627,14 @@ class xFormBone(xFormNode):
 
         pb.custom_shape_transform = None
         pb.custom_shape = None
-        
+
         if len(self.inputs["Custom Object xForm Override"].links) > 0:
             trace = trace_single_line(self, "Custom Object xForm Override")
             try:
                 pb.custom_shape_transform = trace[0][1].bGetObject()
             except AttributeError:
                 pass
-                    
+
         if len(self.inputs["Custom Object"].links) > 0:
             trace = trace_single_line(self, "Custom Object")
             try:
@@ -649,7 +642,7 @@ class xFormBone(xFormNode):
             except AttributeError:
                 ob=None
             if type(ob) in [bpy.types.Object]:
-                pb.custom_shape = ob 
+                pb.custom_shape = ob
 
     def bGetObject(self, mode = 'POSE'):
         if self.bObject is None: return None
@@ -672,7 +665,7 @@ class xFormBone(xFormNode):
         # this is the fill_parameters that is run if it isn't a schema
         setup_custom_props(self)
         super().fill_parameters(prototype)
-        # otherwise we will do this from the schema 
+        # otherwise we will do this from the schema
         # LEGIBILITY TODO - why? explain this?
 
 class xFormGeometryObject(xFormNode):
@@ -768,8 +761,8 @@ class xFormGeometryObject(xFormNode):
             print (wrapGreen(i), wrapWhite(self), wrapPurple(driver_key))
             prOrange(driver_item)
         finish_drivers(self)
-            
-        
+
+
     def bGetObject(self, mode = 'POSE'):
         return self.bObject
 
@@ -882,7 +875,7 @@ class xFormCurvePin(xFormNode):
 
     def bPrepare(self, bContext = None,):
         from bpy import data
-        
+
         if not bContext: # lol
             import bpy
             bContext = bpy.context
@@ -897,9 +890,9 @@ class xFormCurvePin(xFormNode):
             ob.empty_display_size = 0.10
 
         self.bObject = ob
-        
+
         reset_object_data(ob)
-        
+
         node_line = trace_single_line(self, "Parent Curve")[0][1:] # slice excludes self
         for other_node in node_line:
             if other_node.node_type == 'XFORM':
@@ -968,6 +961,6 @@ class xFormCurvePin(xFormNode):
 
     def bFinalize(self, bContext = None):
         finish_drivers(self)
-            
+
     def bGetObject(self, mode = 'POSE'):
-        return self.bObject
+        return self.bObject