iOS应用程序中的SQLite C函数导致EXC_BAD_ACCESS

在iOS应用程序中,我试图从100万行的表中的SQLite字段中去除变音符号。

编辑 : 我引用的原始答案已由其作者更新以反映下面接受的答案。 对于任何想要做同样事情的人来说,这是最好的答案。

Rob从早些时候的回答中得到了一个很好的开始。 对于这个问题,我试图复制一个表到另一个使用INSERT INTO ... SELECT ... FROM ...语句。 这工作正常,直到我引入一个C函数,从字段中去除重音和其他变音符号:

 INSERT INTO DestinationTable (MasterField, SubField, IndexID) SELECT unaccented(MasterField), SubField, IndexID FROM SourceTable 

随着unaccented()函数的介绍,我经常会得到一个EXC_BAD_ACCESS,我将在下面指定。 但令人震惊的是,SQLite操作有时会成功完成所有100万行 。 当我扩展负载以复制500万行时,应用程序将始终崩溃。

TL; DR

这里是我的源代码,EXC_BAD_ACCESS指向第一个函数的底部:

 #import <sqlite3.h> sqlite3 *db; void unaccented(sqlite3_context *context, int argc, sqlite3_value **argv) { if (argc != 1 || sqlite3_value_type(argv[0]) != SQLITE_TEXT) { sqlite3_result_null(context); return; } @autoreleasepool { NSMutableString *string = [NSMutableString stringWithUTF8String:(const char *)sqlite3_value_text(argv[0])]; CFStringTransform((__bridge CFMutableStringRef)string, NULL, kCFStringTransformStripCombiningMarks, NO); char *buf = sqlite3_malloc(sizeof(char) * [string length] + 1); strcpy(buf, [string UTF8String]); sqlite3_result_text(context, buf, -1, sqlite3_free); } // This is where I usually get "EXC_BAD_ACCESS (code=1, address=...)" } @implementation MyClass - (void)myMethod { NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); NSString *cachesDir = [documentPaths objectAtIndex:0]; NSFileManager *fileManager = [NSFileManager defaultManager]; NSError *error = nil; NSDirectoryEnumerator *directoryEnumerator = [fileManager enumeratorAtPath:[[NSBundle mainBundle] resourcePath]]; NSString *fileName; while (fileName = [directoryEnumerator nextObject]) { if ([fileName hasSuffix:@".sqlite"]) { if (![fileManager fileExistsAtPath: [cachesDir stringByAppendingPathComponent:fileName]] == YES) { if (![fileManager copyItemAtPath:[[NSBundle mainBundle] pathForResource:fileName ofType:@""] toPath:[cachesDir stringByAppendingPathComponent:fileName] error:&error]) { NSLog(@"Error description - %@ \n", [error localizedDescription]); NSLog(@"Error reason - %@", [error localizedFailureReason]); } else { NSLog(@"HAI %@", fileName); [self openDB:[cachesDir stringByAppendingPathComponent:fileName]]; NSString *sqlCommand = @"INSERT INTO DestinationTable (MasterField, SubField, IndexID) SELECT unaccented(MasterField), SubField, IndexID FROM SourceTable"; char *sqlError; if (sqlite3_exec(db, [sqlCommand UTF8String], NULL, NULL, &sqlError) != SQLITE_OK) { NSLog(@"sqlite3_exec INSERT NOT SQLITE_OK with error: %d: %s", sqlite3_errcode(db), sqlite3_errmsg(db)); } [self closeDB]; NSLog(@"KTHXBYE %@", fileName); } } } } } - (void) openDB: (NSString *)filePath { if (sqlite3_open([filePath UTF8String], &db) != SQLITE_OK) { sqlite3_close(db); } else { [self createUnaccentedFunction]; } } - (void) closeDB { sqlite3_close(db); } - (void)createUnaccentedFunction { if (sqlite3_create_function_v2(db, "unaccented", 1, SQLITE_ANY, NULL, &unaccented, NULL, NULL, NULL) != SQLITE_OK) { NSLog(@"%s: sqlite3_create_function_v2 error: %s", __FUNCTION__, sqlite3_errmsg(db)); } } 

任何意见,我在做什么错了?

可能是这样的:

 char *buf = sqlite3_malloc(sizeof(char) * [string length] + 1); strcpy(buf, [string UTF8String]); 

您正在分配length Unicode字符,而不是UTF-8字节。

strcpy可能会尝试写入无效的内存。

我build议你让SQLite复制string使用:

 sqlite3_result_text(context, [string UTF8String], -1, SQLITE_TRANSIENT);