Ejemplo n.º 1
0
void test9(){
  char *buf[TEST9_NBUFS];
  VariableAllocatorNolock allocator;
  int i,j;

  for (j=0; j < TEST9_NOPS; ++j){
    for (i=0; i < TEST9_NBUFS; ++i){
      buf[i] = (char*) allocator.alloc(i);
      memset(buf[i], i, i);
    }

    // free every other buffer
    for (i=0; i < TEST9_NBUFS; i += 2){
      allocator.free(buf[i]);
    }

    // reallocate freed buffers
    for (i=0; i < TEST9_NBUFS; i += 2){
      buf[i] = (char*) allocator.alloc(i);
      memset(buf[i], i, i);
    }

    // check that everything is in place
    for (i=0; i < TEST9_NBUFS; ++i){
      assert(memchk(buf[i], i, i) == 0);
    }

    // free everything
    for (i=0; i < TEST9_NBUFS; ++i){
      allocator.free(buf[i]);
    }
  }
}
Ejemplo n.º 2
0
void
iload(void)
{
  nialptr     x = apop();
  int         n = ngetname(x, gcharbuf);

  freeup(x);
  if (n == 0)
    buildfault("invalid file name");
  else {
    FILE       *f1;

    check_ext(gcharbuf, ".nws",FORCE_EXTENSION);
    f1 = openfile(gcharbuf, 'r', 'b');
    if (f1 == OPENFAILED) {
      buildfault("cannot open nws file");
      return;
    }
    wsfileport = f1;
    /* jump to do1command */
    longjmp(loadsave_env, NC_WS_LOAD);
  }

#ifdef DEBUG
  if (debug) {
    memchk();
    nprintf(OF_DEBUG, "after iload memchk\n");
  }
#endif
}
Ejemplo n.º 3
0
/**
 * checks a message authenticity
 *
 * The function computes CMAC of the given plain text and compares
 * it against cmac4. Returns 1 if CMACs matches.
 *
 * @param skey  128-bit session key
 * @param cmac4: points to CMAC message part, i.e. 4 bytes CMAC
 * @param plain: plain text to be CMACked and checked against
 * @param len:   length of plain text in bytes
 */
int macan_check_cmac(struct macan_ctx *ctx, struct macan_key *skey, const uint8_t *cmac4, uint8_t *plain, uint8_t *fill_time, unsigned len)
{
	uint8_t cmac[16];
	uint64_t time;
	int32_t *ftime = (int32_t *)fill_time;
	int i;

	if (!fill_time) {
		macan_aes_cmac(skey, len, cmac, plain);
		/* add memcmp instead of memchk */
		return memchk(cmac4, cmac, 4);
	}

	time = macan_get_time(ctx);

	for (i = -1; i <= 1; i++) {
		*ftime = htole32((int)time + i);
		macan_aes_cmac(skey, len, cmac, plain);

		if (memcmp(cmac4, cmac, 4) == 0) {
			return 1;
		}
	}

	return 0;
}
Ejemplo n.º 4
0
/**
 * checks a message authenticity
 *
 * The function computes CMAC of the given plain text and compares
 * it against cmac4. Returns 1 if CMACs matches.
 *
 * @param skey  128-bit session key
 * @param cmac4: points to CMAC message part, i.e. 4 bytes CMAC
 * @param plain: plain text to be CMACked and checked against
 * @param len:   length of plain text in bytes
 */
int macan_check_cmac(struct macan_ctx *ctx, struct macan_key *skey, const uint8_t *cmac4,
		     uint8_t *plain, int time_index, unsigned len)
{
	uint8_t cmac[16];
	uint32_t *time_ptr;

	if (time_index < 0 || (unsigned)time_index > len - sizeof(*time_ptr)) {
		macan_aes_cmac(skey, len, cmac, plain);
		/* add memcmp instead of memchk */
		return memchk(cmac4, cmac, 4);
	}

	uint32_t time = (uint32_t)macan_get_time(ctx);
	int delta_t;
	time_ptr = (uint32_t *)&plain[time_index];

	for (delta_t = -1; delta_t <= 1; delta_t++) {
		*time_ptr = htole32(time + (uint32_t)delta_t);
		macan_aes_cmac(skey, len, cmac, plain);

		if (memcmp(cmac4, cmac, 4) == 0) {
			return 1;
		}
	}

	return 0;
}
static void verify_log_output(const size_t buf_sz,
							  const char *const expected[],
							  const size_t expected_n)
{
	const size_t modifiable = buf_sz + 1;
	const size_t unmodifiable = ZF_LOG_BUF_SZ - modifiable;
	if (g_line > expected_n)
	{
		fprintf(stderr, "Lines produced: actual=%u, expected=<%u\n",
				(unsigned)g_line, (unsigned)expected_n);
		exit(1);
	}
	size_t complete_lines = 0;
	for (size_t i = 0; g_line > i; ++i)
	{
		const char *const line = g_lines[i];
		const size_t line_len = strlen(expected[i]);
		const size_t untouched = memchk(line + modifiable, -1, unmodifiable);
		const size_t match = common_prefix(expected[i], line_len,
										   line, g_len[i]);
		if (untouched != unmodifiable)
		{
			fprintf(stderr, "Untouched bytes: actual=%u, expected=%u\n",
					(unsigned)untouched, (unsigned)unmodifiable);
			exit(1);
		}
		if (g_null_pos[i] != g_len[i])
		{
			fprintf(stderr, "Null position: actual=%u, expected=%u\n",
					(unsigned)g_null_pos[i], (unsigned)g_len[i]);
			exit(1);
		}
		if (match < g_len[i])
		{
			fprintf(stderr, "Line partial match: actual=%u, expected=>%u\n",
					(unsigned)match, (unsigned)g_len[i]);
			exit(1);
		}
		if (line_len <= buf_sz)
		{
			++complete_lines;
			if (line_len <= buf_sz && match != g_len[i])
			{
				fprintf(stderr, "Line complete match: actual=%u, expected=%u\n",
						(unsigned)match, (unsigned)g_len[i]);
				exit(1);
			}
		}
	}
	if (expected_n == complete_lines && g_line != expected_n)
	{
		fprintf(stderr, "Complete lines produced: actual=%u, expected=<%u\n",
				(unsigned)g_line, (unsigned)expected_n);
		exit(1);
	}
}
Ejemplo n.º 6
0
void
iloaddefs(void)
{
  nialptr     nm,
              x = apop();
  int         mode;

  /* get the file name as a Nial array */
  if (atomic(x) || kind(x) == chartype)
    nm = x;
  else if (kind(x) == atype)
    nm = fetch_array(x, 0);
  else {
    buildfault("invalid file name");
    freeup(x);
    return;
  }

  mode = 0;  /* default to silent mode */
  if (kind(x) == atype && tally(x) == 2) {
    /* argument has a mode filed, select it */
    nialptr     it = fetch_array(x, 1);

    if (kind(it) == inttype)
      mode = intval(it);
    if (kind(it) == booltype)
      mode = boolval(it);
  }

  /* try to put filename into gcharbuf */
  if (!ngetname(nm, gcharbuf)) {
    buildfault("invalid file name");
    freeup(x);
  }

  else 
  { /* check the extension as .ndf */
    check_ext(gcharbuf, ".ndf",NOFORCE_EXTENSION);
    freeup(x);      /* do freeup here so file name doesn't show in iusedspace */

    /* load the definition file */
    if (loaddefs(true, gcharbuf, mode)) {
      apush(Nullexpr);
    }
    else
      buildfault(errmsgptr); /* this is safe since call is from iloaddefs */
  }

#ifdef DEBUG
  memchk();
#endif
}
Ejemplo n.º 7
0
/**
 * aes_unwrap() - AES key unwrap algorithm
 * @key:     AES key
 * @length:  length of src in bytes
 * @dst:     plain text will be written to, i.e. (length - 8) bytes
 * @src:     cipher text
 * @tmp:     auxiliary buffer with length size,
 *
 * The function unwraps key data stored at src. An auxiliary buffer tmp is
 * required, although it is possible to supply src as tmp.
 */
int macan_aes_unwrap(const struct macan_key *key, size_t length, uint8_t *dst, uint8_t *src, uint8_t *tmp)
{
	uint8_t iv[8] = { 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6 };
	uint8_t b[16];
	size_t block_size = 16;
	uint32_t t, n;
	unsigned i;
	int j,k;

	assert((length % 8) == 0 && length > 0);

	memmove(tmp, src, length);
	n = (uint32_t)length / 8 - 1;

	for (j = 5; j >= 0; j--) {
		for (i = n; i > 0; i--) {
			t = (n*(uint32_t)j) + i;
			t = htobe32(t);
			/* We must do bytewise XOR because operands might not be aligned naturally,
			 * we got traps on Tricore.
			 */
			for (k = 0; k < 4; k++) {
				*(tmp + 4 + k) = *(tmp + 4 + k) ^ *(((uint8_t *)&t) + k);
			}

			memcpy(b, tmp, 8);
			memcpy(b + 8, tmp + (8 * i), 8);
			macan_aes_decrypt(key, (unsigned)block_size, b, b);

			memcpy(tmp, b, 8);
			memcpy(tmp + (8 * i), b + 8, 8);   /* ToDo: write to dst */
		}
	}

	if (!memchk(tmp, iv, 8)) {
		memset(dst, 0, length - 8);
		return 1;
	} else {
		memcpy(dst, tmp + 8, length - 8);
		return 0;
	}
}
Ejemplo n.º 8
0
void
wsdump(FILE * f1)
{
  nialptr     startaddr,
              addr,
              highest,
              next;
  nialint     cnt;

#ifdef DEBUG
  if (!continueflag)         /* don't memchk if storing continue */
    memchk();
#endif

#ifdef CALLDLL
  /* This will clear all is_loaded flags for DLL , so that when this
     workspace is loaded later, the DLL will be reloaded */
  DLLclearflags();
#endif

  /* find the address of the highest free block */
  highest = freelisthdr,
  next = freelisthdr;
  while (next != TERMINATOR) {
    if (next > highest)
      highest = next;
    next = fwdlink(next);
  }

  /* store global giving workspace size */
  if (highest + blksize(highest) == memsize)
    wssize = highest;
  else
    wssize = memsize;        /* there is a used block at the end */

  /* set a version stamp for the workspace */

#ifdef DEBUG
  strcpy(wsstamp, systemname);
  strcat(wsstamp, nialversion);
  strcat(wsstamp, " (debug)");
#else
  strcpy(wsstamp, systemname);
  strcat(wsstamp, nialversion);
#endif

  /* write out global structure */
  testerr(writeblock(f1, (char *) &G, (long) sizeof G, false, 0L, 0));


  /* loop to write out allocated blocks */
  addr = membase;
  startaddr = addr;
  cnt = 0;
  while (addr < memsize) {
    if (allocated(addr)) {
      cnt += blksize(addr);
      addr += blksize(addr);
    }
    else {                   /* write out the block */
#ifdef DEBUG
      if (cnt == 0) {
        nprintf(OF_DEBUG, "second empty block in a row found in wsdump\n");
        showfl();
        nabort(NC_ABORT_F);
      }
#endif
/* nprintf(OF_DEBUG,"writing block startaddr %d cnt %d \n",startaddr,cnt); */

      testerr(writeblock(f1, (char *) &cnt, (long) sizeof cnt, false, 0L, 0));
      testerr(writeblock(f1, (char *) &startaddr, (long) sizeof addr, false, 0L, 0));
      testerr(writeblock(f1, (char *) &mem[startaddr], (long) bytespu * cnt, false, 0L, 0));

      /* prepare for next block after free space */

/* nprintf(OF_DEBUG,"skipping free block addr %d blksize %d\n",addr,blksize(addr)); */

      addr = addr + blksize(addr);
      startaddr = addr;
      cnt = 0;
    }
  }

  if (startaddr != memsize) 
  {/* there is a last block to write out */

    /* nprintf(OF_DEBUG,"writing last block startaddr %d cnt %d \n",startaddr,cnt); */

    testerr(writeblock(f1, (char *) &cnt, (long) sizeof cnt, false, 0L, 0));
    testerr(writeblock(f1, (char *) &startaddr, (long) sizeof addr, false, 0L, 0));
    testerr(writeblock(f1, (char *) &mem[startaddr], (long) bytespu * cnt, false, 0L, 0));
  }

  /* write final cnt == 0 to signal end of workspace */
  cnt = 0;
  testerr(writeblock(f1, (char *) &cnt, (long) sizeof cnt, false, 0L, 0));
  closefile(f1);
  return;

fail:  /* the testerr and testrderr macros branch here on an error */

  nprintf(OF_NORMAL_LOG, errmsgptr);
  nprintf(OF_NORMAL_LOG, "workspace failed to write correctly\n");
  closefile(f1);
  exit_cover(NC_WS_WRITE_ERR_W);
}
Ejemplo n.º 9
0
int
loaddefs(int fromfile, char *fname, int mode)
{
  nialptr     ts;
  int         repeatloop,
              keepreading,
              nolines,
              inremark,
              linecnt;
  FILE       *f1 = NULL;     /* initialized to avoid complaint */
  int         errorsfound;

  if (fromfile) {
    f1 = openfile(fname, 'r', 't');
    if (f1 == OPENFAILED)
      return (false);
    pushsysfile(f1);
  }
  /* a loaddefs always affects the global environment. We reset current_env to
     relect this.  The code to restore the environment is below. This must be
     saved on the stack, otherwise it can get thrown away since it may only
     be owned by a transient definition value. The following example failed
     before I protected this on the stack: retry is { host 'vi bug.ndf';
     loaddefs"bug l } where this definition was in the file bug.ndf. */

  apush(current_env);
  current_env = Null;
  ts = topstack;             /* to monitor stack growth on each action */
  errorsfound = 0;           /* reset parse error counter */
  repeatloop = true;
  linecnt = 0;

  /* loop to pick up groups of lines */
  while (repeatloop) {      
    /* continue as long as their are line groups */

    /* test on each circuit if an interrupt signal has been posted */
#ifdef USER_BREAK_FLAG
    if (fromfile)
      checksignal(NC_CS_NORMAL);
#endif

    inremark = false;
    nolines = 0;
    keepreading = true;

    /* loop to pick up lines until a whitespace line occurs */
    while (keepreading) {
      if (fromfile) {
        /* reading a line from the file */
        readfileline(f1, (mode ? 2 : 0)); /* mode==2 only in a loaddefs */

        /* readfileline places result on the stack */
        if (top == Eoffault) {
          apop();            /* to remove the end of file marker */
          repeatloop = false;
          break;             /* to end read loop */
        }
      }

      else {
        /* select a line from array defsndf loadded from defstbl.h */
        char       *line;

        line = defsndf[linecnt++];
        if (linecnt == NOLINES) {
          repeatloop = false;
          keepreading = false;  /* to end read loop */
        }
        mkstring(line);      /* convert the line to a Nial string and push it */
      }

      if (nolines == 0) {    /* check first line of group for a remark */
        char        firstchar;
        int         i = 0;

        /* loop to skip blanks */
        while (i < tally(top) && fetch_char(top, i) <= BLANK)
          i++;

        /* note whether first char is "#" */
        firstchar = fetch_char(top, i);
        if (tally(top))
          inremark = firstchar == HASHSYMBOL;
        else
          inremark = false;
      }

      /* if the line is all while space then we are at the end of a group */
      if (top == Null || allwhitespace(pfirstchar(top))) {
        keepreading = false;
        freeup(apop());      /* to get rid of the empty line */
      }
      else                   /* count the line on the stack */
        nolines++;
    }

    /* we have a group of lines to process */
    if (nolines > 0) {
      mklist(nolines);       /* create a list of lines  and link them*/
      ilink(); 
      if (inremark) {
        freeup(apop()); /* remarks are ignored */
      }                      
      else 
      {                 
        /* carry out the actions of the main loop */
        iscan();
        parse(true);

        /* check whether parse produced an error */
        if (kind(top) == faulttype) {
          if (top != Nullexpr) {
            errorsfound++;
            if (mode == 0) { /* show error message */
              apush(top);
              ipicture();
              show(apop());
            }
          }
        }

        /* evaluate the parse tree, if it is a fault, it is the value returned */
        ieval();

#ifdef DEBUG
        memchk();
#endif

        if (mode) {  /* show the result */
          if (top != Nullexpr) {
            ipicture();
            show(apop());
          }
          else
            apop();          /* the Nullexpr */
        }
        else
          freeup(apop());    /* free because it might not be Nullexpr */
      }

      if (mode) {            /* now display empty line */
        writechars(STDOUT, "", (nialint) 0, true);
        if (keeplog && f1 == STDIN)
          writelog("", 0, true);
      }
    }
    /* check that the stack hasn't grown */
    if (ts != topstack) {
      while (ts != topstack)
        freeup(apop());
      exit_cover(NC_STACK_GROWN_I);
    }
  } 

  /* done reading groups of lines */
  if (fromfile) {
    closefile(f1);
    popsysfile();
  }

  /* restore the current_env */
  current_env = apop();
  if (errorsfound > 0)
    nprintf(OF_NORMAL_LOG, "errors found: %d\n", errorsfound);
  return (true);
}
Ejemplo n.º 10
0
void
wsload(FILE * f1, int user)
{
  nialptr     addr,
              cnt,
              lastfree,
              nextaddr;
  char        stampcheck[256];


  /* read global structure */
  testrderr(readblock(f1, (char *) &G, (long) sizeof G, false, 0L, 0));

  /* nprintf(OF_DEBUG,"wssize read in is %ld\n",wssize); */

  /* check workspace stamp */

#ifdef DEBUG
  strcpy(stampcheck, systemname);
  strcat(stampcheck, nialversion);
  strcat(stampcheck, " (debug)");
#else
  strcpy(stampcheck, systemname);
  strcat(stampcheck, nialversion);
#endif


  if (strcmp(stampcheck, wsstamp) != 0) {
    if (user)
      exit_cover(NC_USER_WS_WRONG_VERSION_W);
    else
      exit_cover(NC_WS_WRONG_VERSION_S);
  }

  /* check that the new workspace will fit in the current memory */

/* printf("wssize %d memsize %d instartup %d\n",wssize,memsize,instartup); */

  if (wssize + MINHEAPSPACE > memsize) {
    if (expansion)
      expand_heap(wssize - memsize);
    else {
      if (interpreter_running) {
        nprintf(OF_MESSAGE, "Not enough memory to load the workspace\n");
        exit_cover(NC_MEM_EXPAND_FAILED_W);
      }
      else {
        nprintf(OF_NORMAL, "Unable to load the workspace\n");
        longjmp(init_buf, NC_MEM_EXPAND_NOT_TRIED_F);
      }
    }
  }

  /* set the link to the first free block */
  fwdlink(freelisthdr) = firstfree;

  /* read memory blocks */

  lastfree = freelisthdr;
  nextaddr = membase;

  testrderr(readblock(f1, (char *) &cnt, (long) sizeof cnt, false, 0L, 0));
  testrderr(readblock(f1, (char *) &addr, (long) sizeof addr, false, 0L, 0));
  while (cnt != 0) {

    /* nprintf(OF_DEBUG,"reading addr %d cnt %d\n",addr,cnt); */

    testrderr(readblock(f1, (char *) &mem[addr],
                        (long) (bytespu * cnt), false, 0L, 0));
    nextaddr = addr + cnt;

    /* get info for next block */
    testrderr(readblock(f1, (char *) &cnt, (long) sizeof cnt, false, 0L, 0));

    if (cnt != 0) {          /* still blocks to read */
      testrderr(readblock(f1, (char *) &addr, (long) sizeof addr, false, 0L, 0));

      /* set up free block between used blocks */
      fwdlink(lastfree) = nextaddr;
      blksize(nextaddr) = addr - nextaddr;

      /* nprintf(OF_DEBUG,"inserting freeblock %d size %d\n",nextaddr,blksize(nextaddr)); */

      bcklink(nextaddr) = lastfree;
      set_freetag(nextaddr); /* sets free tag */
      set_endinfo(nextaddr);
      lastfree = nextaddr;
    }
  }

  if (nextaddr < memsize) {  /* add in last free block */
    fwdlink(lastfree) = nextaddr;
    blksize(nextaddr) = memsize - nextaddr;

    /* nprintf(OF_DEBUG,"adding last freeblock %d size %d\n",nextaddr,blksize(nextaddr)); */

    bcklink(nextaddr) = lastfree;
    set_freetag(nextaddr);
    set_endinfo(nextaddr);
    fwdlink(nextaddr) = TERMINATOR; /* to complete the chain */
  }
  else
    fwdlink(lastfree) = TERMINATOR; /* to complete the chain */

/* reset atomtbl stuff */
atomtblsize = tally(atomtblbase);
atomtbl = pfirstitem(atomtblbase);

#ifdef DEBUG
  memchk();
#endif

  closefile(f1);
  return;

fail:
  closefile(f1);
  nprintf(OF_NORMAL_LOG, "workspace failed to read correctly\n");
  exit_cover(NC_WS_LOAD_ERR_F);
}
Ejemplo n.º 11
0
size_t strchk (const char *str)
{
    return memchk (str, size_t (-1));
}
Ejemplo n.º 12
0
DR_EXPORT
void dr_init(client_id_t id)
{
    char buf[MAXIMUM_PATH];
    int64 pos;
    int i;
    uint prot;
    byte *base_pc;
    size_t size;
    size_t bytes_read, bytes_written;
    byte *edge, *mbuf;
    bool ok;
    byte *f_map;

    /* The Makefile will pass a full absolute path (for Windows and Linux) as the client
     * option to a dummy file in the which we use to exercise the file api routines.
     * TODO - these tests should be a lot more thorough, but the basic functionality
     * is there (should add write tests, file_exists, directory etc. tests). */
    file = dr_open_file(dr_get_options(id), DR_FILE_READ);
    if (file == INVALID_FILE)
        dr_fprintf(STDERR, "Error opening file\n");
    memset(buf, 0, sizeof(buf));
    dr_read_file(file, buf, 10);
    pos = dr_file_tell(file);
    if (pos < 0)
        dr_fprintf(STDERR, "tell error\n");
    dr_fprintf(STDERR, "%s\n", buf);
    if (!dr_file_seek(file, 0, DR_SEEK_SET))
        dr_fprintf(STDERR, "seek error\n");
    memset(buf, 0, sizeof(buf));
    dr_read_file(file, buf, 5);
    dr_fprintf(STDERR, "%s\n", buf);
    for (i = 0; i < 100; i++) buf[i] = 0;
    if (!dr_file_seek(file, pos - 5, DR_SEEK_CUR))
        dr_fprintf(STDERR, "seek error\n");
    memset(buf, 0, sizeof(buf));
    dr_read_file(file, buf, 7);
    dr_fprintf(STDERR, "%s\n", buf);
    if (!dr_file_seek(file, -6, DR_SEEK_END))
        dr_fprintf(STDERR, "seek error\n");
    memset(buf, 0, sizeof(buf));
    /* read "x\nEOF\n" from the data file */
    dr_read_file(file, buf, 6);
    /* check for DOS line ending */
    if (buf[4] == '\r') {
        /* Account for two line endings: the snippet is "x\r\nEOF\r\n".
         * No conversion required--ctest will discard the '\r' when comparing results.
         */
        if (!dr_file_seek(file, -8, DR_SEEK_END))
            dr_fprintf(STDERR, "seek error\n");
            memset(buf, 0, sizeof(buf));
            dr_read_file(file, buf, 8);
    }
    dr_fprintf(STDERR, "%s\n", buf);
#define EXTRA_SIZE 0x60
    size  = PAGE_SIZE + EXTRA_SIZE;
    f_map = dr_map_file(file, &size, 0, NULL, DR_MEMPROT_READ, DR_MAP_PRIVATE);
    if (f_map == NULL || size < (PAGE_SIZE + EXTRA_SIZE))
        dr_fprintf(STDERR, "map error\n");
    /* test unaligned unmap */
    if (!dr_unmap_file(f_map + PAGE_SIZE, EXTRA_SIZE))
        dr_fprintf(STDERR, "unmap error\n");

    /* leave file open and check in exit event that it's still open after
     * app tries to close it
     */
    dr_register_exit_event(event_exit);

    /* Test dr_rename_file. */
    test_dr_rename_delete();

    /* Test the memory query routines */
    dummy_func();
    if (!dr_memory_is_readable((byte *)dummy_func, 1) ||
        !dr_memory_is_readable(read_only_buf+1000, 4000) ||
        !dr_memory_is_readable(writable_buf+1000, 4000)) {
        dr_fprintf(STDERR, "ERROR : dr_memory_is_readable() incorrect results\n");
    }

    if (!dr_query_memory((byte *)dummy_func, &base_pc, &size, &prot))
        dr_fprintf(STDERR, "ERROR : can't find dummy_func mem region\n");
    dr_fprintf(STDERR, "dummy_func is %s%s%s\n", TEST(DR_MEMPROT_READ, prot) ? "r" : "",
              TEST(DR_MEMPROT_WRITE, prot) ? "w" : "",
              TEST(DR_MEMPROT_EXEC, prot) ? "x" : "");
    if (base_pc > (byte *)dummy_func || base_pc + size < (byte *)dummy_func)
        dr_fprintf(STDERR, "dummy_func region mismatch");

    memset(writable_buf, 0, sizeof(writable_buf)); /* strip off write copy */
    if (!dr_query_memory(writable_buf+100, &base_pc, &size, &prot))
        dr_fprintf(STDERR, "ERROR : can't find dummy_func mem region\n");
    dr_fprintf(STDERR, "writable_buf is %s%s%s\n", TEST(DR_MEMPROT_READ, prot) ? "r" : "",
              TEST(DR_MEMPROT_WRITE, prot) ? "w" : "",
#ifdef UNIX
              /* Linux sometimes (probably depends on version and hardware NX
               * support) lists all readable regions as also exectuable in the
               * maps file.  We just skip checking here for Linux to make
               * matching the template file easier. */
              ""
#else
              TEST(DR_MEMPROT_EXEC, prot) ? "x" : ""
#endif
              );
    if (base_pc > writable_buf || base_pc + size < writable_buf)
        dr_fprintf(STDERR, "writable_buf region mismatch\n");
    if (base_pc + size < writable_buf + sizeof(writable_buf))
        dr_fprintf(STDERR, "writable_buf size mismatch "PFX" "PFX" "PFX" "PFX"\n",
                  base_pc, size, writable_buf, sizeof(writable_buf));

    if (!dr_query_memory(read_only_buf+100, &base_pc, &size, &prot))
        dr_fprintf(STDERR, "ERROR : can't find dummy_func mem region\n");
    dr_fprintf(STDERR, "read_only_buf is %s%s\n", TEST(DR_MEMPROT_READ, prot) ? "r" : "",
              TEST(DR_MEMPROT_WRITE, prot) ? "w" : "");
    if (base_pc > read_only_buf || base_pc + size < read_only_buf)
        dr_fprintf(STDERR, "read_only_buf region mismatch");
    if (base_pc + size < read_only_buf + sizeof(read_only_buf))
        dr_fprintf(STDERR, "read_only_buf size mismatch");

    /* test the safe_read functions */
    /* TODO - extend test to cover racy writes and reads (won't work on Linux yet). */
    memset(safe_buf, 0xcd, sizeof(safe_buf));
    if (!dr_safe_read(read_only_buf + 4000, 1000, safe_buf, &bytes_read) ||
        bytes_read != 1000 || !memchk(safe_buf, 0, 1000) || *(safe_buf+1000) != 0xcd) {
        dr_fprintf(STDERR, "ERROR in plain dr_safe_read()\n");
    }
    memset(safe_buf, 0xcd, sizeof(safe_buf));
    /* read_only_buf will be in .rodata on Linux, and can be followed by string
     * constants with the same page protections.  In order to be sure that we're
     * copying zeroes, we map our own memory.
     */
    mbuf = dr_nonheap_alloc(PAGE_SIZE*3, DR_MEMPROT_READ|DR_MEMPROT_WRITE);
    memset(mbuf, 0, PAGE_SIZE*3);
    dr_memory_protect(mbuf + PAGE_SIZE*2, PAGE_SIZE, DR_MEMPROT_NONE);
    edge = find_prot_edge(mbuf, DR_MEMPROT_READ);
    bytes_read = 0xcdcdcdcd;
    if (dr_safe_read(edge - (PAGE_SIZE + 10), PAGE_SIZE+20, safe_buf, &bytes_read) ||
        bytes_read == 0xcdcdcdcd || bytes_read > PAGE_SIZE+10 ||
        !memchk(safe_buf, 0, bytes_read)) {
        dr_fprintf(STDERR, "ERROR in overlap dr_safe_read()\n");
    }
    dr_nonheap_free(mbuf, PAGE_SIZE*3);
    dr_fprintf(STDERR, "dr_safe_read() check\n");

    /* test DR_TRY_EXCEPT */
    DR_TRY_EXCEPT(dr_get_current_drcontext(), {
        ok = false;
        *((int *)4) = 37;
    }, { /* EXCEPT */