Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Reproducible] PropSet inside ScriptClip crashes Avisynth #359

Open
flossy83 opened this issue Jun 3, 2023 · 4 comments
Open

[Reproducible] PropSet inside ScriptClip crashes Avisynth #359

flossy83 opened this issue Jun 3, 2023 · 4 comments

Comments

@flossy83
Copy link

flossy83 commented Jun 3, 2023

This is crashing after 2600-2800 frames rendered:

global bars = Colorbars().Killaudio().ConvertToYV12() #.ChangeFPS(200) # speed up the bug

ScriptClip(bars, "CrashMe(bars, current_frame)", after_frame=true, local=false)

function CrashMe(clip c, int curr_frame){
	
	# Crashes
	global bars = bars.propSet("curr_frame", curr_frame)
	bars

	# Doesn't crash
	# out = bars.propSet("curr_frame", curr_frame)
	# out	
}

PropShow()

This is reproducible on both my systems with 3.7.2 & 3.7.3 under the following scenarios:

  • ffmpeg.exe at the command line rendering the .avs file to an mpeg file
  • Media Player Classic rendering the .avs file using LAV Video source filter (which uses ffmpeg)
  • Media Player Classic rendering the .avs file using the AVI/WAV source filter (Windows default)

In all cases the rendering of the script just stops abruptly at around the 2600-2800 frame mark with no error message (I tried try & catch block to no effect). On one of my machines MPC-HC was reporting ntdll.dll as the crashing module, on the other MPC-HC just closes without any error. ffmpeg.exe just stops rendering without any error.

Speculation: perhaps the ScriptClip and Avisynth are both trying to write frame properties at the same time?

@flossy83 flossy83 changed the title Reproducible: propSet inside ScriptClip crashes Avisynth [Reproducible] PropSet inside ScriptClip crashes Avisynth Jun 3, 2023
@flossy83
Copy link
Author

flossy83 commented Jun 3, 2023

Speculation: perhaps the ScriptClip and Avisynth are both trying to write frame properties at the same time?

Seems not to be the case as reading & writing frame props to a separate clip (bars2) also triggers it:

global bars = Colorbars().Killaudio().ConvertToYV12().ChangeFPS(200) #speed up bug
global bars2 = Colorbars().Killaudio().ConvertToYV12().ChangeFPS(200) #speed up bug

ScriptClip(bars, "CrashMe(bars, current_frame)", after_frame=true, local=false)

function CrashMe(clip c, int curr_frame){
	
	# Scenario 1 - crashes. Implies problem is caused by writing props to the clip being iterated on
	# global bars = bars.propSet("curr_frame", curr_frame)
	# bars
	
	# Scenario 2 - doesn't crash, consistent with scenario 1's implication
	# global bars2 = bars2.propSet("curr_frame", curr_frame)	
	# bars
	
	# Scenario 3 - crashes despite using different clip, thus contradicting scenario 1&2's hypothesis
	if (curr_frame != 0){ var = propGetAny(bars2, "curr_frame") }
	global bars2 = bars2.propSet("curr_frame", curr_frame)	
	bars
	
	# Scenario 4 - doesn't crash, but can't use frame props for messaging between frames
	# out = bars.propSet("curr_frame", curr_frame)
	# out
		
}
PropShow()

@pinterf
Copy link

pinterf commented Jun 3, 2023

Thanks, I can see the crash, thanks for the test script.
EDIT: debug build is showing "Stack overflow", which may occur when too many nested functions are involved (or for example current frame is recursively calling all previous frames backwards, one by one, for some reason) but at the first sight this is not the case. Mine is crashing at about frame number 673, and avsmeter is showing decreasing speed until the crash as if more and more frames would be needed to fetch for the specific current frame.... Investigating further.
EDIT:typo

@pinterf
Copy link

pinterf commented Jun 5, 2023

There is something with setting "global" clip within the function and/or after_frame=true.

It seems that for the first frame the function is doing this:
global bars = bars.propSet("curr_frame", curr_frame)
for frame number = 2
global bars = bars.propSet("curr_frame", curr_frame).propSet("curr_frame", curr_frame)
for frame number = 5
global bars = bars.propSet("curr_frame", curr_frame).propSet("curr_frame", curr_frame).propSet("curr_frame", curr_frame).propSet("curr_frame", curr_frame).propSet("curr_frame", curr_frame)
for frame number = 700 (... imagine)

PropSet gets its child clip, which has another child clip, which has another child clip...

When a big enough depth (~700+ in my debug build) is reached, the initial calling stack (1 MB) is consumed totally ,it will crash with stack overflow (debug build reports this fatal error)

This is why avsmeter was showing incremental slowdown, as more and more call was done as the frame count advanced.

For whatever is the reason, I don't understand it yet.
I don't even know that this is a legal use case, or illegal but Avisynth's script parser cannot detect it and is not able to show script error beforehand.

@flossy83
Copy link
Author

flossy83 commented Jun 5, 2023

Ok well thanks for looking into it, I guess it's just a limitation.

The reason I wanted to write frameprop to global clip is so I can check that same prop the next frame and see what the counter was, for purpose of detecting multithreading desynchronisation and warning user.

Storing the counter in a global var instead of frameprop seems to work too, but I thought it would be safer using a frameprop since Avisynth always displays frames in chronological order, whereas ScriptClip may not occur in chronological order if mulithreading. So the frameprop counter is like a guaranteed reference point for knowing what the counter should be for a given frame.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants