[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Newbie back again...

From: Josh Freeman
Subject: Re: Newbie back again...
Date: Mon, 19 Jun 2017 18:43:14 -0400

To recap: Base & GUI each modify NSThread instance variables directly. The expectation is that the layout of NSThread's ivars as seen by Base is identical to the layout as seen by GUI.

However, this expectation is not met if -fobjc-nonfragile-abi is added to GNUstep-make's INTERNAL_OBJCFLAGS when compiling with clang on Debian-based distros; On the affected distros, Base & GUI compile without error, but despite both compiling with the same abi flag (nonfragile), at runtime they no longer agree on NSThread's ivar layout (NSThread's ivar offset now differs between Base & GUI by 8 bytes).

The segmentation fault happens after Base sets the value of an NSThread ivar, because the memory location it writes to overlaps the area in memory where GUI expects to find a different ivar, due to the mismatched layouts; When GUI reads its ivar, it finds a nonzero value (garbage), and when the garbage value is sent an objc message, it crashes.


I've attached a zip file with some files that might provide some helpful info: install scripts & verbose build outputs (including all compiler commands & flags for base, gui, & back) for both working & broken versions of gnustep-make. These are from a virtual machine (VirtualBox 5.1.22), running a clean, up-to-date install of Ubuntu 17.04.

gnustep_ubuntu1704_build_output.tar.gz contains 4 files:

1) install_gnustep_ubuntu_original.sh:
The current version of the "16.04, 16.10, & 17.04" Ubuntu build script found at http://wiki.gnustep.org/index.php/GNUstep_under_Ubuntu_Linux (this wasn't run, just used as the starting point for install_gnustep_ubuntu_modified.sh)

2) install_gnustep_ubuntu_modified.sh:
This script generated the build output files (sudo prompts were manually removed from the output). Modifications from the original script: * Changed values of APPS & PROMPT vars from true to false (don't build apps, don't require <RET> after each build phase) * Removed 'ninja' package from install requirements (package no longer exists in 17.04 - probably wasn't the correct package anyways; 'ninja' package was a privilege-escalation detector) * Added prompt to choose gnustep-make version: new (broken) version (2017-04-08), or old version (2017-04-06) * Makes base, gui, & back using `make SHELL='sh -x'` command, so the compiler commands are written to the output * Added a gui make check at the end (fails on gnustep-make 2017-04-08, succeeds on gnustep-make 2017-04-06) The script was run until the gnustep-make prompt (after build dependencies are installed) - a VM snapshot was taken, then the build continued with the first (working) make-version (2017-04-06). The second version (2017-04-08) was built by restoring the VM to the make- version-prompt snapshot of the first build, then continuing after choosing the prompt's other option (so all installed packages & sources were identical between both runs).

3) gnustep_build_output_with_make_2017-04-06.txt:
   Build output of a successful build, with gnustep-make from Apr. 6th.

4) gnustep_build_output_with_make_2017-04-08.txt
   Build output of a broken build, with gnustep-make from Apr. 8th.

SHA1(gnustep_ubuntu1704_build_output.tar.gz)= 1f4053e86233eb577ae39e927fddf66a39064ecf



Attachment: gnustep_ubuntu1704_build_output.tar.gz
Description: GNU Zip compressed data

On Jun 19, 2017, at 1:27 AM, Patryk Laurent wrote:

Hi folks,

Just wanted to let you know this issue appears to remain unresolved. Today I checked out and built all sources from the git repo under Ubuntu 16.04. The simple GUI test[1] built with a Makefile and run with openapp ./GUItest.app segfaults.

(But it runs fine if I compile it by hand with

clang `gnustep-config --objc-flags` `gnustep-config --objc-libs` - fobjc-runtime=gnustep -fblocks -lobjc -fobjc-arc -ldispatch - lgnustep-base -lgnustep-gui guitest.m

and then run the resulting ./a.out

Could anyone say how to fix it?

Thank you,

[1] GUI test from http://wiki.gnustep.org/index.php/GNUstep_under_Ubuntu_Linux

On Apr 24, 2017, at 00:42, David Chisnall <address@hidden> wrote:

-fobjc-nonfragile-abi has been a deprecated flag for 2-3 years. Please can someone who understands GNUstep Make fix the build system to use -fobjc-runtime= instead?


On 23 Apr 2017, at 23:34, Josh Freeman <address@hidden > wrote:

Turns out the issue is with the placement of the objc-nonfragile- abi build flag in common.make, line 670: For some reason, the affected distros (seen so far on: Ubuntu 16.04, Mint 18.1, Debian Jessie; 32bit, perhaps 64bit?) will build base & gui with mismatched and/or broken ABIs if -fobjc-nonfragile-abi is added to INTERNAL_OBJCFLAGS. It works fine, however, if fobjc-nonfragile- abi is instead added to INTERNAL_LDFLAGS, which is how it was in the trunk until a couple weeks ago:

Reverting that change fixes the crashes, however, that will also break ARC, according to https://savannah.gnu.org/bugs/?50751 . I also tried installing with fobjc-nonfragile-abi added to both INTERNAL_OBJCFLAGS and INTERNAL_LDFLAGS (matching the pattern used for fobjcexceptions at common.make:662), but the crashes came back; Seems the problem is specifically with adding fobjc- nonfragile-abi to INTERNAL_OBJCFLAGS, regardless of whether it's also added to INTERNAL_LDFLAGS.

Until we can find a permanent solution that hopefully fixes both the broken ABIs and ARC, here are some short-term workarounds to build a working GNUstep with clang/objc2 on the affected distros:

1) Build with the fragile ABI: Remove the --enable-objc-nonfragile- abi flag from the GS make's ./configure commands (both of them) in the build script. This also means you'll need to recompile your apps whenever you install new versions of the GS frameworks.

2) Build with an earlier version of make (though this will break ARC): In the build script, after changing to the make directory, but before configuring make (the first time it's built), add a git checkout command to force it to use a source-tree snapshot from before April 7:

cd make
git checkout `git rev-list -1 --first-parent --before=2017-04-06`
./configure --enable-debug-by-default --with-layout=gnustep -- enable-objc-nonfragile-abi --enable-objc-arc

3) I attached a modified "16.04 & 16.10" script for Ubuntu/Mint from the wiki, which lets you build GS/objc2/libdispatch using checkouts from a particular date, set in the script's CHECKOUT_DATE var. (This automates the workaround in #2 above, but for all the source trees, not just make). It was useful in figuring out the abi issue, because then it just became a question of finding when the problem first appeared. It can also be helpful for testing apps on older GS versions (on Ubuntu or related distros).




On Apr 23, 2017, at 4:18 PM, Fred Kiefer wrote:

Thank you Josh,

this was an excellent analysis. Did you try to unset GNUSTEP_BASE_LIBRARY in NSGraphicsContext.m? That should switch to the other code path that won’t use internal structures from base.

As for the problem with the NSThread ivars. What has changed on your test system? Do you think the change in on the GNUstep side or was there a behaviour change in clang?


Am 23.04.2017 um 09:39 schrieb Josh Freeman <address@hidden >:

Hi Bertrand,

Thanks for the info! I'm seeing the same issue - after making a clean GNUstep install from the trunk, any app built from it segfaults immediately, always in the same location: + [NSGraphicsContext setCurrentContext:]. This is on two different virtual machines, one with Ubuntu 16.04, the other with Linux Mint MATE 18.1 (both up-to-date, 32-bit, Clang 3.8).

I've tried a few different ways of installing GS, including some old scripts that used to work, as well as the current "16.04 & 16.10" script from the "GNUstep under Ubuntu Linux" wiki page. I also tried disabling blocks & ARC, but still get the same problem: the apps (ProjectCenter, Gorm, GWorkspace, SystemPreferences, PikoPixel) build fine, then crash when run.

One thing that still works is building with GCC & its runtime, though this means no blocks, ARC, etc. I've attached a modified version of the "16.04 & 16.10" wiki script that builds successfully with gcc on both of my machines. It doesn't have the 'sudo dpkg --add-architecture i386' line you added, so you might need to put that in (though it might no longer be an issue with the different runtime). Also, the script has libxft-dev uncapitalized, unlike yours where it's libXft-dev (didn't work on Ubuntu/Mint), so you might need to change it back for your machine.

Regarding the crashes, here's what I've figured out so far:

- The crash is from trying to send an objc message to a non- object. - The crash happens inside +[NSGraphicsContext setCurrentContext:] the first time it's called. - Before crashing, setCurrentContext:'s local var, (NSThread *) th, is set to the current thread (return value of GSCurrentThread()), which is a valid object. - setCurrentContext:'s passed parameter value, (NSGraphicsContext *) context, is also a valid object. - th's instance var, (id) _gcontext (pointer to the current graphics context), however, contains a garbage value: 32. - The crash happens inside the macro, ASSIGN(th->_gcontext, context) - after context is sent a retain message and stored in _gcontext, _gcontext's old value (32, non-object) is sent a release message.

* Where did the 32 come from?

- Looking at NSThread.h, the instance var immediately before _gcontext is _autorelease_vars, an autorelease_thread_vars struct (5-member struct, defined in NSAutoreleasePool.h). - When the [NSAutoreleasePool dealloc] method (NSAutoreleasePool.m:561) is called (every time an autorelease pool drains), a pointer to the current thread object's _autorelease_vars ivar struct is stored in dealloc's local var, (struct autorelease_thread_vars *) tv. - dealloc passes tv to the local function, push_pool_to_cache() (NSAutoreleasePool.m:106), where - if the struct needs initialization - tv is then passed to another local function, init_pool_cache(). - init_pool_cache() (NSAutoreleasePool.m:98) sets the value of one of tv's struct members, (int) pool_cache_size, to the value 32.

* How does the 32 move from _autorelease_vars to _gcontext?

- Looking at the autorelease_thread_vars definition in NSAutoreleasePool.h, pool_cache_size is the second-to-last member in the struct, so it's quite close in memory to its neighboring instance var, _gcontext: 8 bytes away, assuming no extra padding.

* How does an address pointer lose/gain 8 bytes?

Somehow NSAutoreleasePool.m (in base) and NSGraphicsContext.m (in gui) are in disagreement about the offsets to an NSThread object's instance vars: In NSAutoreleasePool.m, the statement (&((GSCurrentThread())->_autorelease_vars)) results in a memory address that is less than sizeof(struct autorelease_thread_vars) away from the memory address NSGraphicsContext.m calculates as the location of GSCurrentThread()->_gcontext; When init_pool_cache() sets the current thread's _autorelease_vars' pool_cache_size member near the end of the struct, it's writing the value 32 to the same address later used by setCurrentContext: as the current thread's _gcontext. (I verified this with a gdb memory watchpoint).

The crash in +[NSGraphicsContext setCurrentContext:] also goes away if you add some extra padding bytes in the NSThread struct between _autorelease_vars & _gcontext (not that that's a solution - it just postpones the crash to a later point, in GSWindowDecorationView.m).

So I think the ivar offsets disagreement is the condition that causes the crash - any ideas what's causing the condition? Possibly a config issue that's causing clang to use different struct padding settings between base & gui?




On Apr 22, 2017, at 11:03 PM, Bertrand Gmail wrote:

Preamble : sorry for the noise on gnustep-dev mailing list. I've reposted the messages here.

And...finally, it still doesn't work.

I thought that the problem had disappeared because I could compile and run a sample program given on the ubuntu installation notes on the gnustep wiki.

This is this program : guitest.m

#import <AppKit/AppKit.h> int main() { NSApplication *app; // Without these 2 lines, seg fault may occur app = [NSApplication sharedApplication]; NSAlert * alert = [[NSAlert alloc] init]; [alert setMessageText:@"Hello alert"]; [alert addButtonWithTitle:@"All done"]; int result = [alert runModal]; if (result == NSAlertFirstButtonReturn) { NSLog(@"First button pressed"); } }

This compiles and run fine it i use this command :

clang `gnustep-config --objc-flags` `gnustep-config --objc- libs` -fobjc-runtime=gnustep -fblocks -lobjc -fobjc-arc - ldispatch -lgnustep-base -lgnustep-gui guitest.m

But iif I use the following makefile to compile it (given in the wiki also), running GUItest.app will segfault :

GNUmakefile :
include \$(GNUSTEP_MAKEFILES)/common.make

GUITest_OBJC_FILES = guitest.m

include \$(GNUSTEP_MAKEFILES)/application.make

GUItest.app segfaults with this :

Program received signal SIGSEGV, Segmentation fault.

0x00007ffff63cc500 in objc_msgSend_fpret ()

Backtrace attached.

Then every compilation of a program (projectcenter, gorm etc) fails.

I'm stuck.

I've attached my installation scripts again and the backtrace to this mail.

There seems to be some problem with the compilation options in my setup. This is way beyond my skills.

Cheers, Bertrand Dekoninck.

< my_install_gnustep_first_stage .sh > < my_install_gnustep_second_stage .sh ><backtrace.txt>_______________________________________________
Discuss-gnustep mailing list

Gnustep-dev mailing list

Gnustep-dev mailing list

Discuss-gnustep mailing list

reply via email to

[Prev in Thread] Current Thread [Next in Thread]