Behavioral Analysis of Object Destructure under Unix

zhaozj2021-02-16  56

Fork

() The main task is to initialize the data structure to create the process, and its main steps are

(The following is taken from JOYFIRE notes

):

1

Apply for an idle page to save Task_struct;

2

) Find an empty process slot (Find_empty_Process

())

3

) Apply for kernel_stack_page to apply for another idle memory page as a stack;

4

) Copy the LDT table of the parent process to the child process;

5

) Copy the memory mapping information of the parent process;

6

) Management file descriptors and link points.

So, if an object is created in the parent process, what special performance will there be for the object? Take a look at the procedure below:

#include #include #include #include #include #include #include

Class CA

{

public

:

CA

() {Printf

(

Construct CA / N "

); ~ CA

() {Printf

(

"deStruct CA / N"

}};

int

main

(

Int Argcc

,

charr

** Argv

) {

PID_T PID

;

PID_T WPID

;

Int Status

;

CA A

;

PID

= Fork

();

IF

(PID)

== (PID_T

)

1

) {

FPRINTF

(stderr

,

"% s: failed to fork () / n"

STRERROR

(Errno)

));

Exit

(

13

}

Else IF

(PID)

==

0

) {

PRINTF

(

"PID% ld: Child Started, Parent IS% LD. / N"

, (

Long

GetPid

(),

Long

GetPPID

())

Return

0

}

PRINTF

(

"PID% LD: Started Child PID% ld. / N"

, (

Long

GetPid

(),

Long

PID

);

WPID

= WAIT

(& status)

);

IF

(WPID

== (PID_T

)

1

)

PERROR

(

Wait (2) "

);

Return

0

}

The following is the program a certain run:

Construct CA

PID

29423

: Child Started

, Parent IS

March 29422.

Destruct CA

PID

29422

: Started Child PID

29423.

Destruct CA

The results show that the object is constructed once, but it is destructed twice.

Why is this so? This is the result of the Fork to copy the memory mapping information of the parent process. For code like this:

Void

main

() {

CA A

;

// CA is a class

}

The equivalent assembly code is about this: 10

:

Void

main

()

11

: {

00401030 PUSH EBP

00401031 MOV EBP

ESP

00401033 SUB ESP

44h

00401036 PUSH EBX

00401037 PUSH ESI

00401038 PUSH EDI

00401039 LEA EDI

[EBP

-44h

]

0040103C MOV ECX

11h

00401041 MOV EAX

, 0cccccccch

00401046 Rep STOS DWORD PTR

[edi

]

12

: CA A

;

00401048 LEA ECX

[EBP

-

4

]

0040104B Call @ilt

0

(CA

:: CA

) (

00401005

)

13

}

00401050 Lea ECX

[EBP

-

4

]

00401053 Call @ilt

5

(CA

:: ~ CA

) (0040100A)

)

00401058 POP EDI

00401059 POP ESI

0040105A POP EBX

0040105B Add ESP

44h

0040105E CMP EBP

ESP

00401060 Call __chkesp

(

00401120

)

00401065 MOV ESP

EBP

00401067 POP EBP

00401068 RET

That is, when is inserted into the configuration

/ Destructure function call code, which is determined during compilation. After the Fork, the child process will continue to perform the instruction specified by the call stack due to the complete copy of the parent process memory mapping information (including code segment and calling stack information), so the latter Call @ilt

5

(CA

:: ~ CA

) (0040100A)

) Will be executed twice.

The above features are sometimes used to deliver information between parent son processes (by the parent process)

-> Sub process, this transmission is unidirectional).

So, how do we block the destructure news that repeat the output, by discussing online, have the following recommendations:

1. Advisory: Do not use reusable statements in Fork, such as Printf;

2, the following policy: Add a flag to the CA and output according to the logo in the destructor;

For the second solution, the modified procedure is as follows:

#include #include #include #include #include #include #include

Class CA

{

public

:

CA

(); ~ CA

();

Int_Childflag

};

CA

:: CA

() {

_Childflag

=

0

;

PRINTF

(

"construct ca / ​​n");

CA

:: ~ CA

() {

IF

(! _Childflag

) {

PRINTF

(

"deStruct CA / N"

}}

int

main

(

Int Argcc

,

charr

** Argv

) {

PID_T PID

;

PID_T WPID

;

Int Status

;

CA A

;

PID

= Fork

();

IF

(PID)

== (PID_T

)

1

) {

FPRINTF

(stderr

,

"% s: failed to fork () / n"

STRERROR

(Errno)

));

exit

(

13

}

Else IF

(PID)

==

0

) {

a

._Childflag

=

1

;

PRINTF

(

"PID% ld: Child Started, Parent IS% LD. / N"

, (

Long

GetPid

(),

Long

GetPPID

())

Return

0

}

PRINTF

(

"PID% LD: Started Child PID% ld. / N"

, (

Long

GetPid

(),

Long

PID

);

WPID

= WAIT

(& status)

);

IF

(WPID

== (PID_T

)

1

)

PERROR

(

Wait (2) "

);

Return

0

}

Note: The above is a very boring topic, but it was asked in a few weeks ago, which is recorded here.

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

New Post(0)