Missing max length checks accessing some properties with foreach_get/set #109033
Labels
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset System
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Viewport & EEVEE
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Asset Browser Project
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Module
Viewport & EEVEE
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Severity
High
Severity
Low
Severity
Normal
Severity
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: blender/blender#109033
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
System Information
Operating system: Windows-10-10.0.19045-SP0 64 Bits
Graphics card: NVIDIA GeForce GTX 1070 Ti/PCIe/SSE2 NVIDIA Corporation 4.5.0 NVIDIA 531.41
Blender Version
Broken: version: 4.0.0 Alpha, branch: main, commit date: 2023-06-03 14:21, hash:
ab6860f3de0f
Worked: varies per property:
For example:
MeshVertex.co worked in 3.4, but no longer works in 3.5 (presumably because it's more of a wrapper around the 'position' attribute as of 3.5)
MeshEdge.crease has not worked since before even 2.79 (the new attribute replacing it in 4.0 does not have the issue)
ShapeKey.value has not worked since before even 2.79
Short description of error
Max length checks are missing from some properties when accessing them with foreach_get/set. This means that when the list/array argument to foreach_get/set is longer than the property being accessed it can read/write to other memory and may crash Blender.
I don't know what exactly determines if a property has this issue, but if you open the System Console and then in the Python Console run
my_collection.foreach_get(property_name, [None])
:Error: Array length mismatch (got 1, expected more)
.Error: Array length mismatch (expected 24, got 1)
.For example with a default cube as the active object:
bpy.context.object.data.edges.foreach_get("crease", [None])
-> "got 1, expected more"bpy.context.object.data.vertices.foreach_get("co", [None])
-> "got 1, expected more" (before Blender 3.5 this would instead be "expected 24, got 1")bpy.context.object.data.attributes['position'].data.foreach_get("vector", [None])
-> "expected 24, got 1"bpy.data.objects.foreach_get("add_rest_position_attribute", [None])
-> "got 1, expected more"bpy.context.object.data.attributes.new("my_edge_float", type='FLOAT', domain='EDGE').data.foreach_get("value", [None])
-> "expected 12 got 1"If at least two shape keys are added:
bpy.context.object.data.shape_keys.key_blocks.foreach_get("value", [None])
-> "got 1, expected more"Exact steps for others to reproduce the error
foreach_get
my_list = [None]*100
C.object.data.shape_keys.key_blocks.foreach_get("value", my_list)
(might crash)my_list
my_list
that correspond to the shape keys that were added to the default cube, the rest are garbage that have been read from memory.foreach_set
It's difficult to show that it's writing to memory it shouldn't be, but we can write to memory and then read it back into a different list with the same length:
my_other_list = [0.123]*100
my_list = [None] * len(my_other_list)
C.object.data.shape_keys.key_blocks.foreach_set("value", my_other_list)
(might crash)C.object.data.shape_keys.key_blocks.foreach_get("value", my_list)
(might crash)my_list
my_list
are0.123
, even those beyond the first few that correspond to the shape keys of the default cube.Can you redo the repro steps/description since "creases" have been moved to attributes a few days ago in
e5ec04d73c
.I have updated the reproduction steps and description to use ShapeKey.value.
From debugging it seems that both the
get
andset
cases are using a locally allocated array of appropriate size: 100 elements in both theget
andset
cases. So a crash should not occur, and an ASAN build does not complain about any buffer overruns etc. Are you seeing a crash?However, the array that's allocated is not initialized to, say, 0 or similar. So what's being mapped back into Python is whatever values happened to be lying in memory at the time of that allocation.
Debugging also shows that the proper number of properties are being iterated in both cases (e.g. 4 in the case of the .blend file from your other bug for example). So during a
get
you'll get back 4 proper values and then 96 values of whatever happened to be in memory at the time.Unsure what the API should do in this case. Should it zero out its local array memory? Should it raise an Error if there are fewer property values than the length of the provided array?
Ah, I guess what's happening when writing an oversize list with
set
and then getting the data into a separate oversize list withget
is that the locally allocated array during theget
is being allocated roughly in the same place as the locally allocated array in theset
. That would explain why it sometimes comes back with all the same values and sometimes comes back with only a few different.I did get some crashes, though at most only one per instance of a different version of Blender I had open for testing and the crashes were all in quick succession. Unfortunately I was messing with #109024 at the time and had addons loaded. I'm pretty sure the line I put in the Python Console was the same as I'd done many times before without crashing, so the crashes may have just been coincidence. And if I push the oversized lists in this issue to much larger numbers, I don't get an almost immediate crash like I would expect if it actually was reading from/writing to memory it shouldn't be.
API-wise, I would prefer raising an error if the list length does not match the number of property elements, so that it's consistent with the properties that already do raise an error when given an oversized list. For example, 'BOOLEAN' and 'INT8' attributes allow oversized lists, but 'FLOAT' and 'INT' attributes do not. Unless there's some way to tell through the Python API how individual properties behave in advance, I would prefer them to behave the same. Unfortunately, I don't know enough about the Blender internals to have any idea as to why the behaviour would differ in the first place. I didn't even know that some properties allowed oversized lists in foreach_get/set until today.