_source loaders should all be nocache

When we image_new_from_source, the source object has some of the loader
state: it tracks the current read position of the load library. This
means that we mustn't keep source loaders in the operation cache, since
a second call could give a different result because the source object
read position might have changed.

Also: add a rewind to get_flags_source in spngload, and jp2k needs to
tag its load region as having no thread ownership or you'll get assert
fails in the test suite with debug enabled.
This commit is contained in:
John Cupitt 2021-11-19 13:55:49 +00:00
parent 4fd2de5754
commit cb58d7d960
22 changed files with 73 additions and 4 deletions

View File

@ -642,6 +642,7 @@ vips_foreign_load_csv_source_class_init( VipsForeignLoadCsvFileClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
@ -650,6 +651,8 @@ vips_foreign_load_csv_source_class_init( VipsForeignLoadCsvFileClass *class )
object_class->nickname = "csvload_source";
object_class->build = vips_foreign_load_csv_source_build;
operation_class->flags = VIPS_OPERATION_NOCACHE;
load_class->is_a_source = vips_foreign_load_csv_source_is_a_source;
VIPS_ARG_OBJECT( class, "source", 1,

View File

@ -316,6 +316,7 @@ vips_foreign_load_fits_source_class_init(
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
@ -325,6 +326,8 @@ vips_foreign_load_fits_source_class_init(
object_class->description = _( "load FITS from a source" );
object_class->build = vips_foreign_load_fits_source_build;
operation_class->flags = VIPS_OPERATION_NOCACHE;
load_class->is_a_source =
vips_foreign_load_fits_source_is_a_source;

View File

@ -725,6 +725,11 @@ vips_foreign_find_load_source( VipsSource *source )
return( NULL );
}
/* All source loaders should be NOCACHE.
*/
g_assert( VIPS_OPERATION_CLASS( load_class )->flags &
VIPS_OPERATION_NOCACHE );
return( G_OBJECT_CLASS_NAME( load_class ) );
}

View File

@ -1288,6 +1288,7 @@ vips_foreign_load_heif_source_class_init(
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
@ -1296,6 +1297,8 @@ vips_foreign_load_heif_source_class_init(
object_class->nickname = "heifload_source";
object_class->build = vips_foreign_load_heif_source_build;
operation_class->flags = VIPS_OPERATION_NOCACHE;
load_class->is_a_source = vips_foreign_load_heif_source_is_a_source;
VIPS_ARG_OBJECT( class, "source", 1,

View File

@ -1209,6 +1209,7 @@ vips_foreign_load_jp2k_source_class_init(
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
@ -1217,6 +1218,8 @@ vips_foreign_load_jp2k_source_class_init(
object_class->nickname = "jp2kload_source";
object_class->build = vips_foreign_load_jp2k_source_build;
operation_class->flags = VIPS_OPERATION_NOCACHE;
load_class->is_a_source = vips_foreign_load_jp2k_is_a_source;
VIPS_ARG_OBJECT( class, "source", 1,

View File

@ -880,9 +880,11 @@ vips_foreign_save_jp2k_build( VipsObject *object )
if( !(jp2k->accumulate = VIPS_ARRAY( NULL, sizeof_line, VipsPel )) )
return( -1 );
/* The line of tiles we are building.
/* The line of tiles we are building. It's used by the bg thread, so
* no ownership.
*/
jp2k->strip = vips_region_new( save->ready );
vips__region_no_ownership( jp2k->strip );
/* Position strip at the top of the image, the height of a row of
* tiles.

View File

@ -250,6 +250,7 @@ vips_foreign_load_jpeg_source_class_init(
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
@ -259,6 +260,8 @@ vips_foreign_load_jpeg_source_class_init(
object_class->description = _( "load image from jpeg source" );
object_class->build = vips_foreign_load_jpeg_source_build;
operation_class->flags = VIPS_OPERATION_NOCACHE;
load_class->is_a_source = vips_foreign_load_jpeg_source_is_a_source;
VIPS_ARG_OBJECT( class, "source", 1,

View File

@ -914,6 +914,7 @@ vips_foreign_load_jxl_source_class_init( VipsForeignLoadJxlSourceClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
@ -922,6 +923,8 @@ vips_foreign_load_jxl_source_class_init( VipsForeignLoadJxlSourceClass *class )
object_class->nickname = "jxlload_source";
object_class->build = vips_foreign_load_jxl_source_build;
operation_class->flags = VIPS_OPERATION_NOCACHE;
load_class->is_a_source = vips_foreign_load_jxl_is_a_source;
VIPS_ARG_OBJECT( class, "source", 1,

View File

@ -449,6 +449,7 @@ vips_foreign_load_matrix_source_class_init(
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
@ -457,6 +458,8 @@ vips_foreign_load_matrix_source_class_init(
object_class->nickname = "matrixload_source";
object_class->build = vips_foreign_load_matrix_source_build;
operation_class->flags = VIPS_OPERATION_NOCACHE;
load_class->is_a_source = vips_foreign_load_matrix_source_is_a_source;
VIPS_ARG_OBJECT( class, "source", 1,

View File

@ -767,6 +767,7 @@ vips_foreign_load_nifti_source_class_init(
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
@ -776,6 +777,8 @@ vips_foreign_load_nifti_source_class_init(
object_class->description = _( "load NIfTI volumes" );
object_class->build = vips_foreign_load_nifti_source_build;
operation_class->flags = VIPS_OPERATION_NOCACHE;
load_class->is_a_source =
vips_foreign_load_nifti_source_is_a_source;

View File

@ -853,6 +853,7 @@ vips_foreign_load_nsgif_source_class_init(
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
@ -862,6 +863,8 @@ vips_foreign_load_nsgif_source_class_init(
object_class->description = _( "load gif from source" );
object_class->build = vips_foreign_load_nsgif_source_build;
operation_class->flags = VIPS_OPERATION_NOCACHE;
load_class->is_a_source = vips_foreign_load_nsgif_is_a_source;
VIPS_ARG_OBJECT( class, "source", 1,

View File

@ -1053,6 +1053,7 @@ vips_foreign_load_openslide_source_class_init(
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
@ -1062,6 +1063,8 @@ vips_foreign_load_openslide_source_class_init(
object_class->description = _( "load source with OpenSlide" );
object_class->build = vips_foreign_load_openslide_source_build;
operation_class->flags = VIPS_OPERATION_NOCACHE;
load_class->is_a_source =
vips_foreign_load_openslide_source_is_a_source;

View File

@ -921,6 +921,7 @@ vips_foreign_load_pdf_source_class_init(
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
@ -930,6 +931,8 @@ vips_foreign_load_pdf_source_class_init(
object_class->description = _( "load PDF from source" );
object_class->build = vips_foreign_load_pdf_source_build;
operation_class->flags = VIPS_OPERATION_NOCACHE;
load_class->is_a_source = vips_foreign_load_pdf_source_is_a_source;
VIPS_ARG_OBJECT( class, "source", 1,

View File

@ -223,6 +223,7 @@ vips_foreign_load_png_source_class_init( VipsForeignLoadPngSourceClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
@ -232,6 +233,8 @@ vips_foreign_load_png_source_class_init( VipsForeignLoadPngSourceClass *class )
object_class->description = _( "load png from source" );
object_class->build = vips_foreign_load_png_source_build;
operation_class->flags = VIPS_OPERATION_NOCACHE;
load_class->is_a_source = vips_foreign_load_png_source_is_a_source;
VIPS_ARG_OBJECT( class, "source", 1,

View File

@ -815,6 +815,7 @@ vips_foreign_load_pdf_source_class_init(
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
@ -824,6 +825,8 @@ vips_foreign_load_pdf_source_class_init(
object_class->description = _( "load PDF from source" );
object_class->build = vips_foreign_load_pdf_source_build;
operation_class->flags = VIPS_OPERATION_NOCACHE;
load_class->is_a_source = vips_foreign_load_pdf_source_is_a_source;
VIPS_ARG_OBJECT( class, "source", 1,

View File

@ -872,6 +872,7 @@ vips_foreign_load_ppm_source_class_init( VipsForeignLoadPpmFileClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
@ -880,6 +881,8 @@ vips_foreign_load_ppm_source_class_init( VipsForeignLoadPpmFileClass *class )
object_class->nickname = "ppmload_source";
object_class->build = vips_foreign_load_ppm_source_build;
operation_class->flags = VIPS_OPERATION_NOCACHE;
load_class->is_a_source = vips_foreign_load_ppm_is_a_source;
VIPS_ARG_OBJECT( class, "source", 1,

View File

@ -184,6 +184,7 @@ vips_foreign_load_rad_source_class_init( VipsForeignLoadRadSourceClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
@ -193,6 +194,8 @@ vips_foreign_load_rad_source_class_init( VipsForeignLoadRadSourceClass *class )
object_class->description = _( "load rad from source" );
object_class->build = vips_foreign_load_rad_source_build;
operation_class->flags = VIPS_OPERATION_NOCACHE;
load_class->is_a_source = vips_foreign_load_rad_source_is_a_source;
VIPS_ARG_OBJECT( class, "source", 1,

View File

@ -127,6 +127,8 @@ vips_foreign_load_png_get_flags_source( VipsSource *source )
ctx = spng_ctx_new( SPNG_CTX_IGNORE_ADLER32 );
spng_set_crc_action( ctx, SPNG_CRC_USE, SPNG_CRC_USE );
if( vips_source_rewind( source ) )
return( 0 );
spng_set_png_stream( ctx,
vips_foreign_load_png_stream, source );
if( spng_get_ihdr( ctx, &ihdr ) ) {
@ -533,12 +535,12 @@ vips_foreign_load_png_generate( VipsRegion *or,
}
for( y = 0; y < r->height; y++ ) {
error = spng_decode_row( png->ctx,
VIPS_REGION_ADDR( or, 0, r->top + y ),
VIPS_REGION_SIZEOF_LINE( or ) );
/* libspng returns EOI when successfully reading the
* final line of input.
*/
error = spng_decode_row( png->ctx,
VIPS_REGION_ADDR( or, 0, r->top + y ),
VIPS_REGION_SIZEOF_LINE( or ) );
if( error != 0 &&
error != SPNG_EOI ) {
/* We've failed to read some pixels. Knock this
@ -739,6 +741,7 @@ vips_foreign_load_png_source_class_init( VipsForeignLoadPngSourceClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
@ -748,6 +751,8 @@ vips_foreign_load_png_source_class_init( VipsForeignLoadPngSourceClass *class )
object_class->description = _( "load png from source" );
object_class->build = vips_foreign_load_png_source_build;
operation_class->flags = VIPS_OPERATION_NOCACHE;
load_class->is_a_source = vips_foreign_load_png_source_is_a_source;
VIPS_ARG_OBJECT( class, "source", 1,

View File

@ -626,6 +626,7 @@ vips_foreign_load_svg_source_class_init( VipsForeignLoadSvgSourceClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
@ -634,6 +635,8 @@ vips_foreign_load_svg_source_class_init( VipsForeignLoadSvgSourceClass *class )
object_class->nickname = "svgload_source";
object_class->description = _( "load svg from source" );
operation_class->flags = VIPS_OPERATION_NOCACHE;
load_class->is_a_source = vips_foreign_load_svg_source_is_a_source;
load_class->header = vips_foreign_load_svg_source_header;
load_class->load = vips_foreign_load_svg_source_load;

View File

@ -272,6 +272,7 @@ vips_foreign_load_tiff_source_class_init(
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
@ -281,6 +282,8 @@ vips_foreign_load_tiff_source_class_init(
object_class->description = _( "load tiff from source" );
object_class->build = vips_foreign_load_tiff_source_build;
operation_class->flags = VIPS_OPERATION_NOCACHE;
load_class->is_a_source = vips_foreign_load_tiff_source_is_a_source;
VIPS_ARG_OBJECT( class, "source", 1,

View File

@ -287,6 +287,7 @@ vips_foreign_load_vips_source_class_init( VipsForeignLoadVipsClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
@ -296,6 +297,8 @@ vips_foreign_load_vips_source_class_init( VipsForeignLoadVipsClass *class )
object_class->description = _( "load vips from source" );
object_class->build = vips_foreign_load_vips_source_build;
operation_class->flags = VIPS_OPERATION_NOCACHE;
load_class->is_a_source =
vips_foreign_load_vips_source_is_a_source;

View File

@ -254,6 +254,7 @@ vips_foreign_load_webp_source_class_init(
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
@ -263,6 +264,8 @@ vips_foreign_load_webp_source_class_init(
object_class->description = _( "load webp from source" );
object_class->build = vips_foreign_load_webp_source_build;
operation_class->flags = VIPS_OPERATION_NOCACHE;
load_class->is_a_source = vips__iswebp_source;
VIPS_ARG_OBJECT( class, "source", 1,