Console hangs/crashes when dumping some VST presetdata


(Ledger) #1

When trying to print the active_preset_data on a loaded VSTi instrument, renoise will completely hang with no time-out, requiring user to manually crash.

To test, load a VSTi into the instrument list and run the following snippet in testpad:

local device = renoise.song().selected_instrument.plugin_properties.plugin_device

print(device.active_preset_data)

Scripting Helper Tool: Show Devices Scripting Properties
(dblue) #2

Which VST(s) did you test this with?

The preset data is a chunk of binary data that comes directly from the plugin and could really consist of almost anything at all; ranging from a little bit of XML, a small bit of binary data, or potentially some huge chunk of binary data from a sampler or something like that.

Whenever possible, Renoise should of course try not to crash, but yeah… this preset data could really be anything, so it’s quite unpredictable what you might see when simply dumping that raw data directly to the terminal, and in general I’d probably recommend against doing that.


(Ledger) #3

I first tested ST2 and Drumatic 4 which both hung. Since your post I tried FAW Circle 2 which worked ok. I`ll try and get a longer list from a few more tests:

Hangs
Sampletank 2.X
Drumatic 4
Plugin Boutique Big Kick

Works
Circle2
kiloHeartz Khs1


(joule) #4

An idea… Maybe it won’t hang if you silently iterate the data and strip all non-ascii chars before printing it to screen? See if just a simple char iteration would also hang it, or if it’s only happening when printing it.

(an alternative guess would be that it’s just too many bytes to print)


(dblue) #5

The data is already encoded as CDATA within the XML, so it should technically be safe to view in most cases, but I honestly couldn’t say for sure right now. My rough guess is that certain presets may simply be far too massive for the terminal to safely handle without overflowing somewhere? Hard to say.


(Ledger) #6

@joule

I tried this. The pattern matching is just copied from stack overflow, so maybe you can confirm if right or not?

However still a hang on ST2. Another possible line of enquiry: is it happening on just 32bit plugs?

local device = renoise.song().selected_instrument.plugin_properties.plugin_device

local modded_string = string.gsub(device.active_preset_data, "[\128-\255]", "")

print(modded_string)

(dblue) #7

Confirmed hangs here, too.


(Ledger) #8

thanks,

good to get confirmed, I`ll keep an eye out for more culprits and update the list above


#9

Limit the amount of characters output from the string?

local device = renoise.song().selected_instrument.plugin_properties.plugin_device
print(string.char(string.byte(device.active_preset_data,1,7997)))

Here I’ve limited the amount of characters to around 7997 (the maximum on my machine before a stack overflow occurs.)


(Ledger) #10

Progress!

ST2 works with your snippet but fires an error if we add 1 making max: 7998

*** TestPad.lua:24: stack overflow (string slice too long)
*** stack traceback:
***   [C]: in function 'byte'
***   TestPad.lua:24: in main chunk

(Ledger) #11

History

ledger 2 mins

Progress!

ST2 works with your snippet but fires an error if we add 1 making max: 7998

*** TestPad.lua:24: stack overflow (string slice too long)
*** stack traceback:
***   [C]: in function 'byte'
***   TestPad.lua:24: in main chunk

accidently deleted post above
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

@4tey_guest , just experimenting further with this. If I print the length of one of the working presets from Circle 2 with:

print(#device.active_preset_data)

I get:

32226

which is obviously greater than 7997 limit you gave. Presuming I`m not mixing up string_length with char count, it looks like there still may be something else going on here…


#12

Sure, just to clarify, you are printing a string that is greater than around 8000 characters to the terminal throws a stack overflow. (I agree, now that could be a separate issue also with string.char/string.byte…anyway…)

Firstly, I’d write a program that generates a string > 8000 characters and prints that to the terminal. If okay (no stack overflow, no crash etc…), I’d assume that the string returned from ‘device.active_preset_data’ (which in your case above is around 32226 characters long) causes a crash when printed to the terminal. To me it feels an internal Lua/Renoise thing for taktik to look at (you’ve basically found a bug. [Only Ledger could want to print an entire large CDATA VST parameter string to the terminal, but well done for the effort :+1: :slight_smile: ])

Maybe work out a command that prints just partially the head and tail of the string? Or make sure you can output the entire string say to a file etc…? Things like that. But I know what you mean Ledger when you say there could be something else going on more here. A bit more testing is definitely needed, but also testing from the internal Renoise/Lua side. Hmm, you go and test string allocation/deallocation in Renoise/Lua Ledger…err… while I put the kettle on :slight_smile: :tea:

[Edit:] The other thing to note is to see if the same thing happens under Linux x64.

[Edit2:] Actually just quickly testing under Linux, your snippet Ledger seems to be fine. It pauses a moment, but it does print the entire string (at a length of 37656 characters in my case) to the terminal…albeit it doesn’t much care for it been in the terminal.

Whereas my string.char/string.byte combo is still limited to 7997 characters before a stack overflow…Wait! string.byte puts the parameters i.e. each character as a parameter on the stack. Of course! The parameter stack under Lua is probably 8 KB (8192 bytes) in length, hence why you get the stack overflow error. Okay, forget my crude string limiter, it’s confusing the issue.

So ultimately its a Windows issue moreso, Linux seems to handle it a bit better but not maybe ideal (can’t try Mac OSX), only taktik can look at it properly. I still say a cup of tea is in order though :tea: :slight_smile:


(Ledger) #13

As you well know 4tey, @Ledger likes to stress test Lua and he don`t like bugs! :slight_smile:

I`ll play around a little more with it and see if I can come up with anything for the team, but my guess like yours is best done from the internal renoise side.

kettle should go on here too, but I must say your tea looks a bit green for my taste! :radioactive:


#14

You’re right, it’s the brand that the emoji has selected, they are probably very much into decaf green tea Ledge…I suppose we could make a coffee :coffee: :slight_smile:


(Ledger) #15

Yeah, coffee or a good strong builders tea, does the job :coffee:. Must have been a hipster who decided on the green stuff! :slight_smile:

Just reading your edits now. Seems to be getting more complicated…


#16

I know! You’re like me, I don’t like bugs in programs either. I avoid the bugs by not programming :slight_smile:

Well at least in the emoji section (whilst taktik is deeply contemplating dumping a 32KB string to the terminal without it crashing) we have a regular cafeteria going on, a doughnut with that coffee Ledge? :doughnut: :yum:


(Ledger) #17

We can swat some virtual bugs in here aswell in solidarity with the taktik :ping_pong::bug: :ant::spider:

though I think the virtual cafe inspector won’t like em :policeman:


#18

Just mention something here about that ‘pause’. I’m sure you know yourself Ledger/joule/dblue/Raul, that when a computer pauses for say 1,2,3 seconds (or more) when given a seemingly (on the surface) relatively simple task…I get real nervous. Just thought I’d mention that :slight_smile:

Also probably a little bit better way of limiting output from the string ‘active_preset_data’ is to find roughly where the CDATA is in the string and only print up to that point:

local apd_str = renoise.song().selected_instrument.plugin_properties.plugin_device.active_preset_data
local cdata1,cdata2 = string.find(apd_str,"<ParameterChunk><!%[CDATA%[(.+)%]")
if cdata1 ~= nil then
  print(string.sub(apd_str,1,cdata1-1))
  print("--- CDATA HERE ---")
else
  print(apd_str)
end

(Ledger) #19

Thanks for snippet @4tey_guest ,

Just looking back on this thread after time to digest: Summary:

  1. active_preset_data printout is useful when using renoise devices, as presets are fully stored as characters. i.e. you can store a preset for the renoise Send-Device locally in a Lua file, to load the Send in a custom preset. I do this in my Send tools for example.

  2. As @dblue points out, plugins can contain all manner of non-charcter data, so to save this data to reload later you would need to save directly to a binary document?

If so, I will limit my Show Device Properties tool to only show active_preset_data for renoise devices and start brushing up on binary file storage in Lua. (Any tips / links welcome!)


#20

The CDATA is base64 encoded data from the plugin. It’s encoded in base64 so that there is no corruption of the binary representation (when the string gets decoded from base64 that is) from the ascii xml text string/file Ledge :slight_smile: