Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
memchk.cpp
Go to the documentation of this file.
1
29#ifndef _WIN32
30# include <fcntl.h> // for open()
31# include <unistd.h> // for getpagesize(), write()
32#else // if Windows
33# include <fcntl.h> // for POSIX compatibility APIs
34# include <io.h> // ditto
35# include <windows.h> // for all of Win32 junk
36#endif // _WIN32
37
38#include <errno.h> // for errno, EINTR
39#include <stddef.h> // for size_t
40#include <stdio.h> // for L_tmpnam, P_tmpdir, tempnam()
41#include <stdlib.h> // for mkstemp()
42#include <string.h> // for memchr()
43
44#include <rw/_defs.h>
45
46
47#ifndef EINTR
48# define EINTR 4 /* AIX, HP-UX, IRIX, Linux, SunOS, Tru64 */
49#endif // EINTR
50
51
52#if defined (_RWSTD_NO_MKSTEMP) || !defined (_RWSTD_NO_PURE_C_HEADERS)
53# ifndef _RWSTD_NO_MKSTEMP_IN_LIBC
54
55extern "C" int mkstemp (char*) _LIBC_THROWS();
56
57# undef _RWSTD_NO_MKSTEMP
58# endif // _RWSTD_NO_MKSTEMP_IN_LIBC
59#endif // _RWSTD_NO_MKSTEMP || !_RWSTD_NO_PURE_C_HEADERS
60
61
62#ifndef P_tmpdir
63# ifndef _P_tmpdir
64# define P_tmpdir "/tmp/"
65# else
66# define P_tmpdir _P_tmpdir
67# endif
68#endif // P_tmpdir
69
70
71#if defined (_RWSTD_EDG_ECCP) && !defined (_WIN32)
72
73extern "C" {
74
75int getpagesize ();
76
77} // extern "C"
78
79#endif // vanilla EDG eccp demo on UNIX
80
81
82static int page_size ()
83{
84 static int size = 0;
85
86 if (0 == size) {
87
88#ifdef _WIN32
89
90 SYSTEM_INFO info;
91
92 GetSystemInfo (&info);
93
94 size = int (info.dwPageSize);
95
96#else // any saner OS
97
98 size = getpagesize ();
99
100#endif // _WIN32
101
102 }
103
104 return size;
105}
106
107
108size_t memchk (const void *addr, size_t nbytes)
109{
110 static int fd = -1;
111
112 if (-1 == fd) {
113
114 // writing to /dev/null need not reliably detect invalid
115 // address ranges if the operating system optimizes the
116 // operation away (as SunOS does, for instance)
117 // fd = open ("/dev/null", O_WRONLY);
118
119#ifdef _WIN32
120
121 char* const fname = tempnam (P_tmpdir, ".rwmemchk.tmp");
122
123 if (!fname)
124 return size_t (-1);
125
126 // create a temporary file and have Win32 delete it when
127 // the last file descriptor that refers to it is closed
128 fd = open (fname, O_RDWR | O_CREAT | _O_TEMPORARY, 0666);
129
130 // free storage allocated by tempnam()
131 free (fname);
132
133 if (fd < 0) {
134 // error: unable to check addr
135 return size_t (-1);
136 }
137
138#else // !_WIN32
139
140# define TMP_TEMPLATE P_tmpdir "/rwmemchk-XXXXXX"
141
142 char fname_buf [] = TMP_TEMPLATE;
143
144 fd = mkstemp (fname_buf);
145
146 if (fd < 0) {
147 // error: unable to check addr
148 return size_t (-1);
149 }
150
151 unlink (fname_buf);
152
153#endif // _WIN32
154
155 }
156
157 lseek (fd, 0, SEEK_SET);
158
159 size_t size = size_t (-1); // error
160
161 const int errno_save = errno;
162
163 errno = 0;
164
165 if (size_t (-1) == nbytes) {
166
167 // size not specified, check that addr points
168 // to a valid NUL-terminated byte string (NTBS)
169
170 // get the virtual page size
171 static const size_t pgsz = page_size ();
172
173 // compute the positive offset from the closest page boundary
174 const size_t pgoff = size_t (addr) % pgsz;
175
176 // compute the number of bytes from addr to the end of the page
177 nbytes = pgsz - pgoff;
178
179 // go through memory pointed to by `addr' one page
180 // at a time looking for the terminating NUL
181 for (const char *pc = static_cast<const char*>(addr); ; ) {
182
183 // try to write a page of memory (or what's left of it)
184 const size_t nwrote = write (fd, pc, nbytes);
185
186 if (nwrote == nbytes) {
187
188 // on success, look for the NUL character
189 const void* const pnull = memchr (pc, 0, nbytes);
190
191 if (pnull) {
192
193 // return the offset of the NUL character from `addr'
194 size = static_cast<const char*>(pnull)
195 - static_cast<const char*>(addr) + 1;
196 break;
197 }
198
199 pc += nbytes;
200 nbytes = pgsz;
201 }
202 else if (size_t (-1) == nwrote && EINTR == errno) {
203 // retry the interrupted system call
204 errno = 0;
205 }
206 else if (nwrote < nbytes) {
207 // retry after a partial write
208 errno = 0;
209 pc += nwrote;
210 nbytes -= nwrote;
211 }
212 else {
213 // error: `addr' doesn't point to a valid NTBS
214 break;
215 }
216 }
217 }
218 else {
219
220 const size_t nwrote = write (fd, addr, nbytes);
221
222 if (nwrote == nbytes)
223 size = nbytes;
224 }
225
226 errno = errno_save;
227
228 return size_t (size);
229}
230
231
232size_t strchk (const char *str)
233{
234 return memchk (str, size_t (-1));
235}
#define addr
Definition 17.names.cpp:446
#define open(f, m)
#define SEEK_SET
#define _LIBC_THROWS()
Definition _defs.h:1152
const char * str
Definition exec.cpp:170
#define P_tmpdir
Definition memchk.cpp:64
int mkstemp(char *) _LIBC_THROWS()
#define EINTR
Definition memchk.cpp:48
size_t strchk(const char *str)
Definition memchk.cpp:232
#define TMP_TEMPLATE
size_t memchk(const void *addr, size_t nbytes)
Definition memchk.cpp:108
std::ostream & info() noexcept
replacement for std::cout for NeBuild logging.
Definition Config.h:69