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
This commit is contained in:
Campbell Barton
2025-05-20 09:26:21 +00:00
parent d9d399ccb1
commit 8fea423e00
9 changed files with 62 additions and 33 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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);
}
}
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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<ID *>(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<ID *>(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;

View File

@@ -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. */

View File

@@ -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;

View File

@@ -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<bArmature *>(ob->data), true);