This is the mail archive of the cygwin@cygwin.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

execve() fails in a thread under 98/ME


One of our developers has found a subtle bug due to the fact
that PAGE_GUARD is not valid for VirtualAlloc() under 
Windows 98/ME.  A testcase is provided below.  I don't
have access to 98/ME so I haven't created the failure myself,
but I am assured it happens.  I do know the testcase doesn't
fail under w2k.

Below are the developers comments.

Thanks, Greg


It's in Cygwin's code, but in all fairness it's probably not their fault.  I
suspect this particular part of Cygwin was more than likely coded before
Microsoft corrected their documentation oversight.

You see, if you look at cygwin's "alloc_stack_hard_way" function (in source
module "dcrt0.cc"), you'll notice them doing:


    if (!VirtualAlloc ((LPVOID) m.BaseAddress, 1, MEM_COMMIT,
        PAGE_EXECUTE_READWRITE|PAGE_GUARD))
    api_fatal ("fork: couldn't allocate new stack guard page %p, %E",
        m.BaseAddress);


The only problem is, the "PAGE_GUARD" flag is not supported on Win9x/ME
platforms!

This is NOT mentioned anywhere in the *original* SDK documentation, but
apparently they've finally gotten around to correcting this oversight in their
latest version of the docs, because it now mentions it quite plainly in the
description of the VirtualAlloc function:


-------------------------------
[...]


PAGE_GUARD

Windows NT/2000 or later: Pages in the region become guard pages. Any attempt to
read from or write to a guard page causes the system to raise a
STATUS_GUARD_PAGE exception and turn off the guard page status. Guard pages thus
act as a one-shot access alarm.

PAGE_GUARD is a page protection modifier. An application uses it with one of the
other page protection modifiers, with one exception: it cannot be used with
PAGE_NOACCESS. When an access attempt leads the system to turn off guard page
status, the underlying page protection takes over.

If a guard page exception occurs during a system service, the service typically
returns a failure status indicator.

Windows 95/98/Me: To simulate this behavior, use PAGE_NOACCESS.


PAGE_NOACCESS

Disables all access to the committed region of pages. An attempt to read from,
write to, or execute in the committed region results in an access violation
exception, called a general protection (GP) fault.

[...]
-------------------------------


So Greg, could you mention this to them please? They need to either add some
Win9x specific code to dcrt0.cc or else change it to use PAGE_NOACCESS for
*all* platforms (in which case they'll have to catch the access violation
exception rather than the STATUS_GUARD_PAGE exception).




Test case:

$ cat shtest.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <setjmp.h>
#include <signal.h>
#include <time.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#include <netdb.h>
#include <fcntl.h>
#include <termios.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/mtio.h>
#include <sys/utsname.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <pthread.h>

typedef u_int8_t         BYTE;
typedef pthread_attr_t   ATTR;
typedef pthread_t        TID;

ATTR  detattr;

FILE* msgpiper;
FILE* msgpipew;

int herc_system (char *command)
{
extern char **environ;
int pid, status;

    if (command == 0)
        return 1;

    pid = fork();

    if (pid == -1)
        return -1;

    if (pid == 0) {
        char *argv[4];

        dup2(msgpiper, STDIN_FILENO);
        dup2(fileno(msgpipew), STDOUT_FILENO);
        dup2(fileno(msgpipew), STDERR_FILENO);

        argv[0] = "sh";
        argv[1] = "-c";
        argv[2] = command;
        argv[3] = 0;
        execve("/bin/sh", argv, environ);

        exit(127);
    }
    do {
        if (waitpid(pid, &status, 0) == -1) {
            if (errno != EINTR)
                return -1;
        } else
            return status;
    } while(1);
}

static void *panel_command (void *cmdline)
{
    herc_system("ls -al");
    return NULL;
}

#define CMD_SIZE   32767

#define initialize_detach_attr(pat) \
    pthread_attr_init((pat)); \
    pthread_attr_setdetachstate((pat),PTHREAD_CREATE_DETACHED)

typedef void*THREAD_FUNC(void*);

#define create_thread(ptid,pat,fn,arg) \
    pthread_create(ptid,pat,(THREAD_FUNC*)&(fn),arg)

int main (int argc, char *argv[])
{
TID   cmdtid;
BYTE  cmdline[CMD_SIZE+1];

    msgpiper = stdin;
    msgpipew = stdout;

    initialize_detach_attr (&detattr);

//  panel_command("xxx");
    create_thread (&cmdtid, &detattr, panel_command, cmdline);

    sleep(3);

    return 0;
}

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Bug reporting:         http://cygwin.com/bugs.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]