It is currently April 27th, 2024, 9:50 pm

[BUG] App Crash Due to Nested Variable Self-Reference

Report bugs with the Rainmeter application and suggest features.
User avatar
Jeff
Posts: 332
Joined: September 3rd, 2018, 11:18 am

[BUG] App Crash Due to Nested Variable Self-Reference

Post by Jeff »

Code: Select all

[MeasureHours]
Measure=Calc
Formula=#Minutes# / 60
DynamicVariables=1
[MeterHours]
Meter=String
MeasureName=MeasureHours
FontSize=100
FontColor=FFFFFF
SolidColor=00000001
NumOfDecimals=1
LeftMouseUpAction=[!SetVariable "Minutes" "([#Minutes] + 1)"]
This is the entire skin and I have a very strange feeling of deja-vu.
Basically, I remember reading a part about how Variables can be created dynamically and how they don't need to exist in the skin at all, however, if you have those variable names already in the file, and they are uninitialized/inexistent, but you create them, when Rainmeter gose through the Update cycle, it crashes.
This happens ONLY when the variable is NEVER initialized, it can easily be circumvented by just adding it to [Variables], but the bug pertains to it crashing if the section is never written or when the variable gets spawned out of thin air.
Last edited by Jeff on October 10th, 2023, 7:30 pm, edited 1 time in total.
User avatar
Yincognito
Rainmeter Sage
Posts: 7178
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [BUG] Setting the value of an uninitialized variable while it's used in a Formula crashes the app

Post by Yincognito »

Jeff wrote: October 9th, 2023, 8:39 pm

Code: Select all

[MeasureHours]
Measure=Calc
Formula=#Minutes# / 60
DynamicVariables=1
[MeterHours]
Meter=String
MeasureName=MeasureHours
FontSize=100
FontColor=FFFFFF
SolidColor=00000001
NumOfDecimals=1
LeftMouseUpAction=[!SetVariable "Minutes" "([#Minutes] + 1)"]
This is the entire skin and I have a very strange feeling of deja-vu.
Basically, I remember reading a part about how Variables can be created dynamically and how they don't need to exist in the skin at all, however, if you have those variable names already in the file, and they are uninitialized/inexistent, but you create them, when Rainmeter gose through the Update cycle, it crashes.
This happens ONLY when the variable is NEVER initialized, it can easily be circumvented by just adding it to [Variables], but the bug pertains to it crashing if the section is never written or when the variable gets spawned out of thin air.
Yep, it happens for me too - and it probably shouldn't, but not necessarily because of what you're thinking (at least that's my impression). Before trying to create a variable dynamically without it existing in the skin yet (which I'm sure will not cause Rainmeter to crash), you're actually referencing a variable that doesn't exist yet, in the formula. Even more so, it only happens when using the nested syntax for the variable when referencing it, it won't happen when using the classic syntax. I believe it's these two that cause Rainmneter to crash (well, technically, it hangs, but anyway), and the error appearing in the log before the hang seems to agree (just try to click this with the About > Skins window open, maybe even inserting a !Log before to see the variable's value). Or, it's about the double referencing when using the nested syntax (if my understanding of it is correct), maybe even the lost square brackets that are not replaced from the variable string.
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
User avatar
Brian
Developer
Posts: 2688
Joined: November 24th, 2011, 1:42 am
Location: Utah

Re: [BUG] Setting the value of an uninitialized variable while it's used in a Formula crashes the app

Post by Brian »

Welp....you broke the nested syntax parser.

Yincognito is correct, it technically hangs...then crashes.

There are a couple of things happening here. First, while you are correct that you can create a variable dynamically, you are also assuming that the newly created variable is defaulted to "something" (presumably "0", since you are using it in a formula).

That is the first mistake. When creating the variable, you are basically setting it to itself + 1, but once that variable gets resolved, it doesn't exist yet, so it just returns the original text.

It is no different than this:

Code: Select all

[Variables]
Minutes=([#Minutes] + 1)
That also produces the same hang...then crash. What happens is [#Minutes] is replaced with ([#Minutes] + 1), then it evaluated again and again until the internal stack is too large and Rainmeter crashes.

This self-referencing is the second (unintended, obviously) mistake.

However.....

This all shouldn't hang or crash Rainmeter...and fixing it is somewhat tricky. Either we can't allow a variable to self-reference itself (with nested syntax) within the variable's value, or we may have to limit how many nested substitutions can be done on a variable before it bails out and just returns with what it has. Obviously either way needs to produce an error message.

I'll have to chew on this for bit, so stay tuned...

-Brian
User avatar
Yincognito
Rainmeter Sage
Posts: 7178
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [BUG] Setting the value of an uninitialized variable while it's used in a Formula crashes the app

Post by Yincognito »

Brian wrote: October 10th, 2023, 7:01 amThis all shouldn't hang or crash Rainmeter...and fixing it is somewhat tricky. Either we can't allow a variable to self-reference itself (with nested syntax) within the variable's value, or we may have to limit how many nested substitutions can be done on a variable before it bails out and just returns with what it has. Obviously either way needs to produce an error message.

I'll have to chew on this for bit, so stay tuned...

-Brian
I just hope that the nested syntax and its clear advantages and capabilities (as well as the useful changes done to improve it over the years) won't be afected. In case it's not obvious, the hang and crash also happen when mixing with the escaped syntax, EVEN if the variable is previously defined - I'm sure there is a reason for it as well (maybe the 2nd mistake you mentioned), but just in case it helps:

Code: Select all

[Variables]
Minutes=0

[MeasureHours]
Measure=Calc
Formula=(#Minutes#/60)
DynamicVariables=1

[MeterHours]
Meter=String
MeasureName=MeasureHours
FontSize=100
FontColor=FFFFFF
SolidColor=00000001
NumOfDecimals=1
LeftMouseUpAction=[!Log "[#Minutes]"][!SetVariable Minutes ([#*Minutes*]+1)]
DynamicVariables=1
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
User avatar
Jeff
Posts: 332
Joined: September 3rd, 2018, 11:18 am

Re: [BUG] App Crash Due to Nested Variable Self-Reference

Post by Jeff »

Yincognito wrote: October 10th, 2023, 4:59 am Even more so, it only happens when using the nested syntax for the variable when referencing it, it won't happen when using the classic syntax. I believe it's these two that cause Rainmneter to crash (well, technically, it hangs, but anyway)
I partially decided to use Nested Variables because they are dynamically resolved when they are used, I didn't wanna use Classic Variables because I didn't wanna add DV to the meter too (since I knew that previous function Nested Variables have), I actually didn't even test classic variables, but I understand now why and why referencing with the variable existing in the [Variables] section dosen't do it
Yincognito wrote: October 10th, 2023, 4:59 am and the error appearing in the log before the hang seems to agree
Haha whoops, I didn't even check that window at all, I only checked the Skins tab to see the number go up and crash, never crossed my mind to go one page behind

Brian wrote: October 10th, 2023, 7:01 am What happens is [#Minutes] is replaced with ([#Minutes] + 1), then it evaluated again and again until the internal stack is too large and Rainmeter crashes.

This self-referencing is the second (unintended, obviously) mistake.

However.....

This all shouldn't hang or crash Rainmeter...and fixing it is somewhat tricky. Either we can't allow a variable to self-reference itself (with nested syntax) within the variable's value, or we may have to limit how many nested substitutions can be done on a variable before it bails out and just returns with what it has. Obviously either way needs to produce an error message.

I'll have to chew on this for bit, so stay tuned...

-Brian
Sorry for the long text ahead.

I'll have to be honest with this one, but this seems like an intended behavior, Rainmeter is actually doing the correct job self referencing even if it means the app crashes.
To give an example where we can extract the same behavior, in LUA the _G environment and __index metamethod are self referential, when you do for key, value in pairs(_G) do print(key) end and it references _G back, that is indeed correct and dose the job right. If after that you try to get what each key's references (so for string you try to get that it has string.sub etc.), you'll run into infinity, recursively getting where _G points (to itself).
So Rainmeter is doing the right thing, the question is if to limit the behavior to circumvent the crash in cases like this (I think Formula and Conditional Operations accept only 100 nested conditions, maybe for this behavior 3 nested is enough? but then again in other programming languages there are no rules for this, they just hang... and then crash) or to not do anything.
I personally wouldn't change anything, as the blame falls on the user for this/my error for initializing a self-referential behavior. I feel like this kind of behavior can't happen by accident (well, maybe it can if do [#Minute[#Second]] but [#Second] fails, I'd be hard pressed to find a user that could do this though) and is done only deliberately by hand.
I changed the post title to reflect the problem a bit better.

That's my rant over, as a funny little ending node, if you recursively try to get _G's values you will end up with stuff like _G._G._G._G.Measure.__index.__index.__index.__index.GetValueRange, which I find funny. For some reason getfenv(1) is also in the global list and you have 1.SELF there. LUA Code here for the thing I wrote to get that long string.
User avatar
Yincognito
Rainmeter Sage
Posts: 7178
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [BUG] App Crash Due to Nested Variable Self-Reference

Post by Yincognito »

Jeff wrote: October 10th, 2023, 8:13 pm I partially decided to use Nested Variables because they are dynamically resolved when they are used, I didn't wanna use Classic Variables because I didn't wanna add DV to the meter too (since I knew that previous function Nested Variables have)
Yep, I've seen this approach in other cases too - it's easy to use the nested syntax when it has so many advantages. Personally, I use it only when actually nesting or need the immediate value in the same option, as it also serves as an indication that "somethig special" is happening there, due to the Notepad++ coloring. :D
Jeff wrote: October 10th, 2023, 8:13 pm Haha whoops, I didn't even check that window at all, I only checked the Skins tab to see the number go up and crash, never crossed my mind to go one page behind
Generally, using the log isn't of much help In a hang / crash scenario, but here I thought I could "steal" some info from Rainmeter before dying on me. :lol:
Jeff wrote: October 10th, 2023, 8:13 pm I personally wouldn't change anything, as the blame falls on the user for this/my error for initializing a self-referential behavior.
I kinda tend to agree with this - in a way, it's pointless to have checks on infinite loops or unorthodox self referencing. Up to Brian to decide though. :???:
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
User avatar
Cariboudjan
Posts: 268
Joined: May 12th, 2019, 8:55 am

Re: [BUG] App Crash Due to Nested Variable Self-Reference

Post by Cariboudjan »

Love using nested variables due to them being dynamic in combination with !Delay to execute a different action within the same line if a value changes between when the line is executed vs. when the delay completes. Excellent substitute for using ActionTimer.