How to prevent memory errors and improve code quality

zhaozj2021-02-08  264

Bytecode prevents memory errors and improves code quality

Translation: Cheramiemail: cherami@163.net

Start using Java

Most Java programmers know that their procedures are usually not compiled as a native code but is compiled into a byte format performed by Java Virtual Machine (JVM). However, there are few Java programmers have seen by node code because their tools do not encourage them to see. Most Java debugging tools do not allow single-step execution bytes, they either display source lines, or nothing is also displayed. Fortunately, JDK provides Java, a command line tool, which makes the viewing byte code easy. Let us look at an example:

Public class bytecodedemo {public static void main (string [] args) {system.out.println ("Hello World");}}

After compiling this class, you can open the .class file with the hex editor and then refer to the virtual machine specification to translate the word code. Fortunately is a simpler method. JDK contains a command line reverse editor: javap, which converts the bytecode as a readable macrper, which can get the '-C' parameter to get the bytecode list by passing the '-C' parameter:

Javap -c bytecodedemo

You should see the output like this:

public class ByteCodeDemo extends java.lang.Object {public ByteCodeDemo (); public static void main (java.lang.String []);} Method ByteCodeDemo () 0 aload_0 1 invokespecial # 1 4 ReturnMethod vid main (java.lang.string "0 getStatic # 2 3 LDC # 3 5 InvokeVirtual # 4 8 return

Just from this short list you can learn a lot of information. Starting from the first instruction from the MAIN method:

0 getStatic # 2 The integer starting is the offset value of the instruction in the method, so the first instruction starts at 0. A mnemonic is tight with the offset is the mnemonic. In this example, 'getStatic' instructions presses a static member into a data structure called an operand stack, follow-up instructions to reference members in this data structure. After the GetStatic instruction, it is a member to be pressed. In this example, the member to be pressed is "# 2 ". If you check the bytecode directly, you will see that the member information is not directly embedded instead of all the constants used by the Java class in a shared pool. Store member information in a constant pool to reduce the size of the byte code instruction, because the instruction only needs to store one index in the constant pool instead of the entire constant. In this example, the member information is located in # 2 in the constant pool. The order in the constant pool is related to the compiler, so it may not be '# 2' in your environment.

After the first instruction is analyzed, it is easy to guess the meaning of other instructions. The 'LDC' (Load Constant) instruction presses the constant "Hello, World." into the operator count. The 'Invokevirtual' instruction calls the PrintLn method, which pops its two parameters from the operator stack. Don't forget that there are two parameters such as Println: the string above, plus hidden 'this' reference. Word: How to prevent memory errors

Java language is often touted to develop the "secure" language of the Internet software. How to reflect security on the surface and C so similar code? An important security concept it introduced is to prevent memory-related errors. Computer criminals use memory errors to insert their malicious code in other situations. The Java Biode code is the first example to prevent this attack, like the example below:

Public float add (float f, int N) {RETURN F N;}

If you add this method to the example above, recompile it, then run Javap, you will see the byte size similar to this:

Method float add (float, int) 0 fload_1 1 iLoad_2 2 i2f 3 fadd 4 freturn

At the beginning of the method, the virtual machine puts the parameters of the method into a data structure called a local variable table. Like the name, the local variable table also contains any local variables you declare. In this example, the method begins with the items of three local variables, which are parameters of the ADD method, and the position 0 saves the THIS reference, and the positions 1 and 2 save the FLOAT and INT parameters, respectively.

To actually operate these variables, they must be loaded (press) to the operator stack. The first command fload_1 presses the FLOAT at position 1 into the operator count, the second instruction iLoad_2 presses the INT of the position 2 into the operator count stack. One of these instructions is a payment of the 'i' and 'F' prefix in the instruction, which means that the Java bytecode instruction is stronger. If the type of parameters and the type of bytecode do not match, the VM refuses this byte code as unsafe. More preferably, the bytecode is designed to perform such a type of security check at the class when the class is loaded.

How is this type of security to strengthen security? If an attacker can deceive the virtual machine to use Int as a float or instead, it can easily destroy the calculation with a expected method. If these calculations involve bank balance, then hidden security is obvious. More dangerous is deceived VM to reference an int as an Object reference. In most cases, this will cause the VM crash, but the attacker only needs to find a vulnerability. Don't forget that an attacker does not manually search this vulnerability - writing a program that generates billions of misunderstandings is quite easy, these arrangements try to find the lucky VM.

Another memory security for the bytecode is an array operation. 'Aastore' and 'Aaload' bytecato operation Java array and they always check array boundaries. If the calling program has passed the array, these bytes will throw an ArrayIndexoutofboundSexception. Perhaps all of the most important inspections use branch instructions, for example, bytecodes starting with IF. In the bytecode, the branch instruction can only be transferred to other instructions in the same method. The unique control that can be delivered outside the method is to return it: throw an exception or perform a 'Invoke' instruction. This not only closes a lot of attacks, but also prevents disgusting errors caused by swaying referen or stack conflicts. If you have used the system debugger to open your program and locate a random location in your code, you will be familiar with these errors. It is important to remember in all of these inspections that they are made by virtual machines in bytecode level rather than just in the source code level. A compiler such as a language such as C may prevent some memory errors discussed above when compiling, but these protection is just in the source code level. The operating system will be happy to load the execution of any machine code, regardless of these code generated by a fine C compiler or is generated by a malicious attacker. Simply put, C is just the top-oriented characteristics of the Java to the object to be extended to the compiled code level.

Analysis by node code improve code quality

The memory and security of Java bytecodes are all exist, so why do we pay attention to the word code? In many cases, you know how the compiler converts your code into a byte code to help you write more efficient code, and in some cases you can prevent unusual impossible errors. Consider the following example:

/ / Return Str1 Str2 String String Concat (String Str1, String Str2) {RETURN STR1 STR2;} // Attach STR2 to Str1 Void Concat (StringBuffer Str1, String Str2) {str1.append (str2);}

Guess how many methods are needed for each method. Now compiling these methods and run javap, you will get the output similar to the following:

Method Java.lang.String Concat1 (java.lang.string, java.lang.string) 0 new # 5 3 DUP 4 InvokeSpecial # 6 7 aload_1 8 invokevirtual # 7 11 aload_2 12 invokevirtual # 7 15 invokevirtual # 8 18 ARETURN

Method void concat2 (java.lang.stringbuffer, java.lang.string) 0 aload_1 1 aload_2 2 invokevirtual # 7 5 POP 6 Return

The Concat1 method performs five ways to call S: New, InvokeSpecial, and Three InvokeVirtuals, which is more work than the Concat2 method, the latter only executes an InvokeVirtual call. Most Java programmers have got a warning because string is not variable, and the string connection is more efficient using StringBuffer. This makes this very vivid using JavaP to analyze this. If you can't affirm that both language constructs are equal in performance, you should use JavaP to analyze bytecode. However, be careful about the Just-IN-TIME (JIT) compiler, because the JIT compiler recombinates the bytecode to the native code to perform some Java's unveiled additional optimization. Unless you have the source code of your virtual machine, you should add a reference performance analysis of your bytecode. One of the final examples show how to check the bytecode to help prevent errors in the program. Create two classes as below to ensure they in separate files.

Public class changeload {public static final boolean debug = false; public static boolean log = false;}

public class EternallyConstant {public static void main (String [] args) {System.out.println ( "EternallyConstant beginning execution"); if (ChangeALot.debug) System.out.println ( "Debug mode is on"); if ( ChangeaT.log) System.out.println ("Logging Mode Is On");}} If you run EternalLyConstant, you will get information:

ETERNALLYCONSTANT BEGINNING Execution.

Now try to edit ChangeAlot, modify the value of debug and log variables (two all True). Only recompile ChangeAlot. Run EternalLyconStant again, you will see the output below:

What happened to ETERNALLYCONSTANT BEGINNING EXECUTION logging mode is on debug? Even if you set the debug to true, the information "debug mode is on" did not appear. The answer is in the bytecode. Running javap for EternalLyConstant You will see:

Method vid main (java.lang.string "0 getStatic # 2 3 LDC # 3 5 Invokevirtual # 4 8 getStatic # 5 11 IFEQ 22 14 getStatic # 2 17 LDC # 6 19 Invokevirtual # 4 22 Return is amazed! There is a 'IFEQ' check on the log member, and the code does not check the debug member. Because Debug members are marked as final type, the compiler knows that debug members will never change at runtime, so it optimizes by removing the 'IF' declaration. This is indeed a very useful optimization because it allows you to embed the debug code in the program and set it when you set it to false. Unfortunately this optimization can lead to the main compilation of chaos. If you change a Final member, you must remember to recompile any classes that may reference the member. This is because this 'Reference' may have been optimized. The Java development environment cannot always find this subtle correlation, some of which can lead to a very strange mistake. Therefore, the ancient C motto is still valid for the Java environment: "WHEN in Doubt, Rebuild All." (Having questions, recompiling all the code). Knowing knowledge of some bytecodes is valuable for programmers programming using Java. JavaP tool makes it easy to view the bytecode. Sometimes, using Javap checks your code to improve performance and capture special unrecognized errors.

Bytecodes and VMs are quite complicated, which has exceeded this tip to cover the range. To know more, see "Inside the Java Virtual Machine" written by Bill Venners (Translator Note: http://www.Artima.com/insidejvm/ed2/ There is a book 1, 2, 3, 4, Free HTML version of 5, 7, 8, 9 and 20, English.)

转载请注明原文地址:https://www.9cbs.com/read-1946.html

New Post(0)