-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
Hi team,
Description
When initializing an SMIMESigned object with a MimeMessage (or MimeBodyPart), Bouncy Castle internalizes the message's content by calling getInputStream().
In many JavaMail configurations (especially with complex nested MimeMultipart objects), getInputStream() returns a PipedInputStream. This implementation spawns a background "producer" thread (often named DataHandler.getInputStream) to pump data into the pipe.
If the MimeMessage is malformed or not a valid S/MIME signed message, the SMIMESigned constructor throws a MessagingException or CMSException. However, if the input stream has already been opened, it is not explicitly closed in a finally block. Because the stream remains open but is no longer being read by the now-defunct SMIMESigned instance, the producer thread stays in a Running state indefinitely, leading to a thread leak.
Steps to Reproduce
- Create a MimeMessage that is not a valid S/MIME signed message (e.g., a standard multipart/mixed message).
- Pass this message to the SMIMESigned constructor.
- Catch the resulting exception.
- Observe the JVM thread count or use a debugger to see that the DataHandler.getInputStream thread remains active.
Here is a small java class to reproduce the issue:
PipedStreamThreadStuckTest.java
And here are the threads before SMIMESigned throw exception:

And after Thread [DataHandler.getInputStream] is stuck in Running state after the SMIMESigned constructor failed:

Impact
In high-volume mail processing applications, this results in a gradual exhaustion of the thread pool, eventually leading to OutOfMemoryError or application instability.
Suggested Fix
In the SMIMESigned (and potentially SMIMEMailCap) constructors, ensure that any InputStream obtained from a MimePart is wrapped in a try-finally block or handled such that close() is called if the parsing fails.
Thank you for your help!