Нужна помощь в отслеживании EXC_BAD_ACCESS при вводе функции в MacOS - PullRequest
1 голос
/ 08 октября 2010

У меня есть программа, которая получает KERN_PROTECTION_FAILURE с EXC_BAD_ACCESS в очень странном месте при работе в многопоточном режиме, и я не имею ни малейшего представления, как ее устранить в дальнейшем. Это на MacOS 10.6 с использованием GCC.

Очень странное место, которое он получает, это при входе в функцию. Не в первой строке функции, но фактический переход к функции GetMachineFactors ():

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0xb00009ec
[Switching to process 28242]
0x00012592 in GetMachineFactors () at ../sysinfo/OSX.cpp:168
168 MachineFactors* GetMachineFactors()
(gdb) bt
#0  0x00012592 in GetMachineFactors () at ../sysinfo/OSX.cpp:168
#1  0x000156d0 in CollectMachineFactorsThreadProc (parameter=0x200280) at Threads.cpp:341
#2  0x952f681d in _pthread_start ()
#3  0x952f66a2 in thread_start ()
(gdb) 

Если я запустил эту нить, она работает отлично, без проблем:

#include "MachineFactors.h"

int main( int argc, char** argv )
{
    MachineFactors* factors = GetMachineFactors();
    std::string str = CreateJSONObject(factors);
    cout << str;
    delete factors;
    return 0;
}

Если я запускаю это в pthread, я получаю EXC_BAD_ACCESS выше.

THREAD_FUNCTION CollectMachineFactorsThreadProc( LPVOID parameter )
{
    Main* client = (Main*) parameter;
    if ( parameter == NULL )
    {
        ERRORLOG( "No data passed to machine identification thread.  Aborting." );
        return 0;
    }
    MachineFactors* mfactors = GetMachineFactors(); // This is where it dies.
    // If I don't call GetMachineFactors and do something like mfactors =
    // new MachineFactors(); everything is good and the threads communicate and exit
    // normally.
    if (mfactors == NULL)
    {
        ERRORLOG("Failed to collect machine identification: GetMachineFactors returned NULL." << endl)
        return 0;
    }
    client->machineFactors = CreateJSONObject(mfactors);
    delete mfactors;
    EVENT_RAISE(client->machineFactorsEvent);
    return 0;
}

Вот выдержка из кода GetMachineFactors ():

MachineFactors* GetMachineFactors() // Dies on this line in multi-threaded.
{
    // printf( "Getting machine factors.\n"); // Tried with and without this, never prints.
    factors = new MachineFactors();
    factors->OSName = "MacOS";
    factors->Manufacturer = "Apple";
    ///…
    // gather various machine metrics here.
    //…
    return factors;
}

Для справки, я использую пару сокетов для ожидания завершения потока:

// From the header file I use for cross-platform defines (this runs on OSX, Windows, and Linux.
struct _waitt
{
  int fds[2];
};
#define THREAD_FUNCTION void*
#define THREAD_REFERENCE pthread_t
#define MUTEX_REFERENCE pthread_mutex_t*
#define MUTEX_LOCK(m) pthread_mutex_lock(m)
#define MUTEX_UNLOCK pthread_mutex_unlock
#define EVENT_REFERENCE struct _waitt
#define EVENT_WAIT(m) do { char lc; if (read(m.fds[0], &lc, 1)) {} } while (0)
#define EVENT_RAISE(m) do { char lc = 'j'; if (write(m.fds[1], &lc, 1)) {} } while (0)
#define EVENT_NULL(m) do { m.fds[0] = -1; m.fds[1] = -1; } while (0)

Вот код, с которого я запускаю поток.

void Main::CollectMachineFactors()
{
#ifdef WIN32
    machineFactorsThread = CreateThread(NULL, 0, CollectMachineFactorsThreadProc, this, 0, 0);
    if ( machineFactorsThread == NULL )
    {
        ERRORLOG( "Could not create thread for machine id: " << ERROR_NO << endl )
    }
#else
    int retval = pthread_create(&machineFactorsThread, NULL, CollectMachineFactorsThreadProc, this);
    if (retval)
    {
        ERRORLOG( "Return code from machine id pthread_create() is " << retval << endl )
    }
#endif
}

Вот простой случай сбоя при запуске этой многопоточной программы. Это всегда терпит неудачу для этого кода с трассировкой стека выше:

CollectMachineFactors();
EVENT_WAIT(machineFactorsEvent);
cout << machineFactors;
return 0;

Сначала я заподозрил проблему с библиотекой. Вот мой make-файл:

# Main executable file
PROGRAM = sysinfo
# Object files
OBJECTS = Version.h Main.o Protocol.o Socket.o SSLConnection.o Stats.o TimeElapsed.o Formatter.o OSX.o Threads.o
# Include directories
INCLUDE = -Itaocrypt/include -IyaSSL/taocrypt/mySTL -IyaSSL/include -isysroot /Developer/SDKs/MacOSX10.5.sdk -mmacosx-version-min=10.5
# Library settings
STATICLIBS = libtaocrypt.a libyassl.a -Wl,-rpath,. -ldl -lpthread -lz -lexpat
# Compile settings
RELCXX = g++ -g -ggdb -DDEBUG -Wall $(INCLUDE)

.SUFFIXES:      .o .cpp

.cpp.o :
        $(RELCXX) -c -Wall $(INCLUDE) -o $@ $<

all:    $(PROGRAM)

$(PROGRAM):     $(OBJECTS)
        $(RELCXX) -o $(PROGRAM) $(OBJECTS) $(STATICLIBS)

clean: 
    rm -f *.o $(PROGRAM)

Я не могу на всю жизнь увидеть что-то особенно странное или опасное, и я не уверен, где искать. Тот же самый многопоточный процесс прекрасно работает на любой машине с Linux, которую я пробовал. Какие-либо предложения? Какие инструменты мне стоит попробовать?

Я могу добавить больше информации, если это будет полезно.

Ответы [ 2 ]

0 голосов
/ 10 декабря 2010

Оказывается, и я не могу объяснить почему, что вызов fork () в сочетании с socketpair () в качестве механизма IPC был обходным путем, чтобы все заработало как задумано.

Хотелось бы знать, почему он вообще не удался ( headscratch ), но этот подход, похоже, был хорошим обходным путем.

Это выглядело почти как проблема "build of of whack", которая могла быть вызвана невозможностью запустить make make после изменения заголовочных файлов, но здесь это было не так.

0 голосов
/ 08 октября 2010

Я вижу проблему с вашим кодом Windows, но не с кодом OSX, который вылетает на вас.

Похоже, вы не публикуете фактический код для GetMachineFactors, поскольку переменная factors не объявленоНо что касается отладки, вы не должны воспринимать неявку вывода printf как окончательное, что этот оператор не был выполнен.Используйте средства отладки, такие как установка точки останова, использование специального вывода трассировки отладчика и т. Д. (Не уверен, что обрабатывает gdb, это очень примитивный отладчик, но, возможно, у Apple есть лучшие инструменты?).

Для Windows вам следуетиспользуйте создание потоков библиотеки времени выполнения вместо Windows API CreateThread.Это потому, что с CreateThread библиотека времени выполнения не информируется.Например, выражение new или другой вызов, использующий библиотеку времени выполнения, может завершиться ошибкой.

Извините, я не могу больше помочь.

Я думаю, что это может иметь отношение к GetMachineFactors код, который вы не показали?

...