I got the following segmentation fault:
Program terminated with signal 11, Segmentation fault.
#0 0x000000000040fbf6 in release (this=<value optimized out>, __in_chrg=<value optimized out>)
at /usr/local/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp:145
145 dispose();
Missing separate debuginfos, use: debuginfo-install boost-filesystem- 1.41.0-11.el6_1.2.x86_64 boost-program-options-1.41.0-11.el6_1.2.x86_64 boost-system-1.41.0-11.el6_1.2.x86_64 bzip2-libs-1.0.5-7.el6_0.x86_64 glibc-2.12-1.80.el6.x86_64 libgcc-4.4.6-4.el6.x86_64 libstdc++-4.4.6-4.el6.x86_64 lzo-2.03-3.1.el6.x86_64
(gdb) bt
#0 0x000000000040fbf6 in release (this=<value optimized out>, __in_chrg=<value optimized out>)
at /usr/local/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp:145
#1 boost::detail::shared_count::~shared_count (this=<value optimized out>, __in_chrg=<value optimized out>)
at /usr/local/include/boost/smart_ptr/detail/shared_count.hpp:217
#2 0x00007f13fad83dab in boost::detail::set_tss_data(void const*, boost::shared_ptr<boost::detail::tss_cleanup_function>, void*, bool) ()
from /usr/local/lib/libboost_thread.so.1.40.0
#3 0x000000000042e191 in boost::thread_specific_ptr<infrastructure::tfeed::sequenced_data_queue_element_t::mem_prealloc>::release (this=<value optimized out>)
at /usr/local/include/boost/thread/tss.hpp:95
#4 0x000000000042ed43 in infrastructure::tfeed::sequenced_data_queue_element_t::operator new (size=16)
at ../../../infrastructure/include/tfeed/tfeed_multicast_defs.h:120
Also, I got a similar seg fault in another thread:
(gdb) thread 5
[Switching to thread 5 (Thread 0x7f122e1fe700 (LWP 7547))]
#0 0x000000000040fbf6 in release (this=<value optimized out>, __in_chrg=<value optimized out>)
at /usr/local/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp:145
145 dispose();
(gdb) bt
#0 0x000000000040fbf6 in release (this=<value optimized out>, __in_chrg=<value optimized out>)
at /usr/local/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp:145
#1 boost::detail::shared_count::~shared_count (this=<value optimized out>, __in_chrg=<value optimized out>)
at /usr/local/include/boost/smart_ptr/detail/shared_count.hpp:217
#2 0x00007f13fad83dab in boost::detail::set_tss_data(void const*, boost::shared_ptr<boost::detail::tss_cleanup_function>, void*, bool) ()
from /usr/local/lib/libboost_thread.so.1.40.0
#3 0x000000000042e591 in release (q_elem=<value optimized out>) at /usr/local/include/boost/thread/tss.hpp:95
#4 infrastructure::tfeed::sequenced_data_queue_element_t::operator delete (q_elem=<value optimized out>)
at ../../../infrastructure/include/tfeed/tfeed_multicast_defs.h:144
this happened while using the boost's thread specific pointer at /usr/local/include/boost/thread/tss.hpp:95 at (set_tss_data() call below)
T* release()
{
T* const temp=get();
detail::set_tss_data(this,boost::shared_ptr<detail::tss_cleanup_function>(),0,false);
return temp;
}
and futher at sp_counted_base_gcc_x86.hpp(at dispose())
void release() // nothrow
{
if( atomic_exchange_and_add( &use_count_, -1 ) == 1 )
{
dispose();
weak_release();
}
}
I am using thread specific pointer while specialized new and delete calls for a datastructure(sequenced_data_queue_element_t). As this new and delete are called from multiple threads:
class sequenced_data_queue_element_t
{
public:
sequenced_data_queue_element_t() {
}
~sequenced_data_queue_element_t() {
delete data;
}
unsigned char* data;
uint32_t data_len;
typedef struct mem_prealloc
{
struct mem_prealloc* next;
} mem_prealloc_t;
static boost::thread_specific_ptr<mem_prealloc_t> mem_prealloc_q_head;
static void* operator new(size_t size)
{
mem_prealloc_t* q_elem;
if (UNLIKELY(mem_prealloc_q_head.get() == NULL))
{
/* allocate PREALLOC_BATCH elems at a time */
for (int i=0; i < MEM_PREALLOC_BATCH; i++)
{
q_elem = (mem_prealloc_t*)malloc(size);
q_elem->next = mem_prealloc_q_head.release();
mem_prealloc_q_head.reset(q_elem);
cur_mem_prealloced += size;
}
}
q_elem = mem_prealloc_q_head.release();
mem_prealloc_q_head.reset(q_elem->next);
return (void*)q_elem;
}
static void operator delete(void* q_elem)
{
/* C++ guarantees that an object's destructor
* is automatically called just before delete executes. */
/* next reuses the first pointer of sequenced_data_element_t */
((mem_prealloc_t*)q_elem)->next = mem_prealloc_q_head.release();
mem_prealloc_q_head.reset((mem_prealloc_t*)q_elem);
if (cur_mem_prealloced > MEM_PREALLOC_MAX_BYTES)
{
for (int i=0; i < MEM_PREALLOC_BATCH; i++)
{
mem_prealloc_t* qelem = mem_prealloc_q_head.release();
mem_prealloc_q_head.reset(qelem->next);
free(qelem);
cur_mem_prealloced -= sizeof(sequenced_data_queue_element_t);
if (mem_prealloc_q_head.get() == NULL)
break;
}
}
}
};
cur_mem_prealloced(uint64_t) is a global variable.
What could be the possible reason triggering this bug?
Further, the stack of some other threads of the program seems to be corrupted. Also, the core dump shows unexpected code paths for those other threads.
the kernel logs shows the following error message:
[7547]: segfault at 10 ip 000000000040fbf6 sp 00007f122e1fcd90 error 4
[7531]: segfault at 10 ip 000000000040fbf6 sp 00007fffc94bcca0 error 4 in tbt[400000+a0000] in tbt[400000+a0000]
Can these seg faults be triggered in case of stack corruption as well?
Related
i use multi thread to update each item(string) of global vector
each thread update item(string) with different index
i think is a good way to avoid updating same data
but i still get core, i do not know why
extern vector<string> gTestVec;
#define NUM 10
void * worker(void * args) {
thread_data * p = (thread_data *)args;
int i = p->thread_id;
for (int j=0; j<100; j++) {
gTestVec[i] += "a";
}
return NULL;
}
void do_complete_stage_test::excute() {
int i = 0;
pthread_t thd[NUM];
thread_data data[NUM];
for (i=0; i<NUM; i++) {
gTestVec.push_back(format("%d", i));
data[i].thread_id = i;
if (0 != pthread_create(&(thd[i]), NULL, &worker, (void *)&data[i])) {
printf("pthread_create failed");
}
}
for (int i=0; i<NUM; i++) {
if (0 != pthread_join(thd[i], NULL)) {
printf("pthread_join failed");
}
}
}
when i run the code,sometimes get coredump
Starting program: /data/settle_script/isp_tran_collect/bin/isp_tran_collect -p 2134234
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
[New Thread 0x7ffff2623700 (LWP 6316)]
[New Thread 0x7fffefb0e700 (LWP 6317)]
[New Thread 0x7fffef30d700 (LWP 6318)]
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffef30d700 (LWP 6318)]
0x00007ffff6787d67 in ?? () from /lib64/libstdc++.so.6
(gdb) bt
#0 0x00007ffff6787d67 in ?? () from /lib64/libstdc++.so.6
#1 0x00007ffff678899b in std::string::reserve(unsigned long) () from /lib64/libstdc++.so.6
#2 0x00007ffff6788bbf in std::string::append(char const*, unsigned long) () from /lib64/libstdc++.so.6
#3 0x000000000044babe in append (__s=0x880492 "a", this=<optimized out>) at /usr/include/c++/4.8.2/bits/basic_string.h:1009
#4 operator+= (__s=0x880492 "a", this=<optimized out>) at /usr/include/c++/4.8.2/bits/basic_string.h:942
#5 worker (args=<optimized out>) at ../src/do_complete_stage_test.cpp:21
#6 0x00007ffff7bc6e25 in start_thread () from /lib64/libpthread.so.0
#7 0x00007ffff5ee635d in clone () from /lib64/libc.so.6
thanks for your help!!!
You are potentially changing the capacity of the vector after you already started some threads.
The easiest way to prevent the vector from re-allocating and moving its contents is to reserve the amount of space before you start the first worker thread.
So call
gTestVec.reserve(NUM);
Before your loop.
Short: a (network) Client has a std::shared_ptr<Session>, when a client is destroyed, from ~Client the function queueSessionRemoval(const std::shared_ptr<Session> &session) is called, which adds it to std::map<std::chrono::seconds, std::vector<std::weak_ptr<Session>>> queuedSessionRemovals. This crashes with "double free or corruption".
Simplified code:
class Store
{
std::map<std::chrono::seconds, std::vector<std::weak_ptr<Session>>> queuedSessionRemovals;
std::mutex queuedSessionRemovalsMutex;
}
Client::~Client()
{
// removed irrelevant stuff.
// session is std::shared_ptr<Session>
store->queueSessionRemoval(session);
}
void Store::expireSessions()
{
std::lock_guard<std::mutex>(this->queuedSessionRemovalsMutex);
// Iterate over queuedSessionRemovals, etc, etc
// Removed; not important
}
void Store::queueSessionRemoval(const std::shared_ptr<Session> &session)
{
if (!session)
return;
auto removeAt = std::chrono::steady_clock::now() + std::chrono::seconds(session->getSessionExpiryInterval());
std::chrono::seconds secondsSinceEpoch = std::chrono::duration_cast<std::chrono::seconds>(removeAt.time_since_epoch());
std::lock_guard<std::mutex>(this->queuedSessionRemovalsMutex);
queuedSessionRemovals[secondsSinceEpoch].push_back(session);
}
The line that crashes is queuedSessionRemovals[secondsSinceEpoch].push_back(session);
#0 __GI_raise (sig=sig#entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1 0x00007fc09ab93859 in __GI_abort () at abort.c:79
#2 0x00007fc09abfe29e in __libc_message (action=action#entry=do_abort, fmt=fmt#entry=0x7fc09ad28298 "%s\n") at ../sysdeps/posix/libc_fatal.c:155
#3 0x00007fc09ac0632c in malloc_printerr (str=str#entry=0x7fc09ad2a628 "double free or corruption (fasttop)") at malloc.c:5347
#4 0x00007fc09ac07c95 in _int_free (av=0x7fc084000020, p=0x7fc0842197b0, have_lock=0) at malloc.c:4266
#5 0x00005590242cfb82 in __gnu_cxx::new_allocator<std::weak_ptr<Session> >::deallocate (this=0x7fc08021eaf8, __p=0x7fc0842197c0) at /usr/include/c++/9/ext/new_allocator.h:128
#6 0x00005590242cfae2 in std::allocator_traits<std::allocator<std::weak_ptr<Session> > >::deallocate (__a=..., __p=0x7fc0842197c0, __n=4115453) at /usr/include/c++/9/bits/alloc_traits.h:469
#7 0x00005590242cfa3a in std::_Vector_base<std::weak_ptr<Session>, std::allocator<std::weak_ptr<Session> > >::_M_deallocate (this=0x7fc08021eaf8, __p=0x7fc0842197c0, __n=4115453) at /usr/include/c++/9/bits/stl_vector.h:351
#8 0x000055902430fe13 in std::vector<std::weak_ptr<Session>, std::allocator<std::weak_ptr<Session> > >::_M_realloc_insert<std::weak_ptr<Session> > (this=0x7fc08021eaf8,
__position=<error reading variable: Cannot access memory at address 0x119>) at /usr/include/c++/9/bits/vector.tcc:500
#9 0x000055902430c384 in std::vector<std::weak_ptr<Session>, std::allocator<std::weak_ptr<Session> > >::emplace_back<std::weak_ptr<Session> > (this=0x7fc08021eaf8) at /usr/include/c++/9/bits/vector.tcc:121
#10 0x00005590243091da in std::vector<std::weak_ptr<Session>, std::allocator<std::weak_ptr<Session> > >::push_back (this=0x7fc08021eaf8, __x=...) at /usr/include/c++/9/bits/stl_vector.h:1201
#11 0x0000559024304a3a in Store::queueSessionRemoval (this=0x559024648200, session=std::shared_ptr<class Session> (use count 2, weak count 2) = {...}) at /bla/store.cpp:726
#12 0x00005590242e41f7 in Client::~Client (this=0x55902482ca00, __in_chrg=<optimized out>) at /bla/client.cpp:91
There is nothing going on like putting a raw pointer in a shared or weak one. It's all properly managed and the session is created with std::make_shared.
So, __gnu_cxx::new_allocator<std::weak_ptr<Session> >::deallocate crashes. Probably related to re-balancing of the map.
Changing the std::weak_ptr to a std::shared_ptr in queuedSessionRemovals doesn't help. Using other containers doesn't help. Making the argument to queueSessionRemoval not a reference doesn't help.
When I use a std::list instead of a std::map and keep it sorted with std::upper_bound to find the position, very funky results happen, where an empty list has a size() > 0.
The only thing I can imagine is that it has something to do with calling this from a destructor, but at that point in time, the client::session is still a valid shared pointer, so I wouldn't know why.
Any thoughts?
I came across below code for walking backtrace
struct stack_frame {
struct stack_frame *prev;
void *return_addr;
} __attribute__((packed));
typedef struct stack_frame stack_frame;
__attribute__((noinline, noclone))
void backtrace_from_fp(void **buf, int size)
{
int i;
stack_frame *fp;
__asm__("movl %%ebp, %[fp]" : /* output */ [fp] "=r" (fp));
for(i = 0; i < size && fp != NULL; fp = fp->prev, i++)
buf[i] = fp->return_addr;
}
the reason behind looking for this code is we are using a 3rd party malloc hook hence don't want to use backtrace which again allocates memory. Above doesn't work for x86_64 and I modified asm statement to
__asm__("movl %%rbp, %[fp]" : /* output */ [fp] "=r" (fp));
I get crash
(gdb) bt
#0 backtrace_from_fp (size=10, buf=<optimized out>) at src/tcmalloc.cc:1910
#1 tc_malloc (size=<optimized out>) at src/tcmalloc.cc:1920
#2 0x00007f5023ade58d in __fopen_internal () from /lib64/libc.so.6
#3 0x00007f501e687956 in selinuxfs_exists () from /lib64/libselinux.so.1
#4 0x00007f501e67fc28 in init_lib () from /lib64/libselinux.so.1
#5 0x00007f5029a32503 in _dl_init_internal () from /lib64/ld-linux-x86-64.so.2
#6 0x00007f5029a241aa in _dl_start_user () from /lib64/ld-linux-x86-64.so.2
#7 0x0000000000000001 in ?? ()
#8 0x00007fff22cb8e24 in ?? ()
#9 0x0000000000000000 in ?? ()
(gdb)
(gdb) p $rbp
$2 = (void *) 0x7f501e695f37
(gdb) p (stack_frame *)$rbp
$3 = (stack_frame *) 0x7f501e695f37
(gdb) p *$3
$4 = {prev = 0x69662f636f72702f, return_addr = 0x6d6574737973656c}
(gdb) x /1xw 0x69662f636f72702f
0x69662f636f72702f: Cannot access memory at address 0x69662f636f72702f
(gdb) fr
#0 backtrace_from_fp (size=10, buf=<optimized out>) at src/tcmalloc.cc:1910
1910 in src/tcmalloc.cc
(gdb)
Am I missing something ?. Any help on how can I reconstruct the same via code ?.
Am I missing something ?
The code you referenced assumes the compiled code is using frame pointer register chain.
This was the default on (32-bit) i*86 up until about 5-7 years ago, and has not been the default on x86_64 since ~forever.
The code will most likely work fine in non-optimized builds, but will fail miserably with optimization on both 32-bit and 64-bit x86 platforms using non-ancient versions of the compiler.
If you can rebuild all code (including libc) with -fno-omit-frame-pointer, then this code will work most of the time (but not all the time, because libc may have hand-coded assembly, and that assembly will not have frame pointer chain).
One solution is to use libunwind. Unfortunately, using it from inside malloc can still run into a problem, if you (or any libraries you use) also use dlopen.
I have the following declaration for a 2D dynamic integer linked list in Population.cpp:
sectionProf = new int*[section_count]; //list of professor for each section declaration
It is defined in Population.h as:
int ** sectionProf; //list of professor for each section
It is then filled from a file as such, again in Population.cpp, later on:
sectionProf[section] = new int[professors + 1];
sectionProf[section][0] = professors;
if (professors > 0) {
for (int x = 1; x < professors + 1; ++x) {
sectionProf[section][x] = stoi(tokenizedVersion[x + 1]);
}
}
Then, in the destructor, I destroy it as follows:
if(sectionProf){
for(int i = 0; i < section_count; ++i){
delete [] sectionProf[i];
}
delete [] sectionProf;
}
However, upon execution, I keep getting the following error:
* glibc detected * ./research_scheduling_backend: corrupted double-linked list: 0x00000000020b78c0 ***
Here is the gdb backtrace (#17 is referring to the 'delete [] sectionProf' line):
#0 __lll_lock_wait_private () at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:93
#1 0x00007ffff7085f61 in _L_lock_10611 () at malloc.c:5249
#2 0x00007ffff7083c87 in __GI___libc_malloc (bytes=140737341265696) at malloc.c:2921
#3 0x00007ffff7de7900 in _dl_map_object_deps (map=0x7ffff7fdd4e0, preloads=<optimized out>, npreloads=<optimized out>, trace_mode=0, open_mode=-2147483648) at dl-deps.c:517
#4 0x00007ffff7ded8a9 in dl_open_worker (a=0x7fffffffbb00) at dl-open.c:262
#5 0x00007ffff7de9176 in _dl_catch_error (objname=0x7fffffffbb48, errstring=0x7fffffffbb50, mallocedp=0x7fffffffbb5f, operate=0x7ffff7ded700 <dl_open_worker>, args=0x7fffffffbb00) at dl-error.c:178
#6 0x00007ffff7ded31a in _dl_open (file=0x7ffff717a858 "libgcc_s.so.1", mode=-2147483647, caller_dlopen=0x7ffff710bea5, nsid=-2, argc=3, argv=<optimized out>, env=0x7fffffffeac8) at dl-open.c:639
#7 0x00007ffff7131bb2 in do_dlopen (ptr=0x7fffffffbd00) at dl-libc.c:89
#8 0x00007ffff7de9176 in _dl_catch_error (objname=0x7fffffffbd30, errstring=0x7fffffffbd20, mallocedp=0x7fffffffbd3f, operate=0x7ffff7131b70 <do_dlopen>, args=0x7fffffffbd00) at dl-error.c:178
#9 0x00007ffff7131c74 in dlerror_run (args=0x7fffffffbd00, operate=0x7ffff7131b70 <do_dlopen>) at dl-libc.c:48
#10 __GI___libc_dlopen_mode (name=<optimized out>, mode=<optimized out>) at dl-libc.c:165
#11 0x00007ffff710bea5 in init () at ../sysdeps/x86_64/../ia64/backtrace.c:53
#12 0x00007ffff6df1400 in pthread_once () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S:104
#13 0x00007ffff710bfc4 in __GI___backtrace (array=<optimized out>, size=64) at ../sysdeps/x86_64/../ia64/backtrace.c:104
#14 0x00007ffff707505f in __libc_message (do_abort=2, fmt=0x7ffff717f560 "*** glibc detected *** %s: %s: 0x%s ***\n") at ../sysdeps/unix/sysv/linux/libc_fatal.c:180
#15 0x00007ffff707f846 in malloc_printerr (action=3, str=0x7ffff717be4c "corrupted double-linked list", ptr=<optimized out>) at malloc.c:5047
#16 0x00007ffff7080b1b in _int_free (av=0x7ffff73b9720, p=0x627dd0, have_lock=0) at malloc.c:4125
#17 0x0000000000404b7e in Population::~Population (this=0x7fffffffc910, __in_chrg=<optimized out>) at Population.cpp:91
#18 0x0000000000403919 in main (argc=3, argv=0x7fffffffeaa8) at Scheduler.cpp:101
At absolutely no place in the code is the sectionProf array ever modified. It is only used to check values. Can someone please tell me why I might be getting this error? I have looked all over the place about glibc double-linked list errors and I understand that it is because in some way I am corrupting the symbol table(?) somehow...
For anyone who lands on this problem, here is what is wrong in my specific problem. I was reading garbage value for section index that were out of range (section_count) when I was generating the array. That is, in the for loop,
sectionProf[section] = new int[professors + 1];
sectionProf[section][0] = professors;
if (professors > 0) {
for (int x = 1; x < professors + 1; ++x) {
sectionProf[section][x] = stoi(tokenizedVersion[x + 1]);
}
}
my value for section was not in the range of 0 and section_count, the index used in the delete loop. Hence why I was causing the corruption of memory.
Lesson: Check for PEBKAC errors generated in input files.
I wrote a php extension but couldn't find the reason why it reported segmentation fault.
related code:
char *tkey = (char *)emalloc(sizeof(char)*(result_pair[num-1].length+1));
std::memcpy(tkey, (text+i),result_pair[num-1].length);
tkey[result_pair[num-1].length]='\0';
if (zend_hash_find(HASH_OF(return_value), tkey, result_pair[num-1].length+1, (void**)&origval) == SUCCESS) {
ZVAL_LONG(*origval, Z_LVAL_P(*origval)+1);
zend_hash_update(HASH_OF(return_value), tkey, result_pair[num-1].length+1, origval, sizeof(origval), NULL);
} else {
add_assoc_long(return_value, tkey, 1);
}
efree(tkey);
num--;
The following were from gdb
Program received signal SIGSEGV, Segmentation fault.
_zend_mm_alloc_int (heap=0x1ca07750, size=32) at /php-5.3.3/Zend/zend_alloc.c:1825
1825 heap->cache[index] = best_fit->prev_free_block;
Current language: auto; currently c
(gdb) bt
#0 _zend_mm_alloc_int (heap=0x1ca07750, size=32) at /php-5.3.3/Zend/zend_alloc.c:1825
#1 0x0000000000729160 in add_assoc_long_ex (arg=0x1cc29380, key=0x20 <Address 0x20 out of bounds>, key_len=2, n=2) at /php-5.3.3/Zend/zend_API.c:1117
#2 0x00002b2ebee6552e in zif_xs_search (ht=<value optimized out>, return_value=0x1cc29380, return_value_ptr=<value optimized out>,
this_ptr=<value optimized out>, return_value_used=<value optimized out>) at /release/xsplit_t/xsplit.cpp:1007
#3 0x000000000076b489 in zend_do_fcall_common_helper_SPEC (execute_data=0x2b2ebf070050) at /php-5.3.3/Zend/zend_vm_execute.h:316
#4 0x0000000000741cae in execute (op_array=0x1cc26378) at /php-5.3.3/Zend/zend_vm_execute.h:107
#5 0x000000000071e5c9 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at /php-5.3.3/Zend/zend.c:1194
#6 0x00000000006cc8b8 in php_execute_script (primary_file=0x7fffb5324230) at /php-5.3.3/main/main.c:2260
#7 0x00000000007a897e in main (argc=2, argv=0x7fffb53244a8) at /php-5.3.3/sapi/cli/php_cli.c:1192
(gdb) frame 2
#2 0x00002b2ebee6552e in zif_xs_search (ht=<value optimized out>, return_value=0x1cc29380, return_value_ptr=<value optimized out>,
this_ptr=<value optimized out>, return_value_used=<value optimized out>) at /release/xsplit_t/xsplit.cpp:1007
1007 add_assoc_long(return_value, tkey, 1);
Current language: auto; currently c++
I figured out that the problem was add_assoc_long function, 'tkey' is declared as:
char *tkey = (char *)emalloc(sizeof(char)*(result_pair[num-1].length+1));
Segfault only occurred under some circumstances but not always, but I thought tkey wouldn't have any problems. Any help is appreciated, thanks a lot~
Your memcpy is not copying the NUL character, you need a +1 for the number of bytes to be copied:
std::memcpy(tkey, (text+i),result_pair[num-1].length+1);
^^