-
-
Notifications
You must be signed in to change notification settings - Fork 8.3k
[Bug]: Umbrella issue: matplotlib C/C++ Extension Analysis Report #31424
Description
Bug summary
This is an umbrella issue meant to present the findings of an analysis report so matplotlib developers and contributors can discuss them, figure out which are worth fixing, open individual issues and PRs, etc.
Findings by Priority
FIX
-
std::stringconstructed from NULLft_error_string—ft_error_string()returns NULL for unknown FreeType error codes.THROW_FT_ERRORconstructsstd::string{nullptr}— undefined behavior (typically crashes instrlen). Triggered when FreeType returns an error code not in the compiled-in list.ft2font.h:39,52
-
Inverted
PyErr_Occurredlogic in enum type caster —return !(ival == -1 && !PyErr_Occurred())returnstrue(success) whenPyLong_AsLongfails with an active exception. One-character fix: the!beforePyErr_Occurred()should be removed._enums.h:83
-
Unchecked
malloc+ leakedPy_bufferin_copy_agg_buffer—malloc(sizeof(Py_buffer))not NULL-checked. IfPyObject_GetBufferfails, the buffer is leaked._macosx.m:1221-1225
-
Unchecked
PyOS_double_to_string—strlen(NULL)crash —PyOS_double_to_string()can return NULL on OOM.strlen(str)follows without a NULL check. Crash confirmed under OOM injection._path.h:1070-1073
-
FigureCanvas_set_cursorreturns NULL without exception — Thedefault:case returns NULL without callingPyErr_Set*, causingSystemError._macosx.m:451
-
FigureManager__set_window_modereturns NULL without exception — Whenself->windowis NULL (afterdestroy()), returns NULL without setting an exception._macosx.m:653-654
-
NULL
char*streamed tostd::stringstreaminft_glyph_warn—face->family_namecan be NULL. When NULL is inserted intostd::set<FT_String*>and later streamed viass << *it, it's undefined behavior.ft2font.cpp:457,ft2font_wrapper.cpp:410
-
NSFileHandleleak inwake_on_fd_write—[[NSFileHandle alloc] initWithFileDescriptor: fd]is never released._macosx.m:246-257
CONSIDER
-
GIL not released during Agg rendering —
draw_path,draw_markers,draw_path_collection, etc. hold the GIL during software rasterization, blocking all threads._image_wrapper.cppalready demonstrates the correct GIL-release pattern._backend_agg_wrapper.cpp:41-215
-
GIL not released during Qhull triangulation — 500K-point triangulation holds the GIL for 3+ seconds, reducing background thread throughput to 0.6% of baseline.
_qhull_wrapper.cpp:138-253
-
Global
FT_Librarynot thread-safe —_ft2Libraryis shared across all threads. FreeType is not thread-safe for shared library instances.ft2font.cpp:44
-
FreeType stream read callback lacks GIL guard for free-threading — Calls Python I/O without GIL guard on free-threaded builds.
ft2font_wrapper.cpp:367-388
-
ft_glyph_warncalls Python APIs without GIL guard for free-threading — Module import/attr access without GIL on free-threaded builds.ft2font_wrapper.cpp:405-418
-
Global
p11x::enumsmap lacks synchronization —std::unordered_mapwithpy::objectvalues, no synchronization for free-threading._enums.h:37
-
NSTrackingArealeak inFigureCanvas_init—allocwithout matchingrelease._macosx.m:378-382
-
Window.closedouble-decref risk —Py_DECREF(manager)ifdeallocruns without priordestroy._macosx.m:1177-1188
-
PyFT2Font_initleaks on exception — Rawnewwithoutunique_ptr. ~59 bytes leaked per failed font construction (corrupt font file), ~131 bytes per failed construction (failing file-like object).ft2font_wrapper.cpp:457-505
-
Timer NSTimer captures raw
selfpointer — Block captures Python object withoutPy_INCREF._macosx.m:1807-1816
-
View stores raw
canvaspointer — NoPy_INCREF, potential dangling pointer._macosx.m:139
-
Exception clobbering in ft2font catch-all —
catch(std::exception&)replaces meaningful errors (includingMemoryError,KeyboardInterrupt) with genericTypeError.ft2font_wrapper.cpp:492-494
-
Unchecked
PyUnicode_EncodeFSDefault— NULL wrapped inpy::bytes._tkagg.cpp:333-335
-
PyErr_Fetch/PyErr_Restoredeprecated since 3.12 — Should migrate toPyErr_GetRaisedException/PyErr_SetRaisedException.ft2font_wrapper.cpp:394,402
-
PY_SSIZE_T_CLEANdefines (×3) — No-op since 3.10, can be removed.mplutils.h,py_adaptors.h,_macosx.m
-
Solaris
_XPG4/_XPG3undefs — Likely dead code.mplutils.h:22-28
-
macOS SDK < 10.14 compat defines — Likely dead code.
_macosx.m:11-16
Code for reproduction
See https://gist.github.com/devdanzin/2a79188c7a41a03b1476544c7dd775c1#matplotlib-c-extension--reproducer-appendix for reproducers.
Actual outcome
Expected outcome
Additional information
The issue above is part of an analysis report created by cext-review-toolkit, a Claude Code plugin for reviewing CPython C extensions. It covers the C/C++ source in src/ (13 source files, 9 extension modules — 8 pybind11 + 1 raw Python/C API in _macosx.m).
Some findings may be false positives or low-priority issues not worth fixing. Feedback on any misclassified findings is welcome.
The full report (including a reproducers appendix) is available at https://gist.github.com/devdanzin/2a79188c7a41a03b1476544c7dd775c1.
Operating system
Linux
Matplotlib Version
main
Matplotlib Backend
No response
Python version
No response
Jupyter version
No response
Installation
git checkout