Crash caused by byte alignment problems on iOS platform

Source: Internet
Author: User
Recently, a product we are responsible for developing will crash as soon as it is started, but the version compiled on the development machine is indeed normal. The DB cannot work, which affects the versions in our daily experience development. Therefore, the organization sent me to solve this problem. The first guess is that the certificate of the company RDM is about to expire recently, so it is suspected that it is a certificate problem. I asked the platform staff to check it and confirm that the certificate is correct. However, the compiling environment on the platform is slightly different from that on our development environment, so some colleagues on the platform helped to upgrade the environment. It is not an environment issue. Naturally, we thought of the problem of debug and release versions. DB versions are all release, and we developed and compiled them on our mobile phones with the debug version. Modify the Project Settings, compile the settings to the real machine, and reproduce the crash. [Reproducible bugs cannot be run. :)] After finding the problem, I will post the relevant Code . Here is a pretty strange bug.
1 byte * bytes = (byte *) [ipdata bytes]; 2 // read the total number of IP list groups 3 byte cipgroupcount = bytes [0]; 4 5 If (cipgroupcount = 0) 6 {7 return yes; 8} 9 10 int idx = sizeof (byte); 11 for (byte groupidx = 0; groupidx <cipgroupcount; ++ groupidx) 12 {13 // first read the distribution list type of a short bit. 14 unsigned short type = ntohs (* (unsigned short *) (Bytes + idx )); 15 idx + = sizeof (unsigned short); 16 17 // read the total number of IP addresses in the current IP List Group 18 byte ipitemcount = (byte) * (Bytes + idx ); 19 idx + = sizeof (byte); 20 21 nsmutablearray * IPS = [[nsmutablearray alloc] parts: ipitemcount]; 22 nsmutablearray * ports = [[nsmutablearray alloc] parts: ipitemcount] 23 24 for (byte itemidx = 0; itemidx <ipitemcount; itemidx ++) 25 {26 // read IP address information (the IP address field does not need to be converted to the byte sequence) 27 unsigned int IP = * (unsigned int *) (Bytes + idx); 28 idx + = sizeof (unsigned INT); 29 [IPS addobject: [nsnumber numberwithint: IP]; 30 // read port information 31 unsigned int Port = ntohl (* (unsigned int *) (Bytes + idx); 32 idx + = sizeof (unsigned INT ); 33 [ports addobject: [nsnumber numberwithint: Port]; 34} 35}
The above code is actually very simple, it is to parse a binary format data. There is no problem with running this code, but after the order is adjusted, the crash in the release environment is caused. Or paste the code first (only the changed part of the Code ].
 
1 2 for (byte itemidx = 0; itemidx <ipitemcount; itemidx ++) 3 {4 unsigned int IP = * (unsigned int *) (Bytes + idx ); // This line of code crash 5 idx + = sizeof (unsigned INT); 6 // read port information 7 unsigned int Port = ntohl (* (unsigned int *) (Bytes + idx); 8 idx + = sizeof (unsigned INT); 9 10 [IPS addobject: [nsnumber numberwithint: IP]; 11 [ports addobject: [nsnumber numberwithint: port]; 12}
The changed part is highlighted in bold. Compared with the above code, the code execution sequence is simply changed without any logical modifications. The line of code with comments will crash, and xcode's error is a byte alignment error. Very depressing. Later, I wrote code to verify it. Please refer to the following analysis process. The entire data parsing part is divided into two cycles, and one byte is read at the outermost side of the loop. The data parsing process is as follows: 1. [1 byte] [total number of read bytes] --- 2. the External Loop starts [2 bytes] [read two byte type information] [1 byte] [read the total number of IP addresses in one byte] -------- 3. inner cycle starts * [4 byte] [4 byte IP address] [4 byte] [4 byte port number] When the above process is executed 1 + 2 × 1 (once in an external loop) + 3 × 1 (once in an internal loop, the entire offset is (1 + 2 + 1 + 4 + 4), a multiple of 4. Here, no matter how many times 3 (inner loop) is executed, the entire offset is a multiple of 4. But as long as 2 (External Loop) is executed more than once, when the above process is executed to the line marked with "*", the offset is no longer a multiple of 4. This time Unsigned int IP = * (unsigned int *) (Bytes + idx );This line of code will crash in the relase environment. After analyzing the process, I still have a question: why is there no crash for the first piece of code under the same data. I can only guess that a line of OC code is executed at intervals of a line of C code. 2nd lines of code may be caused by Compiler optimization. If you have any research on this issue, please contact us.   Finally, I will provide my current solution. For parsing this compact format of binary data, it is best to use the following code to process the data type conversion, in this way, the problem of byte alignment can be avoided.
 
1 // read IP address information (the IP address field does not need to be converted to the byte order) 2 unsigned int IP = 0; 3 memcpy (& IP, bytes + idx, sizeof (unsigned INT )); 4 idx + = sizeof (unsigned INT );
A strange problem is that the iOS platform requires memory byte alignment during forced data type conversion. The debug environment is not required. If the two forced conversions are separated by OC code, the release execution is correct, so it is suspected that it is caused by the compiler optimization during xocde compilation. --------------- Later discussion ---------- thanks @ springhu for pointing out the error. memcpy should be used instead of memccpy [I have always understood the usage of memccpy wrong ]. After discussing with springhu for a long time, we separately wrote a demo project to simulate the case above. The result showed that there was no crash in the release environment. The problem only occurs in my project. After some column tests, I found that this strange problem only exists in my scenario code. After the parsing part is separately encapsulated into a function, the call in the application won't go wrong. Unsigned int IP = * (unsigned int *) (Bytes + idx ); In theory, there is no problem with this writing method. You do not need to consider the issue of byte alignment when using it in applications, but you are not afraid of 10 thousand. I am afraid that the compiler is willing to do bad things. Exc_arm_da_align This keyword can be used to Google many related Article
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.