2010-10-07 2 views
1

J'ai un programme qui obtient une KERN_PROTECTION_FAILURE avec EXC_BAD_ACCESS dans un endroit très étrange lors de l'exécution multithread et je n'ai pas la moindre idée sur la façon de résoudre le problème plus loin. C'est sur MacOS 10.6 en utilisant GCC.Besoin d'aide pour le suivi EXC_BAD_ACCESS sur la fonction Entrée sur MacOS

L'endroit très étrange qu'il obtient est lors de l'entrée d'une fonction. Pas sur la première ligne de la fonction, mais le saut réel à la fonction 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) 

Si je lance ce non-thread, il fonctionne très bien, aucun problème:

#include "MachineFactors.h" 

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

Si Je cours ceci dans un pthread, j'obtiens le EXC_BAD_ACCESS ci-dessus.

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; 
} 

Voici un extrait du GetMachineFactors() Code:

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; 
} 

Pour référence, je me sers d'une socketpair attendre sur le fil pour compléter:

// 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) 

Voici le code où je lance le fil.

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 
} 

Voici le cas d'échec simple de l'exécution de ce multithread. Il échoue toujours pour ce code avec la trace de pile ci-dessus:

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

Au début, j'ai suspecté un problème de bibliothèque. Voici mon makefile:

# 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 [email protected] $< 

all: $(PROGRAM) 

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

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

Je ne peux pas pour la vie de me voir tout particulièrement étrange ou dangereux et je ne suis pas sûr où regarder. Le même processus threadé fonctionne très bien sur toutes les machines Linux que j'ai essayées. Aucune suggestion? Tous les outils que je devrais essayer?

Je peux ajouter plus d'informations si ce serait utile.

Répondre

0

Il s'avère, et je ne peux pas expliquer pourquoi, qu'un appel fork() combiné avec un socketpair() comme mécanisme IPC était la solution pour que les choses se passent comme prévu.

Je voudrais savoir pourquoi il échouait en premier lieu (headscratch) mais cette approche semble avoir été une bonne solution de contournement. Cela ressemblait presque au type de problème de «build out of whack» qui pouvait être causé par l'échec de l'exécution d'un «make clean» après la modification des fichiers d'en-tête, mais ce n'était pas le cas ici.

0

Je peux voir un problème avec votre code Windows, mais pas le code OSX qui plante sur vous.

Il semble que vous ne publiez pas le code réel pour GetMachineFactors, puisque la variable factors n'est pas déclarée. Mais en ce qui concerne le débogage, vous ne devez pas considérer comme non concluante la non-sortie de la sortie printf pour que cette instruction n'ait pas été exécutée. Utilisez les fonctions du débogueur telles que la définition d'un point d'arrêt, l'utilisation d'une sortie de débogage spéciale, etc. (pas sûr de ce que gère gdb, c'est un débogueur très primitif, mais Apple a peut-être de meilleurs outils?).

Pour Windows, vous devez utiliser la création de thread de la bibliothèque d'exécution au lieu de Windows API CreateThread. En effet, avec CreateThread, la bibliothèque d'exécution n'est pas informée. Par exemple, une expression new ou un autre appel utilisant la bibliothèque d'exécution peut échouer.

Désolé, je ne peux pas vous aider.

Je pense que cela pourrait avoir quelque chose à voir avec le code GetMachineFactors que vous n'avez pas montré?

+0

Merci d'avoir essayé, mais il s'est avéré être l'un de ces «problèmes inexplicables étranges» qui nécessitaient un fork() pour se comporter correctement. –

Questions connexes