-
-
Notifications
You must be signed in to change notification settings - Fork 656
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
Python 3.8/liblouis helper: add NVDA executable path by calling os.add_dll_directory #12020
Conversation
See test results for failed build of commit 184538c371 |
Hi, No need to worry about Nose test failure. Thanks. |
…luis DLL. Python 3.8 adds os.add_dll_directory to securely load DLL's from known locations, which affects Louis helper when trying to load liblouis.dll from NVDA executable folder. Therefore add NVDA executable path to known DLL directories through os.add_dll_directory, which resolves ModuleNotFoundError.
c3aba71
to
714db9c
Compare
See test results for failed build of commit c3957f5396 |
source/louisHelper.py
Outdated
#This file is covered by the GNU General Public License. | ||
#See the file COPYING for more details. | ||
#Copyright (C) 2018 NV Access Limited, Babbage B.V. | ||
# louisHelper.py |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove this line
source/louisHelper.py
Outdated
# Python 3.8 changes the way DLL's are loaded due to security. | ||
# Thus manually add NVDA executable path to DLL lookup path for loading liblouis.dll. | ||
import os | ||
with os.add_dll_directory(os.path.dirname(__file__)): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
os.path.dirname(__file__)
is not gonna work for binary copies since it would point to nvda_install_dir\library.zip. Please use globalVars.appDir
instead.
Hi, forgot about globalVars.appDir. Thanks for pointing this out.
|
…ble path. Reviewed by Lukasz Golonka: remove file name from header comment. Also, because __file__ will point to library.zip, use globalVars.appDir to locate NVDA executable where liblouis.dll actually resides.
Hi, Upon further testing, globalVars.appDir will not work on source code version but file will. I'll find out if the binary copy is affected by this and come up with something if needed. Thanks. |
Hi, Traceback from source version while using globalVars.appDir: CRITICAL - main (10:56:05.868) - MainThread (13492): This was after compiling NVDA from source (Python 3.8/SCons). Thanks. |
That's quite strange. Have you compared |
Hi, nope it doesn’t. As you pointed out, using __file__ results in library.zip whereas globalVars.appDir results in the parent folder of the executable file e.g. if code is located in nvdapy38/source, globalVars.appDir will point to just nvdapy38 folder. Although ugly, one possible workaround is detecting source vs binary and add “source” to source code version. What’s more interesting is that liblouis.dll is loaded as part of braille input/output initialization later (and one can then work with the DLL from that point on), as the issue with louisHelper/add_dll_directory is encountered early in core.main. Thanks.
|
source/louisHelper.py
Outdated
# Thus manually add NVDA executable path to DLL lookup path for loading liblouis.dll. | ||
import os | ||
import globalVars | ||
with os.add_dll_directory(os.path.dirname(globalVars.appDir)): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe I've found the problem. There is no point in using (os.path.dirname
on globalVars.appDir
as it represents path to the directory already. On my machine using globalVars.appDir
alone allows source copy of NVDA to import liblouis and start correctly whereas when (os.path.dirname
is used I'm getting the traceback you've posted yesterday.
…h os.path.dirname. Pointed out by Lukasz Golonka: globalVars.appDir records the actual path to the executable, including in source code version (nvda.pyw). Therefore use app dir directly.
Fixes #12152 Fixes #12154 Since upgrading to Python 3.8, several serious crashes in NVDA have been reported. Specifically: • NVDA crashing when using the SAPI4 speech synthesizer: #12152 • NVDA crashing when using Windows Explorer on Windows Server 2012: #12154 Both of these issues were traced to stack corruption after a Python callback of NVDA's was called from external libraries. In SAPI4's case, after calling NVDA's implementation of ITTSBufNotifySink::TextDataStarted, and in the Windows Server 2012 case: IUIAutomationPropertyChangedEventHandler::handlePropertyChangedEvent. It seems as though libFFI / Python ctypes is not cleaning the stack properly after executing a Python callback with the stdcall calling convention (ctypes WINFUNCTYPE), where the callback contained at least one argument larger than 4 bytes (E.g. a long long, or a VARIANT struct), and the arguments preceding it were such that this argument was not aligned to an 8 byte boundary. E.g. the callback might be: • callback(void*, long long) or • callback(void*, void*, int, VARIANT) See Python bug: https://bugs.python.org/issue38748 On that bug I have attached a minimal testcase. This bug affects both Python 3.8 and Python 3.9. The bug is most likely in the libFFI project used by Python's ctypes module. Python 3.8 switched to a much more recent and official version of libFFI I believe. Although we do really want to move to Python 3.8+ as soon as we can, right now this bug makes it impossible to do so. We could specifically work around the currently known manifestations by moving some of that code into C++, but that brings its own risks, and we still don't know where else this issue may appear in our code. The appropriate thing to do right now is stay on Python 3.7 until we can work with Python / libFFI to get this resolved. Description of how this pull request fixes the issue: Downgrades to Python 3.7 by referencing Python 3.7 (rather than 3.8) in NVDA's build system. The existing PRs that needed to be reverted were: • Updating brlAPI to a Python 3.8 build: nvaccess/nvda-misc-deps#20 • Switching to using Python's own pgettext: #12109 • calling os.add_dll_directory when loading liblouis: #12020 None of these PRs provided any user visible changes. The rest of the Python 3.8 work, including the switch to a virtual environment etc is all compatible with Python 3.7 and can remain.
Hi,
Required in Python 3.8:
Link to issue number:
Fixes #10416
Summary of the issue:
Python 3.8 adds os.add_dll_directory function to add a specified path to known DLL folders, used to load DLL's more securely. Without this call, liblouis.dll cannot be imported - instead, Python says "ModuleNotFoundError".
Description of how this pull request fixes the issue:
Calls os.add_dll_directory function (context manager form) from louisHelper.py to add NVDA executable path to known DLL's directory in order to import liblouis.dll.
Testing performed:
Tested from source code version of Python 3.8 NVDA with no problems - braille input and output works as expected.
Known issues with pull request:
None
Change log entry:
None
Thanks.