Skip to content
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

Add warning for netCDF4 bug #1835

Closed
wants to merge 8 commits into from
Closed

Add warning for netCDF4 bug #1835

wants to merge 8 commits into from

Conversation

braaannigan
Copy link
Contributor

Closes #1745 by adding a warning message for a bug in netCDF4. The bug occurs when the filepath has 88 characters and the netCDF4 engine has been used with version less than 1.3.1.

The warning message has been added at the first point where the length of the file path is known and the netcdf4 version number is known.

I don't think there is any corresponding test, as the bug leads to a seg fault rather than a python output/exception.

Passes git diff upstream/master **/*py | flake8 --diff (remove if you did not edit any Python files)

Updated whats-new.rst

Copy link
Member

@shoyer shoyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! A good way to test this would be to use mock, e.g.,

with mock.patch('netCDF4.__version__', '1.2.4'):
    with pytest.warns(Warning, match='segmentation fault'):
        xarray.Dataset().to_netcdf('a' * 88)

@@ -281,6 +281,14 @@ def maybe_decode_store(store, lock=False):
engine = _get_default_engine(filename_or_obj,
allow_remote=True)
if engine == 'netcdf4':
import netCDF4
if len( filename_or_obj ) == 88 and float(netCDF4.__version__[:3]) < 1.3:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -281,6 +281,14 @@ def maybe_decode_store(store, lock=False):
engine = _get_default_engine(filename_or_obj,
allow_remote=True)
if engine == 'netcdf4':
import netCDF4
if len( filename_or_obj ) == 88 and float(netCDF4.__version__[:3]) < 1.3:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove spaces around filename_or_obj, per pep8.

'to occur with version 1.2.4 of netCDF4 and can be \n'
'addressed by upgrading netCDF4 to at least version 1.3.1. \n'
'More details can be found here: \n'
'https://github.com/pydata/xarray/issues/1745 \n')
store = backends.NetCDF4DataStore.open(filename_or_obj,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you put this inside NetCDF4DataStore.open() instead? We try to keep the backend specific logic in the backend classes.

@braaannigan
Copy link
Contributor Author

Thanks for the advice @shoyer

I've moved the warning to NetCDF4DataStore.open() and reverted backends/api.py back to the original.

I've used LooseVersion for the version comparison and made the pep8 change.

There is a problem with the test. I've added the test to NetCDF4DataTest. However, when the filename has 88 characters the seg fault occurs and the test gets stopped. The output from

$py.test tests/test_backends.py

is just:

============================= test session starts ==============================
platform linux -- Python 3.6.2, pytest-3.2.1, py-1.4.34, pluggy-0.4.0
rootdir: /my_python_path/xarray, inifile: pytest.ini
plugins: pylama-7.4.3
collected 1042 items

tests/test_backends.py .
*** Error in `/path_to/python': double free or corruption (!prev):  ***
Aborted (core dumped)

If the filename doesn't have 88 characters then the test result is "Failed: DID NOT WARN.", which is fine as it shouldn't trigger the warning.

I've been trying to see how people handle this issue, but haven't been able to find examples of people trying to trigger seg faults in a test yet

@braaannigan
Copy link
Contributor Author

There are some other small issues I need to deal with, I'll leave a message when I've sorted those out

@shoyer
Copy link
Member

shoyer commented Jan 17, 2018

@braaannigan How about we turn warnings into errors, and then catch the appropriate error instead? e.g.,

with warnings.catch_warnings():
    warnings.simplefilter("error")
    with raises_regex(Warning, 'segmentation fault'):
        ...

That should abort (due to the error) before the seg fault.

@@ -244,6 +245,16 @@ def __init__(self, netcdf4_dataset, mode='r', writer=None, opener=None,
def open(cls, filename, mode='r', format='NETCDF4', group=None,
writer=None, clobber=True, diskless=False, persist=False,
autoclose=False):
import netCDF4 as nc4
from distutils.version import LooseVersion
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can put this import at the top level. (We only import netCDF4 inside functions/methods to avoid the hard dependency, but disutils is part of Python's standard library.)

@braaannigan
Copy link
Contributor Author

I've pushed an updated version with a successful test on my machine.

I've modified the dataset name in the test case to ensure it has 88 characters (the filepath on github has to have less than 88 characters of course, this seems like a safe assumption).

I've made some formatting changes to netCDF4_.py to pass the pyflake tests. I've moved the import statement for LooseVersion to the start of the script.

Thanks for the reviews and advice @shoyer

@@ -281,6 +281,14 @@ def maybe_decode_store(store, lock=False):
engine = _get_default_engine(filename_or_obj,
allow_remote=True)
if engine == 'netcdf4':
import netCDF4
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you accidentally kept your changes in this file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought that I had checked out the original version again to replace all of my edits, but that doesn't seem to have worked. I'm looking for a solution.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can simply revert this file (e.g., copy/paste from master) and then add another commit

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was worried that would cause some new unforeseen problem. I've commited this now.

@shoyer
Copy link
Member

shoyer commented Jan 20, 2018

Merged in 47c3b62.

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants