You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]: TkAgg fails to find Tcl/Tk libraries in Windows for processes with a large number of modules loaded #22378
When trying to use the TkAgg backend in a Windows process (a Python process itself or another process with Python embedded) that has a large number of modules loaded (over 1024), the following exception might get raised.
RuntimeError: Failed to load Tcl_SetVar
Code for reproduction
# Within a Windows process with a large number of modules loadedimportmatplotlibasmplmpl.use('TkAgg')
Actual outcome
Loading the TkAgg backend fails with the following error:
RuntimeError: Failed to load Tcl_SetVar
Expected outcome
The TkAgg backend loads correctly.
Additional information
The reason for this error is that the function load_tkinter_funcs, which iterates through each module loaded by the process in search of the ones containing Tcl and Tk functions, calls EnumProcessModules with an output array with a fixed size of 1024. If the process has more than 1024 modules loaded, some of them will not be inspected, and so the code may fail to find it.
Instead, as explained by the documentation of EnumProcessModules, the returned needed array size should be checked:
To determine if the lphModule array is too small to hold all module handles for the process, compare the value returned in lpcbNeeded with the value specified in cb. If lpcbNeeded is greater than cb, increase the size of the array and call EnumProcessModules again.
This implies using dynamically allocated memory. Alternatively, the size of the array could be increased further and hope this pushes away the problem far enough.
In any case, the current code is not safe, as it iterates the array a number of times depending on the needed size, so if that value is greater than the size of the array, the code will accessing memory out of the boundaries of the array. It should only iterate up to the smaller of the needed size and the actual size.
In any case, the current code is not safe, as it iterates the array a number of times depending on the needed size, so if that value is greater than the size of the array, the code will accessing memory out of the boundaries of the array. It should only iterate up to the smaller of the needed size and the actual size.
I didn't write this, but I'm going defer the blame to Microsoft, as their example did not handle resizing the array either. That being said, is it really reading out of bounds, or does the call return an error that the buffer was too small (and thus we check nothing)?
In any case, the current code is not safe, as it iterates the array a number of times depending on the needed size, so if that value is greater than the size of the array, the code will accessing memory out of the boundaries of the array. It should only iterate up to the smaller of the needed size and the actual size.
I didn't write this, but I'm going defer the blame to Microsoft, as their example did not handle resizing the array either. That being said, is it really reading out of bounds, or does the call return an error that the buffer was too small (and thus we check nothing)?
Good point about the example, hadn't seen that. Now that you say that, I'm not sure if the function fails or not, I'm not really familiar with the Windows API. In any case, it doesn't work for the use case described anyway.
Activity
QuLogic commentedon Feb 2, 2022
I didn't write this, but I'm going defer the blame to Microsoft, as their example did not handle resizing the array either. That being said, is it really reading out of bounds, or does the call return an error that the buffer was too small (and thus we check nothing)?
javidcf commentedon Feb 2, 2022
Good point about the example, hadn't seen that. Now that you say that, I'm not sure if the function fails or not, I'm not really familiar with the Windows API. In any case, it doesn't work for the use case described anyway.