Windbg - <HRESULT 0x80004002>, invalid cast, alias as vs. aS

0

Good day,

I have a Windbg script that iterates around the frames of a stack using a .do loop. For each frame it uses !for_each_local and $spat ("@#Local","foo") to match for things I'm interested in getting an initial look at. I then use dx @$t2 = to assign and finally print out what I'm interested in, i.e. dx @$t2 = ((foobase*) this)->m_current->m_name - mostly this works fine.

Every now and again, there'll be a this in a frame that can't be cast successfully with the dx, so it's like barbase it would need, not foobase... the dx seems OK because I've wrapped it in a .foreach (output { dx @$t2 = ((foobase*) this)->m_current->m_name }) {} so it ends up containing something that causes the script to exit (that's despite trying a .catch).

At first I didn't really realise what was going on, but doing a .printf "%ma\n", @$t2 helped me to ascertain the contents is <HRESULT 0x80004002> which I think implies invalid cast - which, if so, makes perfect sense. My script line is using foobase when it would need barbase.

If I'm correct, what I'm looking for is a way to check that, before I delve into the script further and try to access details I know will cause the script to exit.

I seem to have come up with a convoluted way of doing it... but I wanted to ask if there was anything better...

.frame 0a     $$ a frame with barbase, not foobase
dx @$t2 = ((foobase*) this)->m_name
.printf "%ma\n", @$t2     $$ prints <HRESULT 0x80004002>
as /c CastCheck .printf "%ma", @$t2
.if ($spat(@"${CastCheck}","<HRESULT 0x80004002>") = 1) { .printf "yes" } .else { .printf "no" }     $$ prints yes

Is there a way to check if $t2 contains an indicator of invalid cast without using an alias?

I ask this because using the alias has caused me much confusion... in my script (for it to work, and it does seem to work quite well) I've had to use aS instead of as (I can use as fine from the Command Window, and I don't really understand why I need to change to aS from reading the documentation) and I also need to end the line with a semi-colon (unlike any other line in my script) and I need to use ad /q CastCheck; immediately before the aS, and then quickly afterwards, otherwise the alias seems to get lost, somehow... so you can tell the use of this alias has caused me a little trouble.

So, is there either a) an easy way to pre-check whether what I'm looking at is foobase or barbase, or b) post-check after the cast attempt whether $t2 contains this <HRESULT 0x80004002>? If I do a .printf "%d", @$t2 it shows 5... does 5 represent something too?

Or, indeed, any other ideas (or questions).

EDIT:

I'm going to try and illustrate what I mean with 2 short runs of code done in the Command Window... where frame 00 contains a this that can be cast to foobase and then the .printf works nicely, and where frame 0a contains a this that's a barbase (but my script still doesn't expect it and I want to be able to cater for it)... the dx still puts something in $t10... I want to be able to detect that it's garbage (or pre-detect I shouldn't even try the dx, if this is barbase, as it's pointless and I'm not interested in it anyway).

0:038> .frame 00
00 00000006`3e2bc930 00007ffe`926293a8 BlahBlahBlah 
0:038> dx @$t10 = ((foobase *) this)->m_name
@$t10 = ((foobase *) this)->m_name                 : 0x869c7b8 : "nice string" [Type: char *]
0:038> .printf "%ma\n", @$t10
nice string

This is where the this is a barbase, and doesn't even have a m_name:

0:038> .frame 0a
0a 00000006`3e2bd220 00007ffe`91ec7780 BlahBlahBlah 
0:038> dx @$t10 = ((foobase *) this)->m_name
@$t10 = ((foobase *) this)->m_name                 : 0x2265646f00000005 : "--- memory read error at address 0x2265646f`00000005 ---" [Type: char *]
0:038> .printf "%ma\n", @$t10
<HRESULT 0x80004002>

When put inside a loop I've found that the script will exit with a Memory access error on frame 0a when I try to check the length of the string I believe to have been returned by dx.

Basically, in the second block I want a way of either checking $t10 for something that is not a nice string (probably this <HRESULT 0x80004002>?) or, even better, not doing the dx and .printf at all, because I was able to check before that this was a barbase, not a foobase.

Is that making any more sense, or should I start again?

casting
alias
windbg
asked on Stack Overflow Mar 27, 2019 by Hippogriff • edited Mar 27, 2019 by Hippogriff

2 Answers

1

well you attempted but it is still vague

can you explain what is necessity to do .frame
and then dx this ??

you can cast any address to any type

for example in the first run I am casting the this to a proper type and enumerating all Frames

in the next run I am casting to a bogus type and enumerating

in both of this only one frame has a this pointer

when it is proper type it returns proper member

when it is bogus well it returns bogus stuff

0:000> !for_each_frame dx ((Student *) this)->Name
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
00 000000c5`d6f6f8c0 00007ff7`2818117c thisptr!Student::PrintStudent+0x9 [f:\src\thisptr\thisptr.cpp @ 20] 
((Student *) this)->Name                 : 0x7ff7282153e0 : "dave" [Type: char *]
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
01 000000c5`d6f6f8f0 00007ff7`281b6c20 thisptr!main+0x2c [f:\src\thisptr\thisptr.cpp @ 33] 
Error: Unable to bind name 'this'

it found a this but it cant find the Member Name

0:000> !for_each_frame dx ((ntdll!_EPROCESS *) this)->Name
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
00 000000c5`d6f6f8c0 00007ff7`2818117c thisptr!Student::PrintStudent+0x9 [f:\src\thisptr\thisptr.cpp @ 20] 
Error: Unable to bind name 'Name' <<<<<<
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
01 000000c5`d6f6f8f0 00007ff7`281b6c20 thisptr!main+0x2c [f:\src\thisptr\thisptr.cpp @ 33] 
Error: Unable to bind name 'this' 

btw you know what type a this pointer is already so why are you casting it ??

you can find the type of this ptr with various commands some of which are shown below

0:000> dx this
this                 : 0xc5d6f6f910 [Type: Student *] <<<
    [+0x000] Roll             : 1 [Type: int]
    [+0x008] Name             : 0x7ff7282153e0 : "dave" [Type: char *]
    [+0x010] Marks            : 72.300000 [Type: double]


0:000> ?? this 
class Student * 0x000000c5`d6f6f910  <<<
   +0x000 Roll             : 0n1
   +0x008 Name             : 0x00007ff7`282153e0  "dave"
   +0x010 Marks            : 72.299999999999997158 


0:000> x /t this
000000c5`d6f6f8f0 class Student * this = 0x000000c5`d6f6f910  <<<


0:000> x /v /t this
prv local  000000c5`d6f6f8f0    8 class Student * this = 0x000000c5`d6f6f910

0:000> dt this 
Local var @ 0xc5d6f6f8f0 Type Student*
0x000000c5`d6f6f910 
   +0x000 Roll             : 0n1
   +0x008 Name             : 0x00007ff7`282153e0  "dave"
   +0x010 Marks            : 72.299999999999997158 


0:000> dt /v this 
Local var [AddrFlags 90  AddrOff 0000000000000030  Reg/Val rsp (7)] @ 0xc5d6f6f8f0 Type Student*
0x000000c5`d6f6f910 class Student, 5 elements, 0x18 bytes
   +0x000 Roll             : 0n1
   +0x008 Name             : 0x00007ff7`282153e0  "dave"
   +0x010 Marks            : 72.299999999999997158 
   <function> Student     void (
    int, 
    char*, 
    double)+000000c5`d6f6f910
   <function> PrintStudent     void ( void )+000000c5`d6f6f910

0:000> dt /v /t this 
Local var [AddrFlags 90  AddrOff 0000000000000030  Reg/Val rsp (7)] @ 0xc5d6f6f8f0 Type Student*
0x000000c5`d6f6f910 class Student, 5 elements, 0x18 bytes
   +0x000 Roll             : 0n1
   +0x008 Name             : 0x00007ff7`282153e0  "dave"
   +0x010 Marks            : 72.299999999999997158 
   <function> Student     void (
    int, 
    char*, 
    double)+000000c5`d6f6f910
   <function> PrintStudent     void ( void )+000000c5`d6f6f910
answered on Stack Overflow Mar 28, 2019 by blabb
0

adding another answer to emphasize the usage of javascript instead of parsing text

javascript script support was added to windbg quiet a long time back and it is being improved a lot

(to try the latest javascript additions use the windbg preview in latest windows 10 version)

x /v /t or dv /t provides the type of the this pointer

javascript provides a targetType property for these object

here is how to use it

create a .js file foo.js with the contents below

function typethis ( somevar ) 
{
    host.diagnostics.debugLog( somevar.targetType ,  "\t" , JSON.stringify(somevar) , "\n"  )
}

in windbg do

.load jsprovider
.scriptload x:\..\\..\foo.js
dx @$scriptcontents.functionname(argument) to run the script

and the results will be

0:000> .load jsprovider
0:000> .scriptload f:\wdscr\typthis.js
JavaScript script successfully loaded from 'f:\wdscr\typthis.js'
0:000> dx @$scriptContents.typethis( this )
Student *   {"Roll":1,"Name":{},"Marks":72.3}
@$scriptContents.typethis( this )
answered on Stack Overflow Mar 28, 2019 by blabb

User contributions licensed under CC BY-SA 3.0