Recently, I ran Claude Code across several projects(like image-rs, lofty of symphonia) to look for potential issues.
In this projects, a significant portion of reported findings turned out to be incorrect or minor false positives, but a non-trivial subset was valid and included real issues ranging from incorrect comments to actual logic bugs. As a result, the findings generally require manual validation to separate noise from actionable problems.
Full Reports (findings-interactive.html - interactive report view for manual inspection, findings-short.md - compact list ready to copy into GitHub, findings-table.html - compact tabular report version):
findings-interactive.html
findings-short.md
findings-table.html
Example findings (this is only a subset of the findings, specifically those most likely to be actual bugs; for the full list, see the reports above):
=================================
API_1 HIGH
Description: GLDevice::create_texture_from_data calls gl::TexImage2D without a trailing ck() error check, unlike the other GL calls in the function. If TexImage2D fails (e.g. invalid enum/format combination), the error is silently swallowed and only surfaces on the next checked call.
Locations:
gl/src/lib.rs:386-395
386 | gl::TexImage2D(gl::TEXTURE_2D,
387 | 0,
388 | format.gl_internal_format(),
389 | size.x() as GLsizei,
390 | size.y() as GLsizei,
391 | 0,
392 | format.gl_format(),
393 | format.gl_type(),
394 | data_ptr)
395 | }
Fix: Append ; ck(); after the TexImage2D call (matching the pattern used in create_texture).
API_5 LOW
Description: gpu_data::RenderCommand::UploadTexelData carries Arc<Vec<ColorU>>, but in GradientTileBuilder::create_render_commands a fresh Arc::new(tile.texels) is created per gradient tile, defeating the point of Arc (no sharing actually occurs). A Box<[ColorU]> or plain Vec would be equivalent.
Locations:
renderer/src/paint.rs:867-877
867 | fn create_render_commands(self, render_commands: &mut Vec<RenderCommand>) {
868 | for tile in self.tiles {
869 | render_commands.push(RenderCommand::UploadTexelData {
870 | texels: Arc::new(tile.texels),
871 | location: TextureLocation {
872 | rect: RectI::new(vec2i(0, 0), Vector2I::splat(GRADIENT_TILE_LENGTH as i32)),
873 | page: tile.page,
874 | },
875 | });
876 | }
877 | }
Fix: Either drop the Arc wrapper from UploadTexelData or actually share data.
ERR_1 HIGH
Description: fill_or_stroke_text explicitly drops the Result returned by push_layout, silently swallowing GlyphLoadingError. The TODO comment confirms this is a known omission. Failed glyph rasterization produces no rendered text and no diagnostic.
Locations:
canvas/src/text.rs:81-96
81 | // TODO(pcwalton): Report errors.
82 | drop(self.canvas_font_context
83 | .0
84 | .borrow_mut()
85 | .font_context
86 | .push_layout(&mut self.canvas.scene,
87 | &layout.skribo_layout,
88 | &TextStyle { size: layout.font_size },
89 | &FontRenderOptions {
90 | transform,
91 | render_mode,
92 | hinting_options: HintingOptions::None,
93 | clip_path,
94 | blend_mode,
95 | paint_id,
96 | }));
Fix: Propagate the Result up to the caller, or at minimum log the error.
LOGIC_1 CRITICAL
Description: GLDevice::create_texture_from_data() hard-codes the GLTexture.format field to TextureFormat::R8 regardless of the actual format parameter. The OpenGL upload uses the correct format, but the returned GLTexture wrongly reports R8 as its format. This causes every later operation that reads texture.format to misbehave — RGBA8 dummy/font textures will be reported as R8.
Locations:
gl/src/lib.rs:379-399
379 | fn create_texture_from_data(&self, format: TextureFormat, size: Vector2I, data: TextureDataRef)
380 | -> GLTexture {
381 | let data_ptr = data.check_and_extract_data_ptr(size, format);
382 | let mut texture = GLTexture { gl_texture: 0, size, format: TextureFormat::R8 };
383 | unsafe {
384 | gl::GenTextures(1, &mut texture.gl_texture); ck();
385 | self.bind_texture(&texture, 0);
386 | gl::TexImage2D(gl::TEXTURE_2D,
387 | 0,
388 | format.gl_internal_format(),
389 | size.x() as GLsizei,
390 | size.y() as GLsizei,
391 | 0,
392 | format.gl_format(),
393 | format.gl_type(),
394 | data_ptr)
395 | }
396 |
397 | self.set_texture_sampling_mode(&texture, TextureSamplingFlags::empty());
398 | texture
399 | }
Fix: Replace format: TextureFormat::R8 with format (the function argument). Also add a ck() call after the gl::TexImage2D.
LOGIC_2 CRITICAL
Description: Metal upload_to_texture() computes the source buffer byte offset using src_stride (rect.width()*bpp) but the staging buffer was laid out using dest_stride (texture_size.x()*bpp). When uploading a sub-rectangle whose width differs from texture_size.x(), the GPU read offset will be wrong and the texture will receive garbage rows.
Locations:
metal/src/lib.rs:793-808
793 | let dest_origin = MTLOrigin { x: rect.origin_x() as u64, y: rect.origin_y() as u64, z: 0 };
794 | let dest_byte_offset = rect.origin_y() as u64 * src_stride as u64 +
795 | rect.origin_x() as u64 * bytes_per_pixel as u64;
796 |
797 | let blit_command_encoder = command_buffer.real_new_blit_command_encoder();
798 | blit_command_encoder.copy_from_buffer_to_texture(&src_shared_buffer,
799 | dest_byte_offset,
800 | dest_stride,
801 | 0,
802 | src_size,
803 | &dest_texture.private_texture,
804 | 0,
805 | 0,
806 | dest_origin,
807 | MTLBlitOption::empty());
808 | blit_command_encoder.end_encoding();
Fix: Change to let dest_byte_offset = rect.origin_y() as u64 * dest_stride + rect.origin_x() as u64 * bytes_per_pixel; (use dest_stride, not src_stride).
Recently, I ran Claude Code across several projects(like image-rs, lofty of symphonia) to look for potential issues.
In this projects, a significant portion of reported findings turned out to be incorrect or minor false positives, but a non-trivial subset was valid and included real issues ranging from incorrect comments to actual logic bugs. As a result, the findings generally require manual validation to separate noise from actionable problems.
Full Reports (
findings-interactive.html- interactive report view for manual inspection,findings-short.md- compact list ready to copy into GitHub,findings-table.html- compact tabular report version):findings-interactive.html
findings-short.md
findings-table.html
Example findings (this is only a subset of the findings, specifically those most likely to be actual bugs; for the full list, see the reports above):
=================================
API_1
HIGHDescription: GLDevice::create_texture_from_data calls gl::TexImage2D without a trailing
ck()error check, unlike the other GL calls in the function. If TexImage2D fails (e.g. invalid enum/format combination), the error is silently swallowed and only surfaces on the next checked call.Locations:
Fix: Append
; ck();after the TexImage2D call (matching the pattern used increate_texture).API_5
LOWDescription:
gpu_data::RenderCommand::UploadTexelDatacarriesArc<Vec<ColorU>>, but inGradientTileBuilder::create_render_commandsa freshArc::new(tile.texels)is created per gradient tile, defeating the point ofArc(no sharing actually occurs). ABox<[ColorU]>or plainVecwould be equivalent.Locations:
Fix: Either drop the
Arcwrapper fromUploadTexelDataor actually share data.ERR_1
HIGHDescription:
fill_or_stroke_textexplicitlydrops the Result returned bypush_layout, silently swallowing GlyphLoadingError. The TODO comment confirms this is a known omission. Failed glyph rasterization produces no rendered text and no diagnostic.Locations:
Fix: Propagate the Result up to the caller, or at minimum log the error.
LOGIC_1
CRITICALDescription: GLDevice::create_texture_from_data() hard-codes the GLTexture.format field to TextureFormat::R8 regardless of the actual
formatparameter. The OpenGL upload uses the correct format, but the returned GLTexture wrongly reports R8 as its format. This causes every later operation that readstexture.formatto misbehave — RGBA8 dummy/font textures will be reported as R8.Locations:
Fix: Replace
format: TextureFormat::R8withformat(the function argument). Also add ack()call after the gl::TexImage2D.LOGIC_2
CRITICALDescription: Metal upload_to_texture() computes the source buffer byte offset using
src_stride(rect.width()*bpp) but the staging buffer was laid out usingdest_stride(texture_size.x()*bpp). When uploading a sub-rectangle whose width differs from texture_size.x(), the GPU read offset will be wrong and the texture will receive garbage rows.Locations:
Fix: Change to
let dest_byte_offset = rect.origin_y() as u64 * dest_stride + rect.origin_x() as u64 * bytes_per_pixel;(use dest_stride, not src_stride).