-[NSInputStream read:maxLength:] выдает исключение, говорящее, что длина слишком велика, но это не так
Я использую NSInputStream
читать данные из файла. Это потерпит крах, если maxLength
больше 49152.
Когда происходит сбой - иногда, но не каждый раз, он выдает следующее сообщение:
*** Завершение работы приложения из-за необработанного исключения "NSInvalidArgumentException", причина: "*** -[NSConcreteData initWithBytes: длина: копия:freeWhenDone:bytesAreVM:]: абсурдная длина: 4294967295, максимальный размер: 2147483648 байт"
По моим расчетам, 524288 все еще меньше этого максимума и может вписаться в возвращаемое значение. Что я упустил?
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
switch (eventCode)
{
case NSStreamEventHasBytesAvailable:
{
NSInteger bufferSizeNumber = 524288; //this one will crash.
// NSInteger bufferSizeNumber = 491520; // this one will work.
uint8_t buf[bufferSizeNumber];
unsigned int len = 0;
len = [_stream read:buf maxLength:bufferSizeNumber]; //crashing at this line
// more code ...
}
// more code...
}
}
Изменить: (Я думаю, что это важная часть этого поведения)
Если я "запускаюсь" в фоновом потоке, то bufferSizeNumber ведет себя так, как описано выше. Но если я "начну" в главном потоке, то bufferSizeNumber может подняться до 943713, прежде чем произойдет сбой.
- (void)start
{
_stream.delegate = self;
[_stream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[_stream open];
[[NSRunLoop currentRunLoop] run];
}
1 ответ
Ваша проблема - это так называемое "переполнение стека" (вы, возможно, слышали это раньше).
Ваш метод выделяет буфер в стеке, используя массив переменной длины:
uint8_t buf[bufferSizeNumber];
Когда размер буфера настолько велик, что он переполняет размер текущего стека, поведение не определено. Неопределенное поведение может привести к сбою или просто работать так, как ожидается: только то, что вы наблюдаете.
512 КБ - это огромный буфер, особенно на iOS, где фоновые потоки получают стек именно такого размера.
Вы должны разместить его в куче:
NSInteger bufferSizeNumber = 524288;
NSMutableData *myBuffer = [NSMutableData dataWithLength:bufferSizeNumber];
uint8_t *buf = [myBuffer mutableBytes];
unsigned int len = 0;
len = [_stream read:buf maxLength:bufferSizeNumber];
// more code ...