gcc optimising away compound statement

随声附和 提交于 2019-12-13 06:22:37

问题


I am having an issue with implementing a push_back operator for a generic resizable vector in c. For genericity I need to use a void pointer as an argument, but in practice I want to give it values directly.

When I compile the below code with gcc -o t test.c -std=c99, it prints 10 as I expect. When I add -O1 (or higher) to the compile options, the program prints 0.

I think the problem is in the smemcpy code, as when I replace it with memcpy I no longer have this problem.

Simplified code:

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

#define get_pointer(value) ({ __typeof__(value) tmp = value; &tmp; })

// copy from src to dst byte by byte
void* smemcpy(void* dst, void const * src, size_t len) {
    char * pdst = (char *) dst;
    char const * psrc = (char const *) src;

    while (len--) {
        *pdst++ = *psrc++;
    }

    return (dst);
}


int main() {
    void* container = malloc(sizeof(int));

    // copy a 10 into the container via a temporary pointer
    smemcpy(container, get_pointer(10), sizeof(int));

    printf("%d\n", ((int*)container)[0]);

    return 0;
}

Thanks in advance for any help,

B


回答1:


The definition of get_pointer uses a statement in an expression, which is a GCC extension. The semantics of this are barely documented, and there is no reason to believe the storage duration of an object declared in a statement-expression persists beyond the evaluation of the statement.

Thus, in preparing the call to smemcpy, the compiler may evaluate get_pointer by creating the object tmp, producing its address as the value of the statement-expression, and destroying the object tmp. Then the now-invalid address of the no-longer-existing object is passed to smemcpy, which copies invalid data because the space used for tmp has been reused for another purpose.

The code may work when memcpy is used because memcpy is a special function known to GCC, and GCC optimizes it in various special ways.

A compound literal should work; the C standard specifies that a compound literal within the body of a function has automatic storage duration associated with the enclosing block. If we define get_pointer as follows, the enclosing block includes the entire smemcpy call:

#define get_pointer(value) (& (__typeof__(value)) { value })



回答2:


maybe the problem is in the macro. the tmp variable is defined in a block, i'd guess that the block is left immediatly after its evalutated, that is, before smemcpy is entered. that way the adress to the variable becomes meaningless. the adress could be overwritten by some optimization that reutilizes the memory or left intact in the unoptimized build. just an idea, cant confirm.



来源:https://stackoverflow.com/questions/20777555/gcc-optimising-away-compound-statement

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!