From 49a16a1207f2b78b7a885c647fd372c5def349dd Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 29 Jul 2015 16:53:13 +0200 Subject: Fix an issue where Sequel Pro added a NUL byte to the end of every query (fixes #2184) We tried to convert the query string into a c string that could contain NUL bytes - which by definition a c string cannot (making it a byte buffer with a terminating NUL byte) and then tried to pass that to mysql_real_query() which expects a byte buffer anyway. --- .../Source/SPMySQLConnection Categories/Conversion.m | 8 +++++--- .../SPMySQLConnection Categories/Querying & Preparation.m | 13 +++++++------ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Conversion.m b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Conversion.m index a6c6a14c..676684ca 100644 --- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Conversion.m +++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Conversion.m @@ -40,9 +40,11 @@ * the current encoding, a representation will be returned rather than null. * The returned cString will correctly preserve any nul characters within the string, * which prevents the use of faster functions like [NSString cStringUsingEncoding:]. - * Pass in the third parameter to receive the length of the converted string, or pass - * in NULL if you do not want this information. + * Pass in the third parameter to receive the length of the converted string (INCLUDING + * the terminating \0 character), or pass in NULL if you do not want this information. */ +#warning This method doesn't make sense. It's only addition over [str dataUsingEncoding:allowLossyConversion:] is the terminating NUL byte. \ + But the "string" can already contain NUL bytes, so it's not a valid c string anyway. + (const char *)_cStringForString:(NSString *)aString usingEncoding:(NSStringEncoding)anEncoding returningLengthAs:(NSUInteger *)cStringLengthPointer { @@ -56,7 +58,7 @@ // Take the converted data - not null-terminated - and copy it to a null-terminated buffer char *cStringBytes = malloc(convertedDataLength + 1); memcpy(cStringBytes, [convertedData bytes], convertedDataLength); - cStringBytes[convertedDataLength] = 0L; + cStringBytes[convertedDataLength] = '\0'; if (cStringLengthPointer) *cStringLengthPointer = convertedDataLength+1; diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.m b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.m index 6fce5361..48f4fc1e 100644 --- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.m +++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.m @@ -264,16 +264,17 @@ [delegate willQueryString:theQueryString connection:self]; } - // Retrieve a C-style query string from the supplied NSString - NSUInteger cQueryStringLength; - const char *cQueryString = _cStringForStringWithEncoding(theQueryString, theEncoding, &cQueryStringLength); + // Retrieve a byte buffer from the supplied NSString + NSData *queryData = [theQueryString dataUsingEncoding:theEncoding allowLossyConversion:YES]; + NSUInteger queryBytesLength = [queryData length]; + const char *queryBytes = [queryData bytes]; // Check the query length against the current maximum query length. If it is // larger, the query would error (and probably cause a disconnect), so if // the maximum size is editable, increase it and reconnect. - if (cQueryStringLength > maxQuerySize) { + if (queryBytesLength > maxQuerySize) { queryActionShouldRestoreMaxQuerySize = maxQuerySize; - if (![self _attemptMaxQuerySizeIncreaseTo:(cQueryStringLength + 1024)]) { + if (![self _attemptMaxQuerySizeIncreaseTo:(queryBytesLength + 1024)]) { queryActionShouldRestoreMaxQuerySize = NSNotFound; return nil; } @@ -292,7 +293,7 @@ // While recording the overall execution time (including network lag!), run // the raw query uint64_t queryStartTime = mach_absolute_time(); - queryStatus = mysql_real_query(mySQLConnection, cQueryString, cQueryStringLength); + queryStatus = mysql_real_query(mySQLConnection, queryBytes, queryBytesLength); queryExecutionTime = _elapsedSecondsSinceAbsoluteTime(queryStartTime); lastConnectionUsedTime = mach_absolute_time(); -- cgit v1.2.3