简体   繁体   English

输入punning和malloc'ed记忆

[英]Type punning and malloc'ed memory

I originally asked this question: Type Punning with Unions and Heap 我最初问过这个问题: 输入Punning with Union和Heap

And not wanting the question to keep evolving to the point that anyone reading in the future had no idea what the original question was, I have a spin off question. 并且不希望这个问题不断发展,以至于任何读书的人都不知道原来的问题是什么,我有一个旋转问题。

After reading this site: https://kristerw.blogspot.com/2016/05/type-based-aliasing-in-c.html 阅读本网站后: https//kristerw.blogspot.com/2016/05/type-based-aliasing-in-c.html

Near the bottom it talks about malloc'd memory. 在底部附近,它讨论了malloc的内存。 Is it safe to say that casting from one pointer type to another pointer type is safe when memory is on the heap? 可以说当内存在堆上时,从一种指针类型转换为另一种指针类型是安全的吗?

Example: 例:

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

struct test1
{
    int a;
    char b;
};

struct test2
{
    int c;
    char d;
};

void printer(const struct test2* value);

int main()
{
    struct test1* aQuickTest = malloc(sizeof(struct test1));
    aQuickTest->a = 42;
    aQuickTest->b = 'a';
    printer((struct test2*)aQuickTest); //safe because memory was malloc'd???
    return 0;
}

void printer(const struct test2* value)
{
    printf("Int: %i Char: %c",value->c, value->d);
}

And guessing it might not be safe. 并猜测它可能不安全。 What would be the proper way to do this with memcpy? 用memcpy做这个的正确方法是什么? I will attempt to write an example with a function of what might hopefully work? 我将尝试编写一个具有希望功能的函数的示例?

struct test2* converter(struct test1* original);

int main()
{
    struct test1* aQuickTest = malloc(sizeof(struct test1));
    aQuickTest->a = 42;
    aQuickTest->b = 'a';
    struct test2* newStruct = converter(aQuickTest);
    printer(newStruct);
    return 0;
}

struct test2* converter(struct test1* original)
{
    struct test2* temp;
    memcpy(&temp, &original, sizeof(struct test2));
    return temp;
}
void *pnt = malloc(sizeof(struct test1));

What type has the memory behind pnt pointer? pnt指针后面有什么类型的内存? No type. 没有类型。 It is uninitialized (it's value is "indeterminate"). 它是未初始化的(它的价值是“不确定的”)。 There is just "memory". 只有“记忆”。

Then you do: 然后你做:

struct test1* aQuickTest = malloc(sizeof(struct test1));

You only cast the pointer. 你只投了指针。 Nothing happens here. 这里什么都没发生。 No assembly is generated. 不生成任何程序集。 Reading uninitialized memory is undefined behavior tho, so you can't read from aQuickTest->a (yet). 读取未初始化的内存是未定义的行为,因此您无法从aQuickTest->a (尚未)读取。 But you can assign: 但你可以分配:

aQuickTest->a = 1;

This writes to an object struct test1 in the memory. 这将写入内存中的对象struct test1 This is assignment. 这是作业。 You can now read aQuickTest->a , ie. 您现在可以阅读aQuickTest->a ,即。 print it. 打印出来。
But the following 但以下

printf("%d", ((struct test2*)aQuickTest)->a);

is undefined behavior (although it will/should work). 是未定义的行为(虽然它将/应该工作)。 You access the underlying object (ie. struct test1 ) using a not matching pointer type struct test2* . 您使用不匹配的指针类型struct test2*访问底层对象(即struct test1 )。 This is called "strict alias violation". 这称为“严格别名违规”。 Dereferencing an object (ie. doing -> or * ) using a handle of not compatible type results in undefined behavior. 使用不兼容类型的句柄取消引用对象(即,执行->* )会导致未定义的行为。 It does not matter that struct test1 and struct test2 "look the same". struct test1struct test2 “看起来一样”并不重要。 They are different type. 他们是不同的类型。 The rule is in C11 standard 6.5p7 . 该规则符合C11标准6.5p7

In the first code snipped undefined behavior happens on inside printf("Int: %i Char: %c",value->c . The access value-> accesses the underlying memory using incompatible handle. 在第一个代码中,剪切未定义的行为发生在printf("Int: %i Char: %c",value->c内部printf("Int: %i Char: %c",value->c 。访问value->使用不兼容的句柄访问底层内存。

In the second code snipped the variable temp is only a pointer. 在剪切的第二个代码中,变量temp只是一个指针。 Also original is a pointer. original也是一个指针。 Doing memcpy(&temp, &original, sizeof(struct test2)); memcpy(&temp, &original, sizeof(struct test2)); is invalid, because &temp writes into the temp pointer and &original writes into the original pointer. No to the memory behind pointers. As you write out of bounds into 是无效的,因为&temp写入temp指针并且&original写入original pointer. No to the memory behind pointers. As you write out of bounds into original pointer. No to the memory behind pointers. As you write out of bounds into original pointer. No to the memory behind pointers. As you write out of bounds into &temp pointer and read of bounds from &original pointer (because most probably sizeof(temp) < sizeof(struct test2) and sizeof(original) < sizeof(struct test2)`), undefined behavior happens. original pointer. No to the memory behind pointers. As you write out of bounds into &temp pointer and read of bounds from原始pointer (because most probably pointer and read of bounds from pointer (because most probably sizeof(temp)<sizeof(struct test2) and sizeof(原始)<sizeof(struct test2)`),会发生未定义的行为。

Anyway even if it were: 无论如何,即使它是:

    struct test1* original = &(some valid struct test1 object).
    struct test2 temp;
    memcpy(&temp, original, sizeof(struct test2));
    printf("%d", temp.a); // undefined behavior

accessing the memory behind temp variable is still invalid. 访问 temp变量后面的内存仍然无效。 As the original didn't had struct test2 object, it is still invalid. 由于original没有struct test2对象,它仍然无效。 memcpy doesn't change the type of the object in memory. memcpy不会更改内存中对象的类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM