Article 68: Summary of thread deadlock issues and pitfalls when writing scanner UI interfaces in javafx

f548e59533febb66a2a272a2667c5ad2.png

 Part1 Preface 

Hello everyone, my name is ABC_123 . In the past, the graphical interfaces of writing tools were implemented using the swing framework, but the swing framework has not been updated in more than 10 years. Many controls are very troublesome to use, and interface artists require a lot of effort. In order to keep up with the pace of knowledge updates, ABC_123 recently spent time learning javafx (with a foundation in swing, learning javafx is very fast), so it took time to replace the graphical interface of the previous scanning tool with javafx, but in multi- threading When manipulating the graphical interface controls, we encountered a series of thread deadlock problems . In order to solve these problems, ABC_123 stepped on a lot of pitfalls. I will take notes today, review myself, and share my experience with everyone.

 Part2 Technical Research Process 

  • Scanner design ideas

I want to implement the following functions: after burpsuite captures a data packet, right-click to pop up the menu and send the specified scanning task to the "scan task queue" of the server for scanning. Communication with the server is achieved through sockets.

a196e67f8f1d289d07f4648744ee4b77.png

The "scanning task queue" will listen to a port. After receiving the task request from burpsuite, it will create a new Tab label, and then allocate 10 threads for each task to scan. In other words, each Tab label corresponds to a scanning task. Scanning tasks are all running with 10 threads. In the process of writing this scanning tool, I stepped on a lot of pitfalls. Next, I will share the solution with everyone.

70b629dc3e586ead4764801dc22460b4.png

  • Pit 1: Adding a Tab label in multi-threading directly reports an error

I encountered an error when I first started operating the javafx control with multi-threading. When adding a graphical control to the graphical interface, the error message was "Not on FX application thread; currentThread = Thread-3", which roughly means "the current thread is not a JavaFX application thread" ".

362c42c9c996922a9f223d575c7a2061.png

After a series of searches, it was found that the graphical control to control javafx needs to be wrapped with the following Java statement Platform.runLater(() -> { });.

2c2339a0f143b1ac41c5f964dbd09bd1.png

  • Pit 2: Selection issue between Platform.runLater and ReentrantLock reentrant locks

From the previous discussion, we know that Platform.runLater ensures the thread safety of javafx, and the ReentrantLock lock can ensure the thread safety of global variables. This leads to a question. For the following code, when multi-threads manipulate the value of the global variable qq.readResCount = qq.readResCount + 1;, it itself has been wrapped by Platform.runLater(() -> {}); Should I add another ReentrantLock to ensure thread safety?

0c35b75c0b3da378f5d1904f26ce81ee.png

I searched various Baidu and Google on the Internet, and then asked people around me. There were different opinions on this issue, so I simply wrote a test code myself and tested it in practice.

 1 Wrong way of writing global variables without locking

First, let’s review the problem of multi-thread resource competition. An error occurs after the following code is run. Because there are no restrictions on multi-threaded manipulation of global variables, competition problems will obviously occur. The normal output is that 7, 8, 9, and 10 appear randomly, but multiple 10s and multiple 11s appear, and the output result is obviously incorrect. Next, test according to the situation and explore how Platform.runLater and ReentrantLock should be used together .

7176f0b1085c49a2290177bfe4e38dc9.png

 2 Platform.runLater is not used, ReentrantLock is used.

First look at this situation. Various errors are reported immediately after running, indicating that the ReentrantLock lock cannot guarantee the thread safety of the javafx control .

acedbdc57b8f2e3e8636113ca6661596.png

 3 Platform.runLater is used, ReentrantLock is also used

Next, look at this situation. It is very stable after running and there are no problems. But for changes to the Quanjv.count global variable, can the ReentrantLock be removed?

2314e69eef52b53d71323e0bf12bdd88.png

 4 Remove the ReentrantLock

Next, look at this situation, remove the ReentrantLock, and use Platform.runLater to protect Quanjv.count. It is found that after the program is run, there is no problem, indicating that Platform.runLater can also ensure the thread safety of global variables while ensuring the safety of javafx controls.

9030f73e5ea2017884493f1777602544.png

Through the above tests, we finally came to a conclusion:

1.  Platform.runLater(() -> {}); not only ensures the thread safety of the Javafx control, but also ensures the thread safety of the global variable data.

2.  ReentrantLock can ensure the thread safety of global variable data, but it is useless for ensuring the thread safety of javafx controls.

  • Pit 3: Whether the javafx control needs to be locked to obtain and modify the value

I searched a lot of opinions on the Internet, but the answers are different, so let's write test code and test it.

 1 Javafx control value acquisition process test

In order to ensure the test effect, we set up 100 threads to operate the textThread method at the same time. High concurrency can increase the probability of thread safety issues being reported. After testing, we found that for the multi-threaded value acquisition process of TextArea, thread safety can be guaranteed without adding Platform.runLater(() -> {});.

4caf88c0126b46e73e7711c2b922af7a.png

 2 javafx control value modification process test

Next, add a line of code to modify the text box of the javafx control: Quanjv.textarea.setText("test"); and found that the program immediately reported an error under 100 thread operations.

ddd0b6d00748514b8604afc447618bf2.png

Next, wrap the code that modifies the javafx value with Platform.runLater(() -> {});. After the program is run, it is found that there are no errors under 100 threads.

1853f72b1ff5f11b1d4cf7d1fa291f89.png

Finally, it was concluded that the value acquisition process of javafx controls basically does not involve thread safety issues, but for any modification of javafx components, thread safety issues must be considered .

  • Pit 4: Tabs label removal problem

When sending a scanning task queue, TabPane will create a new Tab label, with 10 threads running on each label. Double-clicking the Tab label will stop the multi-thread scanning of the task. The title of the Tab label will prompt "Stop..". The tag is closed until all active thread-safe ends.

386796974c5f70c6f478e0cea3cae6b5.png

The code is written in the following format and wrapped with Platform.runLater(() -> {}); code. Logically, there is no thread safety issue.

d37acf692b9d50862586bcd47d5d2f17.png

However, actual measurement results show that errors often occur in the following code, causing the program to crash and all scanning tasks to stop.

27c780b42841245113e89d6334e12d0c.png

This is a very hidden thread safety bug. It will appear several times a day from time to time, and there is no way to reproduce it, which makes me very troubled . Later, I finally figured out that a TabPane is composed of multiple tabs. When you double-click to close one or two tabs, all the index IDs of the tabPane have changed, while the for loop operation of the Tab tab by another thread is still there. During the process, it was still traversed according to the original index, but the original index changed, causing the program to crash.

  • Pit 5: jdk8 is not compatible with higher versions such as jdk11

For example, the following graphical interface was drag-and-dropped using scenebuilder20.x version, and there seems to be no problem.

2679c5bdd7ea4250dcfe840d5727e89f.png

However, if you open it with sceneBuidler 8.x version, the positions of many controls in the entire interface are messed up and overlapped.

9a021b4fde454fffe6b98e7f3ab63f59.png

Finally came to the conclusion: The graphical interface of javafx has compatibility issues with jdk8 and other higher versions of jdk . Scenebuilder8.x is suitable for the drag and drop of the graphical interface of the jdk8 version, and Scenebuilder20. Pull.

  • Pitfall 6: fmxl will be stuck if there are too many lines.

Using Scenebuilder's drag-and-drop method to draw a graphical interface feels particularly convenient, but it also has problems. For example, for the following tool I wrote, the fxml file has almost 1,500 lines. At this time, dragging with scenebuilder will be particularly stuck.

6c185bf176eae77b20e87833ad73c41d.png

In the end, I had no choice. I deleted the Tab tag from one of the TabPane interfaces and wrote it in pure Java code. Sometimes it is more convenient to write a graphical interface with pure Java code than drag and drop . The following interface has a lot of button controls, and each button has similar functions, so I used a Map collection to place the title of each button and the key values ​​used in the button events, and then used a for loop to traverse the Map collection to add Button button components. , you can quickly get this interface, which is more convenient than the drag-and-drop graphical interface of Scenebuilder.

We can also find that the graphical interface written in pure java code looks more regular than the one dragged by Scenebuilder, because drag and drop will often cause errors in the alignment of controls . This is the benefit of graphical interfaces written in java code.

351ce488500199726832ea1f76e79233.png

  • Pit 7: Compilation issues of javafx from jdk11 to jdk17

According to the normal process of writing javafx programs, the jar package compiled by the idea 2022 version will sometimes prompt that the main class cannot be found, and sometimes it will prompt that the JavaFX running component is missing. For the compilation of javafx under jdk8, it is very simple. You can directly compile it into a jar package and double-click to run it on jdk8, because jdk comes with the javafx library, but for higher versions of jdk, such as jdk11 or jdk17, the default is It does not come with the javafx library, so it causes various problems.

9eb12afb4d864bac8f7b1aa720055265.png

There are many ways to solve this problem on the Internet, but the opinions are different, so after various tests, I came up with the following steps to ensure that the compiled jar package can run normally.

First use idea 2022 to create a new project. For JDK, select a version greater than or equal to jdk8. If it is less than jdk8, javafx is not supported.

18553ecb1155ca58c2b1fcc21c743ba4.png

You can see that the idea 2022 version has automatically added the javafx library to the pom.xml file. So we don't need to add additional javafx jar packages. Some solutions say that you need to download the jar package from the javafx official website and import it. In fact, it is not necessary.

0752828a36a45812f65821a4e6074a24.png

Next is the most important step. We need to create a new main class and write it in the following format:

0783dc9aba012959de25aa85313ead0a.png

2fcec0b8ec7cb7e39821875ac39645e4.png

Next, you need to set how to compile the jar package file. The main class needs to select our new JavaFXBootstrap class. Remember to delete main\resources .

e6c513357233a6952e0c0c95eabf3c6c.png

As shown in the figure below, this is the correct idea configuration. The jar package compiled according to the above operations can run perfectly without error.

55ca2177f9909d5ce36f6df9407025a2.png

 Part3 Summary 

1. When encountering thread safety issues, the best way is to write a demo program and test it repeatedly under high concurrency.

2.  The rest of the summary and conclusions are given in each part of the article and will not be repeated here.

b9495d7dbe5b999b645104d2ce0d9e86.png

The public account focuses on sharing network security technology, including APT event analysis, red team attack and defense, blue team analysis, penetration testing, code audit, etc. One article per week, 99% original, so stay tuned.

Contact me: 0day123abc#gmail.com(replace # with @)

Guess you like

Origin blog.csdn.net/m0_71692682/article/details/131746280