In this program, I clone a child thread with the flags: CLONE_VM | CLONE_SETTLS. The child's stack space is malloced in the father process ahead.
In the child thread, I want to switch its stack by changing the rsp register directly. And the new stack space is also malloced in advance in father.
The bug is:
When I try to free the old stack space, I got a "Segmentation fault", like this

The following four operations will make the bug disappear:
- Don't switch the stack space
mallocthe new stack space after the old stack space and before the clone methodmallocthe new stack space in the child thread- Don't use the TLS
the C program:
#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h>
#include <asm/prctl.h>
#include <string.h>
#include <malloc.h>
extern void gogo_switch_new_free_old_and_jmp(void *new_stack, void *old_stack, void *new_pc);
int arch_prctl(int code, unsigned long *addr);
typedef struct {
void *stack_space;
void *stack_top;
} stack_struct;
typedef struct {
stack_struct stack;
stack_struct stack2;
} T;
void get_tls(void *tls_addr) {
arch_prctl(ARCH_GET_FS, tls_addr);
}
void task_done() {
T *t;
get_tls(&t);
void *old_stack_space = t->stack.stack_space;
t->stack.stack_space = t->stack2.stack_space;
t->stack.stack_top = t->stack2.stack_top;
gogo_switch_new_free_old_and_jmp(t->stack.stack_top, old_stack_space, NULL);
}
#define stack_size 128
int main() {
stack_struct stack2;
stack2.stack_space = malloc(stack_size);
stack2.stack_top = stack2.stack_space + stack_size;
T *t = malloc(sizeof(T));
t->stack.stack_space = malloc(stack_size);
t->stack.stack_top = t->stack.stack_space + stack_size;
t->stack2 = stack2;
clone((void *) task_done, t->stack.stack_top,
CLONE_VM |
CLONE_SETTLS,
NULL, NULL, t, NULL);
sleep(1000000000);
return 0;
}
the Assembler:
#void gogo_switch_new_free_old_and_jmp(void *new_stack, void *old_stack, void *new_pc);
.text
.globl gogo_switch_new_free_old_and_jmp
.type gogo_switch_new_free_old_and_jmp, @function
gogo_switch_new_free_old_and_jmp:
# switch stack
movq %rdi,%rsp
pushq %rdx
# free old space
movq %rsi,%rdi
call free@PLT
#JMP
popq %rax
movq %rsp, %rdi
addq $8, %rdi
pushq %rax
ret