Closed Bug 681694 Opened 13 years ago Closed 12 years ago

Block support code added by Apple's g++/llvm-g++ calls C++ destructor prematurely

Categories

(Core :: Widget: Cocoa, defect)

All
macOS
defect
Not set
normal

Tracking

()

RESOLVED WONTFIX

People

(Reporter: smichaud, Unassigned)

References

Details

(Whiteboard: rdar://10007196)

Attachments

(2 files)

This bug is spun off from bug 678607, to track an Apple bug discovered
there (in bug 678607 comment #44).  It was reported to Apple as rdar
number 10007196 (see bug 678607 comment #68).

Apple's "blocks" are described at
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Blocks/Articles/00_Introduction.html.

In the following I refer to the function in which a block is embedded
as its "parent".

Blocks require a *lot* of support code under the hood.  This is added
by Apple's gcc/g++ (and friends).  The code inside the block itself is
placed in a function named __[parent]_block_invoke_N(), preceded by a
fairly lengthy prologue.

If the block refers to a variable in its scope within the parent, but
not inside the block itself, the block's prologue creates a copy of it
on the block's stack (i.e. in a local variable).  All references to
this variable within the block are translated into references to this
"prologue copy".

In the case of a C++ structure or class, g++ or llvm-g++ prologue code
copies the entire structure onto the stack using a copy constructor.
The bug is that, immediately afterwards, the prologue also calls the
structure's destructor (instead of calling it at the end of the block,
as it should).  The memory occupied by the prologue copy of the
structure isn't released until the end of the block (when it goes out
of scope).  But the contents of the structure are, in general,
undefined -- who knows what the structure's destructor might have done
to it.

Clang's block prologue code is quite different, and doesn't have this
bug.  And Apple seems to be deprecating gcc/g++ and llvm-gcc/llvm-g++
in favor of clang -- so it's unlikely they'll fix this bug.  Which
(probably) means that the only way *we'll* be able to fix it is to
switch to clang on OS X.

It'll be a while before we can change to clang on OS X.  But [NSEvent
trackSwipeEventWithOptions:...] uses blocks, and it seems to be the
best way to provide support for two-finger horizontal swipes on OS X
Lion, which we need right now (see bug 668953).  So we have strong
motivation to work around Apple's bug, which it appears we're able to
do for now (see particularly bug 678607 comment #70).
Whiteboard: rdar://10007196
I generated this using:

lvm-g++ -S -flto -emit-llvm mstange-testcase-orig.mm
As Markus Stange pointed out in bug 678607 comment #40, the following
log output shows the bug in action:

// CPPStruct(0x7fff5fbfe5b0) copy construction from 0x10040f9b8
// CPPStruct(0x7fff5fbfe5b0) destruction
// block called with x = 0, &e: 0x7fff5fbfe5b0, e.mX: 5, [d retainCount]: 1
// CPPStruct(0x7fff5fbfe5b0) copy construction from 0x10040f9b8
// CPPStruct(0x7fff5fbfe5b0) destruction
// block called with x = 1, &e: 0x7fff5fbfe5b0, e.mX: 5, [d retainCount]: 1

In the IL from comment #2, look for definition of the function named
"__-[TestView mouseDown:]_block_invoke_1".

Near the top you'll see the following, where space is allocated on the
stack for the local copy of CPPStruct e:

// %e = alloca %struct.CPPStruct ; <%struct.CPPStruct*> [#uses=4]

Then you'll see the following, where the CPPStruct constructor is
called, and immediately afterwards its destructor:

// call void @_ZN9CPPStructC1ERKS_(%struct.CPPStruct* %e, %struct.CPPStruct* %1) ssp
// call void @_ZN9CPPStructD1Ev(%struct.CPPStruct* %e) ssp

But the call to NSLog() (which refers to the local copy of CPPStruct
e) only takes place at the bottom of the function, after the CPPStruct
destructor was called:

// call void (%struct.NSColor*, ...)*
//   @NSLog(
//     %struct.NSColor* bitcast
//       (%struct.__builtin_CFString* @"\01L_unnamed_cfstring_8" to %struct.NSColor*),
//     i32 %13,
//     %struct.CPPStruct* %e,
//     i32 %12,
//     i64 %10)
Depends on: 682445
See bug 682445 comment 15 for more information on Apple's block support code.
Apple's gcc is dead. We moved to clang.
Status: NEW → RESOLVED
Closed: 12 years ago
Resolution: --- → WONTFIX
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: