Fix #104305: Crash in node editor with large asset libraries

Various UI code would store the `AssetHandle` in a way that turns out to
be unsafe. The file-data is part of the file browser caching system that
releases file-data when a certain maximum of items is in the cache. So
even while just iterating over the assets, earlier iterated asset
handles may become invalid. Now asset handles are really treated as
volatile, short lived objects.

For the asset-view, the fix was more involved. There we need an RNA
collection of asset-handles, because the UI list code requires that. So
we create a dummy collection and get the asset handles as needed by
index. This again meant that I had to keep the index of the collection
and the asset-list in sync, so all filtering had to be moved to the UI
list.
I tried duplicating the file-data out of the cache instead, but that
caused problems with managing the memory/ownership of the preview
images.

`AssetHandle` should be removed and replaced by `AssetRepresentation`,
but this would be an even more disruptive change (breaking API
compatibility too).

Fixes #104305, #105535.

Pull Request: #105773
This commit is contained in:
2023-03-16 15:40:31 +01:00
parent 55811b2919
commit a958ae36e8
24 changed files with 386 additions and 135 deletions

View File

@@ -8,6 +8,7 @@
#include <memory>
#include "BLI_function_ref.hh"
#include "BLI_string_ref.hh"
#include "BLI_vector.hh"
@@ -17,8 +18,10 @@ namespace blender::nodes::geo_eval_log {
struct GeometryAttributeInfo;
}
struct PointerRNA;
struct StructRNA;
struct uiBlock;
struct uiList;
struct uiSearchItems;
namespace blender::ui {
@@ -53,6 +56,60 @@ void attribute_search_add_items(StringRefNull str,
} // namespace blender::ui
enum eUIListFilterResult {
/** Never show this item, even when filter results are inverted (#UILST_FLT_EXCLUDE). */
UI_LIST_ITEM_NEVER_SHOW,
/** Show this item, unless filter results are inverted (#UILST_FLT_EXCLUDE). */
UI_LIST_ITEM_FILTER_MATCHES,
/** Don't show this item, unless filter results are inverted (#UILST_FLT_EXCLUDE). */
UI_LIST_ITEM_FILTER_MISMATCHES,
};
/**
* Function object for UI list item filtering that does the default name comparison with '*'
* wildcards. Create an instance of this once and pass it to #UI_list_filter_and_sort_items(), do
* NOT create an instance for every item, this would be costly.
*/
class uiListNameFilter {
/* Storage with an inline buffer for smaller strings (small buffer optimization). */
struct {
char filter_buff[32];
char *filter_dyn = nullptr;
} storage_;
char *filter_ = nullptr;
public:
uiListNameFilter(uiList &list);
~uiListNameFilter();
eUIListFilterResult operator()(const PointerRNA &itemptr,
blender::StringRefNull name,
int index);
};
using uiListItemFilterFn = blender::FunctionRef<eUIListFilterResult(
const PointerRNA &itemptr, blender::StringRefNull name, int index)>;
using uiListItemGetNameFn =
blender::FunctionRef<std::string(const PointerRNA &itemptr, int index)>;
/**
* Filter list items using \a item_filter_fn and sort the result. This respects the normal UI list
* filter settings like alphabetical sorting (#UILST_FLT_SORT_ALPHA), and result inverting
* (#UILST_FLT_EXCLUDE).
*
* Call this from a #uiListType::filter_items callback with any #item_filter_fn. #uiListNameFilter
* can be used to apply the default name based filtering.
*
* \param get_name_fn: In some cases the name cannot be retrieved via RNA. This function can be set
* to provide the name still.
*/
void UI_list_filter_and_sort_items(uiList *ui_list,
const struct bContext *C,
uiListItemFilterFn item_filter_fn,
PointerRNA *dataptr,
const char *propname,
uiListItemGetNameFn get_name_fn = nullptr);
/**
* Override this for all available view types.
*/