Got my pointers in a twist - Segmentation fault: 11

I don’t think this is the case, a quick print to the console shows that jsonSavePath does indeed update to the current path even though it’s not a pointer (and it doesn’t cause a seg fault)

…scrub that, the path going to and from JSON is the default image, not the updated one, so jsonSavePath is not getting updated, so the pointers are not working as it’s only changing the jsonSavePath on creation

Woohoo! got a new error…

Rack(13817,0x10ece15c0) malloc: Incorrect checksum for freed object 0x7f7f15cadaa8: probably modified after being freed.

Corrupt value: 0x36

Rack(13817,0x10ece15c0) malloc: *** set a breakpoint in malloc_error_break to debug

Maybe it’s something to do with how JSON handles memory allocation, maybe that’s why I can’t have a shared memloc between the widgets and the JSON save load?

I told you those JSON things are tricky. I would not pass them around, and I would for sure not pass a pointer to one. Like @carbon14 says, pass around std::string. Or if you insist on efficiency, std::string&

And, if you used and debugger, it would tell you immediately where your problems is. Clearly there is memory monkey business going on…

it’s not really about efficiency, since the path is required by the widgets and the only reason i need it in the Module struct is because I want to save out to JSON, how else am i supposed to get it from the widget to the Module if I don’t use a pointer?

I guess my issue is that, even if I do use a debugger to confirm that I have a memory leak associated with jsonSavePath, I still wouldn’t have a clue how to fix it. Do you know of a module that saves a file path from a widget? So I might be able to see a working implementation? I kinda thought it would be trivial, but I probably got that wrong too!

Always test what you get from json_object_get as it returns NULL if it can’t find an object.

void dataFromJson(json_t *rootJ) override {
  json_t *savedPATHJ = json_object_get(rootJ, "sPATH");
  if (savedPATHJ)
    jsonSavePath = json_string_value(savedPATHJ);
}
1 Like

Thanks for the tip :+1:

pass a string.

foo(std::string z) {

}

bar() {
   std;:string x ("here I am");
   foo(x);  // just pass the whole string. it works by magic.
}
1 Like

so I have a function in the Module struct that takes a string argument and I call that function from one of the widgets? Sorry, I’m confused as to where this “foo” function is located

i didn’t think i could call a function in one struct from another struct, I thought it all had to be handled with pointers in the Module widget

I’m aware of how to pass a string into a function using an argument, just not sure how that’s going to get a string from the SvgWidget to the Module, if that makes sense?

I can’t keep up. I’ll bow out. Good luck.

1 Like

thank you for trying, it’s most appreciated :+1:

#include "plugin.hpp"
	
	struct _4hp : Module
	{
		enum ParamId
		{
			PARAMS_LEN
		};
		enum InputId
		{
			INPUTS_LEN
		};
		enum OutputId
		{
			OUTPUTS_LEN
		};
		enum LightId
		{
			LIGHTS_LEN
		};
	
		_4hp()
		{
			config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN);
		}
	
		std::string jsonSavePath; // storage for SVG image file path
		bool pathDirty = false; // flag to indicate path has been changed
	
		// save and load filepath to JSON file
	
		json_t *dataToJson() override 
		{
			json_t *rootJ = json_object();
			json_object_set_new(rootJ, "sPATH", json_string(jsonSavePath.c_str()));	
			return rootJ;
		}
	
		void dataFromJson(json_t *rootJ) override
		{
			json_t *savedPATHJ = json_object_get(rootJ, "sPATH");
			if (savedPATHJ)
				jsonSavePath = json_string_value(savedPATHJ);
		}
	};
	
	struct customPanel : SvgWidget
	{
		_4hp *module;
		customPanel()
		{
			// Does nothing because PATH is empty on construction
			//	setSvg(Svg::load(asset::plugin(pluginInstance, PATH))); // set SVG file on creation of customPanel
		}
	
		void draw(const DrawArgs& args) override
		{
			if (module) {
				if (module->pathDirty) {
					module->pathDirty = false;
					setSvg(Svg::load(asset::plugin(pluginInstance, module->jsonSavePath))); // set new file path
				}
			}
	
			SvgWidget::draw(args); // continue to run the rest of the default draw function
		}
	};
	
	struct dnd : TransparentWidget
	{
		_4hp *module;
		std::string svgPath = asset::plugin(pluginInstance, "res/test.svg"); // path with SVG extension
	
		void onPathDrop(const PathDropEvent &e) override
		{
			std::string filePath = e.paths.front(); // get first path in array, all other paths are ignored
	
			if(filePath.substr(filePath.find_last_of(".") + 1) == "svg") // check for SVG extension
			{
				svgPath = filePath; // store path
				if (module) {
					module->jsonSavePath = svgPath;
					module->pathDirty = true;
				}
			}
	
			else
			{
				DEBUG("Invalid file extension: try *.svg\n");
			}
		}
	};
	
	struct _4hpWidget : ModuleWidget
	{
		_4hpWidget(_4hp *module)
		{
			setModule(module);
			setPanel(createPanel(asset::plugin(pluginInstance, "res/4hp.svg")));
	
			// maunally add widgets to allow for pointer references
	
			dnd *DND = new dnd();
			DND->module = module;
			DND->box.pos = Vec(0, 0);
			DND->box.size = Vec(RACK_GRID_WIDTH * 4, RACK_GRID_HEIGHT);
			addChild(DND);
	
			customPanel *CP = new customPanel();
			CP->module = module;
			CP->box.pos = Vec(0, 0);
			CP->box.size = Vec(RACK_GRID_WIDTH * 4, RACK_GRID_HEIGHT);
			addChild(CP);
	
			if (module)
			{
				module->jsonSavePath = DND->svgPath;
				module->pathDirty = true;
				DEBUG("%s\n", module->jsonSavePath.c_str());
			}
		}
	};
	
	Model* model_4hp = createModel<_4hp, _4hpWidget>("4hp");
1 Like

Or this version which will reload the last dragged svg, when you restart Rack. I’m guessing this is what you actually want

#include "plugin.hpp"
	
	struct _4hp : Module
	{
		enum ParamId
		{
			PARAMS_LEN
		};
		enum InputId
		{
			INPUTS_LEN
		};
		enum OutputId
		{
			OUTPUTS_LEN
		};
		enum LightId
		{
			LIGHTS_LEN
		};
	
		_4hp()
		{
			config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN);
		}
	
		std::string jsonSavePath; // storage for SVG image file path
		bool pathDirty = false; // flag to indicate path has been changed
	
		// save and load filepath to JSON file
	
		json_t *dataToJson() override 
		{
			json_t *rootJ = json_object();
			json_object_set_new(rootJ, "sPATH", json_string(jsonSavePath.c_str()));	
			return rootJ;
		}
	
		void dataFromJson(json_t *rootJ) override
		{
			json_t *savedPATHJ = json_object_get(rootJ, "sPATH");
			if (savedPATHJ) {
				jsonSavePath = json_string_value(savedPATHJ);
				pathDirty = true;
			}
		}
	};
	
	struct customPanel : SvgWidget
	{
		_4hp *module;
		customPanel()
		{
			// Does nothing because PATH is empty on construction
			//	setSvg(Svg::load(asset::plugin(pluginInstance, PATH))); // set SVG file on creation of customPanel
		}
	
		void draw(const DrawArgs& args) override
		{
			if (module) {
				if (module->pathDirty) {
					module->pathDirty = false;
					setSvg(Svg::load(asset::plugin(pluginInstance, module->jsonSavePath))); // set new file path
				}
			}
	
			SvgWidget::draw(args); // continue to run the rest of the default draw function
		}
	};
	
	struct dnd : TransparentWidget
	{
		_4hp *module;
		std::string svgPath = asset::plugin(pluginInstance, "res/test.svg"); // path with SVG extension
	
		void onPathDrop(const PathDropEvent &e) override
		{
			std::string filePath = e.paths.front(); // get first path in array, all other paths are ignored
	
			if(filePath.substr(filePath.find_last_of(".") + 1) == "svg") // check for SVG extension
			{
				svgPath = filePath; // store path
				if (module) {
					module->jsonSavePath = svgPath;
					module->pathDirty = true;
				}
			}
	
			else
			{
				DEBUG("Invalid file extension: try *.svg\n");
			}
		}
	};
	
	struct _4hpWidget : ModuleWidget
	{
		_4hpWidget(_4hp *module)
		{
			setModule(module);
			setPanel(createPanel(asset::plugin(pluginInstance, "res/4hp.svg")));
	
			// maunally add widgets to allow for pointer references
	
			dnd *DND = new dnd();
			DND->module = module;
			DND->box.pos = Vec(0, 0);
			DND->box.size = Vec(RACK_GRID_WIDTH * 4, RACK_GRID_HEIGHT);
			addChild(DND);
	
			customPanel *CP = new customPanel();
			CP->module = module;
			CP->box.pos = Vec(0, 0);
			CP->box.size = Vec(RACK_GRID_WIDTH * 4, RACK_GRID_HEIGHT);
			addChild(CP);
	
			if (module)
			{
				if (!module->pathDirty) {
					module->jsonSavePath = DND->svgPath;
					module->pathDirty = true;
				}
				DEBUG("%s\n", module->jsonSavePath.c_str());
			}
		}
	};
	
	Model* model_4hp = createModel<_4hp, _4hpWidget>("4hp");
2 Likes

Oh my goodness! Thank you very much David, super appreciated :slight_smile:

Yeah, that’s exactly the functionality I was after, and it totally makes sense, I think the missing key for me was not knowing I could reference the module from within the widgets, I had presumed that was only possible from the actual moduleWidget. Really appreciate you spending the time going through my code :+1:

4 Likes

I think that you’ll find lldb a lot more friendly, whether you’re on a Mac, windows, or linux. the llvm suite is quite nice.

lldb has been part of Xcode since Xcode started using llvm in Xcode 4 (2010), so it’s not some “new thing”, nor is it a “wrapper”. you can simply start up rack in the debugger (lldb), and run it. if you crash, you should end up with a good backtrace (bt).

you can also attach to the process if you know the PID, which makes it even easier (you can do this in gdb as well):

lldb -p PID

where PID is the process id rack is running as.

if you do this, don’t forget to cont, or continue in the debugger to continue code execution.

1 Like

Yeah I’ll have to have a good look at it when I have some time, not used debugger before for anything like this.

Thanks very much jerrysv, y’all have been most helpful :slight_smile: