【发布时间】:2018-11-09 14:33:34
【问题描述】:
我正在解密一个非常适合小尺寸文件的视频文件,但对于 300mb 以上的文件,会出现内存崩溃。代码如下: 我检查了起始字节值,它上升到 315mb,然后崩溃,我的文件大小为 350mb。
它适用于少数 iphone,但很少会崩溃,最好的解决方案是分块执行以避免内存问题,但这样做也会崩溃。
#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
【问题讨论】:
-
当它崩溃时,上面代码中的什么时候它崩溃了?在那一点上似乎总是崩溃?另外,根据它崩溃的位置,您尝试过什么使其无法解决问题的工作? (这样可以省去别人尝试你已经尝试过的东西的麻烦)thx
-
看到它在 for 循环中崩溃,它永远不会出现。它每次都在循环中的不同点崩溃,比如有时 startByte 大约 200MB 有时大约 300MB,但它不会超过 315
-
你已经回答了它在输入文件中崩溃的地方;我在问崩溃时正在执行哪一行代码?
-
是内存问题吧?因此无法找到它崩溃的行,因为调试器因内存崩溃日志而停止
-
当然可以找到导致内存相关崩溃的代码行;我已经做过数百次了;您所做的是在代码中添加日志行,作为代码执行的跟踪;当程序崩溃时,您检查日志以查看执行流程,直到崩溃前记录的最后一件事;通常(但并非总是 - 取决于问题)这将是您代码中连续测试运行的同一点;你通常从几行调试日志开始,然后在崩溃的地方添加更多,直到你找到崩溃的确切行
标签: ios objective-c cryptography commoncrypto