fix a crash with delayed load

If a delayed load failed, it could leave the pipeline only half-set up.
Sebsequent threads could then segv.

Set a load-has-failed flag and test before generate.

See https://github.com/jcupitt/libvips/issues/893
This commit is contained in:
John Cupitt 2018-03-05 14:42:09 +00:00
parent eefb2dad98
commit 20d840e6da
3 changed files with 25 additions and 6 deletions

View File

@ -4,6 +4,7 @@
writing twice to memory
- better rounding behaviour in convolution means we hit the vector path more
often
- fix a crash if a delayed load failed [gsharpsh00ter]
5/1/18 started 8.6.2
- vips_sink_screen() keeps a ref to the input image ... stops a rare race

View File

@ -18,6 +18,8 @@
* - transform cmyk->rgb if there's an embedded profile
* 16/6/17
* - add page_height
* 5/3/18
* - block _start if one start fails, see #893
*/
/*
@ -796,6 +798,11 @@ vips_foreign_load_start( VipsImage *out, void *a, void *b )
VipsForeignLoad *load = VIPS_FOREIGN_LOAD( b );
VipsForeignLoadClass *class = VIPS_FOREIGN_LOAD_GET_CLASS( load );
/* If this start has failed before in another thread, we can fail now.
*/
if( load->error )
return( NULL );
if( !load->real ) {
if( !(load->real = vips_foreign_load_temp( load )) )
return( NULL );
@ -819,19 +826,25 @@ vips_foreign_load_start( VipsImage *out, void *a, void *b )
g_object_set_qdata( G_OBJECT( load->real ),
vips__foreign_load_operation, load );
if( class->load( load ) ||
vips_image_pio_input( load->real ) )
return( NULL );
/* ->header() read the header into @out, load has read the
/* Load the image and check the result.
*
* ->header() read the header into @out, load has read the
* image into @real. They must match exactly in size, bands,
* format and coding for the copy to work.
*
* Some versions of ImageMagick give different results between
* Ping and Load for some formats, for example.
*
* If the load fails, we need to stop
*/
if( !vips_foreign_load_iscompat( load->real, out ) )
if( class->load( load ) ||
vips_image_pio_input( load->real ) ||
vips_foreign_load_iscompat( load->real, out ) ) {
vips_operation_invalidate( VIPS_OPERATION( load ) );
load->error = TRUE;
return( NULL );
}
/* We have to tell vips that out depends on real. We've set
* the demand hint below, but not given an input there.

View File

@ -158,6 +158,11 @@ typedef struct _VipsForeignLoad {
* TRUE.
*/
gboolean disc;
/* Set if a start function fails. We want to prevent the other starts
* from also triggering the load.
*/
gboolean error;
} VipsForeignLoad;
typedef struct _VipsForeignLoadClass {