Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

修复在threadDispatcher启用时,socket相关的读取造成的死锁问题 #665

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@
import com.github.unidbg.linux.struct.SysInfo32;
import com.github.unidbg.linux.thread.KitKatThread;
import com.github.unidbg.linux.thread.MarshmallowThread;
import com.github.unidbg.linux.thread.ReceiveWaiter;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.memory.SvcMemory;
import com.github.unidbg.pointer.UnidbgPointer;
import com.github.unidbg.thread.PopContextException;
import com.github.unidbg.thread.RunnableTask;
import com.github.unidbg.thread.Task;
import com.github.unidbg.thread.ThreadContextSwitchException;
import com.github.unidbg.unix.IO;
Expand Down Expand Up @@ -1382,6 +1384,15 @@ private int recvfrom(Emulator<?> emulator) {
emulator.getMemory().setErrno(UnixEmulator.EBADF);
return -1;
}

RunnableTask runningTask = emulator.getThreadDispatcher().getRunningTask();
if (threadDispatcherEnabled && runningTask != null) {
runningTask.setWaiter(emulator, new ReceiveWaiter(
file, backend, buf, len, flags, src_addr, addrlen
));
throw new ThreadContextSwitchException().setReturnValue(0);
}

return file.recvfrom(backend, buf, len, flags, src_addr, addrlen);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,13 @@
import com.github.unidbg.linux.struct.RLimit64;
import com.github.unidbg.linux.struct.Stat64;
import com.github.unidbg.linux.thread.MarshmallowThread;
import com.github.unidbg.linux.thread.PPollWaiter;
import com.github.unidbg.linux.thread.ReceiveWaiter;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.memory.SvcMemory;
import com.github.unidbg.pointer.UnidbgPointer;
import com.github.unidbg.thread.PopContextException;
import com.github.unidbg.thread.RunnableTask;
import com.github.unidbg.thread.Task;
import com.github.unidbg.thread.ThreadContextSwitchException;
import com.github.unidbg.unix.IO;
Expand Down Expand Up @@ -756,15 +759,28 @@ private int ppoll(Emulator<?> emulator) {
pollfd.setShort(6, (short) 0);
} else {
short revents = 0;
if ((events & POLLOUT) != 0) {
FileIO io = fdMap.get(fd);
if ((events & POLLOUT) != 0 && io.canWrite()) {
revents = POLLOUT;
} else if ((events & POLLIN) != 0) {
} else if ((events & POLLIN) != 0 && io.canRead()) {
revents = POLLIN;
}
pollfd.setShort(6, revents); // returned events
count++;
if (revents != 0) {
pollfd.setShort(6, revents); // returned events
count++;
}
}
}

if (count == 0) {
RunnableTask runningTask = emulator.getThreadDispatcher().getRunningTask();
if (threadDispatcherEnabled && runningTask != null) {
runningTask.setWaiter(emulator, new PPollWaiter(
emulator, fds, nfds, tmo_p, sigmask, fdMap));
throw new ThreadContextSwitchException().setReturnValue(0);
}
}

return count;
}

Expand Down Expand Up @@ -858,6 +874,15 @@ private int recvfrom(Emulator<?> emulator) {
emulator.getMemory().setErrno(UnixEmulator.EBADF);
return -1;
}

RunnableTask runningTask = emulator.getThreadDispatcher().getRunningTask();
if (threadDispatcherEnabled && runningTask != null) {
runningTask.setWaiter(emulator, new ReceiveWaiter(
file, backend, buf, len, flags, src_addr, addrlen
));
throw new ThreadContextSwitchException().setReturnValue(0);
}

return file.recvfrom(backend, buf, len, flags, src_addr, addrlen);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,12 @@ public int sendto(byte[] data, int flags, Pointer dest_addr, int addrlen) {
return super.sendto(data, flags, dest_addr, addrlen);
}

@Override
public boolean canRead() {
try {
return pipedInputStream != null && pipedInputStream.available() > 0;
} catch (IOException ignored) {
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -293,4 +293,18 @@ public int shutdown(int how) {
public String toString() {
return socket.toString();
}

@Override
public boolean canRead() {
try {
return inputStream != null && inputStream.available() > 0;
} catch (IOException ignored) {
return false;
}
}

@Override
public boolean canWrite() {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package com.github.unidbg.linux.thread;

import com.github.unidbg.Emulator;
import com.github.unidbg.file.FileIO;
import com.github.unidbg.file.linux.AndroidFileIO;
import com.github.unidbg.linux.file.TcpSocket;
import com.github.unidbg.thread.AbstractWaiter;
import com.sun.jna.Pointer;
import unicorn.Arm64Const;
import unicorn.ArmConst;

import java.util.Map;

public class PPollWaiter extends AbstractWaiter {

private final int nfds;
private final Emulator<?> emulator;
private final Pointer fds;
private final Pointer tmo_p;
private final Pointer sigmask;
private final Map<Integer, AndroidFileIO> fdMap;
private final long endWaitTimeInMillis;

public PPollWaiter(Emulator<?> emulator, Pointer fds, int nfds, Pointer tmo_p, Pointer sigmask,
Map<Integer, AndroidFileIO> fdMap) {
this.emulator = emulator;
this.fds = fds;
this.nfds = nfds;
this.tmo_p = tmo_p;
this.sigmask = sigmask;
this.fdMap = fdMap;
long tv_sec = tmo_p.getLong(0);
long tv_nsec = tmo_p.getLong(8);
this.endWaitTimeInMillis = System.currentTimeMillis() + (
tv_sec * 1000L + tv_nsec / 1000000L
);
}

private static final short POLLIN = 0x0001;
private static final short POLLOUT = 0x0004;

@Override
public boolean canDispatch() {
int count = 0;
for (int i = 0; i < nfds; i++) {
Pointer pollfd = fds.share(i * 8L);
int fd = pollfd.getInt(0);
short events = pollfd.getShort(4); // requested events
if (fd >= 0) {
short revents = 0;
FileIO io = fdMap.get(fd);
if ((events & POLLOUT) != 0 && io.canWrite()) {
revents = POLLOUT;
} else if ((events & POLLIN) != 0 && io.canRead()) {
revents = POLLIN;
}
if (revents != 0) {
pollfd.setShort(6, revents); // returned events
count++;
}
}
}

return count > 0 || System.currentTimeMillis() > endWaitTimeInMillis;
}

@Override
public void onContinueRun(Emulator<?> emulator) {

int count = 0;
for (int i = 0; i < nfds; i++) {
Pointer pollfd = fds.share(i * 8L);
int fd = pollfd.getInt(0);
short events = pollfd.getShort(4); // requested events
if (fd < 0) {
pollfd.setShort(6, (short) 0);
} else {
short revents = 0;
FileIO io = fdMap.get(fd);
if ((events & POLLOUT) != 0 && io.canWrite()) {
revents = POLLOUT;
} else if ((events & POLLIN) != 0 && io.canRead()) {
revents = POLLIN;
}
if (revents != 0) {
pollfd.setShort(6, revents); // returned events
count++;
}
}
}

emulator.getBackend().reg_write(emulator.is32Bit() ? ArmConst.UC_ARM_REG_R0 : Arm64Const.UC_ARM64_REG_X0,
count);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.github.unidbg.linux.thread;

import com.github.unidbg.Emulator;
import com.github.unidbg.arm.backend.Backend;
import com.github.unidbg.file.FileIO;
import com.github.unidbg.linux.file.SocketIO;
import com.github.unidbg.thread.AbstractWaiter;
import com.sun.jna.Pointer;
import unicorn.Arm64Const;
import unicorn.ArmConst;

public class ReceiveWaiter extends AbstractWaiter {
private final Thread thread;
private int ret;

public ReceiveWaiter(FileIO file, Backend backend, Pointer buf, int len, int flags,
Pointer src_addr, Pointer addrlen) {
this.thread = new Thread(() -> {
ret = file.recvfrom(backend, buf, len, flags, src_addr, addrlen);
});
this.thread.start();
}

@Override
public void onContinueRun(Emulator<?> emulator) {
emulator.getBackend().reg_write(emulator.is32Bit() ? ArmConst.UC_ARM_REG_R0 : Arm64Const.UC_ARM64_REG_X0,
ret);
}

@Override
public boolean canDispatch() {
if (this.thread.getState() == Thread.State.TERMINATED)
return true;
Thread.yield();
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,11 @@ public boolean canRead() {
return true;
}

@Override
public boolean canWrite() {
return true;
}

protected boolean stdio;

@Override
Expand Down
7 changes: 6 additions & 1 deletion unidbg-api/src/main/java/com/github/unidbg/file/FileIO.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.github.unidbg.Emulator;
import com.github.unidbg.arm.backend.Backend;
import com.github.unidbg.thread.Waiter;
import com.sun.jna.Pointer;

import java.io.IOException;
Expand All @@ -12,6 +13,9 @@ public interface FileIO {
int SEEK_CUR = 1;
int SEEK_END = 2;

boolean canRead();
boolean canWrite();

void close();

int write(byte[] data);
Expand Down Expand Up @@ -53,8 +57,9 @@ public interface FileIO {
int llseek(long offset, Pointer result, int whence);

int recvfrom(Backend backend, Pointer buf, int len, int flags, Pointer src_addr, Pointer addrlen);

String getPath();

boolean isStdIO();

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,4 @@

public interface NewFileIO extends FileIO {

boolean canRead();

}