CALL myBatch.bat can return to the wrong place

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

CALL myBatch.bat can return to the wrong place

#1 Post by jeb » 06 Sep 2019 11:52

Hi,

while refactoring my macro library, I found an unknown behaviour of the CALL/return file logic. :!:
It fails when in the called batch file path at least one question mark or asterix is embedded.
It seems a little bit related to the (goto) 2> nul glitch.

First a sample, showing the normal behaviour with calling just labels.

callTest1.bat

Code: Select all

@echo off

echo [%0]: Before calling
call :func1
echo [%0]: After calling
exit /b

:func1
echo ..[%0]: Before calling
call :func2
echo ..[%0]: After calling
exit /b

:func2
echo ....[%0]: Before calling
call :func3
echo ....[%0]: After calling
exit /b

:func3
echo ......[%0]: Just return
exit /b
output wrote:[callTest1.bat]: Before calling
..[:func1]: Before calling
....[:func2]: Before calling
......[:func3]: Just return
....[:func2]: After calling
..[:func1]: After calling
[callTest1.bat]: After calling
callTest2.bat
Now the same with a trampoline function, that is more a less calling another batch file with an embedded label
The label itself has no special meaning for the CALL command, but it's parsed in the other batch file in the first lines.
For better visibility and for simpler parsing, I chose to enclose the label into colons, but you could use also other characters for that

Code: Select all

@echo off
REM *** Trampoline jump for function calls of the form ex. "C:\:label:\..\temp\thisBatchFile.cmd"
FOR /F "tokens=3 delims=:" %%L in ("%~0") DO goto :%%L

echo [%0]: Before calling
call %~d0\:func1:\..%~pnx0
echo [%0]: After calling
exit /b

:func1
echo ..[%0]: Before calling
call %~d0\:func2:\..%~pnx0
echo ..[%0]: After calling
exit /b

:func2
echo ....[%0]: Before calling
call %~d0\:func3:\..%~pnx0
echo ....[%0]: After calling
exit /b

:func3
echo ......[%0]: Just return
exit /b
More or less the same output, like of sample 1
output wrote:[CallTest2.bat]: Before calling
..[c:\:func1:\..\temp\CallTest2.bat]: Before calling
....[c:\:func2:\..\temp\CallTest2.bat]: Before calling
......[c:\:func3:\..\temp\CallTest2.bat]: Just return
....[c:\:func2:\..\temp\CallTest2.bat]: After calling
..[c:\:func1:\..\temp\CallTest2.bat]: After calling
[CallTest2.bat]: After calling

CallTest3.bat
Only a small harmless change at "C\:func3:?\.."

Code: Select all

@echo off
REM *** Trampoline jump for function calls of the form ex. "C:\:label:\..\temp\thisBatchFile.cmd"
FOR /F "tokens=3 delims=:" %%L in ("%~0") DO goto :%%L

echo [%0]: Before calling
call %~d0\:func1:\..%~pnx0
echo [%0]: After calling
exit /b

:func1
echo ..[%0]: Before calling
call %~d0\:func2:\..%~pnx0
echo ..[%0]: After calling
exit /b

:func2
echo ....[%0]: Before calling
call %~d0\:func3:?\..%~pnx0
echo ....[%0]: After calling
exit /b

:func3
echo ......[%0]: Just return
exit /b
Output wrote:[CallTest3.bat]: Before calling
..[c:\:func1:\..\temp\CallTest3.bat]: Before calling
....[c:\:func2:\..\temp\CallTest3.bat]: Before calling
......[c:\:func3:?\..\temp\CallTest3.bat]: Just return
..[c:\:func1:\..\temp\CallTest3.bat]: After calling
[CallTest3.bat]: After calling
The return from :func3 returns directly to :func1, somewhere the return to :func2 is lost :!:
This behaviour is the same as a block with the (goto) glitch

Code: Select all

:func3
(
(goto) > nul
echo ......[%0]: Just return
exit /b
)
I can reproduce this behaviour only by using calling a batch file, but not when using a label with a question mark.
I found that the asterix * and the question mark activates the behaviour, but I didn't find any other chararcters now.

jeb

siberia-man
Posts: 208
Joined: 26 Dec 2013 09:28
Contact:

Re: CALL myBatch.bat can return to the wrong place

#2 Post by siberia-man » 06 Sep 2019 17:33

By this link http://forum.script-coding.com/viewtopi ... 366#p80366 you can find the research I've made time ago and discussions in Russian.

There is translation from summary only.
The label name can consist of:

-- Latins
-- Digits
-- Underscore _
-- Punctuation signs . (dot), - (dash) [ and ] (square brackets), { and } (curly brackets), / and \ (slashes)
-- ' and ` (forward and backward apostrophes), ~ (tilde), @ (commercial at), # (hash), $ (dollar)

-- ) (closing round bracket) cannot be considered as completely valid

Other symbols are either completely invalid or don't have 100% supportable as the part of labels.
Further in that thread you can find more discussion where we told about * (asterisk) and ? (question mark).

jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: CALL myBatch.bat can return to the wrong place

#3 Post by jeb » 07 Sep 2019 02:15

Hi siberia-man,

thanks for the interesting link, I was able to understand the posts, thanks to google translate.

You described the ? and * for labels, there both characters works as expected, like any other charcter.

But the key difference is using them not in a lable, instead use them in a called filename.
Normally both are not allowed in a filename, because of their special meaning as wildcards.
It's only possible to use them by using the "C:\element to drop by the next dot dot\.." trick.
The trick removes the second path element, ignoring any special character, like "":|&<>?*".
I used this trick to colorize text with the findstr command.

But only for ? and * the CALL (or call stack) itself, works different.
It doesn't push the return postion onto the stack :!:

jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: CALL myBatch.bat can return to the wrong place

#4 Post by jeb » 07 Sep 2019 02:44

I found one useful behaviour for the "missing stack entry".

It works nearly the same as a GOTO, but there is one difference when it's in a command block or there are appended commands.

A GOTO discards the other commands of a block and all appended commands (by &)

Code: Select all

@echo off

echo [%0]: Before calling
call :func1
echo [%0]: After calling
exit /b

:func1
(echo ..[%0]: Before calling
goto :func2 & echo appended command in %0
echo ..[%0]: After calling
)
echo after the block
exit /b

:func2
echo ......[%0]: Just return
exit /b
output wrote:[goto1]: Before calling
..[:func1]: Before calling
......[:func1]: Just return
[goto1]: After calling
But with the CALL-? technic the appended and blocks still works.
CallTest4.bat

Code: Select all

@echo off
REM *** Trampoline jump for function calls of the form ex. "C:\:label:\..\temp\thisBatchFile.cmd"
FOR /F "tokens=3 delims=:" %%L in ("%~0") DO goto :%%L

echo [%0]: Before calling
call %~d0\:func1:\..%~pnx0
echo [%0]: After calling
exit /b

:func1
(echo ..[%0]: Before calling
call %~d0\:func2:?\..%~pnx0 & echo appended command in %0
echo ..[%0]: After calling
)
echo ..[%0]: After BLOCK
exit /b

:func2
echo ......[%0]: Just return
exit /b
output wrote:[CallTest4.bat]: Before calling
..[c:\:func1:\..\temp\CallTest4.bat]: Before calling
......[c:\:func2:?\..\temp\CallTest4.bat]: Just return
appended command in c:\:func1:\..\temp\CallTest4.bat
..[c:\:func1:\..\temp\CallTest4.bat]: After calling
[CallTest4.bat]: After calling

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: CALL myBatch.bat can return to the wrong place

#5 Post by dbenham » 08 Sep 2019 05:51

Very interesting discovery and technique. :shock: 8)

I was worried about SETLOCAL not ending properly, but all seems to be good - all SETLOCAL within both the CALLer and the CALLed are properly ended.

I recommend quoting your CALLed path just in case there are spaces or other problematic characters in %~pnx0 - the quotes don't seem to interfere with the ? double return effect:

Code: Select all

call "%~d0\:func2:?\..%~pnx0" & echo appended command
But I can't imagine every using the ? double return technique. I don't see any benefit that can't be achieved by standard, more expressive syntax:

Code: Select all

call :func2 & echo appended command & exit /b
The EXIT /B still works If for some reason you want to use your "trampoline" CALL:

Code: Select all

call "%~d0\:func2:\..%~pnx0" & echo appended command & exit /b

Dave Benham

Post Reply