Last active
September 3, 2018 13:50
-
-
Save jmjatlanta/63cf7a13b9c88d47c9eb63deee5e5118 to your computer and use it in GitHub Desktop.
What happens when you use an thread-unsafe collection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CC=g++ | |
CFLAGS=-g | |
DEPS= | |
%.o: %.cpp $(DEPS) | |
$(CC) -c -o $@ $< $(CFLAGS) | |
test_threadsafe: test_threadsafe.o | |
$(CC) -g -O0 -lSegFault -o test_threadsafe $^ -lpthread -rdynamic |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Got signal 11, faulty address is 0x8, from 0x559961bec86a | |
[bt] Execution path: | |
[bt] ./test_threadsafe(_ZNKSt12__shared_ptrI8MyObjectLN9__gnu_cxx12_Lock_policyE2EE3getEv+0xc) [0x559961bec86a] | |
[bt] ./test_threadsafe(_ZNKSt12__shared_ptrI8MyObjectLN9__gnu_cxx12_Lock_policyE2EE3getEv+0xc) [0x559961bec86a] | |
[bt] ./test_threadsafe(_ZSteqI8MyObjectS0_EbRKSt10shared_ptrIT_ERKS1_IT0_E+0x2c) [0x559961beeb80] | |
[bt] ./test_threadsafe(_ZNKSt8equal_toISt10shared_ptrI8MyObjectEEclERKS2_S5_+0x27) [0x559961bee8a9] | |
[bt] ./test_threadsafe(_ZNSt8__detail13_Equal_helperISt10shared_ptrI8MyObjectES3_NS_9_IdentityESt8equal_toIS3_EmLb0EE9_S_equalsERKS6_RKS4_RKS3_mPNS_10_Hash_nodeIS3_Lb0EEE+0x50) [0x559961bee5b6] | |
[bt] ./test_threadsafe(_ZNKSt8__detail15_Hashtable_baseISt10shared_ptrI8MyObjectES3_NS_9_IdentityESt8equal_toIS3_ESt4hashIS3_ENS_18_Mod_range_hashingENS_20_Default_ranged_hashENS_17_Hashtable_traitsILb0ELb1ELb1EEEE9_M_equalsERKS3_mPNS_10_Hash_nodeIS3_Lb0EEE+0x54) [0x559961bedf24] | |
[bt] ./test_threadsafe(_ZNKSt10_HashtableISt10shared_ptrI8MyObjectES2_SaIS2_ENSt8__detail9_IdentityESt8equal_toIS2_ESt4hashIS2_ENS4_18_Mod_range_hashingENS4_20_Default_ranged_hashENS4_20_Prime_rehash_policyENS4_17_Hashtable_traitsILb0ELb1ELb1EEEE19_M_find_before_nodeEmRKS2_m+0x65) [0x559961bed663] | |
[bt] ./test_threadsafe(_ZNKSt10_HashtableISt10shared_ptrI8MyObjectES2_SaIS2_ENSt8__detail9_IdentityESt8equal_toIS2_ESt4hashIS2_ENS4_18_Mod_range_hashingENS4_20_Default_ranged_hashENS4_20_Prime_rehash_policyENS4_17_Hashtable_traitsILb0ELb1ELb1EEEE12_M_find_nodeEmRKS2_m+0x30) [0x559961becb3a] | |
[bt] ./test_threadsafe(_ZNSt10_HashtableISt10shared_ptrI8MyObjectES2_SaIS2_ENSt8__detail9_IdentityESt8equal_toIS2_ESt4hashIS2_ENS4_18_Mod_range_hashingENS4_20_Default_ranged_hashENS4_20_Prime_rehash_policyENS4_17_Hashtable_traitsILb0ELb1ELb1EEEE4findERKS2_+0x69) [0x559961bec42f] | |
[bt] ./test_threadsafe(_ZNSt13unordered_setISt10shared_ptrI8MyObjectESt4hashIS2_ESt8equal_toIS2_ESaIS2_EE4findERKS2_+0x23) [0x559961bebc05] | |
[bt] ./test_threadsafe(_Z9find_loopv+0x3a) [0x559961beaea0] | |
[bt] ./test_threadsafe(_ZSt13__invoke_implIvPFvvEJEET_St14__invoke_otherOT0_DpOT1_+0x1d) [0x559961bec653] | |
[bt] ./test_threadsafe(_ZSt8__invokeIPFvvEJEENSt15__invoke_resultIT_JDpT0_EE4typeEOS3_DpOS4_+0x35) [0x559961bebccc] | |
[bt] ./test_threadsafe(_ZNSt6thread8_InvokerISt5tupleIJPFvvEEEE9_M_invokeIJLm0EEEEDTcl8__invokespcl10_S_declvalIXT_EEEEESt12_Index_tupleIJXspT_EEE+0x28) [0x559961beef5a] | |
[bt] ./test_threadsafe(_ZNSt6thread8_InvokerISt5tupleIJPFvvEEEEclEv+0x2c) [0x559961beeec8] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <unordered_set> | |
#include <string> | |
#include <thread> | |
#include <iostream> | |
#include <memory> | |
#include <execinfo.h> | |
#include <signal.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <stdio.h> | |
char* exe = 0; | |
int initialiseExecutableName() | |
{ | |
char link[1024]; | |
exe = new char[1024]; | |
snprintf(link,sizeof link,"/proc/%d/exe",getpid()); | |
if(readlink(link,exe,sizeof link)==-1) { | |
fprintf(stderr,"ERRORRRRR\n"); | |
exit(1); | |
} | |
printf("Executable name initialised: %s\n",exe); | |
} | |
const char* getExecutableName() | |
{ | |
if (exe == 0) | |
initialiseExecutableName(); | |
return exe; | |
} | |
/* get REG_EIP from ucontext.h */ | |
#define __USE_GNU | |
#include <ucontext.h> | |
void bt_sighandler(int sig, siginfo_t *info, | |
void *secret) { | |
void *trace[16]; | |
char **messages = (char **)nullptr; | |
int i, trace_size = 0; | |
ucontext_t *uc = (ucontext_t *)secret; | |
/* Do something useful with siginfo_t */ | |
if (sig == SIGSEGV) | |
fprintf(stderr, "Got signal %d, faulty address is %p, " | |
"from %p\n", sig, info->si_addr, | |
uc->uc_mcontext.gregs[REG_RIP]); | |
else | |
fprintf(stderr, "Got signal %d\n", sig); | |
trace_size = backtrace(trace, 16); | |
/* overwrite sigaction with caller's address */ | |
trace[1] = (void *) uc->uc_mcontext.gregs[REG_RIP]; | |
messages = backtrace_symbols(trace, trace_size); | |
/* skip first stack frame (points here) */ | |
fprintf(stderr, "[bt] Execution path:\n"); | |
for (i=1; i<trace_size; ++i) | |
{ | |
fprintf(stderr, "[bt] %s\n", messages[i]); | |
/* find first occurence of '(' or ' ' in message[i] and assume | |
* everything before that is the file name. (Don't go beyond 0 though | |
* (string terminator)*/ | |
size_t p = 0; | |
while(messages[i][p] != '(' && messages[i][p] != ' ' | |
&& messages[i][p] != 0) | |
++p; | |
char syscom[256]; | |
sprintf(syscom,"addr2line %p -e %.*s", trace[i] , p, messages[i] ); | |
//last parameter is the filename of the symbol | |
system(syscom); | |
} | |
exit(0); | |
} | |
class MyObject | |
{ | |
public: | |
int id; | |
std::string name; | |
}; | |
std::unordered_set<std::shared_ptr<MyObject>> collection; | |
std::shared_ptr<MyObject> main_object = nullptr; | |
void add_loop() | |
{ | |
while (true) | |
{ | |
std::shared_ptr<MyObject> obj = std::make_shared<MyObject>(); | |
obj->id = rand() % 1000; | |
obj->name = "Hello, World!"; | |
collection.emplace(obj); | |
std::this_thread::sleep_for(std::chrono::milliseconds(500)); | |
} | |
} | |
void delete_loop() | |
{ | |
while (true) | |
{ | |
if (collection.size() > 0) | |
{ | |
collection.erase(collection.begin()); | |
std::this_thread::sleep_for(std::chrono::milliseconds(600)); | |
} | |
} | |
} | |
void find_loop() | |
{ | |
while(true) | |
{ | |
bool found = collection.find(main_object) != collection.end(); | |
if (found) | |
std::cout << "Found main_object\n"; | |
else | |
std::cout << "main_object not found.\n"; | |
std::this_thread::sleep_for(std::chrono::milliseconds()); | |
} | |
} | |
/****** | |
* Attempt to modify a collection while another | |
* thread does a find | |
*/ | |
int main(int argc, char** argv) | |
{ | |
struct sigaction sa; | |
sa.sa_sigaction = bt_sighandler; | |
sigemptyset (&sa.sa_mask); | |
sa.sa_flags = SA_RESTART | SA_SIGINFO; | |
sigaction(SIGSEGV, &sa, NULL); | |
sigaction(SIGUSR1, &sa, NULL); | |
main_object = std::make_shared<MyObject>(); | |
main_object->id = 1000; | |
main_object->name = "Main Object"; | |
collection.emplace(main_object); | |
std::thread find_thread(find_loop); | |
std::thread add_thread(add_loop); | |
std::thread delete_thread(delete_loop); | |
// run indefinitely | |
while (true) | |
{ | |
std::this_thread::sleep_for(std::chrono::seconds(10)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment