EnzymeAD / EnzymeAD/Enzyme

Heap corruption issue when having a std::vector within a struct.

Open
#2,789 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
LLVM
Stars
1.7k
Forks
188
Avg merge
1d 22h
Merged PRs (30d)
26

Description

Most probably I am missing something very basic (apologies in advance), but I have a heap corruption issue when having a std::vector within a struct.

minimal code:

```cpp
#include
#include

struct PlainState {
double velocity = 0.0;
double density = 0.0;
double pressure = 0.0;
};

struct VectorState {
double velocity = 0.0;
double density = 0.0;
double pressure = 0.0;
std::vector history; // <-- Causes issue
};

template
void ComputePlain(const T &v, const T &rho, PlainState &state) {
state.velocity = v;
state.density = rho;
state.pressure = 0.5 * rho * v * v;
}

template
void ComputeWithVector(const T &v, const T &rho, VectorState &state) {
state.velocity = v;
state.density = rho;
state.pressure = 0.5 * rho * v * v;
state.history.clear();
state.history.push_back(v);
state.history.push_back(state.pressure);
}

template void ComputePlain(const double&, const double&, PlainState&);
template void ComputeWithVector(const double&, const double&, VectorState&);

extern "C" {
extern int enzyme_dup;
extern int enzyme_const;
extern void __enzyme_autodiff(void*, ...);
}

void adjoint_plain(const double *pv, double *d_pv, const double *prho,
PlainState *pState, PlainState *d_pState) {
__enzyme_autodiff(
(void*)ComputePlain,
enzyme_dup, (double*)pv, d_pv,
enzyme_const, prho,
enzyme_dup, pState, d_pState
);
}

void adjoint_vector(const double *pv, double *d_pv, const double *prho,
VectorState *pState, VectorState *d_pState) {
__enzyme_autodiff(
(void*)ComputeWithVector,
enzyme_dup, (double*)pv, d_pv,
enzyme_const, prho,
enzyme_dup, pState, d_pState
);
}

int main() {
// Test 1: Plain struct - WORKS
printf("Test 1 (plain struct)... ");
double v = 25.0, rho = 1.225;
double d_v = 0.0;
PlainState state = {};
PlainState d_state = {};
d_state.pressure = 1.0;
adjoint_plain(&v, &d_v, &rho, &state, &d_state);
printf("OK (d_v = %.6f)\n", d_v);

// Test 2: Struct with vector - CRASHES
printf("Test 2 (struct with vector)... ");
fflush(stdout);
d_v = 0.0;
VectorState v_state = {};
VectorState v_d_state = {};
v_d_state.pressure = 1.0;
adjoint_vector(&v, &d_v, &rho, &v_state, &v_d_state); // CRASHES HERE
printf("OK (d_v = %.6f)\n", d_v);

return 0;
}
```

how I build it:

```bash
# Compile to LLVM IR
clang++ -std=c++17 -O2 -emit-llvm -c enzyme_vector_issue.cpp -o enzyme_vector_issue.bc

# Apply Enzyme pass
opt-enzyme enzyme_vector_issue.bc -passes=enzyme -o enzyme_vector_issue.ll -S

# Compile to native executable
clang++ enzyme_vector_issue.ll -O3 -o enzyme_vector_issue

# Run
./enzyme_vector_issue
```

I gave it a try in the EnzymeAD Explorer and I get a double free() call:

```
freeing without malloc ptr %1
freeing without malloc ptr %1
warning: didn't implement memmove, using memcpy as fallback which can result in errors
warning: didn't implement memmove, using memcpy as fallback which can result in errors
ASM generation compiler returned: 0
freeing without malloc ptr %1
freeing without malloc ptr %1
warning: didn't implement memmove, using memcpy as fallback which can result in errors
warning: didn't implement memmove, using memcpy as fallback which can result in errors
Execution build compiler returned: 0
Program returned: -1
free(): double free detected in tcache 2
Test 1 (plain struct)... OK (d_v = 30.625000)
Test 2 (struct with vector)...
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.