Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
P
protobuf
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
protobuf
Commits
30bbbe99
Commit
30bbbe99
authored
Aug 09, 2016
by
Thomas Van Lenten
Committed by
GitHub
Aug 09, 2016
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1934 from thomasvl/objc_strings_with_null
Never use strlen on utf8 runs so null characters work.
parents
237f321e
1a6c1d09
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
99 additions
and
32 deletions
+99
-32
GPBCodedOutputStream.m
objectivec/GPBCodedOutputStream.m
+5
-32
GPBUtilities.m
objectivec/GPBUtilities.m
+8
-0
GPBCodedOuputStreamTests.m
objectivec/Tests/GPBCodedOuputStreamTests.m
+86
-0
No files found.
objectivec/GPBCodedOutputStream.m
View file @
30bbbe99
...
...
@@ -144,22 +144,6 @@ static void GPBWriteRawLittleEndian64(GPBOutputBufferState *state,
GPBWriteRawByte
(
state
,
(
int32_t
)(
value
>>
56
)
&
0xFF
);
}
#if defined(DEBUG) && DEBUG && !defined(NS_BLOCK_ASSERTIONS)
+
(
void
)
load
{
// This test exists to verify that CFStrings with embedded NULLs will work
// for us. If this Assert fails, all code below that depends on
// CFStringGetCStringPtr will NOT work properly on strings that contain
// embedded NULLs, and we do get that in some protobufs.
// Note that this will not be compiled in release.
// We didn't feel that just keeping it in a unit test was sufficient because
// the Protobuf unit tests are only run when somebody is actually working
// on protobufs.
CFStringRef
zeroTest
=
CFSTR
(
"Test
\0
String"
);
const
char
*
cString
=
CFStringGetCStringPtr
(
zeroTest
,
kCFStringEncodingUTF8
);
NSAssert
(
cString
==
NULL
,
@"Serious Error"
);
}
#endif // DEBUG && !defined(NS_BLOCK_ASSERTIONS)
-
(
void
)
dealloc
{
[
self
flush
];
[
state_
.
output
close
];
...
...
@@ -282,19 +266,15 @@ static void GPBWriteRawLittleEndian64(GPBOutputBufferState *state,
}
-
(
void
)
writeStringNoTag
:
(
const
NSString
*
)
value
{
// If you are concerned about embedded NULLs see the test in
// +load above.
const
char
*
quickString
=
CFStringGetCStringPtr
((
CFStringRef
)
value
,
kCFStringEncodingUTF8
);
size_t
length
=
(
quickString
!=
NULL
)
?
strlen
(
quickString
)
:
[
value
lengthOfBytesUsingEncoding
:
NSUTF8StringEncoding
];
size_t
length
=
[
value
lengthOfBytesUsingEncoding
:
NSUTF8StringEncoding
];
GPBWriteRawVarint32
(
&
state_
,
(
int32_t
)
length
);
if
(
length
==
0
)
{
return
;
}
const
char
*
quickString
=
CFStringGetCStringPtr
((
CFStringRef
)
value
,
kCFStringEncodingUTF8
);
// Fast path: Most strings are short, if the buffer already has space,
// add to it directly.
NSUInteger
bufferBytesLeft
=
state_
.
size
-
state_
.
position
;
...
...
@@ -1038,14 +1018,7 @@ size_t GPBComputeBoolSizeNoTag(BOOL value) {
}
size_t
GPBComputeStringSizeNoTag
(
NSString
*
value
)
{
// If you are concerned about embedded NULLs see the test in
// +load above.
const
char
*
quickString
=
CFStringGetCStringPtr
((
CFStringRef
)
value
,
kCFStringEncodingUTF8
);
NSUInteger
length
=
(
quickString
!=
NULL
)
?
strlen
(
quickString
)
:
[
value
lengthOfBytesUsingEncoding
:
NSUTF8StringEncoding
];
NSUInteger
length
=
[
value
lengthOfBytesUsingEncoding
:
NSUTF8StringEncoding
];
return
GPBComputeRawVarint32SizeForInteger
(
length
)
+
length
;
}
...
...
objectivec/GPBUtilities.m
View file @
30bbbe99
...
...
@@ -1052,7 +1052,15 @@ static void AppendStringEscaped(NSString *toPrint, NSMutableString *destStr) {
case
'\''
:
[
destStr
appendString
:
@"
\\\'
"
];
break
;
case
'\\'
:
[
destStr
appendString
:
@"
\\\\
"
];
break
;
default:
// This differs slightly from the C++ code in that the C++ doesn't
// generate UTF8; it looks at the string in UTF8, but escapes every
// byte > 0x7E.
if
(
aChar
<
0x20
)
{
[
destStr
appendFormat
:
@"
\\
%d%d%d"
,
(
aChar
/
64
),
((
aChar
%
64
)
/
8
),
(
aChar
%
8
)];
}
else
{
[
destStr
appendFormat
:
@"%C"
,
aChar
];
}
break
;
}
}
...
...
objectivec/Tests/GPBCodedOuputStreamTests.m
View file @
30bbbe99
...
...
@@ -193,6 +193,32 @@
}
}
-
(
void
)
assertWriteStringNoTag
:(
NSData
*
)
data
value
:(
NSString
*
)
value
context
:(
NSString
*
)
contextMessage
{
NSOutputStream
*
rawOutput
=
[
NSOutputStream
outputStreamToMemory
];
GPBCodedOutputStream
*
output
=
[
GPBCodedOutputStream
streamWithOutputStream
:
rawOutput
];
[
output
writeStringNoTag
:
value
];
[
output
flush
];
NSData
*
actual
=
[
rawOutput
propertyForKey
:
NSStreamDataWrittenToMemoryStreamKey
];
XCTAssertEqualObjects
(
data
,
actual
,
@"%@"
,
contextMessage
);
// Try different block sizes.
for
(
int
blockSize
=
1
;
blockSize
<=
16
;
blockSize
*=
2
)
{
rawOutput
=
[
NSOutputStream
outputStreamToMemory
];
output
=
[
GPBCodedOutputStream
streamWithOutputStream
:
rawOutput
bufferSize
:
blockSize
];
[
output
writeStringNoTag
:
value
];
[
output
flush
];
actual
=
[
rawOutput
propertyForKey
:
NSStreamDataWrittenToMemoryStreamKey
];
XCTAssertEqualObjects
(
data
,
actual
,
@"%@"
,
contextMessage
);
}
}
-
(
void
)
testWriteVarint1
{
[
self
assertWriteVarint
:
bytes
(
0x00
)
value
:
0
];
}
...
...
@@ -337,4 +363,64 @@
XCTAssertEqualObjects
(
rawBytes
,
goldenData
);
}
-
(
void
)
testCFStringGetCStringPtrAndStringsWithNullChars
{
// This test exists to verify that CFStrings with embedded NULLs still expose
// their raw buffer if they are backed by UTF8 storage. If this fails, the
// quick/direct access paths in GPBCodedOutputStream that depend on
// CFStringGetCStringPtr need to be re-evalutated (maybe just removed).
// And yes, we do get NULLs in strings from some servers.
char
zeroTest
[]
=
"
\0
Test
\0
String"
;
// Note: there is a \0 at the end of this since it is a c-string.
NSString
*
asNSString
=
[[
NSString
alloc
]
initWithBytes
:
zeroTest
length
:
sizeof
(
zeroTest
)
encoding
:
NSUTF8StringEncoding
];
const
char
*
cString
=
CFStringGetCStringPtr
((
CFStringRef
)
asNSString
,
kCFStringEncodingUTF8
);
XCTAssertTrue
(
cString
!=
NULL
);
// Again, if the above assert fails, then it means NSString no longer exposes
// the raw utf8 storage of a string created from utf8 input, so the code using
// CFStringGetCStringPtr in GPBCodedOutputStream will still work (it will take
// a different code path); but the optimizations for when
// CFStringGetCStringPtr does work could possibly go away.
XCTAssertEqual
(
sizeof
(
zeroTest
),
[
asNSString
lengthOfBytesUsingEncoding
:
NSUTF8StringEncoding
]);
XCTAssertTrue
(
0
==
memcmp
(
cString
,
zeroTest
,
sizeof
(
zeroTest
)));
[
asNSString
release
];
}
-
(
void
)
testWriteStringsWithZeroChar
{
// Unicode allows `\0` as a character, and NSString is a class cluster, so
// there are a few different classes that could end up beind a given string.
// Historically, we've seen differences based on constant strings in code and
// strings built via the NSString apis. So this round trips them to ensure
// they are acting as expected.
NSArray
<
NSString
*>
*
strs
=
@[
@"
\0
at start"
,
@"in
\0
middle"
,
@"at end
\0
"
,
];
int
i
=
0
;
for
(
NSString
*
str
in
strs
)
{
NSData
*
asUTF8
=
[
str
dataUsingEncoding
:
NSUTF8StringEncoding
];
NSMutableData
*
expected
=
[
NSMutableData
data
];
uint8_t
lengthByte
=
(
uint8_t
)
asUTF8
.
length
;
[
expected
appendBytes
:
&
lengthByte
length
:
1
];
[
expected
appendData
:
asUTF8
];
NSString
*
context
=
[
NSString
stringWithFormat
:
@"Loop %d - Literal"
,
i
];
[
self
assertWriteStringNoTag
:
expected
value
:
str
context
:
context
];
// Force a new string to be built which gets a different class from the
// NSString class cluster than the literal did.
NSString
*
str2
=
[
NSString
stringWithFormat
:
@"%@"
,
str
];
context
=
[
NSString
stringWithFormat
:
@"Loop %d - Built"
,
i
];
[
self
assertWriteStringNoTag
:
expected
value
:
str2
context
:
context
];
++
i
;
}
}
@end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment