aws / jsii

jsii allows code in any language to naturally interact with JavaScript classes. It is the technology that enables the AWS Cloud Development Kit to deliver polyglot libraries from a single codebase!
https://aws.github.io/jsii
Apache License 2.0
2.65k stars 246 forks source link

StackOverflowError with Java when overriding Stack.allocateLogicalId #4656

Open mi-laf opened 3 weeks ago

mi-laf commented 3 weeks ago

Describe the bug

CDK with Java produces StackOverflowErrors when overriding Stack.allocateLogicalId (and having many resources in the stack).

Regression Issue

Last Known Working CDK Version

No response

Expected Behavior

Overriding Stack.allocateLogicalId should not cause a StackOverflowError.

Current Behavior

There is a StackOverflowError when synthesizing the app:

Exception in thread "main" java.lang.StackOverflowError
    at software.amazon.jsii.JsiiEngine.invokeMethod(JsiiEngine.java:482)
    at software.amazon.jsii.JsiiEngine.invokeCallbackMethod(JsiiEngine.java:461)
    at software.amazon.jsii.JsiiEngine.handleCallback(JsiiEngine.java:404)
    at software.amazon.jsii.JsiiRuntime.processCallbackResponse(JsiiRuntime.java:171)
    at software.amazon.jsii.JsiiRuntime.requestResponse(JsiiRuntime.java:121)
    at software.amazon.jsii.JsiiRuntime.processCallbackResponse(JsiiRuntime.java:197)
    at software.amazon.jsii.JsiiRuntime.requestResponse(JsiiRuntime.java:121)
    at software.amazon.jsii.JsiiRuntime.processCallbackResponse(JsiiRuntime.java:197)
    at software.amazon.jsii.JsiiRuntime.requestResponse(JsiiRuntime.java:121)
    ...
    at software.amazon.jsii.JsiiRuntime.processCallbackResponse(JsiiRuntime.java:197)
    at software.amazon.jsii.JsiiRuntime.requestResponse(JsiiRuntime.java:121)
    at software.amazon.jsii.JsiiRuntime.processCallbackResponse(JsiiRuntime.java:197)
    at software.amazon.jsii.JsiiRuntime.requestResponse(JsiiRuntime.java:121)
    at software.amazon.jsii.JsiiRuntime.processCallbackResponse(JsiiRuntime.java:197)
node:events:497
    throw er; // Unhandled 'error' event
    ^
Error: write EPIPE
    at afterWriteDispatched (node:internal/stream_base_commons:159:15)
    at writeGeneric (node:internal/stream_base_commons:150:3)
    at Socket._writeGeneric (node:net:958:11)
    at Socket._write (node:net:970:8)
Error: write EPIPE
    at writeOrBuffer (node:internal/streams/writable:572:12)
    at _write (node:internal/streams/writable:501:10)
    at Writable.write (node:internal/streams/writable:510:10)
    at Socket.ondata (node:internal/streams/readable:1009:22)
    at Socket.emit (node:events:519:28)
    at addChunk (node:internal/streams/readable:561:12)
Emitted 'error' event on Socket instance at:
    at Socket.onerror (node:internal/streams/readable:1028:14)
    at Socket.emit (node:events:519:28)
    at emitErrorNT (node:internal/streams/destroy:170:8)
    at emitErrorCloseNT (node:internal/streams/destroy:129:3)
    at process.processTicksAndRejections (node:internal/process/task_queues:90:21) {
errno: -32,
code: 'EPIPE',
syscall: 'write'
}

Reproduction Steps

Put the following code in file call Main.java and run it with arguments "true" and "250" to create 250 buckets in a stack which overrides Stack.allocateLogicalId. This should reproduce the issue.

import org.jetbrains.annotations.NotNull;
import software.amazon.awscdk.App;
import software.amazon.awscdk.CfnElement;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.services.s3.Bucket;
import software.amazon.awscdk.services.s3.BucketProps;
import software.constructs.Construct;

public class Main {

    /**
     * Creates an app with a single stack which just has a lot of buckets.
     * arg 1: whether to use a stack which overrides Stack.allocateLogicalId ("true" or "false")
     * arg 2: the number of buckets to create
     */
    public static void main(final String[] args) {
        boolean overrideAllocateLogicalId = Boolean.parseBoolean(args[0]);
        int bucketCount = Integer.parseInt(args[1]);

        App app = new App();
        Stack stack = overrideAllocateLogicalId ? new AllocateLogicalIdOverridingStack(app, bucketCount) : new AllocateLogicalIdNotOverridingStack(app, bucketCount);
        System.out.println("Using " + stack.getClass().getName() + " to create " + bucketCount + " buckets.");
        app.synth();
        System.out.println("Successfully synthesized app.");
    }

    private abstract static class AbstractStack extends Stack {
        protected AbstractStack(Construct scope, int bucketCount) {
            super(scope);
            for (int i = 0; i < bucketCount; i++) {
                new Bucket(this, "bucket" + i, BucketProps.builder().bucketName("bucket" + i).enforceSsl(true).build());
            }
        }
    }

    private static class AllocateLogicalIdNotOverridingStack extends AbstractStack {
        private AllocateLogicalIdNotOverridingStack(Construct scope, int bucketCount) {
            super(scope, bucketCount);
        }
    }

    private static class AllocateLogicalIdOverridingStack extends AbstractStack {
        private AllocateLogicalIdOverridingStack(Construct scope, int bucketCount) {
            super(scope, bucketCount);
        }

        @Override
        public @NotNull String allocateLogicalId(@NotNull CfnElement cfnElement) {
            // could allocate special ids here
            return super.allocateLogicalId(cfnElement);
        }
    }
}

Possible Solution

Not overriding Stack.allocateLogicalId fixes the issue. This can be verified by running the example code with "false" and "250".

Adding JVM parameter -Xss2m to increase the stack size also fixes the issue. This is an easy work around. But if this is really necessary (in bigger stacks) and if there are any limits one should be aware of, especially when overriding Stack.allocateLogicalId, they should be documented in the respective Javadoc.

Additional Information/Context

The reason there is .enforceSsl(true) on the bucket (in example code) is that the problem was not reproducible without any bucket settings.

CDK CLI Version

2.160.0

Framework Version

2.160.0

Node.js Version

v22.9.0

OS

Linux

Language

Java

Language Version

Java 21 - Corretto-21.0.4.7.1 (build 21.0.4+7-LTS)

Other information

No response

khushail commented 2 weeks ago

Hi @mi-laf , thanks for reaching out.

Looks like this issue is related to JSII so I am moving this to corresponding repo for further action.