From 8fea423e00676dd373280f43cf025285c9b442af Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 20 May 2025 09:26:21 +0000 Subject: [PATCH] Fix #139133: Crash entering edit mode for curve/text objects - Make Curve::type the source of truth for the curve type, instead of Curve::vfont, since it's possible for this to be set to null from RNA which effectively changed it's type. See #138730. - Update objects to match the curve type on file read. Without this, an object may link to a curve in another file which can be replaced by a curve data-block of a different type. Note that updating the object type was already being done when reloading library data and setting object data, just not on file load. Ref !139137 --- .../blender/blenkernel/BKE_blender_version.h | 2 +- source/blender/blenkernel/BKE_curve.hh | 2 +- source/blender/blenkernel/intern/curve.cc | 37 ++++++------------- source/blender/blenkernel/intern/key.cc | 2 +- source/blender/blenkernel/intern/lib_remap.cc | 2 +- source/blender/blenkernel/intern/object.cc | 16 +++++++- .../blenloader/intern/versioning_450.cc | 24 ++++++++++++ source/blender/makesdna/DNA_curve_types.h | 8 +++- source/blender/makesrna/intern/rna_object.cc | 2 +- 9 files changed, 62 insertions(+), 33 deletions(-) diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 4c24b0ecaca..4c0aec2cbd6 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -27,7 +27,7 @@ /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 72 +#define BLENDER_FILE_SUBVERSION 73 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and cancel loading the file, showing a warning to diff --git a/source/blender/blenkernel/BKE_curve.hh b/source/blender/blenkernel/BKE_curve.hh index d708446923b..e53c234db68 100644 --- a/source/blender/blenkernel/BKE_curve.hh +++ b/source/blender/blenkernel/BKE_curve.hh @@ -99,7 +99,7 @@ void BKE_curve_editfont_free(Curve *cu); void BKE_curve_init(Curve *cu, short curve_type); Curve *BKE_curve_add(Main *bmain, const char *name, int type); short BKE_curve_type_get(const Curve *cu); -void BKE_curve_type_test(Object *ob); +void BKE_curve_type_test(Object *ob, bool dimension_update); void BKE_curve_dimension_update(Curve *cu); void BKE_curve_texspace_calc(Curve *cu); diff --git a/source/blender/blenkernel/intern/curve.cc b/source/blender/blenkernel/intern/curve.cc index 2de679f6bfb..5d7a4d96462 100644 --- a/source/blender/blenkernel/intern/curve.cc +++ b/source/blender/blenkernel/intern/curve.cc @@ -179,7 +179,7 @@ static void curve_blend_write(BlendWriter *writer, ID *id, const void *id_addres /* direct data */ BLO_write_pointer_array(writer, cu->totcol, cu->mat); - if (cu->vfont) { + if (cu->type == OB_FONT) { BLO_write_string(writer, cu->str); BLO_write_struct_array(writer, CharInfo, cu->len_char32 + 1, cu->strinfo); BLO_write_struct_array(writer, TextBox, cu->totbox, cu->tb); @@ -223,7 +223,7 @@ static void curve_blend_read_data(BlendDataReader *reader, ID *id) BLO_read_struct_array(reader, CharInfo, cu->len_char32 + 1, &cu->strinfo); BLO_read_struct_array(reader, TextBox, cu->totbox, &cu->tb); - if (cu->vfont == nullptr) { + if (cu->type != OB_FONT) { BLO_read_struct_list(reader, Nurb, &(cu->nurb)); } else { @@ -255,7 +255,7 @@ static void curve_blend_read_data(BlendDataReader *reader, ID *id) BLO_read_struct_array(reader, BPoint, nu->pntsu * nu->pntsv, &nu->bp); BLO_read_float_array(reader, KNOTSU(nu), &nu->knotsu); BLO_read_float_array(reader, KNOTSV(nu), &nu->knotsv); - if (cu->vfont == nullptr) { + if (cu->type != OB_FONT) { nu->charidx = 0; } } @@ -420,24 +420,7 @@ const ListBase *BKE_curve_editNurbs_get_for_read(const Curve *cu) short BKE_curve_type_get(const Curve *cu) { - int type = cu->type; - - if (cu->vfont) { - return OB_FONT; - } - - if (!cu->type) { - type = OB_CURVES_LEGACY; - - LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) { - if (nu->pntsv > 1) { - type = OB_SURF; - break; - } - } - } - - return type; + return cu->type; } void BKE_curve_dimension_update(Curve *cu) @@ -457,14 +440,16 @@ void BKE_curve_dimension_update(Curve *cu) } } -void BKE_curve_type_test(Object *ob) +void BKE_curve_type_test(Object *ob, const bool dimension_update) { ob->type = BKE_curve_type_get((Curve *)ob->data); - if (ob->type == OB_CURVES_LEGACY) { - Curve *cu = (Curve *)ob->data; - if (CU_IS_2D(cu)) { - BKE_curve_dimension_update(cu); + if (dimension_update) { + if (ob->type == OB_CURVES_LEGACY) { + Curve *cu = (Curve *)ob->data; + if (CU_IS_2D(cu)) { + BKE_curve_dimension_update(cu); + } } } } diff --git a/source/blender/blenkernel/intern/key.cc b/source/blender/blenkernel/intern/key.cc index ec89d8583a9..8851585afda 100644 --- a/source/blender/blenkernel/intern/key.cc +++ b/source/blender/blenkernel/intern/key.cc @@ -1785,7 +1785,7 @@ Key **BKE_key_from_id_p(ID *id) } case ID_CU_LEGACY: { Curve *cu = (Curve *)id; - if (cu->vfont == nullptr) { + if (cu->type != OB_FONT) { return &cu->key; } break; diff --git a/source/blender/blenkernel/intern/lib_remap.cc b/source/blender/blenkernel/intern/lib_remap.cc index a2329afec60..461989464a8 100644 --- a/source/blender/blenkernel/intern/lib_remap.cc +++ b/source/blender/blenkernel/intern/lib_remap.cc @@ -412,7 +412,7 @@ static void libblock_remap_data_postprocess_obdata_relink(Main *bmain, Object *o multires_force_sculpt_rebuild(ob); break; case ID_CU_LEGACY: - BKE_curve_type_test(ob); + BKE_curve_type_test(ob, true); break; default: break; diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index 60d899093c7..d5142b459b7 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -940,6 +940,20 @@ static void object_blend_read_after_liblink(BlendLibReader *reader, ID *id) reports->count.missing_obdata++; } + if (ob->data && ELEM(ob->type, OB_FONT, OB_CURVES_LEGACY, OB_SURF)) { + /* NOTE: This case may happen when linked curve data changes it's type, + * since a #Curve may be used for Text/Surface/Curve. + * Since the same ID type is used for all of these. + * Within a file (no library linking) this should never happen. + * see: #139133. */ + + const ID *ob_data_id = static_cast(ob->data); + BLI_assert(GS(ob_data_id->name) == ID_CU_LEGACY); + /* Don't recalculate any internal curve data is this is low level logic + * intended to avoid errors when switching between font/curve types. */ + BKE_curve_type_test(ob, false); + } + /* When the object is local and the data is library its possible * the material list size gets out of sync. #22663. */ if (ob->data && ob->id.lib != static_cast(ob->data)->lib) { @@ -1778,7 +1792,7 @@ char *BKE_object_data_editmode_flush_ptr_get(ID *id) break; } case ID_CU_LEGACY: { - if (((Curve *)id)->vfont != nullptr) { + if (((Curve *)id)->type == OB_FONT) { EditFont *ef = ((Curve *)id)->editfont; if (ef != nullptr) { return &ef->needs_flush_to_id; diff --git a/source/blender/blenloader/intern/versioning_450.cc b/source/blender/blenloader/intern/versioning_450.cc index 9a76661ce57..76aa4ca10eb 100644 --- a/source/blender/blenloader/intern/versioning_450.cc +++ b/source/blender/blenloader/intern/versioning_450.cc @@ -5161,6 +5161,30 @@ void blo_do_versions_450(FileData * /*fd*/, Library * /*lib*/, Main *bmain) version_set_default_bone_drawtype(bmain); } + if (!MAIN_VERSION_FILE_ATLEAST(bmain, 405, 73)) { + /* Make #Curve::type the source of truth for the curve type. + * Previously #Curve::vfont was checked which is error prone + * since the member can become null at run-time, see: #139133. */ + LISTBASE_FOREACH (Curve *, cu, &bmain->curves) { + if (ELEM(cu->type, OB_CURVES_LEGACY, OB_FONT, OB_SURF)) { + continue; + } + short type = OB_CURVES_LEGACY; + if (cu->vfont) { + type = OB_FONT; + } + else { + LISTBASE_FOREACH (const Nurb *, nu, &cu->nurb) { + if (nu->pntsv > 1) { + type = OB_SURF; + break; + } + } + } + cu->type = type; + } + } + /* Always run this versioning (keep at the bottom of the function). Meshes are written with the * legacy format which always needs to be converted to the new format on file load. To be moved * to a subversion check in 5.0. */ diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h index 461afacd0c1..c0005821302 100644 --- a/source/blender/makesdna/DNA_curve_types.h +++ b/source/blender/makesdna/DNA_curve_types.h @@ -231,7 +231,13 @@ typedef struct Curve { float texspace_location[3]; float texspace_size[3]; - /** Creation-time type of curve datablock. */ + /** + * Object type of curve data-block (#ObjectType). + * This must be one of: + * - #OB_CURVES_LEGACY. + * - #OB_FONT. + * - #OB_SURF. + */ short type; char texspace_flag; diff --git a/source/blender/makesrna/intern/rna_object.cc b/source/blender/makesrna/intern/rna_object.cc index 54e6c7a6d4d..dddcf12450b 100644 --- a/source/blender/makesrna/intern/rna_object.cc +++ b/source/blender/makesrna/intern/rna_object.cc @@ -559,7 +559,7 @@ static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value, ReportList *r BKE_object_materials_sync_length(G_MAIN, ob, id); if (GS(id->name) == ID_CU_LEGACY) { - BKE_curve_type_test(ob); + BKE_curve_type_test(ob, true); } else if (ob->type == OB_ARMATURE) { BKE_pose_rebuild(G_MAIN, ob, static_cast(ob->data), true);