(iOS) Jump bypasses initialization of retaining variable when using goto - ios

I got this compiler error when using goto in my ARC iOS project.
Cannot jump from this goto statement to its label. Jump bypasses
initialization of retaining variable
I know goto is bad in general but ... please just tell me how to fix it. The codes are like following,
//some process
NSArray *current = ... ;
if (current.count ==0) goto cleanup;
//proceed to next
if (processed failed) goto cleanup;
//further process
cleanup:
//clean up codes

I finally figured it out! Actually the warning said it clearly, "Jump bypasses initialization of retaining variable" so in the section next
//In proceed to next section I declare & init some object!
My codes/problem is basically the same as c99 goto past initialization
The solution is simple, just added a {} block to it, as here mentioned Why can't variables be declared in a switch statement?
For those who are wondering why I still need goto, I think this explained it Is it ever advantageous to use 'goto' in a language that supports loops and functions? If so, why? , especially "Cleanly exiting a function", check here for an example
http://eli.thegreenplace.net/2009/04/27/using-goto-for-error-handling-in-c
Without goto mainline code is deep inside the nested conditions (Of course we can also introduce a helper function to deal with it).

Related

XCode not stopping on breakpoint in method called from LLDB

XCode 7.2.1
iPad Retina iOS 9.2 Simulator
I have several breakpoints set in a particular class in an XCode project.
Everything I discuss below takes place in this one class file.
I set the breakpoints on -(int16_t)areaNbr by clicking in the gutter, and set no conditions or anything on them. I confirmed they existed as far as LLDB is concerned by running breakpoint list from the LLDB prompt.
The project scheme is set to build for debugging, not release.
I run the project in the simulator, and stop at a breakpoint in a different method than the one in question, at which time I want to go to the LLDB prompt and call po [self areaNbr] and step through areaNbr.
Please note, as this may be quite relevant, I have NO code in the project itself that calls
-(int16_t)areaNbr
Now, I CAN get this to stop at my breakpoints on -(int16_t)areaNbr if I add some code to the project that calls the method.
For example, if I add something like NSLog(#"... %d", [self areaNbr])
I know the issue has nothing to do with compiling away the method simply because nothing calls it, because if that were true, then my call to po [self areaNbr] wouldn't be spitting out the result to the debugger window as pictured below. So the method is being compiled, and certainly recognized as existing by the debugger for execution purposes... just not for stepping purposes.
FYI, [self area] is returning "Area01"
Calling breakpoint list in LLDB returns the following
By default, lldb does not stop at breakpoints in hand-called code. The majority of folks use expr & expr -O -- i.e. po to print values & objects and were annoyed if they stopped at breakpoints they had set for other purposes.
However, it is easy to control this behavior, just use:
(lldb) expr -i 0 -- [self areaNbr]
Then you will stop at your breakpoint.
In this example, I left out the -O which is the object printing part, since if you just want to call this method, you likely don't care about calling description on the result after the expression is evaluated.
You can see all the options for expression evaluation by doing:
(lldb) help expr

What happens when non-void method reaches end in Objective-C?

Question I'd like to ask what happens when a non-void method reaches end without return?
Environment This question is related to iOS and Objective-C. I'm not sure how things described in this question behave elsewhere.
Introduction and background
Normally, when you declare a non-void method in Objective-C and you don't specify a return, Xcode shows a compile error
Control reaches end of non-void function
and forbids you from compiling unless you fix this issue.
The system can be very smart in detecting if your code can or cannot reach an end of non-void function - recognizing if your if/else blocks satisfy all options, going through switches etc.
However, I've found one (and there may be others, really) options of brain-f**king the compiler into thinking "Hey mate, yeah, this code looks perfectly fine, let's compile it and have fun!". It was by accident and caused some head-aches. Here's the code!
The Code
typedef enum eSections { eSectionRecent, eSectionAround, eSectionAll } eSections;
...
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger localSection = section;
if (numberOfSections == 2) localSection++;
switch ((eSections)#(localSection))
{
case eSectionRecent:
return 1;
break;
case eSectionAround:
return 1;
break;
case eSectionAll:
return 3;
break;
}
}
The Result
With this code, the compiler thinks that it's ok to let this method compile, because hey, there's the switch object which is an enum, and there is a case for each of the possible enum values, so, yeah, that sounds legit...
So I'm really interested, what happens now that the compiler was confused and let me run this faulty code to the end?
The Error
For anyone interested, my error was in (eSections)#(localSection), where instead of typing localSection into eSections I typed #(localSection), which compiles into a NSNumber and instead of the value uses the pointer to the object, thus failing to match with any of the the case, since pointers can be quite long (and very probably not 0, 1 or 2). What happened next was that the project tried to allocate space for a really huge number of cells (I think that not specifying a return was something like let's just throw some memory value there) and ultimately crashed the app for memory pressure.
Thanks for all answers!
The result is undefined behavior.
Usually, the caller gets unspecified junk as the return value. Whatever was left in the register or, in some cases, some stack location used by the caller for a local variable is what the caller gets.

Does print() / println() slow execution?

I have an app with a couple of thousand lines and within that code there are a lot of println() commands. Does this slow the app down? It is obviously being executed in the Simulator, but what happens when you archive, submit and download the app from the app store/TestFlight. Is this code still "active", and what about code that is "commented out"?
Is it literally never read or should I delete commented out code when I submit to test flight/app store?
Yes it does slow the code.
Both print and println decrease performance of the application.
Println problem
println is not removed when Swift does code optimisation.
for i in 0...1_000 {
println(i)
}
This code can't be optimised and after compiling Assembly code would perform a loop with 1000 instructions that actually don't do anything valuable.
Analysing Assembly code
The problem is that Swift compiler can't do optimal optimisation to the code with print and println commands.
You can see it if you have a look on generated Assembly code.
You can do see assembly code with Hopper Disassembler or by compiling Swift code to the Assembly with by using swiftc compiler:
xcrun swiftc -emit-assembly myCode.swift
Swift code optimisation
Lets have a look on few examples for better understanding.
Swift compiler can eliminate a lot of unnecessary code like:
Empty function calls
Creating objects that are not used
Empty Loops
Example:
class Object {
func nothing() {
}
}
for i in 0...1_000 {
let object = Object3(x: i)
object.nothing()
object.nothing()
}
In this example Swift complier would do this optimisation:
1. Remove both nothing method calls
After this the loop body would have only 1 instruction
for i in 0...1_000 {
let object = Object(x: i)
}
2. Then it would remove creating Object instance, because it's actually not used.
for i in 0...1_000 {
}
3. The final step would be removing empty loop.
And we end up with no code to execute
Solutions
Comment out print and println
This is definitely not the best solution.
//println("A")
Use DEBUG preprocessor statement
With this solution you can simple change logic of your debug_print function
debug_println("A)
func debug_println<T>(object: T) {
#if DEBUG
println(object)
#endif
}
Conclusion
Always Remove print and println from release application!!
If you add print and println instruction, the Swift code can't be optimised in the most optimal way and it could lead to the big performance penalties.
Generally you should not leave any form of logging turned on in a production app, it will most likely not impact performance but it is poor practice to leave it enabled and unneeded.
As for commented code, this is irrelevant as it will be ignored by the compiler and not be part of the final binary.
See this answer on how to disable println() in production code, there is a variety of solutions, Remove println() for release version iOS Swift
As you do not want to have to comment out all your println() calls just for a release, it is much better to just disable them, otherwise you'll be wasting a lot of time.
printLn shouldn't have much of an impact at all as the bulk of the operation has already been carried out before that point.
Commented out code is sometimes useful, although it can make your source difficult to read it has absolutely no bearing on performance whatsoever and I've never had anything declined for commented out code and my stuff is full of it.

Passing Data through the Stack

I wanted to see if you could pass struct through the stack and I manage to get a local var from a void function in another void function.
Do you guys thinks there is any use to that and is there any chance you can get corrupted data between the two function call ?
Here's the Code in C (I know it's dirty)
#include <stdio.h>
typedef struct pouet
{
int a,b,c;
char d;
char * e;
}Pouet;
void test1()
{
Pouet p1;
p1.a = 1;
p1.b = 2;
p1.c = 3;
p1.d = 'a';
p1.e = "1234567890";
printf("Declared struct : %d %d %d %c \'%s\'\n", p1.a, p1.b, p1.c, p1.d, p1.e);
}
void test2()
{
Pouet p2;
printf("Element of struct undeclared : %d %d %d %c \'%s\'\n", p2.a, p2.b, p2.c, p2.d, p2.e);
p2.a++;
}
int main()
{
test1();
test2();
test2();
return 0;
}
Output is :
Declared struct : 1 2 3 a '1234567890'
Element of struct undeclared : 1 2 3 a '1234567890'
Element of struct undeclared : 2 2 3 a '1234567890'
Contrary to the opinion of the majority, I think it can work out in most of the cases (not that you should rely on it, though).
Let's check it out. First you call test1, and it gets a new stack frame: the stack pointer which signifies the top of the stack goes up. On that stack frame, besides other things, memory for your struct (exactly the size of sizeof(struct pouet)) is reserved and then initialized. What happens when test1 returns? Does its stack frame, along with your memory, get destroyed?
Quite the opposite. It stays on the stack. However, the stack pointer drops below it, back into the calling function. You see, this is quite a simple operation, it's just a matter of changing the stack pointer's value. I doubt there is any technology that clears a stack frame when it is disposed. It's just too costy a thing to do!
What happens then? Well, you call test2. All it stores on the stack is just another instance of struct pouet, which means that its stack frame will most probably be exactly the same size as that of test1. This also means that test2 will reserve the memory that previously contained your initialized struct pouet for its own variable Pouet p2, since both variables should most probably have the same positions relative to the beginning of the stack frame. Which in turn means that it will be initialized to the same value.
However, this setup is not something to be relied upon. Even with concerns about non-standartized behaviour aside, it's bound to be broken by something as simple as a call to a different function between the calls to test1 and test2, or test1 and test2 having stack frames of different sizes.
Also, you should take compiler optimizations into account, which could break things too. However, the more similar your functions are, the less chances there are that they will receive different optimization treatment.
Of course there's a chance you can get corrupted data; you're using undefined behavior.
What you have is undefined behavior.
printf("Element of struct undeclared : %d %d %d %c \'%s\'\n", p2.a, p2.b, p2.c, p2.d, p2.e);
The scope of the variable p2 is local to function test2() and as soon as you exit the function the variable is no more valid.
You are accessing uninitialized variables which will lead to undefined behavior.
The output what you see is not guaranteed at all times and on all platforms. So you need to get rid of the undefined behavior in your code.
The data may or may not appear in test2. It depends on exactly how the program was compiled. It's more likely to work in a toy example like yours than in a real program, and it's more likely to work if you turn off compiler optimizations.
The language definition says that the local variable ceases to exist at the end of the function. Attempting to read the address where you think it was stored may or may produce a result; it could even crash the program, or make it execute some completely unexpected code. It's undefined behavior.
For example, the compiler might decide to put a variable in registers in one function but not in the other, breaking the alignment of variables on the stack. It can even do that with a big struct, splitting it into several registers and some stack — as long as you don't take the address of the struct it doesn't need to exist as an addressable chunk of memory. The compiler might write a stack canary on top of one of the variables. These are just possibilities at the top of my head.
C lets you see a lot behind the scenes. A lot of what you see behind the scenes can completely change from one production compilation or run to the next.
Understanding what's going on here is useful as a debugging skill, to understand where values that you see in a debugger might be coming from. As a programming technique, this is useless since you aren't making the computer accomplish any particular result.
Just because this works for one compiler doesn't mean that it will for all. How uninitialized variables are handled is undefined and one computer could very well init pointers to null etc without breaking any rules.
So don't do this or rely on it. I have actually seen code that depended on functionality in mysql that was a bug. When that was fixed in later versions the program stopped working. My thoughts about the designer of that system I'll keep to myself.
In short, never rely on functionality that is not defined. If you knowingly use it for a specific function and you are prepared that an update to the compiler etc can break it and you keep an eye out for this at all times it might be something you could explain and live with. But most of the time this is far from a good idea.

Should the way NSAssert are handle be raised as a bug

I have a couple of time been caught out putting function code in NSAssert or NSParameter assert, like
NSParameterAssert( [self doSomeWork] );
The problem with this is when you do a release build not only does the code that does an abort if the test fails get omitted from the code, but my code within the () is also omitted also.
Obviously this fix is simple but to me it still this seems wrong, the logic of the code is changed between test build and release build.
I should make it clear I only use this pattern for situation where if the assert fail it is a programmer error.
Personally, I prefer the AssertMacros, which guarantee that the code will be executed, but don't use assertions.
http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/EXTERNAL_HEADERS/AssertMacros.h
I use both assert and NSAssert, and so define the appropriate values to disable them in Distribution builds (I also normally work with a configuration ReleaseWithAsserts to get optimized code with the asserts enabled, so testing as close to the actual distributed code as possible).
What I do is this (you can use the other define if you want NDEBUG is for assert()):
#ifndef NDEBUG
BOOL didWorkSucceed =
#endif
[self doSomeWork]; // returns a BOOL if succeeds
assert(didWorkSucceed);
You can use the defines for all kinds of stuff too - logging etc. Mostly I do test the return codes in Distribution, and return a nil object if it fails instead of ignoring it.

Resources