Re: [python-win32] Memory access violation using pywin32 as WSH

2022-11-30 Thread Bob Kline
We have a glimmer of hope. Just got a fresh build of xmetal.exe from the
vendor, and it's not failing in my initial tests. Much more testing to do,
but this looks very promising. I've asked them to tell me about the fix,
but they've dodged that question so far.

So let me stop here and tell you how grateful I am for your patient
assistance. And (of course) for creating this package in the first place.


Many thanks,
Bob
___
python-win32 mailing list
python-win32@python.org
https://mail.python.org/mailman/listinfo/python-win32


Re: [python-win32] Memory access violation using pywin32 as WSH

2022-11-30 Thread Bob Kline
On Tue, Nov 29, 2022 at 6:19 PM Mark Hammond  wrote:
>
> On 30/11/2022 3:06 am, Bob Kline wrote:
> 
>> As a side note, imp.new_module() [3] was deprecated back in Python 3.4.
>
> Yep, you are looking at a very old version.

True, but I checked HEAD for the main branch, and the code [1] is
still calling the deprecated method.

Cheers,
Bob

[1] 
https://github.com/mhammond/pywin32/blob/main/com/win32comext/axscript/client/pyscript.py#L217
___
python-win32 mailing list
python-win32@python.org
https://mail.python.org/mailman/listinfo/python-win32


Re: [python-win32] Memory access violation using pywin32 as WSH

2022-11-30 Thread Bob Kline
On Tue, Nov 29, 2022 at 6:23 PM Mark Hammond  wrote:

> The close method is 

Microsoft is not helping much here. The documentation to which you
linked has no information about this method other than that it returns
a 32-bit integer for which no semantics are given, and that it lives
in the Microsoft.VisualStudio.Debugger.Interop namespace. I'm having a
little difficulty figuring out how that namespace would be appropriate
for their general scripting language interface.

> It's worth pointing out that any "obvious" bug in pywin32
> here would probably be able to be reproduced in, and
> reported by, the various other hosts, including cscript.exe
> and wscript.exe (which themselves are just active script
> hosts, just like your problematic host)

I had that thought, too. But then I realized that cscript.exe and
wscript.exe use a model of a separate process for each invocation of a
single script. That script can be very complicated, but it's loaded,
parsed, and executed once. I can run a pretty complicated Python macro
once per XMetaL session (by which I mean separate process) without any
problem. If I want to run a script twice using cscript.exe I have to
launch two separate cscript.exe processes.

It occurred to me that a better comparison might be using Internet
Explorer, which can presumably run multiple scripts multiple times in
a single process. So I grabbed form.htm from axscript/Demos/client/ie
(I promise I'm looking at the correct repository now ), thinking I'd
see if clicking the Submit button multiple times caused any problems.
Unfortunately, the scripts didn't fire at all, and the browser's
console window didn't provide any explanation as to why. (By the way,
I had to fix the third INPUT element, which was malformed, as its tag
was missing its right angle bracket delimiter. IE may have been
tolerant of that broken syntax at some time in the past, but it
doesn't accept it now.)

Cheers,
Bob
___
python-win32 mailing list
python-win32@python.org
https://mail.python.org/mailman/listinfo/python-win32


Re: [python-win32] Memory access violation using pywin32 as WSH

2022-11-30 Thread Bob Kline
On Tue, Nov 29, 2022 at 6:19 PM Mark Hammond  wrote:

> ... the ax object isn't going to have a Reset - so whatever that's trying to 
> do isn't getting done.

How would we go about finding out what that missing method was
supposed to do, so that we can know whether the failure to do it is
related to the problem? One of the frustrations here is that while the
documentation for the host application says "You can use any scripting
language that conforms to the Microsoft Scripting Language Interface"
trying to find the specification for that interface on Microsoft's web
site turns up nothing. Has Microsoft published the spec and then gone
to the trouble of extirpating every trace of it? Do you have a copy?

> ... Yep, you are looking at a very old version.

Sorry for the old link. Don't have any idea how I ended up in that
repository. Obviously the copy I was hacking to get my debug logging
was the real thing, installed by pip. I'm suitably embarrassed that I
didn't notice that they didn't match.

> ... when I say I'm hoping to see a stack trace, I mean a native stack trace

I'll see what I can do to produce one.

Thanks,
Bob
___
python-win32 mailing list
python-win32@python.org
https://mail.python.org/mailman/listinfo/python-win32


Re: [python-win32] Memory access violation using pywin32 as WSH

2022-11-29 Thread Mark Hammond

On 30/11/2022 9:09 am, Bob Kline wrote:


So at least part of that puzzle is cleared up, though it's still 
somewhat unsettling that only seven calls to ScriptItem.Close() are 
made, regardless of how many ScriptItem objects have been instantiated 
during a session.



The close method is 
https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.debugger.interop.iactivescript.close?view=visualstudiosdk-2019, 
so it's the responsibility of the host to call that. I agree it's a bit 
of a red flag, and may point to confusion in the host about object 
lifetimes, which could certainly end up causing what you are seeing. 
It's worth pointing out that any "obvious" bug in pywin32 here would 
probably be able to be reproduced in, and reported by, the various other 
hosts, including cscript.exe and wscript.exe (which themselves are just 
active script hosts, just like your problematic host)


Mark
___
python-win32 mailing list
python-win32@python.org
https://mail.python.org/mailman/listinfo/python-win32


Re: [python-win32] Memory access violation using pywin32 as WSH

2022-11-29 Thread Mark Hammond

On 30/11/2022 3:06 am, Bob Kline wrote:

Cranking up the microscope (or spelunking deeper, whichever metaphor
you prefer), the first thing I'll say is that this code is devilishly
complex.

Here's what I've found in the latest pass.

First, there's a minor bug at line 353 of pyscript.py [1], where
globalNameSpaceModule is set to None when it's
self.globalNameSpaceModule which should be set to None. The bug is
currently innocuous, as the only invocation of the method in which
that assignment is made in this version of the code is from
PyScript.Close(), and that method makes the correct assignment:


Oops, yeah, that looks like a bug (but note that the links you are using 
are from sublime text, not from pywin32 - it looks quite old - the 
correct link is 
https://github.com/mhammond/pywin32/blob/main/com/win32comext/axscript/client/pyscript.py 
where it is at line 416.



 self.globalNameSpaceModule = None

It seems to me that there's a more serious problem at line 350 of that
module [2], where that same method appears to be invoking a method
which does not exist, at least as far as I can determine (bearing in
mind that I might not completely understand all the nuances of the
tricky code here).

 self.globalNameSpaceModule.ax._Reset_()

Working backward, to see if I can figure out where _Reset_ would be
defined, I found this code in the PyScript class:

 def InitNew(self):
 framework.COMScript.InitNew(self)
 import imp
 self.scriptDispatch = None
 self.globalNameSpaceModule = imp.new_module("__ax_main__")
 self.globalNameSpaceModule.__dict__['ax'] = AXScriptAttribute(self)
 

It's not completely clear how this method gets invoked (I don't see
any calls to it, but I do see that "InitNew" appears as one of the
strings in the _public_methods_ array attribute of the base class),


Yes, that's a COM method, so called by the host - see 
https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.debugger.interop.iactivescriptparse64. 
That try/except block was probably just handling the case where Reset is 
called twice without an InitNew call in between (in which case 
self.globalNameSpaceModule is None, so will not have a .ax attribute) - 
but I agree with your analysis that even if it *did* have that 
attribute, the ax object isn't going to have a Reset - so whatever 
that's trying to do isn't getting done.



As a side note, imp.new_module() [3] was deprecated back in Python 3.4.


Yep, you are looking at a very old version.


I'm attaching the logs I captured. One set is for a session in which
the macro was only invoked once (and therefore didn't result in any
observable failures) and the other for the session in which the macro
was invoked twice, with the symptoms described earlier in this thread.
Please let me know if anything else stands out as potentially useful


Nothing stands out there :( But that's not particularly surprising as it 
really should be impossible for bugs in that .py code to crash the 
process - strangeness could happen, but an access violation shouldn't be 
possible. Something like a COM reference counting bug in (either in 
axscript or in the host) could explain this.


Re your other message, when I say I'm hoping to see a stack trace, I 
mean a native stack trace, as should be shown in the event viewer or in 
a JIT debugger, which will show the symbols in the various DLLs rather 
than the Python functions. Eg, it showing the crash happening in, say, 
IUnknown::Release would imply such a reference counting bug, or if it 
instead shows it in some other COM method it would help narrow down the 
problem area. Unfortunately, without knowing your environment I can't 
offer specific advice about how to get it - but running the crashing 
program under any Visual Studio version would certainly offer it.


HTH,

Mark

___
python-win32 mailing list
python-win32@python.org
https://mail.python.org/mailman/listinfo/python-win32


Re: [python-win32] Memory access violation using pywin32 as WSH

2022-11-29 Thread Bob Kline
One more data point. I added a bit more to my logging and learned that the
seven calls to the ScriptItem constructor each time the macro is invoked
are for the seven global objects which the host application (XMetaL) makes
available to the scripts:

 * FormDriver
 * ActiveDocument
 * Selection
 * Application
 * FormFuncs
 * ResourceManager

So at least part of that puzzle is cleared up, though it's still somewhat
unsettling that only seven calls to ScriptItem.Close() are made, regardless
of how many ScriptItem objects have been instantiated during a session.

Cheers,
Bob
___
python-win32 mailing list
python-win32@python.org
https://mail.python.org/mailman/listinfo/python-win32


Re: [python-win32] Memory access violation using pywin32 as WSH

2022-11-29 Thread Bob Kline
Cranking up the microscope (or spelunking deeper, whichever metaphor
you prefer), the first thing I'll say is that this code is devilishly
complex.

Here's what I've found in the latest pass.

First, there's a minor bug at line 353 of pyscript.py [1], where
globalNameSpaceModule is set to None when it's
self.globalNameSpaceModule which should be set to None. The bug is
currently innocuous, as the only invocation of the method in which
that assignment is made in this version of the code is from
PyScript.Close(), and that method makes the correct assignment:

self.globalNameSpaceModule = None

It seems to me that there's a more serious problem at line 350 of that
module [2], where that same method appears to be invoking a method
which does not exist, at least as far as I can determine (bearing in
mind that I might not completely understand all the nuances of the
tricky code here).

self.globalNameSpaceModule.ax._Reset_()

Working backward, to see if I can figure out where _Reset_ would be
defined, I found this code in the PyScript class:

def InitNew(self):
framework.COMScript.InitNew(self)
import imp
self.scriptDispatch = None
self.globalNameSpaceModule = imp.new_module("__ax_main__")
self.globalNameSpaceModule.__dict__['ax'] = AXScriptAttribute(self)


It's not completely clear how this method gets invoked (I don't see
any calls to it, but I do see that "InitNew" appears as one of the
strings in the _public_methods_ array attribute of the base class),
but I can tell from my logging that it does get called. However it
gets invoked, that means that the _Reset_() call being made above is
on an instance of the AXScriptAttribute class, which—as far as I can
tell—has no _Reset_() method (and no base class from which it could
inherit that method). This is confirmed by an exception which is
caught at shutdown time in the PyScript.ResetNamespace() method. The
handler for that exception looks like this:

except AttributeError:
pass # ???

The obvious questions would be
  * what was the non-existent method expected to do?
  * could the fact that it didn't get done be causing my problem?

The ResetNamespace method has no documentation, so all I would have
for answers to those questions would be wild guesses.

As a side note, imp.new_module() [3] was deprecated back in Python 3.4.

I'm attaching the logs I captured. One set is for a session in which
the macro was only invoked once (and therefore didn't result in any
observable failures) and the other for the session in which the macro
was invoked twice, with the symptoms described earlier in this thread.
Please let me know if anything else stands out as potentially useful
in the logs.

Cheers,
Bob

[1] 
https://github.com/SublimeText/Pywin32/blob/master/lib/x64/win32comext/axscript/client/pyscript.py#L353
[2] 
https://github.com/SublimeText/Pywin32/blob/master/lib/x64/win32comext/axscript/client/pyscript.py#L350
[3] https://docs.python.org/3/library/imp.html#imp.new_module


pyscript-logs.tar
Description: Unix tar archive
___
python-win32 mailing list
python-win32@python.org
https://mail.python.org/mailman/listinfo/python-win32


Re: [python-win32] Memory access violation using pywin32 as WSH

2022-11-29 Thread Bob Kline
On Mon, Nov 28, 2022 at 7:24 PM Mark Hammond  wrote:
> ...
> The absolute best thing for us would be to reproduce the crash in the
> test code at
> https://github.com/mhammond/pywin32/tree/main/com/win32comext/axscript/test.

I presume that would depend on getting the vendor to open the kimono
and reveal which calls to the scripting engine the application is
making at what times. One handicap I'm dealing with is the fact that I
don't have a good understanding of what the "Microsoft Scripting
Language Interface" is. Searching for it in MSDN turns up only an
article ("Using COM Objects in Windows Script Host") which describes
running scripts using WScript.exe or CScript.exe. It seems unlikely
that the XMetaL application would be launching a fresh CScript.exe or
WScript.exe process every time a macro is invoked (with the massive
performance hit that would introduce), so presumably they have a copy
of this elusive interface specification which they're following to
emulate what those applications are doing.

> The next best thing would probably be a stack trace of the crash.

Any tips for how I would go about obtaining such a thing? I suppose
it's possible that the crash happens while some Python code is
running, and I'd be able to wrap that code in a try block and dump a
stack track to a file (assuming I can guess what code that would be).
But it seems at least as likely that when the crash occurs (that is,
when the dialog window appears at logoff time reporting the memory
access violation) we are no longer anywhere near any of the Python
code. Perhaps the Python code (or C code underneath it) has done
something naughty (for example, trashing a pointer somewhere) well
before the actual crash happens and it only manifests itself at logoff
time when the OS forces the application to let go and really shut
down.

Any advice you can provide to help me get a better understanding of
how the moving parts interact and what I should try next would be
immensely appreciated.

Many thanks,
Bob
___
python-win32 mailing list
python-win32@python.org
https://mail.python.org/mailman/listinfo/python-win32


Re: [python-win32] Memory access violation using pywin32 as WSH

2022-11-28 Thread Mark Hammond
It's been years since I've looked at this, but IIRC, a "script item" is 
whatever the host wants it to be - eg, in a HTML page, it would be 
anything between  tags. I believe WSH would just use 
one for a script file.


The Close() method will generally be called by the host - not calling 
this could cause a memory leak (particularly if the COM reference count 
also didn't hit zero), but it shouldn't cause a crash. That said though, 
I certainly would not rule out a bug in pywin32's implementation.


The absolute best thing for us would be to reproduce the crash in the 
test code at 
https://github.com/mhammond/pywin32/tree/main/com/win32comext/axscript/test. 
The next best thing would probably be a stack trace of the crash.


Cheers,

Mark

On 29/11/2022 10:38 am, Bob Kline wrote:

On Mon, Nov 28, 2022 at 4:12 PM Bob Kline  wrote:


Perhaps, for example, I'll be able to find something which is supposed
to get released at application shutdown time but which isn't. 


I've added some debug logging to the top of most methods in
pyscript.py, mostly just announcing that the method was invoked. I was
a little surprised to find that for each invocation of the macro seven
instances of the ScriptItem class were created, instead of just one.
So clearly I have yet to figure out exactly what a ScriptItem is. The
really interesting thing is that if I invoke the macro once for a
given run of the host application, the ScriptItem.Close() method is
called seven times, matching the seven times the ScriptItem
constructor is hit. However, if the macro is invoked twice for a run
of the host application, I still see only seven calls to
ScriptItem.Close(), even though there are now fourteen calls to the
ScriptItem constructor. Can I assume that this is a problem? Sure
smells like one. Where does the responsibility for calling the Close()
method ultimately fall?



___
python-win32 mailing list
python-win32@python.org
https://mail.python.org/mailman/listinfo/python-win32


Re: [python-win32] Memory access violation using pywin32 as WSH

2022-11-28 Thread Bob Kline
On Mon, Nov 28, 2022 at 4:12 PM Bob Kline  wrote:
> 
> Perhaps, for example, I'll be able to find something which is supposed
> to get released at application shutdown time but which isn't. 

I've added some debug logging to the top of most methods in
pyscript.py, mostly just announcing that the method was invoked. I was
a little surprised to find that for each invocation of the macro seven
instances of the ScriptItem class were created, instead of just one.
So clearly I have yet to figure out exactly what a ScriptItem is. The
really interesting thing is that if I invoke the macro once for a
given run of the host application, the ScriptItem.Close() method is
called seven times, matching the seven times the ScriptItem
constructor is hit. However, if the macro is invoked twice for a run
of the host application, I still see only seven calls to
ScriptItem.Close(), even though there are now fourteen calls to the
ScriptItem constructor. Can I assume that this is a problem? Sure
smells like one. Where does the responsibility for calling the Close()
method ultimately fall?

-- 
Bob Kline
https://www.rksystems.com
mailto:bkl...@rksystems.com
___
python-win32 mailing list
python-win32@python.org
https://mail.python.org/mailman/listinfo/python-win32


[python-win32] Memory access violation using pywin32 as WSH

2022-11-28 Thread Bob Kline
We've got a project we've supported for many years which involves
using XMetaL (a commercial XML editor) customized with macros written
in JScript. The vendor claims that the scripting "can use any
scripting language that conforms to the Microsoft Scripting Language
Interface." Since JScript is much more restricted in what it can do,
and since our team is much more familiar with Python than with
JScript, we would like to switch to Python for our scripts. However, a
dirt-simple proof of concept fails with a memory access violation. We
created a macro file with a single macro which displays an alert box
with a simple string. If the lang attribute for the macro element (the
macros are stored in an XML file, with the code for each macro stored
in a MACRO element) is set to "JScript" the macro can be run an
unlimited number of times without any problems. If the lang attribute
is set to "Python" (the macro is so simple that the syntax is
identical for the two languages) the macro can be run once without any
apparent problems, as long as you close the XMetaL application and
launch it again before the next run of the macro. However, if XMetaL
is launched and the macro is run twice or more before shutting down
the application, it is no longer possible to launch it again until the
user logs off the machine and logs back in. When the user logs off, a
dialog box appears reporting a memory access violation ("xmetal.exe -
Application Error. The instruction at  referenced
memory at . The memory could not be read."). To be
clear — the macro does what it's supposed to (display a dialog box
with a string) each time it is run. The problem only manifests itself
when trying to launch the application again or when logging off the
machine. Interestingly, when the application is in this "I can't be
launched again and I will report a failure at logoff time" state there
is no evidence that the process is still hanging around. It doesn't
show up in Process Manager, for example. But it seems clear from the
title bar of the error dialog that it's coming from the application.

At this point I don't know for sure whether the problem is caused by
something the XMetaL application is doing wrong (and presumably
differently than what it does when the scripting engine is JScript) or
by something that pyscript.py is doing. I am aware that I could easily
get caught between two projects, each of which claims that the failure
must be caused by the other. I have reported the problem to the XMetaL
support team and I am waiting to hear what they have to say. I'm
hoping that the data point of "one macro invocation succeeds, two
macro invocations fail" provides a useful clue.

What would be helpful from the pywin32 team's side would be any
suggestions you might have for how I might go about tracking what's
going on, presumably by hacking pyscript.py and/or framework.py in
win32comext/axscript/client to add logging to the file system.
Perhaps, for example, I'll be able to find something which is supposed
to get released at application shutdown time but which isn't. I'm
still trying to absorb the axscript/client code and wrap my head
around what the processing flow is and what the different classes are
doing.

Any clues for where to start? Anyone else run into similar memory
access violations using Python as a Windows Scripting Host?

Many thanks!

-- 
Bob Kline
https://www.rksystems.com
mailto:bkl...@rksystems.com
___
python-win32 mailing list
python-win32@python.org
https://mail.python.org/mailman/listinfo/python-win32