Repository navigation
SIGSEGV on shutdown of tests #1830
Description
Environment
- Pythonnet version: 3.0.0.a2
- Python version: 3.10.4 (locally, 3.8 through 3.10 in GitHub actions)
- Operating System: Ubuntu 22.04 (works find under Windows)
- .NET Runtime:
Details
-
Describe what you were trying to get done.
In several new projects, unit tests running fine under Windows, but when run under Ubuntu would would fail. On examining closer found that the unit tests all ran and passed, but there would be a SIGSEGV fault during shutdown. In chasing down possibly causes of the issue, the most common trigger appeared to a having a variable at the module level of .Net Type or of a Python container type which contained a .Net type.
-
What commands did you run to trigger this issue? If you can provide a
Minimal, Complete, and Verifiable example
this will help us understand the issue.Starting with one of the simpler projects, reducing it down a simple test case that reproduces the code.
src/acmedlls/netstandard2.0- There were other DLLs from the results of a csproj build, but to reproduce this error only
Microsoft.Extensions.Logging.Abstractions.dllis needed.
- There were other DLLs from the results of a csproj build, but to reproduce this error only
python_logger_working.py"""Implementation of PythonLogger.""" import logging import os import sys import clr # type: ignore sys.path.append(os.path.join(os.path.dirname(__file__), "dlls/netstandard2.0")) clr.AddReference(r"Microsoft.Extensions.Logging.Abstractions") from Microsoft.Extensions.Logging import LogLevel # type: ignore def get_python_level(log_level: LogLevel) -> int: """Get the equivalent python logging level for a .NET LogLevel.""" python_level: int = logging.CRITICAL if log_level == getattr(LogLevel, "None"): python_level = logging.NOTSET elif log_level == LogLevel.Trace: # Python has no trace level, so we return the level right below debug as trace. python_level = logging.DEBUG - 1 elif log_level == LogLevel.Debug: python_level = logging.DEBUG elif log_level == LogLevel.Information: python_level = logging.INFO elif log_level == LogLevel.Warning: python_level = logging.WARN elif log_level == LogLevel.Error: python_level = logging.ERROR return python_level
teststest_python_logger.pyimport logging import pytest import clr from src.acme.python_logger_working import get_python_level clr.AddReference(r"Microsoft.Extensions.Logging.Abstractions") from Microsoft.Extensions.Logging import LogLevel @pytest.mark.parametrize( "dotnet_level,expected_level", [ pytest.param(LogLevel.Critical, logging.CRITICAL), pytest.param(LogLevel.Error, logging.ERROR), pytest.param(LogLevel.Warning, logging.WARNING), pytest.param(LogLevel.Information, logging.INFO), pytest.param(LogLevel.Debug, logging.DEBUG), pytest.param(LogLevel.Trace, logging.DEBUG - 1) ] ) def test_get_python_level(dotnet_level, expected_level) -> None: result = get_python_level(dotnet_level) # Verify assert( result == expected_level)
-
Workarounds and addition scenarios follow in comments.
Activity
potterphx commentedon Jun 22, 2022
One can avoid the SIGSEGV fault by transforming the
test_python_logger.pyeither:pytest.mark.parmetrizeto not use .Net types.pytest.mark.parametrizeand instead write multiple tests for each test case.potterphx commentedon Jun 22, 2022
Rewriting
src/python_logger.pyso as to not use a chained-if, but to use a dictionary may cause the SIGSEGV fault:One can work around this issue by adding an
atexitfunction to deallocate the lookup dictionary during shutdown.potterphx commentedon Jun 22, 2022
Using the second modification from the first comment to avoid the issue in the test file, and the first modification from the second comment to have the issue be caused from the code, I then added to the test file a main so that the tests could be run without pytest.
Directly running this also generated the SIGSEGV fault, thus demonstrating that pytest is not a requirements to reproduce the issue.
potterphx commentedon Jun 22, 2022
As soon as I finished the above write-up I thought of a simpler case:
tests/test_simple.py:lostmsu commentedon Jun 22, 2022
3.0.0a2is rather old. We had a similar (crash on exit) issue fixed after it was released. Can you try Installing frommasterinstead?potterphx commentedon Jun 22, 2022
"rather old", it is the latest alpha release. 😁 Sorry, sarcasm slipped out.
Updating to current latest master (3.0.0.dev1 43d1640), and all the cases documented above no longer generated a SIGSEGV. Thanks.
Any ETA on another alpha?
lostmsu commentedon Jun 22, 2022
@filmor can you publish a3 on pypi? That was a nasty bug we fixed. And the latest (a2) is from Dec 2021.
filmor commentedon Jun 23, 2022
I'll finish up #1817 today (at least structurally) and release it as rc1.