Fix invalid filedata passed to linked data for versioning.

Code would not keep filedata for read libraries long enough to be able
to pass along to the 'after_liblink' versioning code. Instead, it was
passing the main file data, leading to all kind of potential breakage in
versioning code, e.g. in case of checks on available DNA data.

Fix #111776.
This commit is contained in:
Bastien Montagne
2023-09-01 17:58:18 +02:00
parent e3a8cd3141
commit bfdfde18e1

View File

@@ -3226,6 +3226,8 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
static void do_versions_after_linking(FileData *fd, Main *main)
{
BLI_assert(fd != nullptr);
CLOG_INFO(&LOG,
2,
"Processing %s (%s), %d.%d",
@@ -3738,7 +3740,9 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
blo_split_main(&mainlist, bfd->main);
LISTBASE_FOREACH (Main *, mainvar, &mainlist) {
BLI_assert(mainvar->versionfile != 0);
do_versions_after_linking(fd, mainvar);
do_versions_after_linking(
(mainvar->curlib && mainvar->curlib->filedata) ? mainvar->curlib->filedata : fd,
mainvar);
}
blo_join_main(&mainlist);
@@ -3748,6 +3752,14 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
BKE_main_id_refcount_recompute(bfd->main, false);
}
LISTBASE_FOREACH (Library *, lib, &bfd->main->libraries) {
/* Now we can clear this runtime library filedata, it is not needed anymore. */
if (lib->filedata) {
blo_filedata_free(lib->filedata);
lib->filedata = nullptr;
}
}
if (bfd->main->is_read_invalid) {
return bfd;
}
@@ -4269,6 +4281,9 @@ static Main *library_link_begin(Main *mainvar,
/* which one do we need? */
mainl = blo_find_main(fd, filepath, BKE_main_blendfile_path(mainvar));
if (mainl->curlib) {
mainl->curlib->filedata = fd;
}
/* needed for do_version */
mainl->versionfile = short(fd->fileversion);
@@ -4459,8 +4474,27 @@ void BLO_library_link_end(Main *mainl, BlendHandle **bh, const LibraryLink_Param
if (!mainl->is_read_invalid) {
library_link_end(mainl, &fd, params->flag);
*bh = reinterpret_cast<BlendHandle *>(fd);
}
LISTBASE_FOREACH (Library *, lib, &params->bmain->libraries) {
/* Now we can clear this runtime library filedata, it is not needed anymore. */
if (lib->filedata == reinterpret_cast<FileData *>(*bh)) {
/* The filedata is owned and managed by caller code, only clear matching library ponter. */
lib->filedata = nullptr;
}
else if (lib->filedata) {
/* In case other libraries had to be read as dependencies of the main linked one, they need
* to be cleared here.
*
* TODO: In the future, could be worth keeping them in case data are linked from several
* libraries at once? To avoid closing and re-opening the same file several times. Would need
* a global cleanup callback then once all linking is done, though. */
blo_filedata_free(lib->filedata);
lib->filedata = nullptr;
}
}
*bh = reinterpret_cast<BlendHandle *>(fd);
}
void *BLO_library_read_struct(FileData *fd, BHead *bh, const char *blockname)
@@ -4765,13 +4799,15 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
* do_versions multiple times, which would have bad consequences. */
split_main_newid(mainptr, main_newid);
/* File data can be zero with link/append. */
/* `filedata` can be NULL when loading linked data from inexistant or invalid library
* reference. Or during linking/appending, when processing data from a library not involved
* in the current linking/appending operation.
*
* Skip versioning in these cases, since the only IDs here will be placeholders (missing
* lib), or already existing IDs (linking/appending). */
if (mainptr->curlib->filedata) {
do_versions(mainptr->curlib->filedata, mainptr->curlib, main_newid);
}
else {
do_versions(basefd, nullptr, main_newid);
}
add_main_to_main(mainptr, main_newid);
}
@@ -4784,13 +4820,10 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
/* NOTE: No need to call #do_versions_after_linking() or #BKE_main_id_refcount_recompute()
* here, as this function is only called for library 'subset' data handling, as part of
* either full blendfile reading (#blo_read_file_internal()), or library-data linking
* (#library_link_end()). */
/* Free file data we no longer need. */
if (mainptr->curlib->filedata) {
blo_filedata_free(mainptr->curlib->filedata);
}
mainptr->curlib->filedata = nullptr;
* (#library_link_end()).
*
* For this to work reliably, `mainptr->curlib->filedata` also needs to be freed after said
* versioning code has run. */
}
BKE_main_free(main_newid);
}