iOS:多次使用同一sqlite参数会导致内存过早释放 [英] ios: using the same sqlite parameter more than once causes premature memory deallocation

查看:72
本文介绍了iOS:多次使用同一sqlite参数会导致内存过早释放的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意: 问题是误导..我认为它使用了多个参数导致内存错误..但这不是原因..原因是格式不正确的sql语句..请参见下面的答案.

Note: the question is misleading.. i thought it was using more than one parameter that causes a memory error.. but that's not the reason.. the reason was an incorrectly formed sql statement.. see the answer below.

如果创建一个使用相同参数多次的sqlite语句,即

if create an sqlite statement that uses the same parameter more than once ie

    NSString* updateStmt = @"INSERT INTO search_email(..., subject, ...)"
    " SELECT ..., :subject, ...,"
    " coalesce((SELECT search_email.threadID "
    " FROM search_email "
    " WHERE search_email.subject MATCH :subject2 "
    " ),"
    " :uid"
    " )";

int subjectIndex = sqlite3_bind_parameter_index(searchEmailInsertStmt,":subject");
int subjectIndex2 = sqlite3_bind_parameter_index(searchEmailInsertStmt,":subject2");

...    
sqlite3_bind_text(searchEmailInsertStmt, subjectIndex, [subject UTF8String], -1, SQLITE_TRANSIENT);        // subject
sqlite3_bind_text(searchEmailInsertStmt, subjectIndex2, [subjectCopy UTF8String], -1, SQLITE_TRANSIENT);        // search_email.subject


if (sqlite3_step(searchEmailInsertStmt) != SQLITE_DONE) {
    NSLog(@"Failed step in searchEmailInsertStmt: '%s', '%i'", sqlite3_errmsg([[AddEmailDBAccessor sharedManager] database]), pk);
}

然后崩溃,并显示以下错误: malloc: *** error for object 0x9b6350: pointer being freed was not allocated *** set a breakpoint in malloc_error_break to debug

then it crashes with the following error: malloc: *** error for object 0x9b6350: pointer being freed was not allocated *** set a breakpoint in malloc_error_break to debug

知道为什么吗?

更新: 如果我用字符串常量即@"subject1"和@"subject2"替换subject和subjectCopy的话,它就可以正常工作..但是由于某种原因,我尝试以编程方式复制此内容,即

update: if i replace subject and subjectCopy with string constants ie @"subject1" and @"subject2" it works just fine.. but for some reason i tried duplicating this programmatically ie

NSString* subjectCopy = [NSString alloc];
subjectCopy = [subject retain];

这些都不起作用..还将SQLITE_TRANSIENT更改为SQLITE_STATIC无效.

and none of those work.. also changing SQLITE_TRANSIENT to SQLITE_STATIC has no effect.

更新2:在malloc_error_break断开后的bt输出:

update 2: output of bt after breaking at malloc_error_break:

thread #6: tid = 0x2503, 0x99a20815 libsystem_c.dylib`malloc_error_break, stop reason = breakpoint 1.1
frame #0: 0x99a20815 libsystem_c.dylib`malloc_error_break
frame #1: 0x99a21d51 libsystem_c.dylib`free + 346
frame #2: 0x0005d5e8 reMail`sqlite3MemFree + 40 at sqlite3.c:12272
frame #3: 0x0002a53e reMail`sqlite3_free + 126 at sqlite3.c:15653
frame #4: 0x0004e670 reMail`sqlite3Fts3ExprFree + 64 at sqlite3.c:101490
frame #5: 0x0004e665 reMail`sqlite3Fts3ExprFree + 53 at sqlite3.c:101489
frame #6: 0x0003fbf1 reMail`fulltextClose + 49 at sqlite3.c:97401
frame #7: 0x000b48f3 reMail`sqlite3VdbeFreeCursor + 163 at sqlite3.c:47461
frame #8: 0x000aebb8 reMail`sqlite3VdbeExec + 17576 at sqlite3.c:54042
frame #9: 0x00032273 reMail`sqlite3Step + 467 at sqlite3.c:49459
frame #10: 0x00031f5e reMail`sqlite3_step + 78 at sqlite3.c:49531
frame #11: 0x000ff2ae reMail`-[EmailProcessor insertIntoSearch:withMetaString:withUid:withSubject:withBody:withFrom:withTo:withCc:withFolder:] + 1854 at EmailProcessor.m:934
frame #12: 0x001005a1 reMail`-[EmailProcessor addEmail:] + 3153 at EmailProcessor.m:1015
frame #13: 0x000fd673 reMail`-[EmailProcessor addEmailWrapper:] + 4035 at EmailProcessor.m:651
frame #14: 0x0324c1bd CoreFoundation`__invoking___ + 29
frame #15: 0x0324c0d6 CoreFoundation`-[NSInvocation invoke] + 342
frame #16: 0x017c36b5 Foundation`-[NSInvocationOperation main] + 45
frame #17: 0x01738d23 Foundation`-[__NSOperationInternal start] + 736
frame #18: 0x01738a34 Foundation`-[NSOperation start] + 79
frame #19: 0x017c5301 Foundation`__block_global_6 + 150
frame #20: 0x02ec053f libdispatch.dylib`_dispatch_call_block_and_release + 15
frame #21: 0x02ed2014 libdispatch.dylib`_dispatch_client_callout + 14
frame #22: 0x02ec32e8 libdispatch.dylib`_dispatch_root_queue_drain + 335
frame #23: 0x02ec3450 libdispatch.dylib`_dispatch_worker_thread2 + 39
frame #24: 0x99a09e12 libsystem_c.dylib`_pthread_wqthread + 441

推荐答案

我终于找到了它!追了那么多红鲱鱼之后..我得到的最佳建议是

I finally found it! after chasing so many red herrings.. the best advice i got was on a forum specialized for sqlite: the point was to keep the guts of sqlite out of my debugging reach, it's extremely unlikely that it's sqlite's fault.

我基本上决定将我的sql语句分解为较小的部分,并自行运行每个语句:

i basically decided to break my sql statement into smaller pieces and run each on it's own:

导致内存问题的原始sql语句:

    NSString* updateStmt = @"INSERT INTO search_email(docid, meta, subject, body, sender, tos, ccs, folder, threadid)"
    " SELECT ?, ?, ?, ?, ?, ?, ?, ?,"
    " coalesce((SELECT search_email.threadID "
    " FROM search_email "
    " WHERE search_email.subject MATCH ?  UNION SELECT * FROM "
    " (SELECT threadID FROM  (SELECT threadID FROM search_email WHERE search_email.sender MATCH ? "
    " INTERSECT SELECT threadID FROM search_email WHERE search_email.tos MATCH ? ) "
    "  UNION "
    " SELECT threadID FROM (SELECT threadID FROM search_email WHERE search_email.sender MATCH ? "
    "       INTERSECT SELECT threadID FROM search_email WHERE search_email.tos MATCH ?)) "
    " LIMIT 1"
    " ),"
    " ?"
    " )";

每当我提供带有特殊字符的字符串以匹配时,就会发生问题. 以下是发送给MATCH的有问题的参数的示例:

the problem happened whenever i supplied strings with special characters to match.. the following are examples of problematic parameters sent to MATCH:

sabaho :)
2月1日新的核心音频问题-代码日志 参考;伊利诺伊州芝加哥市以数据为中心的测试/ETL测试仪的机会.

sabaho :)
New core-audio questions for Feb 1 - Stack Exchange
Ref; Data Centric testing/ETL Tester oppurtunity at Chicago, IL.

为了解决这个问题,我只用普通的=比较替换了MATCH.但是首先使用了regex清理了参数:

so to go around that i simply replaced MATCH with a normal = comparison.. but cleaned up the parameter using regex first:

NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"re:(\\s)*"
                                                                       options:NSRegularExpressionCaseInsensitive
                                                                         error:&error];


                            error:&error];

NSString *filteredSubjectFromRe = [regex stringByReplacingMatchesInString:subject
                                                                  options:0
                                                                    range:NSMakeRange(0, [subject length])
                                                             withTemplate:@""];

if(searchEmailInsertStmt == nil) {

    NSString* updateStmt = @"INSERT INTO search_email(docid, meta, subject, body, sender, tos, ccs, folder, threadid)"
    " SELECT ?, ?, ?, ?, ?, ?, ?, ?,"
    " coalesce((SELECT search_email.threadID "
    " FROM search_email "
    " WHERE search_email.subject = ? UNION SELECT * FROM "
    " (SELECT threadID FROM  (SELECT threadID FROM search_email WHERE search_email.sender = ? "
    " INTERSECT SELECT threadID FROM search_email WHERE search_email.tos = ? ) "
    "  UNION "
    " SELECT threadID FROM (SELECT threadID FROM search_email WHERE search_email.sender = ? "
    "       INTERSECT SELECT threadID FROM search_email WHERE search_email.tos = ?)) "
    " LIMIT 1"
    " ),"
    " ?"
    " )";

这篇关于iOS:多次使用同一sqlite参数会导致内存过早释放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆