Leaks when passing NSInputSteam to completionhandler in URLSession:task:needNewBodyStream:

I am creating a library for HTTPS access using NSURLSession. My library is built with non-ARC.

I'm trying to create a class like this:

@interface MyURLSession : NSObject <NSURLSessionDataDelegate, NSURLSessionDownloadDelegate>
:
@property (nonatomic, assign) MyInputStream *inputStream;
:
@end

For the GET Method, I created a task with dataTaskWithRequest and was able to access it without memory leaks.

As for the POST Method, when I created and processed the task with uploadTaskWithStreamedRequest, many memory leaks was detected in Leaks of Instruments.

Specifically, calling completionHandler(_inputStream) in URLSession:task:needNewBodyStream: leaks. I think that many other leaks are caused by passing the _inputStream to the completionHandler.

Searching Leaks for HTTP, Session, and Stream words looks like this:

Snapshot Growth Persistent
MyInputStream		176 Bytes	1
CFHTTPMessage		1.72 KiB	6
HTTP2Connection		1.06 KiB	2
HTTP2Stream		928 Bytes	2
HTTPConnectionCacheKey		384 Bytes	3
HTTP2ConnectionCache		288 Bytes	2
HTTP2ConnectionCacheEntry		256 Bytes	2
HTTPHeaderDict		192 Bytes	6
std::__1::__shared_ptr_pointer<HTTP2Stream*, std::__1::default_delete<HTTP2Stream>, std::__1::allocator<HTTP2Stream> >		64 Bytes	2
__NSCFURLSessionConfiguration		512 Bytes	1
__NSURLSessionLocal		368 Bytes	1
HTTP2Stream		928 Bytes	2
RequestBodyStreamProvider		352 Bytes	2
_CFStreamDelegate		128 Bytes	2
std::__1::__shared_ptr_pointer<HTTP2Stream*, std::__1::default_delete<HTTP2Stream>, std::__1::allocator<HTTP2Stream> >		64 Bytes	2
std::__1::__shared_ptr_pointer<__CFReadStream*, Deleter_CFRelease, std::__1::allocator<__CFReadStream> >		64 Bytes	2
std::__1::__shared_ptr_pointer<BlockHolderVar<CFStreamError>*, SmartBlockWithArgs<CFStreamError>::Deleter, std::__1::allocator<BlockHolderVar<CFStreamError> > >		64 Bytes	2

I also searched Leaks for words such as Task and Request, but couldn't find them.

Since the reference counter of _inputSteam is 1 in the end, it seems that the one passed by completionHandler is still referenced.

I tried releasing more reference counters once, and although _inputSteam was released, the other leaks weren't resolved.

Passing MyInputStream * inputSteam is a original derivative class of NSInputStream and is a simple class that just passes data using read:maxLength:.

Could you give me some advice on how to resolve those leaks?

Thanks.

My Environments:XCode 12.4, dev target:iOS 7.0+, Device:iPhone X(OS 12.1)

Answered by mkawasaki in 698419022

I have submitted a bug report.

I'll also consider using a TSI.

Thank you so much for your answer.

It’s quite possible that these leaks are in the OS itself and thus not something that you can fix on your side. However, it’s probably worth checking some things at your end.

To start, is your Objective-C code using ARC?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I understood that there was no way to deal with it.

is your Objective-C code using ARC?

I already mentioned.

My library is built with non-ARC.

I attach a file which is history of refference counter of inputSteam in Leaks. Could you check it to make sure?

Thank you.

I already mentioned.

Oh, right, sorry I missed that.

Hunting memory management bugs in non-ARC code is definitely not fun. Before you start down that path, I recommend that you rule out a problem with the OS first. To do that, create a small test project from one of the built-in templates (which means it’ll use ARC) that uses an upload task with a streamed body to upload some dummy data. Does that leak?

If it does, that’s strong evidence that there’s an OS problem in play. If it doesn’t, you can then look for memory management problems in your code.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I created and tested a sample from the built-in template using ARC as you told me, the leak occurred as well. When using the GET Method, no leaks occured, and when using the POST Method, leaks occured. To use Objective-C with the iOS App, I chose the Storyboard as the interface.

You can download my sample and Leaks results from the following URL.

Sample project(TestHttp) https://1drv.ms/u/s!AjI_SS2OaUbdgRVXDWnuxp4q1F7r?e=tKolBb

Result of Leaks(inputStreamLeaks.trace, Run 1 ... POST Method, Run 2 ... GET Method) https://1drv.ms/u/s!AjI_SS2OaUbdgRI64XG2IFjOm2RW?e=qPudv7

You can find out if it has been leaked by searching word "input" from the Result of Leaks. You will see the leaked MyInputStream with a reference counter of 1 only in Run 1.

Please confirm if it is indeed a problem on the OS side and if there is really no workaround.

Thanks.

Please confirm if it is indeed a problem on the OS side

That seems likely but it’s hard to confirm without a more in-depth investigation, and that’s not something I can do here on DevForums. You have a couple of choices here:

Doing both is fine too (-:

and if there is really no workaround.

That’s something we can look into as part of your TSI.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Accepted Answer

I have submitted a bug report.

I'll also consider using a TSI.

Thank you so much for your answer.

Leaks when passing NSInputSteam to completionhandler in URLSession:task:needNewBodyStream:
 
 
Q