Pavel Labath 8f4db787d5 Fix TestAttachDenied on linux
This test was timing out because the test inferior was forking a child, which was not terminated
correctly. The test contained provisions to terminate this child, but these were no longer
working. The idea was to wake up upon receiving SIGTERM and then kill the child. However, this
was failing because the test first tried to use SIGHUP, which ended up killing the inferior.

Fix: make sure we catch SIGHUP also.
llvm-svn: 248889
2015-09-30 10:59:39 +00:00

109 lines
2.7 KiB
C++

#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/stat.h>
#include <sys/wait.h>
#if defined(PTRACE_ATTACH)
#define ATTACH_REQUEST PTRACE_ATTACH
#define DETACH_REQUEST PTRACE_DETACH
#elif defined(PT_ATTACH)
#define ATTACH_REQUEST PT_ATTACH
#define DETACH_REQUEST PT_DETACH
#else
#error "Unsupported platform"
#endif
bool writePid (const char* file_name, const pid_t pid)
{
char *tmp_file_name = (char *)malloc(strlen(file_name) + 16);
strcpy(tmp_file_name, file_name);
strcat(tmp_file_name, "_tmp");
int fd = open (tmp_file_name, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR);
if (fd == -1)
{
fprintf (stderr, "open(%s) failed: %s\n", tmp_file_name, strerror (errno));
free(tmp_file_name);
return false;
}
char buffer[64];
snprintf (buffer, sizeof(buffer), "%ld", (long)pid);
bool res = true;
if (write (fd, buffer, strlen (buffer)) == -1)
{
fprintf (stderr, "write(%s) failed: %s\n", buffer, strerror (errno));
res = false;
}
close (fd);
if (rename (tmp_file_name, file_name) == -1)
{
fprintf (stderr, "rename(%s, %s) failed: %s\n", tmp_file_name, file_name, strerror (errno));
res = false;
}
free(tmp_file_name);
return res;
}
void signal_handler (int)
{
}
int main (int argc, char const *argv[])
{
if (argc < 2)
{
fprintf (stderr, "invalid number of command line arguments\n");
return 1;
}
const pid_t pid = fork ();
if (pid == -1)
{
fprintf (stderr, "fork failed: %s\n", strerror (errno));
return 1;
}
if (pid > 0)
{
// Make pause call to return when a signal is received. Normally this happens when the
// test runner tries to terminate us.
signal (SIGHUP, signal_handler);
signal (SIGTERM, signal_handler);
if (ptrace (ATTACH_REQUEST, pid, NULL, 0) == -1)
{
fprintf (stderr, "ptrace(ATTACH) failed: %s\n", strerror (errno));
}
else
{
if (writePid (argv[1], pid))
pause (); // Waiting for the debugger trying attach to the child.
if (ptrace (DETACH_REQUEST, pid, NULL, 0) != 0)
fprintf (stderr, "ptrace(DETACH) failed: %s\n", strerror (errno));
}
kill (pid, SIGTERM);
int status = 0;
if (waitpid (pid, &status, 0) == -1)
fprintf (stderr, "waitpid failed: %s\n", strerror (errno));
}
else
{
// child inferior.
pause ();
}
printf ("Exiting now\n");
return 0;
}