-
-
Notifications
You must be signed in to change notification settings - Fork 21.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use-after-free in canvas batching #96960
Comments
Update, the following patch seems indeed to fix the crash on my end but as above I have no idea on whether this is a proper fix. diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index b0851efe5f..6022e48aaf 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -2148,7 +2148,7 @@ void RendererCanvasRenderRD::_render_batch_items(RenderTarget p_to_render_target
Transform2D base_transform = p_canvas_transform_inverse * ci->final_transform;
if (!ci->repeat_size.x && !ci->repeat_size.y) {
- _record_item_commands(ci, p_to_render_target, base_transform, current_clip, p_lights, instance_index, batch_broken, r_sdf_used);
+ _record_item_commands(ci, p_to_render_target, base_transform, current_clip, p_lights, instance_index, batch_broken, r_sdf_used, current_batch);
} else {
Point2 start_pos = ci->repeat_size * -(ci->repeat_times / 2);
Point2 end_pos = ci->repeat_size * ci->repeat_times + ci->repeat_size + start_pos;
@@ -2156,7 +2156,7 @@ void RendererCanvasRenderRD::_render_batch_items(RenderTarget p_to_render_target
do {
do {
Transform2D transform = base_transform * Transform2D(0, pos / ci->xform_curr.get_scale());
- _record_item_commands(ci, p_to_render_target, transform, current_clip, p_lights, instance_index, batch_broken, r_sdf_used);
+ _record_item_commands(ci, p_to_render_target, transform, current_clip, p_lights, instance_index, batch_broken, r_sdf_used, current_batch);
pos.y += ci->repeat_size.y;
} while (pos.y < end_pos.y);
@@ -2262,7 +2262,7 @@ void RendererCanvasRenderRD::_render_batch_items(RenderTarget p_to_render_target
state.last_instance_index += instance_index;
}
-void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTarget p_render_target, const Transform2D &p_base_transform, Item *&r_current_clip, Light *p_lights, uint32_t &r_index, bool &r_batch_broken, bool &r_sdf_used) {
+void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTarget p_render_target, const Transform2D &p_base_transform, Item *&r_current_clip, Light *p_lights, uint32_t &r_index, bool &r_batch_broken, bool &r_sdf_used, Batch *&r_current_batch) {
Batch *current_batch = &state.canvas_instance_batches[state.current_batch_index];
RenderingServer::CanvasItemTextureFilter texture_filter = p_item->texture_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? default_filter : p_item->texture_filter;
@@ -2784,6 +2784,8 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
// will make it re-enable clipping if needed afterwards
r_current_clip = nullptr;
}
+
+ r_current_batch = current_batch;
}
void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineVariants *p_pipeline_variants, RenderingDevice::FramebufferFormatID p_framebuffer_format, Light *p_lights, Batch const *p_batch, RenderingMethod::RenderInfo *r_render_info) {
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
index 87de07464e..8d90cd23ce 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
@@ -559,7 +559,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
};
void _render_batch_items(RenderTarget p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool &r_sdf_used, bool p_to_backbuffer = false, RenderingMethod::RenderInfo *r_render_info = nullptr);
- void _record_item_commands(const Item *p_item, RenderTarget p_render_target, const Transform2D &p_base_transform, Item *&r_current_clip, Light *p_lights, uint32_t &r_index, bool &r_batch_broken, bool &r_sdf_used);
+ void _record_item_commands(const Item *p_item, RenderTarget p_render_target, const Transform2D &p_base_transform, Item *&r_current_clip, Light *p_lights, uint32_t &r_index, bool &r_batch_broken, bool &r_sdf_used, Batch *&r_current_batch);
void _render_batch(RD::DrawListID p_draw_list, PipelineVariants *p_pipeline_variants, RenderingDevice::FramebufferFormatID p_framebuffer_format, Light *p_lights, Batch const *p_batch, RenderingMethod::RenderInfo *r_render_info = nullptr);
void _prepare_batch_texture(Batch *p_current_batch, RID p_texture) const;
void _bind_canvas_texture(RD::DrawListID p_draw_list, RID p_uniform_set); |
Good find! Passing it in as a reference makes sense; however, I'll update the |
Closes godotengine#96960 Fixes regression of godotengine#95574 using fix from godotengine#95666
Closes godotengine#96960 Fixes regression of godotengine#95574 using fix from godotengine#95666
Closes godotengine#96960 Fixes regression of godotengine#95574 using fix from godotengine#95666
Tested versions
System information
Godot v4.4.dev (74de05a) - KISS Linux Community #17 SMP PREEMPT_DYNAMIC Sat Aug 24 18:13:54 CEST 2024 - Wayland - Vulkan (Forward+) - integrated AMD Radeon Vega 8 Graphics (RADV RAVEN) - AMD Ryzen 5 3500U with Radeon Vega Mobile Gfx (8 Threads)
Issue description
Recently I pulled master and got a consistent crash I couldn't explain. Further bisecting and debugging brought me to #92797, commit a657ea4
Valgrind uncovered that the issue was an use-after-free in
_render_batch_items
. Why nobody is replicating it except me is a bit weird, but that might be because I'm running a musl distro.I'm getting an invalid read here, in the condition, when dereferencing
current_batch
:godot/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
Lines 2115 to 2119 in 74de05a
The problematic call trace looks something like this:
_render_batch_items
->_record_item_commands
->_new_batch
current_batch
points into aLocalVector
, which can be updated by_new_batch
, triggering a reallocation.As you can see in the code above (and in the rest of the codebase AFAICT),
current_batch
gets correctly updated in case of an update, but not when calling_record_item_commands
:godot/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
Lines 2150 to 2167 in 74de05a
I suppose that a potential fix might be to return the new
current_batch
just like inadd_to_batch
.This is the current signature of
add_to_batch
for reference:Notice how it returns the new current_batch pointer.
I don't have the confidence to file a PR as I don't have any experience with this part of the codebase so I have no idea if this might have some unforseen consequences.
Steps to reproduce
icon.svg
into it from the 2D viewMinimal reproduction project (MRP)
An empty project :P
The text was updated successfully, but these errors were encountered: