diff --git a/libvips/conversion/sequential.c b/libvips/conversion/sequential.c index 9da91786..c90b4cdc 100644 --- a/libvips/conversion/sequential.c +++ b/libvips/conversion/sequential.c @@ -195,6 +195,11 @@ vips_sequential_build( VipsObject *object ) if( vips_linecache( sequential->in, &t, "tile_height", sequential->tile_height, "access", VIPS_ACCESS_SEQUENTIAL, + /* We need seq caches to persist across minimise, in case + * someone is trying to read an image with a series of crop + * operations. + */ + "persistent", TRUE, NULL ) ) return( -1 ); diff --git a/libvips/foreign/jpeg2vips.c b/libvips/foreign/jpeg2vips.c index 838bb27b..f2726866 100644 --- a/libvips/foreign/jpeg2vips.c +++ b/libvips/foreign/jpeg2vips.c @@ -134,9 +134,9 @@ */ /* + */ #define DEBUG_VERBOSE #define DEBUG - */ #ifdef HAVE_CONFIG_H #include @@ -472,7 +472,8 @@ attach_blob( VipsImage *im, const char *field, void *data, size_t data_length ) } #ifdef DEBUG - printf( "attach_blob: attaching %d bytes of %s\n", data_length, field ); + printf( "attach_blob: attaching %zd bytes of %s\n", + data_length, field ); #endif /*DEBUG*/ vips_image_set_blob_copy( im, field, data, data_length ); diff --git a/test/test_descriptors.c b/test/test_descriptors.c new file mode 100644 index 00000000..f8c32a6e --- /dev/null +++ b/test/test_descriptors.c @@ -0,0 +1,91 @@ +/* Read an image and check that file handles are being closed on minimise. + * + * This will only work on linux: we signal success and do nothing if /dev/proc + * does not exist. + */ + +#include +#include + +#include + +/* Count the number of files in a directory, -1 for directory not found etc. + */ +static int +count_files( const char *dirname ) +{ + GDir *dir; + int n; + + if( !(dir = g_dir_open( dirname, 0, NULL )) ) + return( -1 ); + + for( n = 0; g_dir_read_name( dir ); n++ ) + ; + + g_dir_close( dir ); + + return( n ); +} + +int +main( int argc, char **argv ) +{ + VipsImage *image, *x; + char fd_dir[256]; + int n_files; + double average; + + if( VIPS_INIT( argv[0] ) ) + vips_error_exit( "unable to start" ); + + vips_snprintf( fd_dir, 256, "/proc/%d/fd", getpid() ); + n_files = count_files( fd_dir ); + if( n_files == -1 ) + /* Probably not linux, silent success. + */ + return( 0 ); + + /* This is usually 4. stdout / stdin / stderr plus one more made for + * us by glib, I think, doing what I don't know. + */ + + /* Opening an image should read the header, then close the fd. + */ + if( !(image = vips_image_new_from_file( argv[1], + "access", VIPS_ACCESS_SEQUENTIAL, + NULL )) ) + vips_error_exit( NULL ); + if( count_files( fd_dir ) != n_files ) + vips_error_exit( "fd not closed after header read" ); + + /* We should be able to read a chunk near the top, then have the fd + * closed again. + */ + if( vips_crop( image, &x, 0, 0, image->Xsize, 10, NULL ) || + vips_avg( x, &average, NULL ) ) + vips_error_exit( NULL ); + g_object_unref( x ); + if( count_files( fd_dir ) != n_files ) + vips_error_exit( "fd not closed after first read" ); + + /* We should be able to read again, a little further down, and have + * the input restarted and closed again. + */ + if( vips_crop( image, &x, 0, 20, image->Xsize, 10, NULL ) || + vips_avg( x, &average, NULL ) ) + vips_error_exit( NULL ); + g_object_unref( x ); + if( count_files( fd_dir ) != n_files ) + vips_error_exit( "fd not closed after second read" ); + + /* Clean up, and we should still just have three open. + */ + g_object_unref( x ); + vips_shutdown(); + + if( count_files( fd_dir ) != n_files ) + vips_error_exit( "fd not closed after shutdown" ); + + return( 0 ); +}