我试图运行execve时遇到错误的地址

时间:2018-03-17 23:32:46

标签: c++11 valgrind

所以我正在尝试一个字符串向量,其中包含我想尝试并使用execve命令运行的参数。我也在复制环境,因为我写的应用程序需要有一个来自进程的传入环境的副本。这个应用程序是用c ++编写的,我收到的错误是#34; Bad Address"来自execve电话。这是我目前的代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#include <vector>

using namespace std; 

int main (int argc, char * argv[], char * envp[]) {

    int total = 0;
    int a = 0;
    int b = 0;
    char **my_array;
    char **my_envp;

    // Setup copy the environment.
    while (envp[a] != NULL) {
        total++;
        a++;
    }

    my_envp = new char*[total+1];

    for (a = 0; a < total; a++) {
        my_envp[a] = new char[strlen(envp[a])+1];
        strcpy(my_envp[a], envp[a]);
    }
    a++;
    my_envp[a] = NULL;

    // Get my path and arguments.
    vector<string> random = { "/bin/echo", "Grace ", "Will ", "Dan ", "Scott ", "Kevin ", "Amanda " };
    my_array = new char*[random.size()+1];

    for (b = 0; b < random.size(); b++) {
        my_array[b] = new char[strlen(random[b].c_str())+1];
        strcpy(my_array[b], random[b].c_str());
    }
    b++;
    my_array[b] = NULL;

    // Run my arguments.
    pid_t pid;
    pid = fork();
    if (pid == 0) {
        if (execve(my_array[0], my_array, my_envp) == -1)
            perror("");
        exit(1);
    } else {
        waitpid(pid, 0, WUNTRACED);
    }

    // Clean up time.
    for (b = 0; b < random.size(); b++) 
        delete [] my_array[b];

    delete [] my_array;

    for (a = 0; a < total; a++) 
        delete [] my_envp[a];

    delete [] my_envp;

    return 0;
}

这是我的Valgrind输出:

{"
==27594== Memcheck, a memory error detector
==27594== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==27594== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==27594== Command: ./a.out
==27594== 
==27594== Invalid write of size 8
==27594==    at 0x40115A: main (in /home/examples/a.out)
==27594==  Address 0x5ab6eb0 is 0 bytes after a block of size 560 alloc'd
==27594==    at 0x4C2E80F: operator new[](unsigned long) (o)
==27594==    by 0x40106E: main (in /home/examples/a.out)
==27594== 
==27594== Invalid write of size 8
==27594==    at 0x4014E0: main (in /home/examples/a.out)
==27594==  Address 0x5ab9220 is 0 bytes after a block of size 64 alloc'd
==27594==    at 0x4C2E80F: operator new[](unsigned long) ()
==27594==    by 0x4013D1: main (in /home/examples/a.out)
==27594== 
==27595== Syscall param execve(argv) points to uninitialised byte(s)
==27595==    at 0x549E777: execve (syscall-template.S:84)
==27595==    by 0x40151D: main (in /home/examples/a.out)
==27595==  Address 0x5ab9218 is 56 bytes inside a block of size 64 alloc'd
==27595==    at 0x4C2E80F: operator new[](unsigned long) ()
==27595==    by 0x4013D1: main (in /home/examples/a.out)
==27595== 
==27595== Syscall param execve(envp) points to uninitialised byte(s)
==27595==    at 0x549E777: execve (syscall-template.S:84)
==27595==    by 0x40151D: main (in /home/examples/a.out)
==27595==  Address 0x5ab6ea8 is 552 bytes inside a block of size 560 alloc'd
==27595==    at 0x4C2E80F: operator new[](unsigned long) ()
==27595==    by 0x40106E: main (in /home/examples/a.out)
==27595== 
Grace  Will  Dan  Scott  Kevin  Amanda 
==27594== 
==27594== HEAP SUMMARY:
==27594==     in use at exit: 72,704 bytes in 1 blocks
==27594==   total heap usage: 80 allocs, 79 frees, 77,249 bytes allocated
==27594== 
==27594== LEAK SUMMARY:
==27594==    definitely lost: 0 bytes in 0 blocks
==27594==    indirectly lost: 0 bytes in 0 blocks
==27594==      possibly lost: 0 bytes in 0 blocks
==27594==    still reachable: 72,704 bytes in 1 blocks
==27594==         suppressed: 0 bytes in 0 blocks
==27594== Reachable blocks (those to which a pointer was found) are not show
==27594== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==27594== 
==27594== For counts of detected and suppressed errors, rerun with: -v
==27594== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
"}

我有一种感觉,我创建cstring指针的char指针的方式不正确,或者我遗漏了一些非常明显的东西。感谢。

1 个答案:

答案 0 :(得分:2)

您的代码存在问题,既不是您的环境列表也不是 参数列表NULL终止。然后你从中更新了你的代码 我的建议:

  

valgrind与之有什么关系?您执行my_array = new char*[random.size() + 1];并在制作副本的循环之后执行my_array[b] = NULL

但你做错了错误

for (a = 0; a < total; a++) {
    my_envp[a] = new char[strlen(envp[a])+1];
    strcpy(my_envp[a], envp[a]);
}
a++; // <-- does not belong here
my_envp[a] = NULL;

for (b = 0; b < random.size(); b++) {
        my_array[b] = new char[strlen(random[b].c_str())+1];
        strcpy(my_array[b], random[b].c_str());
}
b++; // <-- does not belong here
my_array[b] = NULL;

和valgrind抱怨说:

==27594== Invalid write of size 8
==27594==    at 0x40115A: main (in /home/examples/a.out)
==27594==  Address 0x5ab6eb0 is 0 bytes after a block of size 560 alloc'd
==27594==    at 0x4C2E80F: operator new[](unsigned long) (o)
==27594==    by 0x40106E: main (in /home/examples/a.out)
==27594== 
==27594== Invalid write of size 8
==27594==    at 0x4014E0: main (in /home/examples/a.out)
==27594==  Address 0x5ab9220 is 0 bytes after a block of size 64 alloc'd
==27594==    at 0x4C2E80F: operator new[](unsigned long) ()
==27594==    by 0x4013D1: main (in /home/examples/a.out)

正确的版本应该是(正如我在评论中写的那样)

for (b = 0; b < random.size(); b++) {
        my_array[b] = new char[strlen(random[b].c_str())+1];
        strcpy(my_array[b], random[b].c_str());
}
my_array[b] = NULL;

你不需要b++的原因是因为循环已经在做了。

循环

for(int i = 0; i < 5; ++i)
{
    printf("i in loop: %d\n", i);
}

printf("i out of loop\n");

你会得到

i in loop: 0
i in loop: 1
i in loop: 2
i in loop: 3
i in loop: 4
i out of loop: 5

因为当条件计算结果为false时循环结束,并且会发生这种情况 何时i == 5。如果您增加for,这同样适用于上面的b循环 在循环结束后再次增加。

所以让我们说random.size()是5(就像在我的循环示例中)并且你已经分配了 random.size() + 1 == 6元素的空间,因此您只能从内存中索引 从0到5.在循环结束时b为5,如果你再做b++,那么b 是6和6超出my_array的范围。

要证明这是我编译的代码

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#include <vector>

using namespace std; 

int main (int argc, char * argv[], char * envp[]) {

    // these variables must be unsigned, vector.size()
    // returns an unsigned value
    unsigned int total = 0;
    unsigned int a = 0;
    unsigned int b = 0;
    char **my_array;
    char **my_envp;

    // Setup copy the environment.
    while (envp[a] != NULL) {
        total++;
        a++;
    }

    my_envp = new char*[total+1];

    for (a = 0; a < total; a++) {
        my_envp[a] = new char[strlen(envp[a])+1];
        strcpy(my_envp[a], envp[a]);
    }
    my_envp[a] = NULL;

    // Get my path and arguments.
    vector<string> random = { "/bin/echo", "Grace ", "Will ", "Dan ", "Scott ", "Kevin ", "Amanda " };
    my_array = new char*[random.size()+1];

    for (b = 0; b < random.size(); b++) {
        my_array[b] = new char[strlen(random[b].c_str())+1];
        strcpy(my_array[b], random[b].c_str());
    }
    my_array[b] = NULL;

    // Run my arguments.
    pid_t pid;
    pid = fork();
    if (pid == 0) {
        if (execve(my_array[0], my_array, my_envp) == -1)
            perror("");
        exit(1);
    } else {
        waitpid(pid, 0, WUNTRACED);
    }

    // Clean up time.
    for (b = 0; b < random.size(); b++) 
        delete [] my_array[b];

    delete [] my_array;

    for (a = 0; a < total; a++) 
        delete [] my_envp[a];

    delete [] my_envp;

    return 0;
}

和输出

$ g++ a.cpp -oa -g -Wall 
$ valgrind ./a 
==15833== Memcheck, a memory error detector
==15833== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==15833== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==15833== Command: ./a
==15833== 
Grace  Will  Dan  Scott  Kevin  Amanda 
==15833== 
==15833== HEAP SUMMARY:
==15833==     in use at exit: 0 bytes in 0 blocks
==15833==   total heap usage: 79 allocs, 79 frees, 78,730 bytes allocated
==15833== 
==15833== All heap blocks were freed -- no leaks are possible
==15833== 
==15833== For counts of detected and suppressed errors, rerun with: -v
==15833== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)