我正在解密一个视频文件,这对小尺寸的文件很好,但对于300mb以上的文件,有内存崩溃。代码如下:我检查了开始字节值,它一直到315mb,然后崩溃,我的文件大小是350mb。
它在很少的iphones上工作,对少数人崩溃,最好的解决方案是分块进行,以避免内存问题,但它也会崩溃。
#define kChunkSizeBytes (1024*1024) // 1 MB
@implementation NSMutableData (Crypto)
-(BOOL) doCrypto:(NSString *)key operation: (CCOperation) operation
{
//Keeping it 32 as per our key
char keyPtr[512 + 1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// Fetch key data
if (![key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding]) {return FALSE;} // Length of 'key' is bigger than keyPtr
CCCryptorRef cryptor;
CCCryptorStatus cryptStatus = CCCryptorCreate(operation, kCCAlgorithmRC4, 0,
keyPtr, key.length,
NULL, // IV - needed?
&cryptor);
if (cryptStatus != kCCSuccess) { // Handle error here
return FALSE;
}
size_t dataOutMoved;
size_t dataInLength = kChunkSizeBytes; // #define kChunkSizeBytes (16)
size_t dataOutLength = CCCryptorGetOutputLength(cryptor, dataInLength, FALSE);
size_t totalLength = 0; // Keeps track of the total length of the output buffer
size_t filePtr = 0; // Maintains the file pointer for the output buffer
NSInteger startByte; // Maintains the file pointer for the input buffer
char *dataIn = malloc(dataInLength);
char *dataOut = malloc(dataOutLength);
NSRange bytesRange = NSMakeRange((NSUInteger) 0, (NSUInteger) 0);
for (startByte = 0; startByte <= [self length]; startByte += kChunkSizeBytes) {
if ((startByte + kChunkSizeBytes) > [self length]) {
dataInLength = [self length] - startByte;
}
else {
dataInLength = kChunkSizeBytes;
}
// Get the chunk to be ciphered from the input buffer
bytesRange = NSMakeRange((NSUInteger) startByte, (NSUInteger) dataInLength);
[self getBytes:dataIn range:bytesRange];
cryptStatus = CCCryptorUpdate(cryptor, dataIn, dataInLength, dataOut, dataOutLength, &dataOutMoved);
if (startByte >= 203728200) {
NSLog(@"%ld",(long)startByte);
}
if (dataOutMoved != dataOutLength) {
NSLog(@"dataOutMoved (%d) != dataOutLength (%d)", dataOutMoved, dataOutLength);
}
if ( cryptStatus != kCCSuccess)
{
NSLog(@"Failed CCCryptorUpdate: %d", cryptStatus);
}
// Write the ciphered buffer into the output buffer
bytesRange = NSMakeRange(filePtr, (NSUInteger) dataOutMoved);
[self replaceBytesInRange:bytesRange withBytes:dataOut];
totalLength += dataOutMoved;
filePtr += dataOutMoved;
}
// Finalize encryption/decryption.
cryptStatus = CCCryptorFinal(cryptor, dataOut, dataOutLength, &dataOutMoved);
totalLength += dataOutMoved;
if ( cryptStatus != kCCSuccess)
{
NSLog(@"Failed CCCryptorFinal: %d", cryptStatus);
}
// In the case of encryption, expand the buffer if it required some padding (an encrypted buffer will always be a multiple of 16).
// In the case of decryption, truncate our buffer in case the encrypted buffer contained some padding
[self setLength:totalLength];
// Finalize the buffer with data from the CCCryptorFinal call
NSRange bytesNewRange = NSMakeRange(filePtr, (NSUInteger) dataOutMoved);
[self replaceBytesInRange:bytesNewRange withBytes:dataOut];
CCCryptorRelease(cryptor);
free(dataIn);
free(dataOut);
return 1;
}
@end发布于 2018-11-11 03:52:03
如果replaceBytesInRange:bytesRange导致了崩溃,那么我关于如何避免崩溃的第一个建议是为它所依赖的前面的函数调用添加错误检查。
例如,在它崩溃的情况下,bytesRange可能不是一个有效/可用的值。也许它的dataOut是无效/可用的。问题中的代码从函数调用中设置这些值,但不检查错误条件/错误指示器/无效值的返回值。
它可能是一个相关的依赖函数调用。例如,通过调用CCCryptorUpdate()来设置cryptStatus,它将dataOut作为输入参数。我不知道Objective-C,也不熟悉函数CCCryptorUpdate(),但它看起来会影响/填充dataOut。如果它实际上返回了一个错误,那么当您在replaceBytesInRange行上使用它时,dataOut可能还没有处于可用状态。检查cryptStatus的返回值可能会标记不应在以后的调用中继续使用dataOut的情况。
这就引出了我注意到的另一件事:您确实检查了一些东西,但只记录了它们。对if (dataOutMoved != dataOutLength)和(cryptStatus != kCCSuccess)的检查看起来应该停止执行,或者中断循环,或者类似的事情,而不仅仅是记录发生的事情。
我看到的另一件事是dataOut只被malloc()'d一次,而不是被清除,并且被重复使用。这在某些情况下是完全有效的,但它也可能导致您所看到的那种错误。您的代码中是否有任何关于dataOut内容的假设?我在考虑采用空值终止的C字符串操作。如果不小心,假设在那里(或者可能实际上一开始就在那里)的空终止符可能会被覆盖,比如说,如果整个缓冲区被填满了。再说一次,我不太了解Objective-C和这些函数,所以这不是一个特定的声明,而是对可能发生的事情的一种类比。
TL;DR:向每个函数调用添加错误检查,并做出相应的响应(中断、退出、重试等),这样以后的函数调用就不会尝试使用指示错误或其他无效的值。
我敢打赌,通过添加错误检查,您将(1)停止崩溃,(2)了解为什么大于一定数量的文件会导致这些崩溃。
https://stackoverflow.com/questions/53227711
复制相似问题