[GRASSLIST:8036] Re: error reading large rasters in 5.4/6.0

Glynn Clements glynn at gclements.plus.com
Tue Aug 23 17:25:05 EDT 2005

Andrew Danner wrote:

> After looking into the problem of reading very large rasters, I believe
> I have isolated the bug. The problem only happens when reading row 0 and
> triggers the following block in flate.c:186
>  else if (b[0] != G_ZLIB_COMPRESSED_YES)
>     {
>         /* We're not at the start of a row */
>         G_free (b);
>         return -1;
>     }
> I think the problem is a bug in writing rasters, not reading them. When
> creating a new raster, it writes a vector of row offsets to the fcell
> file in the function G__write_row_ptrs. It attempts to guess the size of
> the file offsets. 
>  int nbytes = sizeof(off_t);
> ...
>  if (nbytes > 4 && fcb->row_ptr[nrows] <= 0xffffffff)
>     nbytes = 4;
> ...
>  len = (nrows + 1) * nbytes + 1;
>  b = buf = G_malloc(len);
> The problem is that when a new raster is created fcb->row_ptr[nrows]=0,
> so nbytes is always 4. Later when writing the rows and actually
> computing the offsets, if fcb->row_ptr[nrows] > 0xffffffff, it bumps
> nbytes upto 8, but row 0 was written to the file assuming an offset of 4
> and row 0 becomes corrupted if the raster is larger than 4GB. 

Right. I'd overlooked the fact that G_write_row_ptrs() gets called

> Commenting out the "if" block seems to fix the problem. 

The reader will handle 8-byte offsets even if off_t is only 4 bytes so
long as the offsets themselves don't exceed the 32-bit range.

There isn't any practical way to determine in advance whether the
offsets will fit into 4 bytes, so removing the "if" block is the right

> Should I submit a bug report?

No need; I've comitted the fix to CVS.

One other bug which I've just noticed: the reader checks whether an
offset exceeds the range of an off_t, but only in the sense that it
checks whether it occupies too many bytes.

This check is wrong for files between 2GiB and 4GiB, where the offset
fits into 4 bytes, but exceeds the 31-bit (signed) range of an off_t. 
There needs to be an "if (offset < 0)" check in there somewhere.

Glynn Clements <glynn at gclements.plus.com>

More information about the grass-user mailing list