From: winalski@adserv.enet.dec.com (Paul S. Winalski)
Subject: Re: sys$crmpsc crashing on me
Reply-To: winalski@adserv.enet.dec.com (Paul S. Winalski)
Organization: Digital Equipment Corporation, Nashua NH
Date: Tue, 15 Dec 1992 04:10:24 GMT


In article <1992Dec15.032058.24265@tc.cornell.edu>,
kutcha@eos.acm.rpi.edu (Phillip Rzewski) writes:

[description of original Pascal program having trouble with $CRMPSC call
 omitted]

|>#include <stdio.h>
|>#include <ssdef.h>
|>#include <secdef.h>
|>#include <starlet.h>
|>#include <descrip.h>
|>#include "[-]syscall.h"
|>
|>#define GSDNAM "SHARED_X"
|>
|>int main(void)
|>{
|>  unsigned long x;
|>  unsigned long in_addr[2];
|>  unsigned long ret_status;
|>  $DESCRIPTOR(gsdnam_dsc, GSDNAM);
|>
|>  in_addr[0] = (unsigned long) &x;
|>  in_addr[1] = (unsigned long) (&x + 3);
|>  printf("%u\n", in_addr[0]);
|>  printf("%u\n", in_addr[1]);
|>  ret_status = sys$crmpsc(&in_addr, 0, 0, SEC$M_GBL + SEC$M_WRT + SEC$M_PERM +
|>          SEC$M_DZRO + SEC$M_PAGFIL, &gsdnam_dsc, 0, 0, 0, (unsigned long) 1,
|>          0, 0, 0);
|>.
|>.
|>.
Sections are sized and mapped in pages.  The minimum size for a section
is thus 1 page (512 bytes).  Furthermore, they can only be mapped on a page
boundary.  That is what the ALIGNED(9) clause in the original Pascal program
was there for--it aligns the variable x on a page boundary.  What the above
code is attempting to do is to set up a page of memory, then to create a global
section mapped to that virtual address.

The above C code has several things wrong with it:

1) Variable x is of storage class auto, and thus is allocated on the stack.
   This is why in_addr got assigned really big integer values in our C program
   but not in the Pascal original (where the variables were declared var,
   causing them to be storage class static, in C terms).  Stack addresses are
   allocated downward from address 7FFFFFFF (hex).

   There's nothing per se wrong with mapping a global section to stack
   addresses, but it's better practice to allocate them in heap memory.  If you
   map to the stack and then the routine returns to its caller, you could end
   up with stack corruption.  Since main() is the routinein this case, it's OK,
   but in general it's bad practice.

   I recommend declaring x as static.

2) You have only reserved 4 bytes (one longword) for x.  However, $CRMPSC is
   going to map an entire page of memory, not just 4 bytes.  You therefore
   killed everything that occurred on the stack after the address of x.
   In your case, you stomped all over a bunch of VAX DEBUG's data structures
   that it was keeping on the stack (yet another reason not to map global
   sections to the stack).

   You must declare x to be 512 bytes long.  I suggest declaring it char[512].

3) You haven't instructed VAX C to allocate x on a page boundary.  $CRMPSC
   rounds the inadr[0] value down to the nearest page boundary when it does the
   allocation.  Thus, unless you got lucky and x happened to be exactly at the
   start of a page, you have corrupted stuff that is on the stack above
   variable x (probably another reason why debug died).

   You should declare x with the _align(page) attribute so that it ends up
   page-aligned.

Here is a corrected version of your code (n.b.: I haven't tested it):

  int main(void)
  {
    static char x[512] _align(page);
    unsigned long in_addr[2];
    unsigned long ret_status;
    $DESCRIPTOR(gsdnam_dsc, GSDNAM);
  
    in_addr[0] = (unsigned long) &x;
    in_addr[1] = (unsigned long) &x[511];
    printf("%u\n", in_addr[0]);
    printf("%u\n", in_addr[1]);
    ret_status = sys$crmpsc(&in_addr, 0, 0, SEC$M_GBL + SEC$M_WRT + SEC$M_PERM +
            SEC$M_DZRO + SEC$M_PAGFIL, &gsdnam_dsc, 0, 0, 0, (unsigned long) 1,
           0, 0, 0);