Skip to content

C11: Translation of compound assignment into normal assignment introduces additional behavior #233

Description

@michael-schwarz

CIL lowers compound assignments such as g += 1 to normal assignments g = g + 1. For C11 programs, this is not a semantics preserving operation (see C11 draft (https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1548.pdf), 6.5.16.2)

In the program below, the assertion holds:

#include <assert.h>
#include <pthread.h>
#include <stdatomic.h>

static _Atomic int g;

void *t1(void *arg)
{
    g += 4;
    return NULL;
}

int main(void)
{
    pthread_t thread;

    pthread_create(&thread, NULL, t1, NULL);

    g += 4;

    pthread_join(thread, NULL);
    assert(g == 8);

    return 0;
}

CIL transforms the program into something like

#include <assert.h>
#include <pthread.h>
#include <stdatomic.h>

static _Atomic int g;

void *t1(void *arg)
{
    g  = g + 4;
    return NULL;
}

int main(void)
{
    pthread_t thread;

    pthread_create(&thread, NULL, t1, NULL) ;

    g = g+4;

    pthread_join(thread, NULL);
    assert(g == 8);

    return 0;
}

where after the assert g may also be 4, but no race has occurred. For usage within Goblint this is only a precision problem, but more generally I think this could be considered a miscompilation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions