首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >8大小的无效写入(uintptr_t *)

8大小的无效写入(uintptr_t *)
EN

Stack Overflow用户
提问于 2021-11-12 15:07:59
回答 1查看 120关注 0票数 0

我和memcpyvalgrind有个问题,告诉我关于Invalid write of size 8的事。我想弄清楚错误代码在哪里,但我不知道为什么会有错误……我知道在这方面还有其他的问题,但它们并不能真正帮助我。

以下摘录了我在某种程度上“通用”堆栈上的方法中最重要的部分,当我的常规值为uintptr_t类型时。

下面是我在下面使用的两个定义:

代码语言:javascript
复制
// default stack batch size
#define STACK_BATCH_DEFAULT 8
// size of one value in the stack
#define STACK_SIZEOF_ONE    sizeof(uintptr_t)

堆栈的结构如下:

代码语言:javascript
复制
typedef struct Stack
{
    size_t count;       // count of values in the stack
    size_t size;        // size of one value in bytes
    size_t alloced;     // allocated count
    uintptr_t *value;   // the values
    int batch;          // memory gets allocated in those batches
}
Stack;

我有一个堆栈的初始化函数:

代码语言:javascript
复制
bool stack_init(Stack *stack, size_t size, int batch)
{
    if(!stack) return false;
    stack->batch = batch ? batch : STACK_BATCH_DEFAULT;
    stack->size = size;
    stack->count = 0;
    stack->value = 0;
    stack->alloced = 0;
    return true;
}

然后是stack_push函数,其中val差制抛出错误Invalid write of size 8

代码语言:javascript
复制
bool stack_push(Stack *stack, uintptr_t *value)
{
    if(!stack || !value) return false;
    // calculate required amount of elements
    size_t required = stack->batch * (stack->count / stack->batch + 1);
    // allocate more memory if we need to
    if(required > stack->alloced)
    {
        uintptr_t *tmp = realloc(stack->value, required * stack->size);
        if(!tmp) return false;
        stack->value = tmp;
        stack->alloced = required;
    }
    // set the value
    if(stack->size > STACK_SIZEOF_ONE)
    {
        memcpy(stack->value + stack->size * stack->count, value, stack->size);  // <--- valgrind throws the error here
    }
    else
    {
        stack->value[stack->count] = *value;
    }
    // increment count
    stack->count++;
    return true;
}

然后,在我的程序中,我按如下方式调用函数:

代码语言:javascript
复制
Stack stack = {0};  
stack_init(&stack, sizeof(SomeStruct), 0);
/* ... */
SomeStruct push = { // this is a struct that is larger than STACK_SIZEOF_ONE
    .int_a = 0,
    .int_b = 0,
    .int_c = 0,
    .id = 0,
    .pt = pointer_to_struct,    // it is a pointer to some other struct that was allocated beforehand
};
stack_push(&stack, (uintptr_t *)&push);

具有普遍性,我的意思是我也可以有一个普通的堆栈:

代码语言:javascript
复制
Stack stack = {0};
stack_init(&stack, sizeof(uintptr_t), 0);
/* ... */
uintptr_t a = 100;
stack_push(&stack, &a);

此外,如果有什么需要/可以改进的地方,我愿意听取一些一般性的建议和建议:)

编辑:下面是可运行的代码。

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>

// default stack batch size
#define STACK_BATCH_DEFAULT 8
// size of one value in the stack
#define STACK_SIZEOF_ONE    sizeof(uintptr_t)

#define TESTCOUNT   10
#define MAX_BUF     16

typedef struct Stack
{
    size_t count;       // count of values in the stack
    size_t size;        // size of one value in bytes
    size_t alloced;     // allocated count
    uintptr_t *value;   // the values
    int batch;          // memory gets allocated in those batches
}
Stack;

typedef struct SomeStruct
{
    size_t a;
    size_t b;
    size_t c;
    size_t id;
    char *str;
}
SomeStruct;

bool stack_init(Stack *stack, size_t size, int batch)
{
    if(!stack) return false;
    stack->batch = batch ? batch : STACK_BATCH_DEFAULT;
    stack->size = size;
    stack->count = 0;
    stack->value = 0;
    stack->alloced = 0;
    return true;
}

bool stack_push(Stack *stack, uintptr_t *value)
{
    if(!stack || !value) return false;
    // calculate required amount of elements
    size_t required = stack->batch * (stack->count / stack->batch + 1);
    // allocate more memory if we need to
    if(required > stack->alloced)
    {
        uintptr_t *tmp = realloc(stack->value, required * stack->size);
        if(!tmp) return false;
        stack->value = tmp;
        stack->alloced = required;
    }
    // set the value
    if(stack->size > STACK_SIZEOF_ONE)
    {
        memcpy(stack->value + stack->size * stack->count, value, stack->size);  // <--- valgrind throws the error here
    }
    else
    {
        stack->value[stack->count] = *value;
    }
    // increment count
    stack->count++;
    return true;
}

bool stack_pop(Stack *stack, uintptr_t *value)
{
    if(!stack) return false;
    if(!stack->count) return false;

    // decrement count of elements
    stack->count--;

    // return the value if we have an address
    if(value)
    {
        if(stack->size > STACK_SIZEOF_ONE)
        {
            memcpy(value, stack->value + stack->size * stack->count, stack->size);
        }
        else
        {
            *value = stack->value[stack->count];
        }
    }
    
    int required = stack->batch * (stack->count / stack->batch + 1);
    if(required < stack->alloced)
    {
        uintptr_t *tmp = realloc(stack->value, required * stack->size);
        if(!tmp) return false;
        stack->value = tmp;
        stack->alloced = required;
    }
    if(!stack->value) return false;

    return true;
}

int main(void)
{
    // initialize variables
    bool valid = false;
    Stack default_stack = {0};
    Stack some_stack = {0};

    // initialize stacks
    stack_init(&default_stack, sizeof(uintptr_t), 0);
    stack_init(&some_stack, sizeof(SomeStruct), 0);

    // test default case - push
    printf("Testing the default case, pushing...\n");
    for(int i = 0; i < TESTCOUNT; i++)
    {
        uintptr_t push = i;
        valid = stack_push(&default_stack, &push);
        if(!valid) return -1;
    }
    // ...now pop
    printf("Testing the default case, popping...\n");
    do
    {
        uintptr_t pop = 0;
        valid = stack_pop(&default_stack, &pop);
        if(valid) printf("%llu,", pop);
    }
    while(valid);
    printf("\n");

    // test some case - push
    printf("Testing some case, pushing...\n");
    for(int i = 0; i < TESTCOUNT; i++)
    {
        // generate the push struct
        SomeStruct push = {
            .a = i * 10,
            .b = i * 100,
            .c = i * 1000,
            .id = i,
            .str = 0,
        };
        // allocate a string
        push.str = malloc(MAX_BUF + 1);
        snprintf(push.str, MAX_BUF, "%d", i);
        // push
        valid = stack_push(&some_stack, (uintptr_t *)&push);
        if(!valid) return -1;
    }
    // ...now pop
    printf("Testing some case, popping...\n");
    do
    {
        SomeStruct pop = {0};
        valid = stack_pop(&some_stack, (uintptr_t *)&pop);
        if(valid)
        {
            printf("a=%d,b=%d,c=%d,id=%d,str=%s\n", pop.a, pop.b, pop.c, pop.id, pop.str);
            free(pop.str);
        }
    }
    while(valid);
    printf("\n");

    /* leave out free functions for this example.... */

    return 0;
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-11-12 20:14:05

几个小时后,我想明白了:D错误发生了,因为我很少做指针运算.简而言之,我假设它总是使用字节进行计算。

让我们看看包含以下内容的行:

代码语言:javascript
复制
memcpy(stack->value + stack->size * stack->count, value, stack->size);

...and分解了它,所以它更易读。此外,我甚至还会在其中添加一条方便的、花哨的评论:

代码语言:javascript
复制
size_t offset = stack->size * stack->count; // offset in bytes
void *dest = stack->value + offset;
void *src = value;
memcpy(dest, src, stack->size);

现在,亲C程序员应该立即发现问题。在计算stack->value + offset时,它应该以字节添加偏移量,但它不是,因为stack->valueuintptr_t *类型的,而不是uint8_t *类型的。

因此,为了修复它,我用以下一行替换了它:

代码语言:javascript
复制
void *dest = (uint8_t *)stack->value + offset;

密码起作用了。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69945001

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档