AviSynth / AviSynthPlus

AviSynth with improvements
http://avs-plus.net
930 stars 74 forks source link

`Import` leaves `ScriptName/File/Dir[Utf8]` in an inconsistent state if an error occurs during the import #349

Open osir3z opened 1 year ago

osir3z commented 1 year ago

Issue

Consider the following example:

# import-bug\test2.avs
SetLogParams("stderr", LOG_DEBUG)

LogMsg(Format(e"ScriptName()=\"{0}\"", ScriptName()), LOG_DEBUG)
LogMsg(Format(e"ScriptFile()=\"{0}\"", ScriptFile()), LOG_DEBUG)
LogMsg(Format(e"ScriptDir()=\"{0}\"", ScriptDir()), LOG_DEBUG)
try {
  Import(ScriptDir() + "\lib\bom.avsi")
}
catch (error) {
  LogMsg(error, LOG_WARNING)
}
LogMsg(Format(e"ScriptName()=\"{0}\"", ScriptName()), LOG_DEBUG)
LogMsg(Format(e"ScriptFile()=\"{0}\"", ScriptFile()), LOG_DEBUG)
LogMsg(Format(e"ScriptDir()=\"{0}\"", ScriptDir()), LOG_DEBUG)
Import(ScriptDir() + "\lib\valid.avsi")

BlankClip()
return Last

which gives the following output:

---------------------------------------------------------------------
DEBUG: ScriptName()="C:\import-bug\test2.avs"
---------------------------------------------------------------------
DEBUG: ScriptFile()="test2.avs"
---------------------------------------------------------------------
DEBUG: ScriptDir()="C:\import-bug\"
---------------------------------------------------------------------
ERROR: Import: UTF-8 source files with BOM are not supported, re-save script with ANSI or UTF8 w/o BOM encoding! : "C:\import-bug\\lib\bom.avsi"
---------------------------------------------------------------------
ERROR: Import: UTF-8 source files with BOM are not supported, re-save script with ANSI or UTF8 w/o BOM encoding! : "C:\import-bug\\lib\bom.avsi"
(import-bug\test2.avs, line 8)
---------------------------------------------------------------------
WARNING: Import: UTF-8 source files with BOM are not supported, re-save script with ANSI or UTF8 w/o BOM encoding! : "C:\import-bug\\lib\bom.avsi"
(import-bug\test2.avs, line 8)
---------------------------------------------------------------------
DEBUG: ScriptName()="C:\import-bug\lib\bom.avsi"
---------------------------------------------------------------------
DEBUG: ScriptFile()="bom.avsi"
---------------------------------------------------------------------
DEBUG: ScriptDir()="C:\import-bug\lib\"
---------------------------------------------------------------------
ERROR: Import: couldn't open "C:\import-bug\lib\lib\valid.avsi"
---------------------------------------------------------------------
ERROR: Import: couldn't open "C:\import-bug\lib\lib\valid.avsi"
(import-bug\test2.avs, line 16)
avs2pipemod[error]: Import: couldn't open "C:\import-bug\lib\lib\valid.avsi"
(import-bug\test2.avs, line 16)

In the example, lib\valid.avsi exists and contains valid code, whilst lib\bom.avsi exists but contains a UTF-8 BOM which causes an error. As you can see, after the error importing lib\bom.avsi, all the ScriptName/File/Dir[Utf8] functions return values referring to lib\bom.avsi when they should refer to test2.avs.

Something similar occurs if you replace the Import line in the try/catch block above with:

Import(ScriptDir() + "\lib\valid.avsi", ScriptDir() + "noexist.avsi")

(where noexist.avsi doesn't exist), except this time the ScriptName/File/Dir[Utf8] functions end up referring to lib\valid.avsi.

The code and files for these examples can be found in import-bug.zip.

Cause

When run successfully, Import saves the ScriptName/File/Dir[Utf8] environment variables, imports the scripts (changing ScriptName/File/Dir[Utf8] as it goes), and then restores the original environment variables before returning. But the restore code is never executed if an error occurs. https://github.com/AviSynth/AviSynthPlus/blob/45404659f0fed07e369978924efd417221bdc782/avs_core/core/parser/script.cpp#L484-L653

Possible Solution(s)

It looks as though you could just wrap the whole for-loop in a try/catch and do a cleaup and re-throw on error. Or, if that's too inelegant, you could use something similar to the CWDChanger object (referenced in the Import function). But I'm no expert, so I'll just keenly keep an eye out to see what the final solution is.

Thanks again for all the work you folks do to make AviSynth+ better, and better.