To prove alloca() *lies*, one needs to show e.g. a 5-10 C program independent of anything else exemplifying a clear specification violation. Otherwise, how do you know the LIARS_LIARS_PANTS_ON_FIRE macros are not compensating for undefined behavior elsewhere?
On 11/29/16 16:23 , Nicolas Cellier wrote:
Though, it's necessary to define ALLOCA_LIES_SO_USE_GETSP to zero to
make FFI work with gcc.
That does not mean that alloca does not lie, just that there is another
problem with stack management...
2016-11-29 21:22 GMT+01:00 Nicolas Cellier
<nicolas.cellier.aka.nice@gmail.com
<mailto:nicolas.cellier.aka.nice@gmail.com >>:<mailto:estebanlm@gmail.com>>:
Thanks Ronie and Esteban.
This seems to be an alignment problem indeed.
What I see is that alignment is defined at least in 3 different places:
- platforms/Cross/vm/sqCogStackAlignment.h
- platforms/Cross/plugins/IA32ABI/ia32abicc.c
- src/plugins/SqueakFFIPrims/IA32FFIPlugin.c and friends...
That's just too many different opinions!!! We have to unify that
rather than adding a 4th opinion in a Makefile.
However, about ALLOCA_LIES_SO_USE_GETSP, I'm not so sure that "It is
NOT the case of mingw."
Last time I used gdb, it WAS still the case, alloca was STILL lying.
See
http://lists.squeakfoundation.org/pipermail/vm-dev/2016-Augu st/022985.html
<http://lists.squeakfoundation.org/pipermail/vm-dev/2016- >August/022985.html
BUT:
-----
forcing 16 bytes alignment supersedes the alloca hack, making it not
strictly necessary anymore
see below in generated src/plgins/IA32FFIPlugin.c:
allocation = alloca(((stackSize +
((calloutState->structReturnSize)))) + (cStackAlignment()));
if (allocaLiesSoUseGetsp()) {
allocation = getsp();
}
if ((cStackAlignment()) != 0) {
allocation = ((char *) ((((((usqInt)allocation)) |
((cStackAlignment()) - 1)) - ((cStackAlignment()) - 1))));
}
(calloutState->argVector = allocation);
but we further do:
if ((0 + (cStackAlignment())) > 0) {
setsp((calloutState->argVector));
}
So if ever the stack pointer is greater than alloca return value,
but we removed the ALLOCA_LIES hack,
the stack pointer is then set back to alloca returned value,
avoiding the stack pointer offset problem
It would be worth writing a unit test case, and inquiring the
reason why it lies in gcc mailing list to be sure...
cheers
2016-11-29 18:14 GMT+01:00 Esteban Lorenzano <estebanlm@gmail.com
hah!
you know what is the sad part of this? I wrote that message… it
was for the future me, but I forget to check our flags :P
I lost 2.5 days then + 2 days now.
this fixes the problem with Windows crashes (yay!) but not the
problem with callbacks (booo!)… any idea in that area?
cheers,
Esteban
On 29 Nov 2016, at 17:30, Ronie Salgado <roniesalg@gmail.com
<mailto:roniesalg@gmail.com>> wrote:
The last week I was having this exactly same crash in the
MinimalisticHeadless branch, with both MinGW and with Visual
Studio. I managed to get the VM working with MinGW (not yet
with MSVC) by using the following defines,which I copied from
the old Pharo CMake scripts:
-DSTACK_ALIGN_BYTES=16 -DALLOCA_LIES_SO_USE_GETSP=0
In the pharo-vm, the CogFamilyWindowsConfig >>
#commonCompilerFlags method starts with the following comment:
commonCompilerFlags
"omit -ggdb2 to prevent generating debug info"
"Some flags explanation:
STACK_ALIGN_BYTES=16 is needed in mingw and FFI (and I
suppose on other modules too).
DALLOCA_LIES_SO_USE_GETSP=0 Some compilers return the
stack address+4 on alloca function,
then FFI module needs to adjust that. It is NOT the case
of mingw.
For more information see this thread:
http://forum.world.st/There-are-something-fishy-with-FFI-plu gin-td4584226.html
<http://forum.world.st/There-are-something-fishy-with-FFI-pl >ugin-td4584226.html
"
2016-11-29 9:32 GMT-03:00 Esteban Lorenzano
<estebanlm@gmail.com <mailto:estebanlm@gmail.com>>:
On 29 Nov 2016, at 13:04, Clément Bera
<bera.clement@gmail.com <mailto:bera.clement@gmail.com>>
wrote:
Hi,
Can you confirm this bug happen only in Windows ?
yes, the crash is just in windows.
the callback problem is general (note that
FFICallbackTests works fine, but I think this is related
to the fact that it never enters the 2nd condition with
the qsort function) .
Do you have version number (both VMMaker and git commit)
of the last version you have that was working ?
sadly, not… I tried to get the latest working version, but
with the mess I have to get the VM to build with
opensmalltalk-vm, I couldn’t track it.
I suspect is related to the work on 64bits for windows,
but I have no proof of that :P
Esteban
Thanks.
On Tue, Nov 29, 2016 at 11:54 AM, Esteban Lorenzano<estebanlm@gmail.com <mailto:estebanlm@gmail.com>> wrote:
Hi,
So, I’m building the PharoVM along with all his
dependencies. For me, this is a major step because I
can drop the old build process finally.
Now, I’m having serious problems with FFI (that they
were not present before), :
1. CRASH IN WINDOWS (32bits):
In Win32, it crashes automatically when trying to
access this funtion:
getEnvSize: nameString
^ self ffiCall: #( int
GetEnvironmentVariableA ( String nameString, nil, 0 )
) module: #Kernel32
(this works perfectly fine in older versions)
2. CALLBACKS FAILING:
Callbacks have problems. The examples passes but they
are very simple… as soon as I try to do something
complicates (like unqlite bindings or libgit2
bindings, who use callbacks intensively), callbacks
stops working.
I traced the problem up to this method:
StackInterpreter>>#returnAs:ThroughCallback:Context:
returnAs: returnTypeOop ThroughCallback:
vmCallbackContext Context: callbackMethodContext
"callbackMethodContext is an activation of
invokeCallback:[stack:registers:jmpbuf:].
Its sender is the VM's state prior to the
callback. Reestablish that state (via longjmp),
and mark callbackMethodContext as dead."
<export: true>
<var: #vmCallbackContext type:
#'VMCallbackContext *'>
| calloutMethodContext theFP thePage |
<var: #theFP type: #'char *'>
<var: #thePage type: #'StackPage *'>
((self isIntegerObject: returnTypeOop)
and: [self isLiveContext:
callbackMethodContext]) ifFalse:
[^false].
calloutMethodContext := self externalInstVar:
SenderIndex ofContext: callbackMethodContext.
(self isLiveContext: calloutMethodContext)
ifFalse:
[^false].
"We're about to leave this stack page; must
save the current frame's instructionPointer."
self push: instructionPointer.
self externalWriteBackHeadFramePointers.
"Mark callbackMethodContext as dead; the
common case is that it is the current frame.
We go the extra mile for the debugger."
(self isSingleContext: callbackMethodContext)
ifTrue: [self markContextAsDead:
callbackMethodContext]
ifFalse:
[theFP := self
frameOfMarriedContext: callbackMethodContext.
framePointer = theFP "common
case"
ifTrue:
[(self
isBaseFrame: theFP)
ifTrue: [stackPages freeStackPage: stackPage]
ifFalse: "calloutMethodContext is immediately below
on the same page. Make it current."
[instructionPointer := (self frameCallerSavedIP:
framePointer) asUnsignedInteger.
stackPointer := framePointer + (self
frameStackedReceiverOffset: framePointer) +
objectMemory wordSize.
framePointer := self frameCallerFP: framePointer.
self setMethod: (self frameMethodObject:
framePointer).
self restoreCStackStateForCallbackContext:
vmCallbackContext.
"N.B. siglongjmp is defines as _longjmp on
non-win32 platforms.
This matches the use of _setjmp in ia32abicc.c."
self siglong: vmCallbackContext trampoline jmp:
(self integerValueOf: returnTypeOop).
^true]]
ifFalse:
[self
externalDivorceFrame: theFP andContext:
callbackMethodContext.
self
markContextAsDead: callbackMethodContext]].
"Make the calloutMethodContext the active
frame. The case where calloutMethodContext
is immediately below callbackMethodContext
on the same page is handled above."
(self isStillMarriedContext:
calloutMethodContext)
ifTrue:
[theFP := self
frameOfMarriedContext: calloutMethodContext.
thePage := stackPages
stackPageFor: theFP.
"findSPOf:on: points to the
word beneath the instructionPointer, but
there is no
instructionPointer on the top frame of the current page."
self assert: thePage ~=
stackPage.
stackPointer := (self
findSPOf: theFP on: thePage) - objectMemory wordSize.
framePointer := theFP]
ifFalse:
[thePage := self
makeBaseFrameFor: calloutMethodContext.
framePointer := thePage headFP.
stackPointer := thePage headSP].
instructionPointer := self popStack.
self setMethod: (objectMemory fetchPointer:
MethodIndex ofObject: calloutMethodContext).
self setStackPageAndLimit: thePage.
self restoreCStackStateForCallbackContext:
vmCallbackContext.
"N.B. siglongjmp is defines as _longjmp on
non-win32 platforms.
This matches the use of _setjmp in
ia32abicc.c."
self siglong: vmCallbackContext trampoline
jmp: (self integerValueOf: returnTypeOop).
"NOTREACHED"
^true
with the first siglongjmp callbacks are passing fine.
with the last (it would be if framePointer = theFP
AND !(isBaseFrame: theFP) ) it doesn’t.
So… from here I’m a bit lost… I need some help :)
thanks,
Esteban