The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: NoCforMe on October 11, 2011, 10:42:00 AM

Title: Rookie mistake: spot the error
Post by: NoCforMe on October 11, 2011, 10:42:00 AM
See if you can find the problem here:



; First, zero out entire structure:
PUSH EDI
LEA EDI, ofn
MOV ECX, SIZEOF OPENFILENAME
MOV ofn.lStructSize, ECX ;Stuff length while we have it.
XOR EAX, EAX
REP STOSB ;Zero it out.
POP EDI



This one survived about a half-hour of debugging, head scratching and swearing ...
("ofn" is the structure used by GetOpenFileName() )

I post this in hopes that others won't make this same mistake.
Title: Re: Rookie mistake: spot the error
Post by: jj2007 on October 11, 2011, 11:08:44 AM
Better?
LOCAL ofn:OPENFILENAME
push edi
lea edi, ofn
push OPENFILENAME
pop eax
stosd
xchg eax, ecx
sub ecx, 4
xor eax, eax
rep stosb ;zero it out.
pop edi
Title: Re: Rookie mistake: spot the error
Post by: dedndave on October 11, 2011, 11:27:34 AM
 :red
lea edi, ofn

:P
mov edi,offset ofn

szSaveAs        db 'Save As...',0
szFileTypes     db 'Text Files',0,'*.txt',0,'All Files',0,'*.*',0,0

        .CODE

;EAX = filename buffer address
;ECX = 0
;EDX = filename buffer length

        push    ecx                                                      ;lpTemplateName
        push    ecx                                                      ;lpfnHook
        push    ecx                                                      ;lCustData
        push    offset szFileTypes+13                                    ;lpstrDefExt - 'txt',0
        push    ecx                                                      ;nFileOffset/nFileExtension
        push    OFN_LONGNAMES or OFN_HIDEREADONLY or OFN_OVERWRITEPROMPT ;Flags or OFN_ENABLEHOOK or OFN_EXPLORER
        push    offset szSaveAs                                          ;lpstrTitle
        push    ecx                                                      ;lpstrInitialDir
        push    ecx                                                      ;nMaxFileTitle
        push    ecx                                                      ;lpstrFileTitle
        push    edx                                                      ;nMaxFile
        push    eax                                                      ;lpstrFile
        push    1                                                        ;nFilterIndex
        push    ecx                                                      ;nMaxCustFilter
        push    ecx                                                      ;lpstrCustomFilter
        push    offset szFileTypes                                       ;lpstrFilter
        push    ecx                                                      ;hInstance
        push    hWnd                                                     ;hwndOwner
        push    76                                                       ;lStructSize
        INVOKE  GetSaveFileName,esp
        add     esp,76                                                   ;sizeof OPENFILENAME
Title: Re: Rookie mistake: spot the error
Post by: sinsi on October 11, 2011, 11:34:05 AM
; First, zero out entire structure
; Then, fill in ofn.lStructSize

edit: jj forgot something?
Title: Re: Rookie mistake: spot the error
Post by: dedndave on October 11, 2011, 11:37:28 AM
it may not be a local - if it is, then use LEA EDI,ofn

push edi
mov edi,offset ofn
push sizeof OPENFILENAME
push (sizeof OPENFILENAME-4)/4
pop ecx
pop eax
stosd
xor eax,eax
rep stosd ;zero out the rest of it
pop edi


of course, we shouldn't do this in the campus, but it's fun   :bg
and, NoCforMe isn't a real n00b, anyways
Title: Re: Rookie mistake: spot the error
Post by: jj2007 on October 11, 2011, 11:43:39 AM
Quote from: sinsi on October 11, 2011, 11:34:05 AM
; First, zero out entire structure
; Then, fill in ofn.lStructSize

edit: jj forgot something?

No :bg
Title: Re: Rookie mistake: spot the error
Post by: drizz on October 11, 2011, 11:54:13 AM

PUSH EDI
LEA EDI, ofn
MOV ECX, SIZEOF OPENFILENAME
MOV ofn.lStructSize, ECX ;Stuff length while we have it.
XOR EAX, EAX
REP STOSB ;Zero it out.
POP EDI

MOV ofn.lStructSize, SIZEOF OPENFILENAME; :-)

Title: Re: Rookie mistake: spot the error
Post by: jj2007 on October 11, 2011, 12:28:22 PM
@drizz: as it stands, 36 bytes; with small changes...
LOCAL ofn:OPENFILENAME
push edi
lea edi, ofn
mov ecx, sizeof OPENFILENAME
;MOV ofn.lStructSize, ECX ;Stuff length while we have it.
xor eax, eax
rep stosb ;zero it out.
pop edi
m2m ofn.lStructSize, sizeof OPENFILENAME;
ret

... down to 31, still 2 more than mine ;)
Title: Re: Rookie mistake: spot the error
Post by: oex on October 11, 2011, 12:47:21 PM
mov esi, alloc(SIZE OPENFILENAME)
mov [esi].OPENFILENAME.lStructSize, SIZE OPENFILENAME;

Smaller than 31 bytes?

:lol I know technically not but size is relative
Title: Re: Rookie mistake: spot the error
Post by: jj2007 on October 11, 2011, 12:55:31 PM
Quote from: oex on October 11, 2011, 12:47:21 PM
Smaller than 31 bytes?

Sorry, it's 32 bytes ;-)

MyTesto proc arg1, arg2
push esi
mov esi, alloc(SIZE OPENFILENAME)
mov [esi].OPENFILENAME.lStructSize, SIZE OPENFILENAME
; ...
free esi
pop esi
ret
MyTesto endp
Title: Re: Rookie mistake: spot the error
Post by: oex on October 11, 2011, 12:56:00 PM
Quote from: jj2007 on October 11, 2011, 12:55:31 PM
Quote from: oex on October 11, 2011, 12:47:21 PM
Smaller than 31 bytes?

Sorry, it's 32 bytes ;-)

:lol.... Well I beat the almighty Drizz.... I am not ashamed.... And my code is pretty neat and tidy :lol
Title: Re: Rookie mistake: spot the error
Post by: dedndave on October 11, 2011, 01:22:45 PM
Quote from: dedndave on October 11, 2011, 11:37:28 AM
it may not be a local - if it is, then use LEA EDI,ofn

push edi
mov edi,offset ofn
push sizeof OPENFILENAME
push (sizeof OPENFILENAME-4)/4
pop ecx
pop eax
stosd
xor eax,eax
rep stosd ;zero out the rest of it
pop edi

18 bytes if ofn is global
16 bytes if ofn is local
Title: Re: Rookie mistake: spot the error
Post by: jj2007 on October 11, 2011, 01:38:45 PM
Dave,
It's 28 bytes with frame etc, but still: 1 byte shorter than my version - you win :cheekygreen:
Title: Re: Rookie mistake: spot the error
Post by: dedndave on October 11, 2011, 01:42:03 PM
 :lol

i dunno how i miscounted the bytes, though
Title: Re: Rookie mistake: spot the error
Post by: jj2007 on October 11, 2011, 01:48:17 PM
Quote from: dedndave on October 11, 2011, 01:42:03 PM
:lol

i dunno how i miscounted the bytes, though

it's the overhead.
MyTestdave_s:  ; 28
MyTestdave proc arg1, arg2
LOCAL ofn:OPENFILENAME
dave_s::  ; 16
push edi
lea edi, ofn
push sizeof OPENFILENAME
push (sizeof OPENFILENAME-4)/4
pop ecx
pop eax
stosd
xor eax,eax
rep stosd ;zero out the rest of it
pop edi
dave_endp::
ret
MyTestdave endp
MyTestdave_endp:
Title: Re: Rookie mistake: spot the error
Post by: dedndave on October 11, 2011, 01:52:27 PM
ok - i wasn't counting the code i didn't write   :P
Title: Re: Rookie mistake: spot the error
Post by: NoCforMe on October 11, 2011, 06:14:39 PM
Guys, guys, guys: You're completely missing the point. You can't see the forest for the trees.

The code I posted doesn't work correctly. There's a glaring error in it (hence the "rookie mistake"). I finally fixed it, and I posted this as a possible help to others.

It wasn't intended as an exercise on how to generate the absolute smallest code.

I gave you a problem with changing a tire on a car and you all responded with stuff on quantum mechanics. Sheesh.

So class, can anyone tell me what the problem was with my code? (BTW, the structure is a LOCAL, but it doesn't make any difference.)
Title: Re: Rookie mistake: spot the error
Post by: oex on October 11, 2011, 06:22:29 PM
Quote from: NoCforMe on October 11, 2011, 06:14:39 PM
It wasn't intended as an exercise on how to generate the absolute smallest code.

So class, can anyone tell me what the problem was with my code?

It wasn't small enough?
Title: Re: Rookie mistake: spot the error
Post by: drizz on October 11, 2011, 06:23:32 PM
jj, I didn't realize it was a pissing competition.   :red



Title: Re: Rookie mistake: spot the error
Post by: dedndave on October 11, 2011, 06:29:59 PM
Quote from: NoCforMe on October 11, 2011, 06:14:39 PM
Guys, guys, guys: You're completely missing the point. You can't see the forest for the trees.

The code I posted doesn't work correctly. There's a glaring error in it (hence the "rookie mistake"). I finally fixed it, and I posted this as a possible help to others.

It wasn't intended as an exercise on how to generate the absolute smallest code.

I gave you a problem with changing a tire on a car and you all responded with stuff on quantum mechanics. Sheesh.

So class, can anyone tell me what the problem was with my code? (BTW, the structure is a LOCAL, but it doesn't make any difference.)

:lol

; First, zero out entire structure:
PUSH EDI
LEA EDI, ofn
MOV ECX, SIZEOF OPENFILENAME
MOV ofn.lStructSize, ECX ;Stuff length while we have it.
XOR EAX, EAX
REP STOSB ;Zero it out.
POP EDI

the problem that i see is that you set the lStructSize member, then overwrite it with 0(s)
that probably generates an ERROR_INVALID_PARAMETER or ERROR_INVALID_DATA error
Title: Re: Rookie mistake: spot the error
Post by: NoCforMe on October 11, 2011, 06:33:28 PM
Not even close, and no cigar.

Wow, maybe it wasn't that glaring an error after all. As I said, I was banging my head against the keyboard for a good half hour before I spotted it.

Hint: the error I got back from GetOpenFileName() was CDERR_STRUCTSIZE. (That's too big a hint, actually. And you have to call CommDlgExtendedError() to retrieve the error code.)

@Dave: Bingo! You got it. (Actual error is shown above.)
Title: Re: Rookie mistake: spot the error
Post by: jj2007 on October 11, 2011, 06:34:41 PM
Quote from: drizz on October 11, 2011, 06:23:32 PM
jj, I didn't realize it was a pissing competition.   :red

Quote from: dedndave on October 11, 2011, 11:37:28 AM
of course, we shouldn't do this in the campus, but it's fun   :bg

OK, maybe you are right that we shouldn't play such games in the Campus. The Forum rules clearly say it's a humour-free zone :red

Therefore, for all those who want to learn assembly in the Campus (OP code):

MOV ofn.lStructSize, ECX ;Stuff length while we have it. <<< that's ok

XOR EAX, EAX
LEA EDI, ofn      ; that points to the same memory as ofn.lStructSize
REP STOSB      ; and here we mercilessly overwrite the ecx value



Still, those who want to write correct and elegant code should study Dave's example. Even in the Campus :bg
Title: Re: Rookie mistake: spot the error
Post by: dedndave on October 11, 2011, 06:35:16 PM
Quotethe problem that i see is that you set the lStructSize member, then overwrite it with 0(s)

i thought that's what i said   :P
Title: Re: Rookie mistake: spot the error
Post by: NoCforMe on October 11, 2011, 06:39:15 PM
Yes, the co-winners are jj and Dave. You may collect your prize (a brand-new shrink-wrapped copy of DOS 3.1) as you leave.

By the way, I vote in favor of fun, at all times. We can do things the correct way, or we can do things the fun way ...
Title: Re: Rookie mistake: spot the error
Post by: jj2007 on October 11, 2011, 06:40:40 PM
Quote from: NoCforMe on October 11, 2011, 06:14:39 PM
Guys, guys, guys: You're completely missing the point. You can't see the forest for the trees.

The code I posted doesn't work correctly.

We surely saw the forest. All examples posted work correctly, and yes everybody saw the "glaring mistake" but nobody in here smokes cigars  :wink
Title: Re: Rookie mistake: spot the error
Post by: qWord on October 11, 2011, 06:42:14 PM
... and as we all know, the direction flag is a constant :wink
Title: Re: Rookie mistake: spot the error
Post by: dedndave on October 11, 2011, 06:52:41 PM
seeing as we are on the subject of the OPENFILENAME structure size   :bg

if you look on MSDN, it is defined as
typedef struct tagOFN {
  DWORD         lStructSize;
  HWND          hwndOwner;
  HINSTANCE     hInstance;
  LPCTSTR       lpstrFilter;
  LPTSTR        lpstrCustomFilter;
  DWORD         nMaxCustFilter;
  DWORD         nFilterIndex;
  LPTSTR        lpstrFile;
  DWORD         nMaxFile;
  LPTSTR        lpstrFileTitle;
  DWORD         nMaxFileTitle;
  LPCTSTR       lpstrInitialDir;
  LPCTSTR       lpstrTitle;
  DWORD         Flags;
  WORD          nFileOffset;
  WORD          nFileExtension;
  LPCTSTR       lpstrDefExt;
  LPARAM        lCustData;
  LPOFNHOOKPROC lpfnHook;
  LPCTSTR       lpTemplateName;
#if (_WIN32_WINNT >= 0x0500)
  void          *pvReserved;
  DWORD         dwReserved;
  DWORD         FlagsEx;
#endif
} OPENFILENAME, *LPOPENFILENAME;


the new members apply to everything windows 2000 and above
however, the windows.inc file defines the structure without them

if you refer to this post, you will see that i hard-code the size value so that it assembles the same if windows.inc is updated
http://www.masm32.com/board/index.php?topic=17525.msg147288#msg147288
Title: Re: Rookie mistake: spot the error
Post by: NoCforMe on October 11, 2011, 07:02:36 PM
Quote from: qWord on October 11, 2011, 06:42:14 PM
... and as we all know, the direction flag is a constant :wink

Good point, and I thought of that as I was coding this: what if someone leaves the direction flag set?

Made me think that, while I've never seen the innards of Windows code (I mean the OS), I imagine every place that uses string moves/stores/scans probably does something like this:


pushf
cld

(operation involving STOSx, SCASx, MOVSx, CMPSx}

popf


in order to "bulletproof" it, don't you think?
Title: Re: Rookie mistake: spot the error
Post by: jj2007 on October 11, 2011, 07:10:29 PM
By default, the direction flag is cleared. If you have to set it (rare case), it's your duty to clear it on exit. You would use cld, not a slow pushfd/popfd pair.
Title: Re: Rookie mistake: spot the error
Post by: dedndave on October 11, 2011, 07:10:48 PM
it's part of the ABI definition - that the DF should remain cleared
in fact, some API functions will hang or have other problems if called with it set - some get really slow

as a side note, instructions that set or clear this flag (POPFD, CLD, STD) execute surprisingly slow

if i am interested in speed, i will sometimes test the flag bit, executing CLD only if it is set
Title: Re: Rookie mistake: spot the error
Post by: NoCforMe on October 11, 2011, 07:13:44 PM
Ah, I see: yet another way to crash Windoze:

STD--> Boom!

(And of course I mean STD without a corresponding CLD.)
Title: Re: Rookie mistake: spot the error
Post by: MichaelW on October 11, 2011, 07:23:33 PM
Quote from: NoCforMe on October 11, 2011, 07:13:44 PM
Ah, I see: yet another way to crash Windoze

It won't crash Windows, but it may cause your app to crash.