/*************************************************************************** * * memchk.cpp - definitions of memory checking helper functions * * $Id: memchk.cpp 648752 2008-04-16 17:01:56Z faridz $ * *************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Copyright 2001-2008 Rogue Wave Software, Inc. * **************************************************************************/ #ifndef _MSC_VER # include // for open() # include // for getpagesize(), write() #else // if MSVC # include // for POSIX compatibility APIs # include // ditto # include // for all of Win32 junk #endif // MSVC #include // for errno, EINTR #include // for size_t #include // for L_tmpnam, P_tmpdir, tempnam() #include // for mkstemp() #include // for memchr() #include #ifndef EINTR # define EINTR 4 /* AIX, HP-UX, IRIX, Linux, SunOS, Tru64 */ #endif // EINTR #if defined (_RWSTD_NO_MKSTEMP) || !defined (_RWSTD_NO_PURE_C_HEADERS) # ifndef _RWSTD_NO_MKSTEMP_IN_LIBC extern "C" int mkstemp (char*) _LIBC_THROWS(); # undef _RWSTD_NO_MKSTEMP # endif // _RWSTD_NO_MKSTEMP_IN_LIBC #endif // _RWSTD_NO_MKSTEMP || !_RWSTD_NO_PURE_C_HEADERS #ifndef P_tmpdir # ifndef _P_tmpdir # define P_tmpdir "/tmp/" # else # define P_tmpdir _P_tmpdir # endif #endif // P_tmpdir #if defined (_RWSTD_EDG_ECCP) && !defined (_WIN32) extern "C" { int getpagesize (); } // extern "C" #endif // vanilla EDG eccp demo on UNIX static int page_size () { static int size = 0; if (0 == size) { #if defined (_WIN32) || defined (_WIN64) SYSTEM_INFO info; GetSystemInfo (&info); size = int (info.dwPageSize); #else // any saner OS size = getpagesize (); #endif // WIN{32,64} } return size; } size_t memchk (const void *addr, size_t nbytes) { static int fd = -1; if (-1 == fd) { // writing to /dev/null need not reliably detect invalid // address ranges if the operating system optimizes the // operation away (as SunOS does, for instance) // fd = open ("/dev/null", O_WRONLY); #if defined (_WIN32) || defined (_WIN64) char* const fname = tempnam (P_tmpdir, ".rwmemchk.tmp"); if (!fname) return size_t (-1); // create a temporary file and have Win32 delete it when // the last file descriptor that refers to it is closed fd = open (fname, O_RDWR | O_CREAT | _O_TEMPORARY, 0666); // free storage allocated by tempnam() free (fname); if (fd < 0) { // error: unable to check addr return size_t (-1); } #else // !_WIN{32,64} # define TMP_TEMPLATE P_tmpdir "/rwmemchk-XXXXXX" char fname_buf [] = TMP_TEMPLATE; fd = mkstemp (fname_buf); if (fd < 0) { // error: unable to check addr return size_t (-1); } unlink (fname_buf); #endif // _WIN{32,64} } lseek (fd, 0, SEEK_SET); size_t size = size_t (-1); // error const int errno_save = errno; errno = 0; if (size_t (-1) == nbytes) { // size not specified, check that addr points // to a valid NUL-terminated byte string (NTBS) // get the virtual page size static const size_t pgsz = page_size (); // compute the positive offset from the closest page boundary const size_t pgoff = size_t (addr) % pgsz; // compute the number of bytes from addr to the end of the page nbytes = pgsz - pgoff; // go through memory pointed to by `addr' one page // at a time looking for the terminating NUL for (const char *pc = static_cast(addr); ; ) { // try to write a page of memory (or what's left of it) const size_t nwrote = write (fd, pc, nbytes); if (nwrote == nbytes) { // on success, look for the NUL character const void* const pnull = memchr (pc, 0, nbytes); if (pnull) { // return the offset of the NUL character from `addr' size = static_cast(pnull) - static_cast(addr) + 1; break; } pc += nbytes; nbytes = pgsz; } else if (size_t (-1) == nwrote && EINTR == errno) { // retry the interrupted system call errno = 0; } else if (nwrote < nbytes) { // retry after a partial write errno = 0; pc += nwrote; nbytes -= nwrote; } else { // error: `addr' doesn't point to a valid NTBS break; } } } else { const size_t nwrote = write (fd, addr, nbytes); if (nwrote == nbytes) size = nbytes; } errno = errno_save; return size_t (size); } size_t strchk (const char *str) { return memchk (str, size_t (-1)); }