On 3 Aug 2000, Alexandre Julliard wrote:

> "Deven T. Corzine" <[EMAIL PROTECTED]> writes:
> 
> > Still, why should libsafe affect normal C library calls like strcat()?
> > Surely you follow normal calling conventions for that call, right?  While
> > the bottom of the stack may look scrambled, the top of the stack (starting
> > with the call into strcat() that libsafe intercepts) should be perfectly
> > normal, shouldn't it?
> 
> Yes but libsafe needs to walk up the stack to locate the buffer, and
> there is no guarantee that the Windows app uses the stack layout that
> libsafe expects. Besides we are using multiple threads and stacks and
> I don't know if libsafe can cope with this at all.

Is it feasible for Wine to use compatible stack layouts (this would help
gdb also), or is this impossible due to the Windows API?

As for threads, I haven't seen libsafe kill either Netscape 4.72 (which
uses user-space threads) or Mozilla (which uses kernel threads), so I'd
guess it can handle it.

> > I see no reason to doubt (in this instance) that libsafe was doing its job
> > correctly.  After all, Wine is hardly bug-free; that's why it's marked as a
> > developer-only release.
> 
> Well, let's look at the trace:
> 
> > Call kernel32.348: GetModuleFileNameA(42d40000,40b061c4,00000200) ret=42d43871 
>fs=008f
>                                                  ^^^^^^^^^^^^^^^^^^
> The buffer at 0x40b061c4 is 0x200 bytes long according to the app
> 
> > Ret  kernel32.348: GetModuleFileNameA() retval=00000018 ret=42d43871 fs=008f
> > Call kernel32.773: lstrcpyA(40b061d0,42d4d0d0 "LF") ret=42d438bd fs=008f
> > Ret  kernel32.773: lstrcpyA() retval=40b061d0 ret=42d438bd fs=008f
> > Call kernel32.764: lstrcatA(40b061c4 "C:\\quickenw\\LF",42d4b5ac "MSP") 
>ret=42d438ce fs=008f
> > Detected an attempt to write across stack boundary.
> 
> We are adding a 3 chars string to a 14 chars string in a 512 chars
> buffer, this looks perfectly sane. libsafe is confused IMO.

The entire libsafe library is only 1705 lines of code in *.[ch] files.
Here is the key function that searches the stack:

/* Given an address 'addr' returns 0 iff the address does not point to
 * a stack variable.  Otherwise, it returns a positive number
 * indicating the number of bytes (distance) between the 'addr' and
 * the frame pointer it resides in.  Note: stack grows down, and
 * arrays/structures grow up.
 */
uint _libsafe_stackVariableP(void *addr)
{
        /*
         * (Vandoorselaere Yoann)
         * We have now just one cast.
         */
        void *fp, *sp;

        /*
         * (Arash Baratloo / Yoann Vandoorselaere)
         * use the stack address of the first declared variable
         * to get the 'sp' address in a portable way.
         */
        sp = &fp;

        /*
         * Stack grows downwards (toward 0x00).  Thus, if the stack pointer
         * is above (>) 'addr', 'addr' can't be on the stack.
         */
        if (sp > addr)
                return 0;

        /*
         * Note: the program name is always stored at 0xbfffffb (documented
         * in the book Linux Kernel).  Search back through the frames to
         * find the frame containing 'addr'.
         */
        fp = __builtin_frame_address(0);

        while ((sp < fp) && (fp <= stack_start)) {
                if (fp > addr)
                        return (fp - addr);     /* found the frame */

                fp = *(void **) fp;

        }
        /*
         * reached end of stack and did not find the appropriate frame.
         */
        return 0;
}

I don't know if this helps you at all, but it would be nice if gdb, libsafe
and other Unix programs depending on stack frames could work properly...

> And even if we assume that libsafe is right and that the buffer really
> is too short, this would be a bug in Quicken itself so there's
> absolutely nothing we can do about it.

Good point.  (But could it be a bug in non-Windows DLL's?)

Thanks for your input...

Deven

Reply via email to