【问题标题】:Segfault on strncpy callstrncpy 调用的段错误
【发布时间】:2019-09-11 13:06:13
【问题描述】:

我想在 C 中模拟一个向下增长的调用堆栈,并将以下内容压入堆栈:

这是我编写的测试代码,我只尝试推送字符串,字对齐,然后将地址推送到我刚刚推送的字符串:

#include <math.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>

int main(){

    /*Initialize stack */
    size_t stack_size = (size_t) pow(2,10);
    uint8_t *esp;                             /*Use byte-addressable stack pointer */
    esp = (uint8_t *) malloc(stack_size);

    esp += stack_size - 1;                    /*Set esp to top of allocated memory,
                                            since stack grows downwards */

    /* Parse the string into its tokens */
    char s[]  = "/bin/ls -l foo bar";
    char *tokens[4];
    char *token = strtok(s, " ");
    int num_tokens = 0;                                
    while (token != NULL)
    {
        tokens[num_tokens++] = token;
        token = strtok(NULL, " ");
    }


    size_t esp_iter = 0;                      /*number of bytes pushed,
                                            needed for word alignment */    

    char *stack_pointers[num_tokens];         /* Array to store addresses of
                                               strings that were pushed */

    /* Push the char arrays on the stack */
    for (int j = 0; j < num_tokens; j++)
    {
        esp_iter += strlen(tokens[j]) + 1;      /* +1 because of ‘\0’, which is
                                                  included in strncpy */

        /* Address to store next string into */
        char *next_pointer = (char *) ((uint8_t *) ( esp - esp_iter));

        /* Store address in stack to which token j was pushed */
        stack_pointers[j] = strncpy(next_pointer, tokens[j],
                                    strlen(tokens[num_tokens]) + 1);
    }

    /* word aligning */
    size_t pad = 4 - esp_iter % 4;
    for (int j = 0; j < (int) pad; j++)
    {
        esp_iter += 1;
    }

    /* Push pointers to previously pushed strings */
    for (int j = 0; j < num_tokens; j++)
    {
        esp_iter -= sizeof(char *);

        /* Address on stack to store address of previously
           pushed token to */
        char *stack_pointer = (char *) (esp - esp_iter);
        stack_pointer = (char *) stack_pointers[j];
    }
    return 0;
}

我想在字节级别上寻址堆栈,所以我使用 (uint8_t *) 作为堆栈指针。然后我应该能够在调用 strncpy.但是 strncpy 会产生分段错误,我不明白为什么。 我将内存从 0x7fc4c5001000 分配到 0x7fc4c50013ff。 Esp 设置为 0x7fc4c50013ff,然后我想例如将“bar”推入堆栈,因此我将堆栈指针(堆栈向低内存地址增长)递减 4,并使用目标地址 0x7fc4c50013fb 调用 strncpy,这应该有足够的空间来推这4个字符。为什么会出现段错误?

【问题讨论】:

  • 您的代码可以真的使用一些间距...(和重新样式)。
  • 我不需要完整阅读所有代码。我什至无法阅读它。我读了你的要求,如果它的格式正确并且提供了一个真正的minimal reproducible example,这很可能是一个很好的问题。向下投票箭头是有原因的。
  • 此代码无法编译。我猜你在 main() 的某个地方错过了一个右括号
  • 这一最新的编辑使代码的有效性和可构建性更低。请发布实际产生您所说的代码的代码。尽管有最新的变化,我已经回答了这个问题。您访问的范围超出了tokens
  • 现在编辑了代码并修复了编译错误。很抱歉这个问题编辑得不好,希望现在至少可以阅读。

标签: c string


【解决方案1】:

修复代码后快速运行以便编译告诉我们段错误来自strlen(),而不是strncpy()

stack_pointers[j] = strncpy(next_pointer, tokens[j], strlen(tokens[i]) + 1);

tokens[i] 为空。

在你的代码的前面,你这样做:

int i = 0;
while (token != NULL){
  tokens[i++] = token;
  printf("%s \n", token);
  token = strtok(NULL, " ");
}

这会将 i 增加到 4,因为数组只包含 4 个字符串,而您访问的是第五个位置,自然,strlen() 在访问数组外部时会出现段错误。

#0  __strlen_sse42 () at ../sysdeps/x86_64/multiarch/strlen-sse4.S:32
#1  0x00000000004007b8 in main () at main.c:32
(gdb) f 1
#1  0x00000000004007b8 in main () at main.c:32
32      stack_pointers[j] = strncpy(next_pointer, tokens[j], strlen(tokens[i]) + 1);
(gdb) print tokens[i]
$1 = 0x0
(gdb) print i
$2 = 4
(gdb) print tokens
$3 = {0x7fffffffe020 "/bin/ls", 0x7fffffffe028 "-l", 0x7fffffffe02b "foo", 0x7fffffffe02f "bar", 
  0x0}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多