Need help with crashing thread

I’m trying to debug a crashing thread, but I can’t seem to determine what is causing the crash. (I’m using an older version of Real Studio, btw)

In this window, I have a listbox which needs to list details from many files dropped on it. The process which extracts the data from the files can take a while, so it’s called from a thread subclass to keep the interface responsive, and display a counter of the current file. I’ve added a constant ‘constBYPASS_THREAD’ to the window, which allows me to bypass using the thread (the method executed by the thread is executed in the main thread instead), and that works without crashing (although the interface is obviously locked up while it processes all of the files). When the thread is used, sometimes the crash comes while it’s processing the files, and other times, it finishes processing but crashes when that window is closed.

When files/folders are dropped on the listbox, it passes those to a recursive method ‘AddFolderItem’, which adds them to the thread’s array, then runs the thread (If the thread is bypassed, it instead starts the timer which finalizes the process)

[code]// DROP OBJECT CODE
Do
If Obj.FolderItemAvailable Then
AddFolderItem(obj.FolderItem)
End if
Loop Until Not Obj.NextItem

if constBYPASS_THREAD then
// Thread has been skipped, Finalize
timEndThread.Mode = timer.ModeSingle
timEndThread.Enabled = true
else
// Run thread
Self.threadAddFiles.Run
end if
[/code]

The ‘AddFolderItem’ method recurses though any subdirectories, and adds the files to the thread (or, if bypassed, directly processes the files)

// AddFolderItem CODE if NOT(f is nil) then if f.Directory then // Run AddFolderItem on each child - recursive code omitted for brevity else if f.Visible then if constBYPASS_THREAD then ProcessFile(f) // This is the same method call that the thread uses else self.threadAddFiles.FolderItem = f end if end if end if end if

The thread has 2 events, When it runs, it loops through all files that have been added to it’s array, and calls the ‘ProcessFile’ method on each, then raises a ‘Complete’ event.

// threadAddFiles ACTION ProcessFile(f)

[code] // threadAddFiles COMPLETE
self.mFileCount = me.Count
self.mFileIndex = 0

timEndThread.Mode = timer.ModeSingle
timEndThread.Enabled = true
[/code]

The ‘ProcessFile’ method does all of the heavy lifting, and does not access any user interface elements (I’m double and triple checking that now, as it’s a lot of code, which calls a few other methods, and uses another class instance to parse the file data). At the end, it creates an instance of a class which contains all of the collected data for the file, and passes that to an ‘AddFiles’ Timer, which adds a row to the listbox and populates the data.

[code]//AddFiles TIMER CODE
Dim currentRow as integer

self.mFileIndex = self.mFileIndex + 1
Self.lblFileProcessing.Visible = true
Self.lblFileProcessing.Caption = "Processing file " + str(self.mFileIndex) + " of " + str(Self.mFileCount) + “…”

’ Add image
if NOT (imageData is nil) then

Self.lbxFileList.AddRow("")
currentRow = Self.lbxFileList.LastIndex
Self.lbxFileList.RowTag(currentRow) = imageData

Call setRowData(currentRow)

end if[/code]

At one point, I found that I had code within the ‘ProcessFile’ method which read the values of a few checkboxes (but didn’t update anything in the user interface). I have since made sure that all of these were removed, and changes to the UI elements set private properties of the window, which are accessed within the method. I had hoped that would fix the crashing issue, but it did not.

I can post crash logs (Mac OS 10.10.5); I’m not sure what parts are relevant (they are quite long), and they don’t seem to have any consistency. I didn’t see anything that I could tell indicated what part of the code was the cause.

Does anyone have any suggestions on where I can look for the cause of this crash?

I’d say that if your app worked well up to OS X 10.7 and now doesn’t work in later versions, it is most probably a Thread / UI issue. I think Apple enforced it with OS X 10.8, but I’m not sure.

About crash logs on OS X:
Interesting in the crash log are these bits:
– Exception Type:
– Application Specific Information:

The thread which crashed starts like this:

Thread nnn Crashed

Go down until you reach the first line with your application name:

0 libobjc.A.dylib 0x93f89ed7 objc_msgSend + 23 1 com.apple.AppKit 0x936143ea -[NSTableView preparedCellAtColumn:row:] + 335 2 com.apple.AppKit 0x9362e8bc -[NSTableView _drawContentsAtRow:column:wi 3 ... 4 yourApplicationName 0x9362e8bc >>>here is the name of the last method call<<<

Before going down that path, are we talking about a crash in the sense that the app just disappears? Or is it that you’re getting an exception and you’re not handling it?

If it does just disappear, it could be that the OS is killing your app for not yielding.

I’m not sure when the crashing started, it may have been around that time. This is an ongoing project that I use and am constantly updating as I need it. The crashing has been happening for a while, although only occasionally, and if I added the files to the listbox in batches, it would usually work properly. Lately, it seems to happen consistently, so I’m finally getting time to look into trying to fix this.

I’ll look through the crash logs to see if I can tell what is going on, and I’ll post the relevant parts if I can.

Yes, the app completely shuts down, I have exception traps in all of the main methods, although not necessarily in each of the called methods or the class methods. I’ll check those as well, but I also have a message in the app.unhandledException event, and that is not getting called.

But if it’s an exception, I’d assume it would happen whether I was using the thread or not, since the same code is called when I bypass the thread:

ListboxDropObject >> Thread >> ProcessFile >> Timer >> addToListbox
ListboxDropObject >> ProcessFile >> Timer >> addToListbox

The only difference is the method to process the file is getting called directly after the object is dropped on the listbox, instead of the file getting passed to the thread to send to the processing method.

The ‘RUN’ event of the thread’s subclass calls app.YieldToNextThread after processing each file, and it crashes whether I yield or not. I’m assuming that I’m doing this properly:

[code] Dim f as FolderItem

While NOT (ubound(self.mFolderItems) < 0)
Self.mListIndex = Self.mListIndex + 1
f = self.mFolderItems(0)
if NOT (f is nil) then
// Raise event to process file
RaiseEvent ProcessFile(f)
end if
Self.mFolderItems.Remove(0)

// Yield here?
Call app.YieldToNextThread()

Wend

// Raise event to signal process completed for any post-processing
RaiseEvent Complete

Self.mCount = 0
Self.mListIndex = 0
[/code]

Do you see your app as “not responding” when you open Activity Viewer? The crash logs really would help.

Somehow, my response with the crash log text doesn’t seem to be showing up (at least not on my end; it shows that I’m the last post, but I don’t see any posts past Beatrix’s)

When the app crashes, it is instantly removed from the Activity Monitor. My latest crash log does include some of the code from my program listed in the crashed thread (earlier ones did not)

[code]Process: Main Menu [2910]
Path: /Users/USER/Desktop/Main Menu TEST.app/Contents/MacOS/Main Menu
Identifier: ???
Version: 1.5 (1.5.0.0.530)
Code Type: X86 (Native)
Parent Process: ??? [1]
Responsible: Main Menu [2910]
User ID: 501

Date/Time: 2016-09-30 11:28:56.198 -0400
OS Version: Mac OS X 10.10.5 (14F1912)
Report Version: 11
Anonymous UUID: B2DBBBF6-B3F8-76CA-1748-D80C216E63A6

Time Awake Since Boot: 14000 seconds

Crashed Thread: 2

Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x00000000c033ffff

VM Regions Near 0xc033ffff:
Stack 00000000bf800000-00000000c0000000 [ 8192K] rw-/rwx SM=COW
–>
Submap 00000000ffff0000-00000000ffff1000 [ 4K] r–/r-- SM=PRV process-only VM submap
[/code]

Thread 2 Crashed: 0 ??? 0xc033ffff 0 + 3224633343 1 rbframework.dylib 0x01d8ba65 TextEncodingClass() + 409 2 rbframework.dylib 0x01d8bde4 RuntimeUnlockObject + 36 3 0x002acdf1 DBCode_Generic.ClearErrors + 204 4 0x002a75c3 DBCode_Generic.SQL_Select%o<RecordSet>%so<Database> + 626 5 0x018580cd clsMarsItem.getItemInfo%i4%o<clsMarsItem>i4si4<clsMarsItem.NumberTypes> + 20718 6 0x01852f56 clsMarsItem.Constructor%%o<clsMarsItem>i4 + 101 7 0x004fdebd wndwCreateImages_CURRENT.wndwCreateImages_CURRENT.AddItemToListbox%%o<wndwCreateImages_CURRENT.wndwCreateImages_CURRENT>o<FolderItem> + 69099 8 0x004ef040 wndwCreateImages_CURRENT.wndwCreateImages_CURRENT.AddItemToListbox%%o<wndwCreateImages_CURRENT.wndwCreateImages_CURRENT>o<FolderItem> + 8046 9 0x004eefd5 wndwCreateImages_CURRENT.wndwCreateImages_CURRENT.AddItemToListbox%%o<wndwCreateImages_CURRENT.wndwCreateImages_CURRENT>o<FolderItem> + 7939 10 0x004eefd5 wndwCreateImages_CURRENT.wndwCreateImages_CURRENT.AddItemToListbox%%o<wndwCreateImages_CURRENT.wndwCreateImages_CURRENT>o<FolderItem> + 7939 11 0x004771f5 wndwCreateImages_CURRENT.wndwCreateImages_CURRENT.threadAddFiles_ProcessFile%%o<wndwCreateImages_CURRENT.wndwCreateImages_CURRENT>o<FolderItem> + 136 12 0x0035204b AddFilesThread.ProcessItems%%o<AddFilesThread> + 6749 13 0x00350518 AddFilesThread.Event_Run%%o<AddFilesThread> + 109 14 rbframework.dylib 0x01dc9e85 threadRun + 633 15 com.apple.CoreServices.CarbonCore 0x93b40b88 CooperativeThread + 305 16 libsystem_pthread.dylib 0x97284c25 _pthread_body + 138 17 libsystem_pthread.dylib 0x97284b9b _pthread_start + 162 18 libsystem_pthread.dylib 0x97281e32 thread_start + 34

Thread 2 crashed with X86 Thread State (32-bit): eax: 0xc033ffff ebx: 0x01d8ba48 ecx: 0x1911e2f0 edx: 0x1910fc20 edi: 0x023c44a0 esi: 0x01912c51 ebp: 0xb02147c8 esp: 0xb021476c ss: 0x00000023 efl: 0x00010286 eip: 0xc033ffff cs: 0x0000001b ds: 0x00000023 es: 0x00000023 fs: 0x00000023 gs: 0x0000000f cr2: 0xc033ffff

I’d be looking at DBCode_Generic.ClearErrors

The crash is because of an invalid pointer. DBCode_Generic.ClearErrors is the last method you call. And a Xojo framework internal method called TextEncodingClass() is last mentioned before the crash so I assume it is because of a string. Maybe the string does not have an encoding? Maybe a string that comes from a database call or a filestream and DefineEncoding is missing?

Ok, thanks.

What that does is clear a dictionary to store error codes (dictErrorCodes = new dictionary). I’m not getting any errors from the database, but I’m now wondering if the thread is accessing the database at the same time the main thread is. It shouldn’t be, but I’m guessing that would be a possible cause for this crash.

BTW, none of the other error logs I’ve collected have DBCode_Generic.ClearErrors listed anywhere in them, just this latest one I generated this morning.

Ok, scratch that, I think it actually is accessing the database in the main thread as well as the file processing thread. This is beginning to look like the issue to me. I’m going to see if I can move any calls to the database outside of the processing thread, and only process the actual data within the file itself in the file processing thread.

Thanks for the assistance, this was very helpful!

Give the thread its own database connection.

[quote=289337:@Mark Walsh]Ok, scratch that, I think it actually is accessing the database in the main thread as well as the file processing thread. This is beginning to look like the issue to me. I’m going to see if I can move any calls to the database outside of the processing thread, and only process the actual data within the file itself in the file processing thread.

Thanks for the assistance, this was very helpful![/quote]

If you can reproduce this reliably, please file a bug report with the project and clear steps on how to reproduce.

I was originally thinking this as well, but unfortunately, it’s not that simple. The method used by the thread accesses several class instances and methods, the same methods and classes that manage the data after the listbox is filled, and values are changed by the user.

Every time I have gotten the program to crash while debugging, it always quits out immediately, without any warning, except for twice, when it actually dropped into the debugger. One of those times, it gave me an outOfBounds error on the line ‘For each key in aDictionary.keys’, which really confused me, as I can’t see how that is possible. I’m thinking that the file processing thread is stepping on the main thread at times (or vice versa), and it may not be the database connection itself, just whatever object it is that it is trying to access at the same time. (btw, that dictionary does not get changed during the running of this process, just read)

I tested having the timer which adds the data to the listbox wait for the thread to finish, and bypassing the thread altogether. In both cases, the process completes without any crash, although it doesn’t update the interface as the files are being added.

I’m looking into the Semaphore and CriticalSection examples, to see if this is what I need to use. I’m not familiar with these at all, so I’m not sure how to incorporate them into my current code just yet.

At this point, I don’t think that this is a bug with RS/XOJO, more an issue with my coding.

Yes, you definitely need to protect the data that’s being accessed. It sounds very much like the thread is modifying objects while the main thread is trying to read them. That can certainly lead to crashes like you describe.

[quote=289714:@Tim Hare]Yes, you definitely need to protect the data that’s being accessed. It sounds very much like the thread is modifying objects while the main thread is trying to read them. That can certainly lead to crashes like you describe.

[/quote]
Success!!

I’ve added CriticalSections to both methods which access database, and are used throughout the application, as well as the timer which processes the files. Also, I have refactored the method I was originally calling in the thread, and moved some of the code to another method which is accessed by the timer. So far, no problems.

I will spend some more time refactoring to clean up some of the code to get it a little more efficient. When I get time, I’ll post some of the code I’m using to see if it’s being used properly, or if there are any improvements I can make.

Thanks to everyone who contributed, I couldn’t have gotten here without your help!