1

I'am doing an exercice for an Operational Systems class and getting an SegFault error when calling printf with arguments.

The objective of the exercice is to simulate the initialization of a thread and print a counter, not very difficult. I have a table of 4 entries each with size 4096 bytes, each entry must represent the thread's stack represented as

#define STACK_SIZE 4096

char table[4][STACK_SIZE];

I defined a type called coroutine that will get only a stack address

typedef void* coroutine_t;

The i have a initialization code. This code must take the end of the routine stack, append the address of the coroutine and the initialization of the registers and return the pointer that will be the stack pointer for the coroutine.

coroutine_t init_coroutine(void *stack_begin, unsigned int stack_size,
                           void (*initial_pc)(void)) {
    char *stack_end = ((char *)stack_begin) + stack_size;
    void **ptr = (void**) stack_end;
    ptr--;
    *ptr = initial_pc;
    ptr--;
    *ptr = stack_end; /* Frame pointer */
    ptr--;
    *ptr = 0; /* RBX*/
    ptr--;
    *ptr = 0; /* R12 */
    ptr--;
    *ptr = 0; /* R13 */
    ptr--;
    *ptr = 0; /* R14 */
    ptr--;
    *ptr = 0; /* R15 */

    return ptr;
}

Then i have this code in x86 assembly to enter the coroutine that just pop the register previously pushed

.global enter_coroutine /* Makes enter_coroutine visible to the linker*/
enter_coroutine:
mov %rdi,%rsp /* RDI contains the argument to enter_coroutine. */
              /* And is copied to RSP. */
pop %r15
pop %r14
pop %r13
pop %r12
pop %rbx
pop %rbp
ret /* Pop the program counter */

The rest of my code is this

coroutine_t cr;
void test_function() {
    int counter = 0;
    while(1) {
        printf("counter1: %d\n", counter);
        counter++;
    }
}

int main() {
    cr = init_coroutine(table[0], STACK_SIZE, &test_function);
    enter_coroutine(cr);
    return 0;
}

So for the error If i run as it is i will get a segfault when the program call printf the output from gdb is

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7dfcfdd in __vfprintf_internal (s=0x7ffff7f9d760 <_IO_2_1_stdout_>, format=0x555555556004 "counter1: %d\n", ap=ap@entry=0x555555558f48 <table+3848>, mode_flags=mode_flags@entry=0) at vfprintf-internal.c:1385

I assume it has some thing happening with the stack for two causes:

  • If i just print a string without parameters i get no error
  • If i remove the first ptr-- statement from the init_coroutine function it will also work, but will alocate things in the end of the stack and hence in the other thread's stack

I'am running this in a Intel(R) Core(TM) i5-5200U CPU with ubuntu 21.10 and ggc version 11.2.0

Could you give me some light here ?

1 Answer 1

1

I wasn't able to reproduce the problem on my x86_64 Linux box, but I was on compiler explorer, and the problem seems to be simple stack overflow (i.e., 4096 is too small a stack for printf). Increasing the stack size (or choosing table[1], table[2], or table[3] instead table[0], which is effectively the same as increasing stack size) appears to make it work: https://gcc.godbolt.org/z/rnfMThbjo

Sign up to request clarification or add additional context in comments.

2 Comments

I also believe the coro-entering code can be just mov %rdi,%rsp; ret; and correspondingly, the coro-initializing code could end after storing the intial pc. The values of the callee-saved registers at the start of a coro shouldn't matter, IMO.
I could not solve the problem only resizing the stack, but changing the assigment *ptr = initial_pc to *ptr=initial_pc + 8 which just jumps over the stack and frame registers initialization when test_function is called can solve the problem, I really don't know why this is happening just for me and it doesn't make sense

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.