Refactor: Blend file reading asserts for broken pointers #120997

Open
Brecht Van Lommel wants to merge 1 commits from brecht/blender:refactor-assert-broken-pointer into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
11 changed files with 99 additions and 37 deletions

View File

@ -5435,7 +5435,7 @@ static void blend_read_paint_mask(BlendDataReader *reader,
static void blend_read_layer_data(BlendDataReader *reader, CustomDataLayer &layer, const int count)
{
const size_t elem_size = CustomData_sizeof(eCustomDataType(layer.type));
BLO_read_struct_array(reader, char, elem_size *count, &layer.data);
BLO_read_struct_array_allow_broken_pointer(reader, char, elem_size *count, &layer.data);
if (CustomData_layer_ensure_data_exists(&layer, count)) {
/* Under normal operations, this shouldn't happen, but...
* For a CD_PROP_BOOL example, see #84935.

View File

@ -337,7 +337,7 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id)
BLO_read_struct_array(reader, MEdge, mesh->edges_num, &mesh->medge);
BLO_read_struct_array(reader, MFace, mesh->totface_legacy, &mesh->mface);
BLO_read_struct_array(reader, MTFace, mesh->totface_legacy, &mesh->mtface);
BLO_read_struct_array(reader, MDeformVert, mesh->verts_num, &mesh->dvert);
BLO_read_struct_array_allow_broken_pointer(reader, MDeformVert, mesh->verts_num, &mesh->dvert);
BLO_read_struct_array(reader, TFace, mesh->totface_legacy, &mesh->tface);
BLO_read_struct_array(reader, MCol, mesh->totface_legacy, &mesh->mcol);

View File

@ -960,7 +960,7 @@ static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock)
BLO_read_struct(reader, IDProperty, &sock->prop);
IDP_BlendDataRead(reader, &sock->prop);
BLO_read_struct(reader, bNodeLink, &sock->link);
BLO_read_struct_allow_broken_pointer(reader, bNodeLink, &sock->link);
sock->typeinfo = nullptr;
BLO_read_data_address(reader, &sock->storage);
BLO_read_data_address(reader, &sock->default_value);
@ -1070,7 +1070,7 @@ void ntreeBlendReadData(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree)
* `IDTypeInfo.foreach_cache` callback. */
}
else {
BLO_read_data_address(reader, &node->storage);
BLO_read_data_address_allow_broken_pointer(reader, &node->storage);
}
if (node->storage) {

View File

@ -728,7 +728,7 @@ static void object_blend_read_data(BlendDataReader *reader, ID *id)
}
/* Only for versioning, vertex group names are now stored on object data. */
BLO_read_struct_list(reader, bDeformGroup, &ob->defbase);
BLO_read_struct_list_allow_broken_pointer(reader, bDeformGroup, &ob->defbase);
BLO_read_struct_list(reader, bFaceMap, &ob->fmaps);
/* XXX deprecated - old animation system <<< */

View File

@ -1356,7 +1356,8 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id)
else {
seqbase_poin = POINTER_OFFSET(ed->seqbasep, -seqbase_offset);
seqbase_poin = BLO_read_get_new_data_address(reader, seqbase_poin);
const bool allow_broken_pointer = true;
seqbase_poin = BLO_read_get_new_data_address(reader, seqbase_poin, allow_broken_pointer);
if (seqbase_poin) {
ed->seqbasep = (ListBase *)POINTER_OFFSET(seqbase_poin, seqbase_offset);

View File

@ -1136,7 +1136,7 @@ void BKE_screen_area_map_blend_write(BlendWriter *writer, ScrAreaMap *area_map)
static void direct_link_panel_list(BlendDataReader *reader, ListBase *lb)
{
BLO_read_struct_list(reader, Panel, lb);
BLO_read_struct_list_allow_broken_pointer(reader, Panel, lb);
LISTBASE_FOREACH (Panel *, panel, lb) {
panel->runtime = MEM_new<Panel_Runtime>(__func__);
@ -1158,9 +1158,10 @@ static void direct_link_region(BlendDataReader *reader, ARegion *region, int spa
direct_link_panel_list(reader, &region->panels);
BLO_read_struct_list(reader, PanelCategoryStack, &region->panels_category_active);
BLO_read_struct_list_allow_broken_pointer(
reader, PanelCategoryStack, &region->panels_category_active);
BLO_read_struct_list(reader, uiList, &region->ui_lists);
BLO_read_struct_list_allow_broken_pointer(reader, uiList, &region->ui_lists);
/* The area's search filter is runtime only, so we need to clear the active flag on read. */
/* Clear runtime flags (e.g. search filter is runtime only). */
@ -1173,7 +1174,7 @@ static void direct_link_region(BlendDataReader *reader, ARegion *region, int spa
IDP_BlendDataRead(reader, &ui_list->properties);
}
BLO_read_struct_list(reader, uiPreview, &region->ui_previews);
BLO_read_struct_list_allow_broken_pointer(reader, uiPreview, &region->ui_previews);
if (spacetype == SPACE_EMPTY) {
/* unknown space type, don't leak regiondata */
@ -1250,7 +1251,7 @@ void BKE_screen_view3d_do_versions_250(View3D *v3d, ListBase *regions)
static void direct_link_area(BlendDataReader *reader, ScrArea *area)
{
BLO_read_struct_list(reader, SpaceLink, &(area->spacedata));
BLO_read_struct_list_allow_broken_pointer(reader, SpaceLink, &(area->spacedata));
BLO_read_struct_list(reader, ARegion, &(area->regionbase));
BLI_listbase_clear(&area->handlers);

View File

@ -102,7 +102,7 @@ void BKE_viewer_path_blend_write(BlendWriter *writer, const ViewerPath *viewer_p
void BKE_viewer_path_blend_read_data(BlendDataReader *reader, ViewerPath *viewer_path)
{
BLO_read_struct_list(reader, ViewerPathElem, &viewer_path->path);
BLO_read_struct_list_allow_broken_pointer(reader, ViewerPathElem, &viewer_path->path);
LISTBASE_FOREACH (ViewerPathElem *, elem, &viewer_path->path) {
BLO_read_string(reader, &elem->ui_name);
switch (ViewerPathElemType(elem->type)) {

View File

@ -241,14 +241,20 @@ bool BLO_write_is_undo(BlendWriter *writer);
* Avoid using the generic BLO_read_data_address when possible, use typed functions instead.
* \{ */
void *BLO_read_get_new_data_address(BlendDataReader *reader, const void *old_address);
void *BLO_read_get_new_data_address(BlendDataReader *reader,
const void *old_address,
bool allow_broken_pointer = false);
void *BLO_read_get_new_data_address_no_us(BlendDataReader *reader,
const void *old_address,
size_t data_size);
void *BLO_read_get_new_packed_address(BlendDataReader *reader, const void *old_address);
size_t expected_size,
bool allow_broken_pointer = false);
void *BLO_read_get_new_packed_address(BlendDataReader *reader,
const void *old_address,
bool allow_broken_pointer = false);
void *BLO_read_struct_array_with_size(BlendDataReader *reader,
const void *old_address,
size_t data_size);
size_t expected_size,
bool allow_broken_pointer = false);
#define BLO_read_data_address(reader, ptr_p) \
*((void **)ptr_p) = BLO_read_get_new_data_address((reader), *(ptr_p))
@ -261,15 +267,36 @@ void *BLO_read_struct_array_with_size(BlendDataReader *reader,
#define BLO_read_packed_address(reader, ptr_p) \
*((void **)ptr_p) = BLO_read_get_new_packed_address((reader), *(ptr_p))
/* Variations for cases where pointer may exist but is not able
* to be resolved. This is generally due to deprecated struct members
* that should have been set to null in versioning but were not.
*
* When using these, the following code must be able to handle the
* resulting null pointers.
*/
#define BLO_read_data_address_allow_broken_pointer(reader, ptr_p) \
*((void **)ptr_p) = BLO_read_get_new_data_address((reader), *(ptr_p), true)
#define BLO_read_struct_allow_broken_pointer(reader, struct_name, ptr_p) \
*((void **)ptr_p) = BLO_read_struct_array_with_size( \
reader, *((void **)ptr_p), sizeof(struct_name), true)
#define BLO_read_struct_array_allow_broken_pointer(reader, struct_name, array_size, ptr_p) \
*((void **)ptr_p) = BLO_read_struct_array_with_size( \
reader, *((void **)ptr_p), sizeof(struct_name) * (array_size), true)
/* Read all elements in list
*
* Updates all `->prev` and `->next` pointers of the list elements.
* Updates the `list->first` and `list->last` pointers.
*/
void BLO_read_struct_list_with_size(BlendDataReader *reader, size_t elem_size, ListBase *list);
void BLO_read_struct_list_with_size(BlendDataReader *reader,
size_t elem_size,
bool allow_broken_pointer,
ListBase *list);
#define BLO_read_struct_list(reader, struct_name, list) \
BLO_read_struct_list_with_size(reader, sizeof(struct_name), list)
BLO_read_struct_list_with_size(reader, sizeof(struct_name), false, list)
#define BLO_read_struct_list_allow_broken_pointer(reader, struct_name, list) \
BLO_read_struct_list_with_size(reader, sizeof(struct_name), true, list)
/* Update data pointers and correct byte-order if necessary. */

View File

@ -2117,7 +2117,7 @@ static void direct_link_id_common(
/* Link direct data of ID properties. */
if (id->properties) {
BLO_read_struct(reader, IDProperty, &id->properties);
BLO_read_struct_allow_broken_pointer(reader, IDProperty, &id->properties);
/* this case means the data was written incorrectly, it should not happen */
IDP_BlendDataRead(reader, &id->properties);
}
@ -4781,43 +4781,73 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
}
static void *blo_verify_data_address(void *new_address,
const void * /*old_address*/,
const size_t expected_size)
const void *old_address,
const size_t expected_size,
const bool allow_broken_pointer = false)
{
if (new_address != nullptr) {
if (new_address == nullptr) {
if (old_address == nullptr) {
return nullptr;
}
if (!allow_broken_pointer) {
BLI_assert_msg(expected_size == 0, "Corrupt .blend file, expected non-zero data.");
}
}
else {
/* Not testing equality, since size might have been aligned up,
* or might be passed the size of a base struct with inheritance. */
BLI_assert_msg(MEM_allocN_len(new_address) >= expected_size,
"Corrupt .blend file, unexpected data size.");
BLI_assert_msg(expected_size == 0 || MEM_allocN_len(new_address) >= expected_size,
"Corrupt .blend file, unexpected data size");
}
return new_address;
}
void *BLO_read_get_new_data_address(BlendDataReader *reader, const void *old_address)
void *BLO_read_get_new_data_address(BlendDataReader *reader,
const void *old_address,
const bool allow_broken_pointer)
{
return newdataadr(reader->fd, old_address);
void *new_address = newdataadr(reader->fd, old_address);
if (!allow_broken_pointer) {
BLI_assert_msg(old_address == nullptr || new_address != nullptr,
"Corrupt .blend file, expected non-zero pointer.");
}
return new_address;
}
void *BLO_read_get_new_data_address_no_us(BlendDataReader *reader,
const void *old_address,
const size_t expected_size)
const size_t expected_size,
const bool allow_broken_pointer)
{
void *new_address = newdataadr_no_us(reader->fd, old_address);
return blo_verify_data_address(new_address, old_address, expected_size);
return blo_verify_data_address(new_address, old_address, expected_size, allow_broken_pointer);
}
void *BLO_read_get_new_packed_address(BlendDataReader *reader, const void *old_address)
void *BLO_read_get_new_packed_address(BlendDataReader *reader,
const void *old_address,
const bool allow_broken_pointer)
{
return newpackedadr(reader->fd, old_address);
void *new_address = newpackedadr(reader->fd, old_address);
if (!allow_broken_pointer) {
BLI_assert_msg(old_address == nullptr || new_address != nullptr,
"Corrupt .blend file, expected non-zero pointer.");
}
return new_address;
}
void *BLO_read_struct_array_with_size(BlendDataReader *reader,
const void *old_address,
const size_t expected_size)
const size_t expected_size,
const bool allow_broken_pointer)
{
void *new_address = newdataadr(reader->fd, old_address);
return blo_verify_data_address(new_address, old_address, expected_size);
return blo_verify_data_address(new_address, old_address, expected_size, allow_broken_pointer);
}
ID *BLO_read_get_new_id_address(BlendLibReader *reader,
@ -4845,18 +4875,20 @@ bool BLO_read_requires_endian_switch(BlendDataReader *reader)
void BLO_read_struct_list_with_size(BlendDataReader *reader,
const size_t expected_elem_size,
const bool allow_broken_pointer,
ListBase *list)
{
if (BLI_listbase_is_empty(list)) {
return;
}
list->first = BLO_read_struct_array_with_size(reader, list->first, expected_elem_size);
list->first = BLO_read_struct_array_with_size(
reader, list->first, expected_elem_size, allow_broken_pointer);
Link *ln = static_cast<Link *>(list->first);
Link *prev = nullptr;
while (ln) {
ln->next = static_cast<Link *>(
BLO_read_struct_array_with_size(reader, ln->next, expected_elem_size));
ln->next = static_cast<Link *>(BLO_read_struct_array_with_size(
reader, ln->next, expected_elem_size, allow_broken_pointer));
ln->prev = prev;
prev = ln;
ln = ln->next;

View File

@ -312,7 +312,7 @@ static void console_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
{
SpaceConsole *sconsole = (SpaceConsole *)sl;
BLO_read_struct_list(reader, ConsoleLine, &sconsole->scrollback);
BLO_read_struct_list_allow_broken_pointer(reader, ConsoleLine, &sconsole->scrollback);
BLO_read_struct_list(reader, ConsoleLine, &sconsole->history);
/* Comma expressions, (e.g. expr1, expr2, expr3) evaluate each expression,

View File

@ -869,7 +869,8 @@ static void file_space_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
sfile->previews_timer = nullptr;
sfile->tags = 0;
sfile->runtime = nullptr;
BLO_read_struct(reader, FileSelectParams, &sfile->params);
BLO_read_struct_allow_broken_pointer(reader, FileSelectParams, &sfile->params);
BLO_read_struct(reader, FileAssetSelectParams, &sfile->asset_params);
if (sfile->params) {
sfile->params->rename_id = nullptr;