首页 > 解决方案 > strncpy 调用的段错误

问题描述

我想在 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个字符。为什么我会在这里遇到段错误?

标签: cstring

解决方案


修复代码后快速运行以便编译告诉我们段错误来自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}

推荐阅读