So I tried running our app with "Address Sanitizer" enabled. And I got this crash:
let sData = "-e5069fba-3612".data(using:String.Encoding.utf8)!
var pointer = sData.withUnsafeBytes {(bytes: UnsafePointer<CChar>) -> UnsafePointer<CChar> in
return bytes
}
pointer = pointer.advanced(by: 1)
let tmpPIN = String(cString: pointer)
print(tmpPIN)
the crash points to let tmpPIN = String(cString: pointer). Does anyone know the reason behind this? I can't figure out why this is happening.
Note, the app runs fine when I disabled the "Address Sanitizer". Should I be worry about this or just ignore it?
It seems you found an answer that works, but I'm adding one because I'm still kind of baffled by such complex code for such a simple problem.
Your code:
Transforms a Swift string to a Data object,
Gets unsafe bytes from that
Does pointer math on the unsafe bytes to move ahead one byte,
Finally converts the result back into a String.
Your fix makes it even more complex by appending an extra byte you don't even want (it works because C strings are expected to have a null character at the end, and your fix adds that).
This could be done far more simply as:
let sData = "-e5069fba-3612"
let tmpPIN = sData2.dropFirst()
The result is exactly the same.
Or you could handle multiple - characters at the start with something like
let tmpPIN = sData.drop { $0 == "-" }
Which gives the same result for this string.
I found this thread... When I add sData.append(0) after I initialize the sData the Address Sanitizer error is gone.
Related
I've updated to swift 5 and one of the dependencies I use won't compile in swift 5. I've fixed it, but now I'm getting 350+ deprecation warnings all over the file. They're all similar to this:
withUnsafeMutableBytes is deprecated: use withUnsafeMutableBytes<R>(_: (UnsafeMutableRawBufferPointer) throws -> R) rethrows -> R instead
And this is a snipit of the code (it's basically just calling a c library's functions):
var k = Data(count: crypto_generichash_keybytes())
k.withUnsafeMutableBytes { kPtr in
flutter_sodium.crypto_generichash_keygen(kPtr)
}
For reference, in the above crypto_generichash_keybytes() just returns a size_t and crypto_generichash_keygen's signature is void crypto_generichash_keygen(unsigned char k[crypto_generichash_KEYBYTES]);.
I figured out (as this answer states) that the way to get around this should be to call kPtr.baseAddress:
var k = Data(count: crypto_generichash_keybytes())
k.withUnsafeMutableBytes { kPtr in
flutter_sodium.crypto_generichash_keygen(kPtr.baseAddress)
}
as that should use the withUnsafeMutableBytes<ResultType> variant rather than the deprecated withUnsafeMutableBytes<ResultType, ContentType>. However, this instead results in the error
value of type 'UnsafeMutablePointer<_>' has no member 'baseAddress'.
If I explicitly specify the resultType and kPtr:
var k = Data(count: crypto_generichash_keybytes())
k.withUnsafeMutableBytes { (kPtr: UnsafeMutableRawBufferPointer) -> Void in
flutter_sodium.crypto_generichash_keygen(kPtr.baseAddress)
}
I instead get
UnsafeMutableRawBufferPointer' is not convertible to 'UnsafeMutablePointer<_>'.
Are there any swift experts out there that can help me figure out the right way to do this? I know the warnings are just warnings, but I prefer to have code that compiles with no warnings.
I took a look at Swift 5.0: 'withUnsafeBytes' is deprecated: use `withUnsafeBytes<R>(...) before posting this question and it doesn't help my situation as I'm not loading the pointer but rather using the data. Also, I've done exactly what the documentation tells me to but that still isn't helping.
EDIT: To be a bit more clear, some of the 350+ warnings were related to code where the Data is allocated in the code, however some of them are where I receive Data from an external source. That looks something like this:
let args = call.arguments as! NSDictionary
let server_pk = (args["server_pk"] as! FlutterStandardTypedData).data
let server_sk = (args["server_sk"] as! FlutterStandardTypedData).data
let client_pk = (args["client_pk"] as! FlutterStandardTypedData).data
var rx = Data(count: flutter_sodium.crypto_kx_sessionkeybytes())
var tx = Data(count: flutter_sodium.crypto_kx_sessionkeybytes())
let ret = rx.withUnsafeMutableBytes { rxPtr in
tx.withUnsafeMutableBytes { txPtr in
server_pk.withUnsafeBytes { server_pkPtr in
server_sk.withUnsafeBytes { server_skPtr in
client_pk.withUnsafeBytes { client_pkPtr in
flutter_sodium.crypto_kx_server_session_keys(rxPtr, txPtr, server_pkPtr, server_skPtr, client_pkPtr)
}
}
}
}
}
with the corresponding method call
SODIUM_EXPORT
int crypto_kx_client_session_keys(unsigned char rx[crypto_kx_SESSIONKEYBYTES],
unsigned char tx[crypto_kx_SESSIONKEYBYTES],
const unsigned char client_pk[crypto_kx_PUBLICKEYBYTES],
const unsigned char client_sk[crypto_kx_SECRETKEYBYTES],
const unsigned char server_pk[crypto_kx_PUBLICKEYBYTES])
__attribute__ ((warn_unused_result));
(and I know that the code is not really optimal swift, but when dealing with interoperability between dart and swift this is what the flutter team came up with for how to do it).
When I asked the question I was trying to distill it down to the simplest case but that case had a specific answer which differs to the overall problem I'm having.
I wouldn't use Data here – Data represents an untyped collection of "raw" bytes, however crypto_generichash_keygen wants a mutable pointer to typed memory. The reason why the UnsafeMutablePointer<T> variant of withUnsafeMutableBytes was deprecated is that it's fundamentally the wrong abstraction to be providing on untyped memory.
The simplest way to get a buffer of typed memory in Swift is with an Array:
var k = [UInt8](repeating: 0, count: crypto_generichash_keybytes())
flutter_sodium.crypto_generichash_keygen(&k)
You can always turn the resulting buffer into a Data value afterwards by saying Data(k).
Another option is to use an UnsafeMutableBufferPointer:
let k = UnsafeMutableBufferPointer<UInt8>.allocate(capacity: crypto_generichash_keybytes())
defer {
k.deallocate()
}
flutter_sodium.crypto_generichash_keygen(k.baseAddress!)
// Now use the buffer `k` – just make sure you finish using it before the end of
// the scope when `deallocate()` gets called!
Unlike Array, this avoids having to pre-fill the resulting buffer with zeros before being passed off to the C API, however this likely isn't of concern. But just like Array, you can turn such a buffer into a Data by just saying Data(k).
For cases where you get handed a Data value from some external source and need to pass it off to an API as a typed pointer, the simplest and safest option is to just turn it into an array before passing it by saying Array(someData).
For example:
let args = call.arguments as! NSDictionary
let server_pk = (args["server_pk"] as! FlutterStandardTypedData).data
let server_sk = (args["server_sk"] as! FlutterStandardTypedData).data
let client_pk = (args["client_pk"] as! FlutterStandardTypedData).data
var rx = [UInt8](repeating: 0, count: flutter_sodium.crypto_kx_sessionkeybytes())
var tx = [UInt8](repeating: 0, count: flutter_sodium.crypto_kx_sessionkeybytes())
flutter_sodium.crypto_kx_server_session_keys(
&rx, &tx, Array(server_pk), Array(server_sk), Array(client_pk)
)
You probably could use withUnsafeBytes and call bindMemory on the underlying pointer, but I would discourage it, as it changes the type of the underlying memory which could subtly impact the soundness of any other Swift code sharing that memory due to the fact that you're switching out the type from under it.
let first = postalText.text?[(postalText.text?.startIndex)!]
let second = postalText.text?[(postalText.text?.index((postalText.text?.startIndex)!, offsetBy: 1))!]
let third = postalText.text?[(postalText.text?.index((postalText.text?.startIndex)!, offsetBy: 2))!]
I'm trying to capitalize the FIRST and THIRD character and then merge all 3 into a new string
but the .uppercase and .capitalized doesn't work .
Also how do i check that the SECOND character is a number ?
.uppercased and .capitalized only work for strings, what you show there are Characters. You can cast a Character as a String and make it capitalized.
let firstCapitalized = String(first!).capitalized
If you want to check if a Character is an int, you can also make it a String, and then check if casting the String as an Int is non-nil:
if Int("\(second!)") != nil {
print("Is Integer")
}
These cases all assume your first, second, and third are all non-nil, and force-unwraps them.
EDIT
I had some free time and was overlooking some old posts on SO, and I realized this answer I posted isn't using the best coding form. First off, force unwrapping anything is always a bad idea (it's a recipe for a crash in the future), so for the first part. Do something like this:
let firstCapitalized = String(first ?? "").capitalized
This at least gives you a back-out in case first == nil then you'll just be stuck with an empty string.
For the second part, I would use optional unwrapping instead of if Int("\(second!)") != nil. I would say the more proper method would be something like this:
if let second = second, let stringConvertedToInteger = Int("\(String(second))") {
print("\(stringConvertedToInteger) is an integer")
} else {
print("Either second is nil, or it cannot be converted to an integer")
}
This will optionally unwrap the character second, and if it has a value, convert it to an integer (should it be one, checked by optional unwrapping). This is the safest way to do it, and will keep you from experiencing any runtime errors.
So I'm very new to Swift and have been following this tutorial to make this app https://www.youtube.com/watch?v=NJHsdjH2HdY
This was the first problem: currentNumber = currentNumber * 10 + Float(sender.titleLabel!.text!.toInt()!)
In the comments section the guy said to change that line to:
currentNumber = currentNumber * 10 + Float(Int(sender.titleLabel!.text!)!)
I did this and I get the error: Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
As said in the comments, you should always avoid using the 'crash operator' (!) – and learn to safely deal with optional values instead.
Your program is crashing because either the titleLabel, text or Int(...) are nil – and you are then trying to force unwrap them. This could mean that your button doesn't have a titleLabel or that titleLabel's text isn't convertible to an Int.
The solution is to safely deal with the optionals as you encounter them. There are many ways of doing this, but I usually like to use one or multiple guard statements. This allows you to safely unwrap an optional if it has a value, otherwise it will execute the code within the brackets. This is useful for when future code depends on the optional not being nil. For example:
guard let buttonText = sender.titleLabel?.text else {
print("Sender didn't have either a titleLabel or text!")
return
}
guard let textAsInt = Int(buttonText) else {
print("Text wasn't convertible to an Int!")
return
}
currentNumber = currentNumber*10 + Float(textAsInt)
Now you get helpful print messages instead of crashes! Therefore you know exactly what went wrong, and what you can do to fix it (if it needs fixing).
You could also consolidate both of these checks into a single guard if you want more concise code, but less precise errors:
guard let buttonText = sender.titleLabel?.text, textAsInt = Int(buttonText) else {
print("Something went wrong when converting the button title to an Int!")
return
}
currentNumber = currentNumber*10 + Float(textAsInt)
Or you can use flatMap if you like closures:
guard let i = sender.titleLabel?.text.flatMap({Int($0)}) else {
print("Something went wrong when converting the button title to an Int!")
return
}
currentNumber = currentNumber*10 + Float(i)
The flatMap option can look a bit weird at first, but all it's doing is attempting to convert the button's titleLabel's text to an Int. If it fails it will return nil (which the guard will pick up), else it will return the numerical value of the text.
As #vacawama said in the comments, you could also use the nil coalescing operator in order to use 0 in the event that the titleLabel, text or Int(...) are nil:
currentNumber = currentNumber * 10 + Float(Int(sender.titleLabel?.text ?? "") ?? 0)
However bear in mind that this could lead to unexpected behaviour. I suspect that your program is crashing because your logic is getting run for non-numerical buttons, for example the "+" button. If this is the case, you'll be multiplying your number by 10 every time you press a non-numerical button. You'd have to first ensure that your logic only gets called on numerical buttons.
Although without seeing your full code, it's hard to say for sure.
For more info about how to safely deal with optionals, see this extensive Q&A on the subject.
I'm working with a third party c API I'm trying to call one of the functions with a simple string. Something like this:
some_c_func("aString");
I get a build error:
Type 'UnsafeMutablePointer<char_t>' does not conform to protocol 'StringLiteralConvertible'
I've seen some suggestions to use utf8 on String or similar conversions, which gets nearly there, but with the following error:
some_c_func("aString".cStringUsingEncoding(NSUTF8StringEncoding));
'UnsafePointer<Int8>' is not convertible to 'UnsafeMutablePointer<char_t>'
How can I create an UnsafeMutablePointer?
It all depends on what char_t is.
If char_t converts to Int8 then the following will work.
if let cString = str.cStringUsingEncoding(NSUTF8StringEncoding) {
some_c_func(strdup(cString))
}
This can be collapsed to
some_c_func(strdup(str.cStringUsingEncoding(NSUTF8StringEncoding)!))
WARNING! This second method will cause a crash if func cStringUsingEncoding(_:) returns nil.
Updating for Swift 3, and to fix memory leak
If the C string is only needed in a local scope, then no strdup() is needed.
guard let cString = str.cString(using: .utf8) else {
return
}
some_c_func(cString)
cString will have the same memory lifecycle as str (well similar at least).
If the C string needs to live outside the local scope, then you will need a copy. That copy will need to be freed.
guard let interimString = str.cString(using: .utf8), let cString = strdup(interimString) else {
return
}
some_c_func(cString)
//…
free(cString)
it may be simpler than that - many C APIs pass strings around as char * types, and swift treats these as unsafe.
try updating the C API (good) or hack it's header files (bad) to declare these as const char * instead.
in my experience this allows you to pass standard swift String types directly to the C API.
apparently a constant is required, in order to conform to the protocol.
I haven't tried passing strings like that, but I have a C function that I call from Swift, that takes a lot more parameters than shown here, among which is a reference to a Swift C typecast buffer to hold an error string. The compiler doesn't complain and the function call works. Hopefully this will steer you closer to the answer and you can provide an update with the final answer or someone else can.
var err = [CChar](count: 256, repeatedValue: 0)
var rv = somefunc((UnsafeMutablePointer<Int8>)(err))
if (rv < 0) {
println("Error \(err)")
return
}
OK... so I have no idea why this happens but:
Compare the following two lines:
let pointCurve: [AnyObject] = self.curve.map{NSValue(point:$0)}
and
let pointCurve: [NSPoint] = self.curve.map{$0}
In either case, the variable is local and not used at all after assignment. The line resides in a method that is called repeatedly and very quickly. The first case results in terrible and ever faster growing of memory usage. But when I change it to the second, the memory stats are flat as a disc.
You may say, "oh, you're not doing anything in the second line". So I tried the following:
var pointCurve: [AnyObject] = []
for c in self.curve {
pointCurve.append(NSValue(point:NSPoint(x:1, y:1))
}
vs
var pointCurve: [NSPoint] = []
for c in self.curve {
pointCurve.append(NSPoint(x: 1, y: 1))
}
Now I see the exact same results. The culprit seems to be NSValue. I checked with Instruments that a whole bunch of NSConcreteValues are allocated, and I read online these are related to NSValue. But I didn't find anything about them causing memory leaks.
The question is what can I do about this. I'm supposed to send an array of points to some ObjC code, and until I figure out how to fix this, I can't do it without huge performance issues.
Try:
func pointCurvy() {
autoreleasepool {
let pointCurve: [AnyObject] = self.curve.map{NSValue(point:$0)}
// Do something with pointCurve.
}
}