gpt4 book ai didi

C上下文切换堆栈变量损坏

转载 作者:太空宇宙 更新时间:2023-11-04 07:51:01 29 4
gpt4 key购买 nike

我试图通过创建一个简单的上下文切换函数和一个 FCFS 调度程序来在 C 中实现自定义线程。

我要执行的第一步是将整个函数堆栈帧复制到堆中,并将其替换为队列中的第一个帧。

我遇到的问题是,在完成第一个任务后,第二个任务的堆栈被破坏了。我不知道为什么。

我的代码如下:

#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#define ITERATIONS 10
#define SSIZE 15

int * last;

void kwrite(const char*);
void kyield(int *);

void f1() {
int i = ITERATIONS;
while (i--) kwrite("A\n");
}

void f2() {
int i = ITERATIONS*2;
while (i--) {
printf("[%d]", i);
kwrite("B\n");
getchar();
}
}

void kwrite(const char* str) {
int a[10] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5};
write(1, str, strlen(str));

int *frame = malloc(sizeof(int)*SSIZE);
memcpy(frame, a, SSIZE*sizeof(int));
kyield(frame);
printf("ERROR\n");
}

void kyield(int * from) {
if (from == NULL) {
f1();
from = malloc(sizeof(int)*SSIZE);
memcpy(from, last, SSIZE*sizeof(int));
}
if (last == NULL) {
last = malloc(sizeof(int)*SSIZE);
memcpy(last, from, SSIZE*sizeof(int));
free(from);
f2();
exit(0);
}

int a[10] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3};
memcpy(a, last, SSIZE*sizeof(int));
memcpy(last, from, SSIZE*sizeof(int));
free(from);
}

int main(int argc, char** argv) {
kyield(NULL);
free(last);
}

它应该调用 10 次 f1 和 20 次 f2 然后退出。但是当 f2 的 var i 为 8 时,它会在下一次迭代中损坏。因此进入死循环。

如有任何帮助或建议,我们将不胜感激!祝你有美好的一天。

[编辑]我想代码可能有点难以理解,所以这里稍微澄清一下:

main 调用 kyield,参数为 null。

kyield 检测到它并调用 f1

f1 执行直到 kwrite 被调用

kwrite 调用 kyield 并传递其当前栈帧

kyield 检测到最后一个堆栈帧为空,因此它复制 kwrite 给出的堆栈帧(从现在开始为 sf),然后调用 f2f2 和 f1 一样

当接下来执行 kyield 时,from 和 last 都不会为 NULL,因此它将用 last 中的那个覆盖它当前的 s f,将它与 from 中的那个交换,最后它会返回,因为堆栈已被更改它将因此,跳转到最后一个 kwrite 的返回地址,而不是实际的返回地址。从 f1 线程跳转到 f2。

Your memcpy(frame, a, SSIZE*sizeof(int)) looks wrong. Your SSIZE is defined to 15, but a has only a size of 10.

这是故意的,因为通过复制 4 个字节的 15 个元素,我们复制了 rax 的最后一个值、最后一个 ebp 和函数的返回地址。

https://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/

最佳答案

我发现设计存在一些问题。调度不同线程的正常方式是让它们获得完整的堆栈,而不是共享同一个堆栈。

在这种情况下,这意味着堆栈取决于所使用的地址。

+---------+--------+---------+--------+---------+
| main | kyield | f1 | kwrite | kyield |
| | | |a[10] | |
+---------+--------+---------+--------+---------+

|-------------| << copied by the slice of the stack.

您正在获取的堆栈切片独立于它前面的函数中使用的数量,因此如果调用 kwrite 的函数具有不同的堆栈要求(需要不同数量的状态),则会被破坏。

它也坏了,因为在堆栈上捕获的信息量不完整。执行状态基于堆栈和非 volatile 寄存器中的当前值。这些值会污染备用线程。

最后,堆栈还包含地址。该方案只有在所有执行的线程具有相同的堆栈要求时才有效,就好像 yield 函数将需要地址的值粘贴回其中,然后它们始终必须对齐。

关于C上下文切换堆栈变量损坏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53843976/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com