-[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 ...
Другие вопросы по тегам