2016-07-26 02:43:28 +02:00
|
|
|
Describe 'Exceptions flow for classes' -Tags "CI" {
|
2017-01-16 22:31:14 +01:00
|
|
|
|
2016-07-19 22:52:03 +02:00
|
|
|
$canaryHashtable = @{}
|
|
|
|
|
|
|
|
$iss = [initialsessionstate]::CreateDefault()
|
|
|
|
$iss.Variables.Add([System.Management.Automation.Runspaces.SessionStateVariableEntry]::new('canaryHashtable', $canaryHashtable, $null))
|
|
|
|
$iss.Commands.Add([System.Management.Automation.Runspaces.SessionStateFunctionEntry]::new('Get-Canary', '$canaryHashtable'))
|
|
|
|
$ps = [powershell]::Create($iss)
|
|
|
|
|
|
|
|
BeforeEach {
|
|
|
|
$canaryHashtable.Clear()
|
|
|
|
$ps.Commands.Clear()
|
|
|
|
}
|
|
|
|
|
|
|
|
Context 'All calls are inside classes' {
|
2017-01-16 22:31:14 +01:00
|
|
|
|
2016-07-19 22:52:03 +02:00
|
|
|
It 'does not execute statements after instance method with exception' {
|
2017-01-16 22:31:14 +01:00
|
|
|
|
|
|
|
# Put try-catch outside to avoid try-catch logic altering analysis
|
2016-07-19 22:52:03 +02:00
|
|
|
try {
|
|
|
|
|
|
|
|
$ps.AddScript( @'
|
|
|
|
class C
|
|
|
|
{
|
|
|
|
[void] m1()
|
|
|
|
{
|
|
|
|
$canaryHashtable = Get-Canary
|
|
|
|
$canaryHashtable['canary'] = 42
|
|
|
|
$this.ImThrow()
|
|
|
|
$canaryHashtable['canary'] = 100
|
|
|
|
}
|
|
|
|
|
2017-01-16 22:31:14 +01:00
|
|
|
[void] ImThrow()
|
2016-07-19 22:52:03 +02:00
|
|
|
{
|
|
|
|
throw 'I told you'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[C]::new().m1()
|
|
|
|
'@).Invoke()
|
2017-01-16 22:31:14 +01:00
|
|
|
|
2016-07-19 22:52:03 +02:00
|
|
|
} catch {}
|
|
|
|
|
|
|
|
$canaryHashtable['canary'] | Should Be 42
|
|
|
|
}
|
|
|
|
|
|
|
|
It 'does not execute statements after static method with exception' {
|
2017-01-16 22:31:14 +01:00
|
|
|
|
|
|
|
# Put try-catch outside to avoid try-catch logic altering analysis
|
2016-07-19 22:52:03 +02:00
|
|
|
try {
|
|
|
|
|
|
|
|
$ps.AddScript( @'
|
|
|
|
class C
|
|
|
|
{
|
|
|
|
static [void] s1()
|
|
|
|
{
|
|
|
|
$canaryHashtable = Get-Canary
|
|
|
|
$canaryHashtable['canary'] = 43
|
|
|
|
[C]::ImThrow()
|
|
|
|
$canaryHashtable['canary'] = 100
|
|
|
|
}
|
|
|
|
|
2017-01-16 22:31:14 +01:00
|
|
|
static [void] ImThrow()
|
2016-07-19 22:52:03 +02:00
|
|
|
{
|
|
|
|
1 / 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[C]::s1()
|
|
|
|
'@).Invoke()
|
2017-01-16 22:31:14 +01:00
|
|
|
|
2016-07-19 22:52:03 +02:00
|
|
|
} catch {}
|
|
|
|
|
|
|
|
$canaryHashtable['canary'] | Should Be 43
|
|
|
|
}
|
|
|
|
|
|
|
|
It 'does not execute statements after instance method with exception and deep stack' {
|
2017-01-16 22:31:14 +01:00
|
|
|
|
|
|
|
# Put try-catch outside to avoid try-catch logic altering analysis
|
2016-07-19 22:52:03 +02:00
|
|
|
try {
|
|
|
|
|
|
|
|
$ps.AddScript( @'
|
|
|
|
class C
|
|
|
|
{
|
|
|
|
[void] m1()
|
|
|
|
{
|
|
|
|
$canaryHashtable = Get-Canary
|
|
|
|
$canaryHashtable['canary'] = 1
|
|
|
|
$this.m2()
|
|
|
|
$canaryHashtable['canary'] = -6101
|
|
|
|
}
|
|
|
|
|
2017-01-16 22:31:14 +01:00
|
|
|
[void] m2()
|
2016-07-19 22:52:03 +02:00
|
|
|
{
|
|
|
|
$canaryHashtable = Get-Canary
|
|
|
|
$canaryHashtable['canary'] += 10
|
|
|
|
$this.m3()
|
2017-01-16 22:31:14 +01:00
|
|
|
$canaryHashtable['canary'] = -6102
|
2016-07-19 22:52:03 +02:00
|
|
|
}
|
|
|
|
|
2017-01-16 22:31:14 +01:00
|
|
|
[void] m3()
|
2016-07-19 22:52:03 +02:00
|
|
|
{
|
|
|
|
$canaryHashtable = Get-Canary
|
|
|
|
$canaryHashtable['canary'] += 100
|
|
|
|
$this.m4()
|
2017-01-16 22:31:14 +01:00
|
|
|
$canaryHashtable['canary'] = -6103
|
2016-07-19 22:52:03 +02:00
|
|
|
}
|
|
|
|
|
2017-01-16 22:31:14 +01:00
|
|
|
[void] m4()
|
|
|
|
{
|
2016-07-19 22:52:03 +02:00
|
|
|
$canaryHashtable = Get-Canary
|
|
|
|
$canaryHashtable['canary'] += 1000
|
|
|
|
$this.ImThrow()
|
|
|
|
$canaryHashtable['canary'] = -6104
|
|
|
|
}
|
|
|
|
|
2017-01-16 22:31:14 +01:00
|
|
|
[void] ImThrow()
|
2016-07-19 22:52:03 +02:00
|
|
|
{
|
|
|
|
$canaryHashtable = Get-Canary
|
|
|
|
$canaryHashtable['canary'] += 10000
|
2017-01-16 22:31:14 +01:00
|
|
|
|
2016-07-19 22:52:03 +02:00
|
|
|
1 / 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[C]::new().m1()
|
|
|
|
'@).Invoke()
|
2017-01-16 22:31:14 +01:00
|
|
|
|
2016-07-19 22:52:03 +02:00
|
|
|
} catch {}
|
|
|
|
|
|
|
|
$canaryHashtable['canary'] | Should Be 11111
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Context 'Class method call PS function' {
|
2017-01-16 22:31:14 +01:00
|
|
|
|
2016-07-19 22:52:03 +02:00
|
|
|
$body = @'
|
|
|
|
class C
|
|
|
|
{
|
2017-01-16 22:31:14 +01:00
|
|
|
[void] m1()
|
2016-07-19 22:52:03 +02:00
|
|
|
{
|
|
|
|
m2
|
|
|
|
}
|
|
|
|
|
|
|
|
static [void] s1()
|
|
|
|
{
|
|
|
|
s2
|
|
|
|
}
|
|
|
|
}
|
2017-01-16 22:31:14 +01:00
|
|
|
|
2016-07-19 22:52:03 +02:00
|
|
|
|
|
|
|
function m2()
|
|
|
|
{
|
|
|
|
$canary = Get-Canary
|
|
|
|
$canary['canaryM'] = 45
|
|
|
|
ImThrow
|
|
|
|
$canary['canaryM'] = 100
|
|
|
|
}
|
|
|
|
|
|
|
|
function s2()
|
|
|
|
{
|
|
|
|
$canary = Get-Canary
|
|
|
|
$canary['canaryS'] = 46
|
|
|
|
CallImThrow
|
|
|
|
$canary['canaryS'] = 100
|
|
|
|
}
|
|
|
|
|
|
|
|
function CallImThrow()
|
|
|
|
{
|
|
|
|
ImThrow
|
|
|
|
}
|
|
|
|
|
2017-01-16 22:31:14 +01:00
|
|
|
function ImThrow()
|
2016-07-19 22:52:03 +02:00
|
|
|
{
|
|
|
|
1 / 0
|
|
|
|
}
|
|
|
|
|
|
|
|
'@
|
|
|
|
|
|
|
|
It 'does not execute statements after function with exception called from instance method' {
|
2017-01-16 22:31:14 +01:00
|
|
|
|
|
|
|
# Put try-catch outside to avoid try-catch logic altering analysis
|
2016-07-19 22:52:03 +02:00
|
|
|
try {
|
|
|
|
|
|
|
|
$ps.AddScript($body).Invoke()
|
|
|
|
$ps.AddScript('$c = [C]::new(); $c.m1()').Invoke()
|
2017-01-16 22:31:14 +01:00
|
|
|
|
2016-07-19 22:52:03 +02:00
|
|
|
} catch {}
|
2017-01-16 22:31:14 +01:00
|
|
|
|
2016-07-19 22:52:03 +02:00
|
|
|
$canaryHashtable['canaryM'] | Should Be 45
|
|
|
|
}
|
|
|
|
|
|
|
|
It 'does not execute statements after function with exception called from static method' {
|
2017-01-16 22:31:14 +01:00
|
|
|
|
|
|
|
# Put try-catch outside to avoid try-catch logic altering analysis
|
2016-07-19 22:52:03 +02:00
|
|
|
try {
|
|
|
|
|
|
|
|
$ps.AddScript($body).Invoke()
|
|
|
|
$ps.AddScript('[C]::s1()').Invoke()
|
2017-01-16 22:31:14 +01:00
|
|
|
|
2016-07-19 22:52:03 +02:00
|
|
|
} catch {}
|
2017-01-16 22:31:14 +01:00
|
|
|
|
2016-07-19 22:52:03 +02:00
|
|
|
$canaryHashtable['canaryS'] | Should Be 46
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Context "No class is involved" {
|
|
|
|
It "functions calls continue execution by default" {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
$ps.AddScript( @'
|
|
|
|
|
|
|
|
$canaryHashtable = Get-Canary
|
|
|
|
function foo() { 1 / 0; $canaryHashtable['canary'] += 10 }
|
|
|
|
$canaryHashtable['canary'] = 1
|
|
|
|
foo
|
|
|
|
$canaryHashtable['canary'] += 100
|
|
|
|
|
|
|
|
'@).Invoke()
|
2017-01-16 22:31:14 +01:00
|
|
|
|
2016-07-19 22:52:03 +02:00
|
|
|
} catch {}
|
|
|
|
|
|
|
|
$canaryHashtable['canary'] | Should Be 111
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-25 23:01:41 +02:00
|
|
|
Describe "Exception error position" -Tags "CI" {
|
2016-07-19 22:52:03 +02:00
|
|
|
class MSFT_3090412
|
|
|
|
{
|
|
|
|
static f1() { [MSFT_3090412]::bar = 42 }
|
|
|
|
static f2() { throw "an error in f2" }
|
|
|
|
static f3() { "".Substring(0, 10) }
|
|
|
|
static f4() { dir nosuchfile -ea Stop }
|
|
|
|
}
|
|
|
|
|
|
|
|
It "Setting a property that doesn't exist" {
|
2017-01-16 22:31:14 +01:00
|
|
|
try {
|
2016-07-19 22:52:03 +02:00
|
|
|
[MSFT_3090412]::f1()
|
|
|
|
throw "f1 should have thrown"
|
|
|
|
} catch {
|
|
|
|
$_.InvocationInfo.Line | Should Match ([regex]::Escape('[MSFT_3090412]::bar = 42'))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
It "Throwing an exception" {
|
2017-01-16 22:31:14 +01:00
|
|
|
try {
|
2016-07-19 22:52:03 +02:00
|
|
|
[MSFT_3090412]::f2()
|
|
|
|
throw "f2 should have thrown"
|
|
|
|
} catch {
|
|
|
|
$_.InvocationInfo.Line | Should Match ([regex]::Escape('throw "an error in f2"'))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
It "Calling a .Net method that throws" {
|
2017-01-16 22:31:14 +01:00
|
|
|
try {
|
2016-07-19 22:52:03 +02:00
|
|
|
[MSFT_3090412]::f3()
|
|
|
|
throw "f3 should have thrown"
|
|
|
|
} catch {
|
|
|
|
$_.InvocationInfo.Line | Should Match ([regex]::Escape('"".Substring(0, 10)'))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
It "Terminating error" {
|
2017-01-16 22:31:14 +01:00
|
|
|
try {
|
2016-07-19 22:52:03 +02:00
|
|
|
[MSFT_3090412]::f4()
|
|
|
|
throw "f4 should have thrown"
|
|
|
|
} catch {
|
|
|
|
$_.InvocationInfo.Line | Should Match ([regex]::Escape('dir nosuchfile -ea Stop'))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-26 23:52:03 +02:00
|
|
|
Describe "Exception from initializer" -Tags "CI" {
|
2016-07-19 22:52:03 +02:00
|
|
|
class MSFT_6397334a
|
|
|
|
{
|
|
|
|
[int]$a = "zz"
|
|
|
|
MSFT_6397334a() {}
|
|
|
|
}
|
2017-01-16 22:31:14 +01:00
|
|
|
|
2016-07-19 22:52:03 +02:00
|
|
|
class MSFT_6397334b
|
|
|
|
{
|
|
|
|
[int]$a = "zz"
|
|
|
|
}
|
|
|
|
|
|
|
|
class MSFT_6397334c
|
|
|
|
{
|
|
|
|
static [int]$a = "zz"
|
|
|
|
static MSFT_6397334a() {}
|
|
|
|
}
|
2017-01-16 22:31:14 +01:00
|
|
|
|
2016-07-19 22:52:03 +02:00
|
|
|
class MSFT_6397334d
|
|
|
|
{
|
|
|
|
static [int]$a = "zz"
|
|
|
|
}
|
2017-01-16 22:31:14 +01:00
|
|
|
|
2016-07-19 22:52:03 +02:00
|
|
|
It "instance member w/ ctor" {
|
|
|
|
try {
|
|
|
|
[MSFT_6397334a]::new()
|
|
|
|
throw "[MSFT_6397334a]::new() should have thrown"
|
|
|
|
}
|
|
|
|
catch
|
|
|
|
{
|
|
|
|
$e = $_
|
|
|
|
$e.FullyQualifiedErrorId | Should Be InvalidCastFromStringToInteger
|
2017-01-16 22:31:14 +01:00
|
|
|
$e.InvocationInfo.Line | Should Match 'a = "zz"'
|
2016-07-19 22:52:03 +02:00
|
|
|
}
|
|
|
|
}
|
2017-01-16 22:31:14 +01:00
|
|
|
|
2016-07-19 22:52:03 +02:00
|
|
|
It "instance member w/o ctor" {
|
|
|
|
try {
|
|
|
|
[MSFT_6397334b]::new()
|
|
|
|
throw "[MSFT_6397334b]::new() should have thrown"
|
|
|
|
}
|
|
|
|
catch
|
|
|
|
{
|
|
|
|
$e = $_
|
|
|
|
$e.FullyQualifiedErrorId | Should Be InvalidCastFromStringToInteger
|
2017-01-16 22:31:14 +01:00
|
|
|
$e.InvocationInfo.Line | Should Match 'a = "zz"'
|
2016-07-19 22:52:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
It "static member w/ ctor" {
|
|
|
|
try {
|
|
|
|
$null = [MSFT_6397334c]::a
|
2017-02-16 01:40:51 +01:00
|
|
|
throw "No Exception!"
|
2016-07-19 22:52:03 +02:00
|
|
|
}
|
|
|
|
catch
|
|
|
|
{
|
2017-02-16 01:40:51 +01:00
|
|
|
$_.Exception | Should BeOfType System.TypeInitializationException
|
2016-07-19 22:52:03 +02:00
|
|
|
$e = $_.Exception.InnerException.InnerException.ErrorRecord
|
|
|
|
$e.FullyQualifiedErrorId | Should Be InvalidCastFromStringToInteger
|
2017-01-16 22:31:14 +01:00
|
|
|
$e.InvocationInfo.Line | Should Match 'a = "zz"'
|
2016-07-19 22:52:03 +02:00
|
|
|
}
|
|
|
|
}
|
2017-01-16 22:31:14 +01:00
|
|
|
|
2016-07-19 22:52:03 +02:00
|
|
|
It "static member w/o ctor" {
|
|
|
|
try {
|
|
|
|
$null = [MSFT_6397334d]::a
|
2017-02-16 01:40:51 +01:00
|
|
|
throw "No Exception!"
|
2016-07-19 22:52:03 +02:00
|
|
|
}
|
|
|
|
catch
|
|
|
|
{
|
2017-02-16 01:40:51 +01:00
|
|
|
$_.Exception | Should BeOfType System.TypeInitializationException
|
2016-07-19 22:52:03 +02:00
|
|
|
$e = $_.Exception.InnerException.InnerException.ErrorRecord
|
|
|
|
$e.FullyQualifiedErrorId | Should Be InvalidCastFromStringToInteger
|
2017-01-16 22:31:14 +01:00
|
|
|
$e.InvocationInfo.Line | Should Match 'a = "zz"'
|
2016-07-19 22:52:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|