You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Local array initializers can cause linear AST growth and compiler memory exhaustion #602
CompCert expands the implicit tail of an automatic-storage array declaration initializer into one assignment AST node per omitted element. As a result, a constant-size initializer such as { 0 } can make compiler memory consumption proportional to the declared array bound and can exhaust memory on valid C programs.
This minimal reproducer can be verified in a container limited to 512 MiB, where compilation is killed while the front end processes the initializer. Reducing the bound to 100,000 and compiling with -dparse makes the expansion directly visible in the post-Unblock.parsed.c output.
During the Unblock front-end transformation, the local initializer is recursively expanded into assignments for every array position, including every implicit zero-initialized element. Therefore the intermediate C AST itself becomes linear in the number of omitted elements.
I initially reproduced the problem with CompCert 3.17 and reproduced it again with CompCert 3.18 at commit 66a9fd0. The issue also affects real programs such as certain post-quantum cryptographic algorithms, which require a workaround to compile on typical consumer-grade hardware.
Expected behavior
The size of the AST produced for an implicit tail of a local array declaration should be independent of the number of omitted elements, apart from the nesting depth and the structure needed to initialize one element.
Explicitly written initializer expressions must retain their current typing and lowering behavior, and each expression must still be evaluated exactly once. Implicit elements must receive the typed default initialization required by C, including for nested aggregates, pointers, floating-point objects, and volatile subobjects.
Proposed solution
For an automatic array declaration with bound N and K explicitly supplied elements:
Keep the explicit prefix as the existing typed assignments.
If K < N, emit one counted loop over the half-open range [K, N).
Use a fresh function-local induction variable with the target's size_t
integer kind.
Recursively emit the existing typed default initialization for one element
as the loop body.
Conceptually:
Ta[N] = { e0, e1 };
would be lowered to the equivalent of:
a[0] =e0;
a[1] =e1;
for (size_t__init_index=2; __init_index<N; ++__init_index) {
/* existing typed default initialization of a[__init_index] */
}
Activity