I described this in the forum too: https://forums.sketchup.com/t/creating-and-loading-models-using-live-c-extension-ruby-c-extension/343829
- If you are developing a Ruby C Extension and want access to the open "live" model, you use
SUApplicationGetActiveModel , and make sure not to call SUModelRelease on the model reference. That is well documented on the C API. We are told that the SketchUp Application "owns" the model, so we do not release it in the extension - let's call this "Assumption 1".
- However, what if you were to use a Ruby C Extension (or Live C API) to create/open a new model outside of the current application? If the model is not open in the Sketchup application, then you would think that you should call
SUModelRelease once you are done to avoid memory leaks. Call this "Assumption 2".
- Following assumption 2, you create a new model in the Live C API, save it to disk and call
SUMorelRelease on it. You pass the file path of the model back to Sketchup, and using Ruby API's DefinitionsList::load method, you attempt to load the model as a component to the active model. Assumption 3 is that the SketchUp Application loads the model afresh using DefinitionsList::load, and there will be no problem.
However, doing the above will cause an exception and crash. I have reproduced the error minimally, by adapting the Live-C-Examples project, by adding the function below into example_extension.cpp
// Creates a model, saves it then returns the file_path.
VALUE load_definition(VALUE self) {
// Create a Model and fill it with a simple face:
SUModelRef output_model = SU_INVALID;
SU(SUModelCreate(&output_model));
SUEntitiesRef entities = SU_INVALID;
SU(SUModelGetEntities(output_model, &entities));
SUGeometryInputRef input = SU_INVALID;
SU(SUGeometryInputCreate(&input));
// Define a simple square in the XY plane
std::vector<SUPoint3D> points{
{ 0.0, 0.0, 0.0 },
{ 9.0, 0.0, 0.0 },
{ 9.0, 9.0, 0.0 },
{ 0.0, 9.0, 0.0 }
};
for (size_t i = 0; i < points.size(); ++i) {
SU(SUGeometryInputAddVertex(input, &points[i]));
}
// Outer loop
SULoopInputRef outer_loop = SU_INVALID;
SULoopInputCreate(&outer_loop);
for (size_t i = 0; i < points.size(); ++i) {
SU(SULoopInputAddVertexIndex(outer_loop, i));
}
size_t face_index = 0;
SU(SUGeometryInputAddFace(input, &outer_loop, &face_index));
// Fill entities using the geometry input
SU(SUEntitiesFill(entities, input, true));
SU(SUGeometryInputRelease(&input));
// Put the file in the same folder as the open file
SUModelRef open_model = SU_INVALID;
SU(SUApplicationGetActiveModel(&open_model));
if (SUIsInvalid(open_model)) {
rb_raise(rb_eTypeError, "invalid model");
}
SUStringRef open_model_path = SU_INVALID;
SUStringCreate(&open_model_path);
SUModelGetPath(open_model, &open_model_path);
std::string open_model_path_str = GetString(open_model_path);
SUStringRelease(&open_model_path);
size_t last_slash = open_model_path_str.find_last_of("/\\");
if (last_slash != std::string::npos) {
open_model_path_str = open_model_path_str.substr(0, last_slash);
}
// Save to a temporary path and return it
std::string file_path = open_model_path_str + "/load_definition.skp";
SU(SUModelSaveToFile(output_model, file_path.c_str()));
SU(SUModelRelease(&output_model)); // <== this line will cause SketchUp to crash on Ruby API's DefinitionsList::load. Commenting it out will make it work
VALUE ruby_path = rb_str_new_cstr(file_path.c_str());
return ruby_path;
}
there are also bits you need to add to get this to run...for reference, I have attached the cpp file below:
example_extension.cpp
...and you will also need to add a ruby method to main.rb call the function:
sub_menu.add_item('Load Definition') {
file_path = self.load_definition
definition = Sketchup.active_model.definitions.load(file_path)
Sketchup.active_model.entities.add_instance(definition, Geom::Transformation.new)
}
On Mac, using SketchUp v2025 the call stack following the crash is:
[Unknown/Just-In-Time compiled code] (Unknown Source:0)
SketchUp!CUndoOperation::GetModifiedParents(CEntitySet&) const (Unknown Source:0)
SketchUp!CBaseDoc::OnTransactionEnd(ETransactionType, unsigned int, unsigned int) (Unknown Source:0)
SketchUp!CBaseEditDoc::OnTransactionEnd(ETransactionType, unsigned int, unsigned int) (Unknown Source:0)
SketchUp!CMacSketchUpDoc::OnTransactionEnd(ETransactionType, unsigned int, unsigned int) (Unknown Source:0)
SketchUp!CDbTalker::EndTransactionNotification(ETransactionType, unsigned int, unsigned int) (Unknown Source:0)
SketchUp!CUndoManager::CommitCurrentOperation(unsigned int, bool) (Unknown Source:0)
SketchUp!CRubyUndoOperation::CommitRubyOperation(unsigned int) (Unknown Source:0)
SketchUp!___lldb_unnamed_symbol59538 (Unknown Source:0)
Ruby!vm_call_cfunc_with_frame (Unknown Source:0)
Ruby!vm_exec_core (Unknown Source:0)
Ruby!rb_vm_exec (Unknown Source:0)
Ruby!vm_invoke_proc (Unknown Source:0)
Ruby!vm_call0_body (Unknown Source:0)
Ruby!rb_funcallv (Unknown Source:0)
SketchUp!___lldb_unnamed_symbol61188 (Unknown Source:0)
Ruby!rb_protect (Unknown Source:0)
SketchUp!protect_funcall(unsigned long, unsigned long, std::__1::vector<unsigned long, std::__1::allocator<unsigned long>> const&) (Unknown Source:0)
SketchUp!protect_funcall(unsigned long, unsigned long, int, ...) (Unknown Source:0)
SketchUp!CRubyCommand::Invoke() const (Unknown Source:0)
SketchUp!common::CommandManager::RunCommand(unsigned int, command_bindings::ICommandEntryDocument*) const (Unknown Source:0)
AppKit!-[NSApplication(NSResponder) sendAction:to:from:] (Unknown Source:0)
[.....lots of other calls that I omit ....]
SketchUp!main (Unknown Source:0)
start (Unknown Source:0)
I get EXC_BAD_ACCESS error on my fuller extension that does something similar, which I think to non-Mac developers is a Segmentation Fault(?).
Now this raises a lot of issues and questions. Assumptions 2 or 3, or both must be wrong. To list the key questions:
- Should one ever call
SUModelRelease on a model created with SUModelCreate when using the Live C API (Ruby Extension)? What about SUModelCreateFromFile, and the other C API functions used to load/create a model? NOT calling SUModelRelease makes me think you would get memory leaks every time.
- What is going on under the hood with Ruby API's
DefinitionList::load ? I have known this method to be rather cryptic as I discovered some time ago: https://forums.sketchup.com/t/fix-definitionlist-load-problems-in-some-situations/5655 . I am inclined to think that "DefinitionList" may be better thought of as a collection of SketchUp models rather than components, some "internal" and others "external" to the active model. Does calling SUModelCreate create a new ComponentDefinition in DefinitionList - or does it access some sort of cache of "created" models?
- What is (or should be) the guaranteed behaviours of
DefinitionList::load and the various SUModelCreate*** methods in the context of the Live C API? Or put it another way - how is model ownership handled between the Live C API and the active SketchUp Application?
I described this in the forum too: https://forums.sketchup.com/t/creating-and-loading-models-using-live-c-extension-ruby-c-extension/343829
SUApplicationGetActiveModel, and make sure not to callSUModelReleaseon the model reference. That is well documented on the C API. We are told that the SketchUp Application "owns" the model, so we do not release it in the extension - let's call this "Assumption 1".SUModelReleaseonce you are done to avoid memory leaks. Call this "Assumption 2".SUMorelReleaseon it. You pass the file path of the model back to Sketchup, and using Ruby API'sDefinitionsList::loadmethod, you attempt to load the model as a component to the active model. Assumption 3 is that the SketchUp Application loads the model afresh usingDefinitionsList::load, and there will be no problem.However, doing the above will cause an exception and crash. I have reproduced the error minimally, by adapting the Live-C-Examples project, by adding the function below into
example_extension.cppthere are also bits you need to add to get this to run...for reference, I have attached the cpp file below:
example_extension.cpp
...and you will also need to add a ruby method to
main.rbcall the function:On Mac, using SketchUp v2025 the call stack following the crash is:
I get EXC_BAD_ACCESS error on my fuller extension that does something similar, which I think to non-Mac developers is a Segmentation Fault(?).
Now this raises a lot of issues and questions. Assumptions 2 or 3, or both must be wrong. To list the key questions:
SUModelReleaseon a model created withSUModelCreatewhen using the Live C API (Ruby Extension)? What aboutSUModelCreateFromFile, and the other C API functions used to load/create a model? NOT callingSUModelReleasemakes me think you would get memory leaks every time.DefinitionList::load? I have known this method to be rather cryptic as I discovered some time ago: https://forums.sketchup.com/t/fix-definitionlist-load-problems-in-some-situations/5655 . I am inclined to think that "DefinitionList" may be better thought of as a collection of SketchUp models rather than components, some "internal" and others "external" to the active model. Does callingSUModelCreatecreate a newComponentDefinitioninDefinitionList- or does it access some sort of cache of "created" models?DefinitionList::loadand the variousSUModelCreate***methods in the context of the Live C API? Or put it another way - how is model ownership handled between the Live C API and the active SketchUp Application?