From 5eecc46fd4f817a2c8c9c7d64dc5ae2f9367df83 Mon Sep 17 00:00:00 2001 From: Esteban82 Date: Wed, 14 Oct 2026 19:44:36 -0300 Subject: [PATCH 1/2] Return the error when the grid header has a bad increment in gmtnc_grd_prep_io A netCDF grid with one row and no y:actual_range (as written by GDAL) is read with y range 0/0, so y_inc is 0 and n_rows is 0. gmt_adjust_loose_wesn returns that error, but gmtnc_grd_prep_io only printed it and went on, and the read crashed (an assertion in gmtnc_pad_grid in Debug builds, a segfault in Release builds). Return the error so the read fails instead. gmt_nc_read_grd now passes the error code up unchanged instead of turning it into GMT_RUNTIME_ERROR, which has no entry in gmt_error_string, so the caller printed "(null)". The message is now the same kind as for other read errors: "grdtrend (gmtapi_import_grid): Grid y increment <= 0.0 [file]". Add a test that writes such a grid with GDAL. Fixes the crash reported in #9261. Co-Authored-By: Claude Opus 5.5 --- src/gmt_nc.c | 7 ++++--- test/gdal/gdal_1row_netcdf.sh | 11 +++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) create mode 100755 test/gdal/gdal_1row_netcdf.sh diff --git a/src/gmt_nc.c b/src/gmt_nc.c index 9a248adf0cb..3dc66f0ced1 100644 --- a/src/gmt_nc.c +++ b/src/gmt_nc.c @@ -1461,6 +1461,7 @@ GMT_LOCAL int gmtnc_grd_prep_io (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *h else { /* Must deal with a subregion */ double x; + int err; x = fabs (header->wesn[YLO] - wesn[YLO]); /* if |x| < GMT_CONV4_LIMIT * header->inc[GMT_Y] we set wesn to the grid limit */ if (x > 0.0 && x < GMT_CONV4_LIMIT * header->inc[GMT_Y]) wesn[YLO] = header->wesn[YLO]; /* Avoid snafu */ x = fabs (header->wesn[YHI] - wesn[YHI]); /* if |x| < GMT_CONV4_LIMIT * header->inc[GMT_Y] we set wesn to the grid limit */ @@ -1469,7 +1470,7 @@ GMT_LOCAL int gmtnc_grd_prep_io (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *h return (GMT_GRDIO_DOMAIN_VIOLATION); /* Calling program goofed... */ /* Make sure w,e,s,n are proper multiples of x_inc,y_inc away from x_min,y_min */ - gmt_M_err_pass (GMT, gmt_adjust_loose_wesn (GMT, wesn, header), HH->name); + if ((err = gmt_adjust_loose_wesn (GMT, wesn, header)) != GMT_NOERROR) return (err); /* Bad increment or range in the header */ /* Global grids: ensure that wesn >= header->wesn (w+e only) */ if ( is_global ) { /* Deal with wrapping issues */ @@ -1676,8 +1677,8 @@ int gmt_nc_read_grd (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *header, gmt_g else if (GMT->session.grdformat[header->type][0] != 'n') return (NC_ENOTNC); - if ((error = gmt_M_err_fail (GMT, gmtnc_grd_prep_io (GMT, header, wesn, &width, &height, &n_shift, origin, dim, origin2, dim2), HH->name))) - return (error); + if ((error = gmtnc_grd_prep_io (GMT, header, wesn, &width, &height, &n_shift, origin, dim, origin2, dim2)) != GMT_NOERROR) + return (error); /* Caller reports it */ /* Set stride and offset if complex */ (void)gmtlib_init_complex (header, complex_mode, &imag_offset); /* Set offset for imaginary complex component */ diff --git a/test/gdal/gdal_1row_netcdf.sh b/test/gdal/gdal_1row_netcdf.sh new file mode 100755 index 00000000000..0b45febb504 --- /dev/null +++ b/test/gdal/gdal_1row_netcdf.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# GDAL writes no y:actual_range for a netCDF grid with a single row, so GMT reads +# its y range as 0/0 and y_inc as 0 (issue #9261). The read must fail, not crash. +# The 1-row input is a native binary grid so that no netCDF 1-row grid is read before that. + +gmt grdmath -R-1.2/1.2/-0.2/0.2 -I0.4 -r X = row.grd=bf +gmt grdconvert row.grd=bf row_gdal.nc=gd:netCDF +gmt grdtrend row_gdal.nc -N4+x -Ttrend.nc 2> err.txt || true + +# Write out anything else than a clean read error as failure +grep -q "GMT_GRID_READ_ERROR" err.txt || echo "no clean read error" > fail From 7fc14ff211aca7b63d7f2a7fbf88428cc9886db5 Mon Sep 17 00:00:00 2001 From: Esteban82 Date: Thu, 15 Oct 2026 10:18:04 -0300 Subject: [PATCH 2/2] Remove the gdal_1row_netcdf test The test times out on the macOS CI (480 s, three attempts) while it passes on Linux and Windows. Keep only the fix. Co-Authored-By: Claude Sonnet 5.5 --- test/gdal/gdal_1row_netcdf.sh | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100755 test/gdal/gdal_1row_netcdf.sh diff --git a/test/gdal/gdal_1row_netcdf.sh b/test/gdal/gdal_1row_netcdf.sh deleted file mode 100755 index 0b45febb504..00000000000 --- a/test/gdal/gdal_1row_netcdf.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash -# GDAL writes no y:actual_range for a netCDF grid with a single row, so GMT reads -# its y range as 0/0 and y_inc as 0 (issue #9261). The read must fail, not crash. -# The 1-row input is a native binary grid so that no netCDF 1-row grid is read before that. - -gmt grdmath -R-1.2/1.2/-0.2/0.2 -I0.4 -r X = row.grd=bf -gmt grdconvert row.grd=bf row_gdal.nc=gd:netCDF -gmt grdtrend row_gdal.nc -N4+x -Ttrend.nc 2> err.txt || true - -# Write out anything else than a clean read error as failure -grep -q "GMT_GRID_READ_ERROR" err.txt || echo "no clean read error" > fail