Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
memattr.cpp
Go to the documentation of this file.
1
30#define _RWSTD_LIB_SRC
31
32#include <errno.h> // for ENOMEM, errno
33#include <string.h> // for memchr
34
35#ifndef EFAULT
36# define EFAULT 14 // Linux value
37#endif // EFAULT
38
39#ifdef __CYGWIN__
40 // use the Windows API on Cygwin
41# define _WIN32
42#endif
43
44#ifndef _WIN32
45# ifdef __SUNPRO_CC
46 // working around SunOS bug #568
47# include <time.h>
48# endif
49# include <unistd.h> // for getpagesize(), sysconf()
50
51# if defined (_RWSTD_OS_LINUX) && !defined (__USE_BSD)
52 // needed for caddr_t, madvise, and MADV_WILLNEED
53# define __USE_BSD
54# endif // _RWSTD_OS_LINUX && !__USE_BSD
55
56# include <sys/mman.h> // for mincore()
57# include <sys/types.h>
58
59# ifndef _SC_PAGE_SIZE
60 // fall back on the alternative macro if it exists,
61 // or use getpagesize() otherwise
62# ifndef _SC_PAGESIZE
63# define GETPAGESIZE() getpagesize ()
64# else
65# define GETPAGESIZE() sysconf (_SC_PAGESIZE)
66# endif
67# else
68# define GETPAGESIZE() sysconf (_SC_PAGE_SIZE)
69# endif // _SC_PAGE_SIZE
70#else
71# include <windows.h> // for everything (ugh)
72#endif // _WIN32
73
74#include <rw/_defs.h>
75
76// define ENOMEM if it's not #defined (e.g., when using pure libc headers)
77#ifndef ENOMEM
78# define ENOMEM 12 /* HP-UX, Solaris, Tru64, ... */
79#endif // ENOMEM
80
81
82// FIXME: implement PROT_READ and PROT_WRITE correctly
83#ifndef _RWSTD_PROT_READ
84# define _RWSTD_PROT_READ -1
85#endif
86
87#ifndef _RWSTD_PROT_WRITE
88# define _RWSTD_PROT_WRITE 0
89#endif
90
91
92#define DIST(addr1, addr2) \
93 ( _RWSTD_REINTERPRET_CAST (const char*, addr1) \
94 - _RWSTD_REINTERPRET_CAST (const char*, addr2))
95
96
98
100__rw_memattr (const void *addr, _RWSTD_SIZE_T nbytes, int attr)
101{
102 // FIXME: allow attr to be set to the equivalent of PROT_READ,
103 // PROT_WRITE, and (perhaps also) PROT_EXEC, or any combination
104 // of the three, in addition to 0 (PROT_NONE)
105 _RWSTD_UNUSED (attr);
106
107#ifndef _WIN32
108
109 const int errno_save = errno;
110
111 // determine the system page size in bytes
112 static const _RWSTD_SIZE_T pgsz = size_t (GETPAGESIZE ());
113
114 // compute the address of the beginning of the page
115 // to which the address `addr' belongs
116 caddr_t const page =
118 _RWSTD_REINTERPRET_CAST (_RWSTD_SIZE_T, addr) & ~(pgsz - 1));
119
120 // compute the maximum number of pages occuppied by the memory
121 // region pointed to by `addr' (nbytes may be -1 as a request
122 // to compute, in a safe way, the length of the string pointed
123 // to by `addr')
124 _RWSTD_SIZE_T npages = nbytes ? nbytes / pgsz + 1 : 0;
125
126 for (size_t i = 0; i < npages; ++i) {
127
128 const caddr_t next = _RWSTD_REINTERPRET_CAST (char*, page) + i * pgsz;
129
130# ifdef _RWSTD_OS_SUNOS
131
132 char dummy = '\0';
133
134 // on Solaris use mincore() instead of madvise() since
135 // the latter is unreliable
136 if (-1 == mincore (next, 1, &dummy)) {
137
138 const int err = errno;
139 errno = errno_save;
140
141 if (ENOMEM == err)
142 return next == page ? -1 : DIST (next, addr);
143 }
144
145# elif defined (_RWSTD_OS_OSF1)
146
147 // use Tru64 mvalid()
148 if (-1 == mvalid (next, 1, PROT_READ)) {
149
150 const int err = errno;
151 errno = errno_save;
152
153 if (err)
154 return next == page ? -1 : DIST (next, addr);
155 }
156
157# elif defined (_RWSTD_OS_IRIX64)
158
159 // as of 6.5, IRIX has no mincore() or mvalid() call,
160 // or posix_madvise(), and madvise() is unreliable
161 // use msync() instead
162 if (-1 == msync (next, 1, MS_ASYNC)) {
163
164 const int err = errno;
165 errno = errno_save;
166
167 if (err)
168 return next == page ? -1 : DIST (next, addr);
169 }
170
171# elif !defined (_RWSTD_NO_MADVISE)
172
173# ifdef _RWSTD_OS_IRIX64
174 // IRIX 6.5 recognizes only MADV_DONTNEED
175 const int advice = MADV_DONTNEED;
176# else
177 const int advice = MADV_WILLNEED;
178# endif
179
180 // on HP-UX, Linux, use madvise() as opposed to mincore()
181 // since the latter fails for address ranges that aren't
182 // backed by a file (such as stack variables)
183 if (-1 == madvise (next, 1, advice)) {
184
185 const int err = errno;
186 errno = errno_save;
187
188 bool bad_address;
189
190# ifdef _RWSTD_OS_LINUX
191 // Linux fails with EBADF when "the map exists,
192 // but the area maps something that isn't a file"
193 bad_address = EFAULT == err || ENOMEM == err;
194# else // not Linux
195 // EINVAL implies bad (e.g., unimplemented, such as
196 // IRIX 6.5) advice, misaligned addr (not on page size
197 // boundary), or zero size
198 bad_address = !(0 == err || EINVAL == err);
199# endif // Linux
200
201 if (bad_address)
202 return next == page ? -1 : DIST (next, addr);
203 }
204
205# else
206 _RWSTD_UNUSED (errno_save);
207# endif
208
209 if (_RWSTD_SIZE_MAX == nbytes) {
210
211 // when the size of the region is unspecified look
212 // for the first NUL byte and when found, return
213 // the total size of the memory region between
214 // `addr' and the NUL byte (i.e., the length of
215 // the string pointed to by `addr'); this should
216 // be safe since the first byte of the range has
217 // been determined to be readable
218
219 const _RWSTD_SIZE_T maxpage =
220 next == page ? pgsz - DIST (addr, next) : pgsz;
221
222 const void* const pnul =
223 memchr (next == page ? addr : next, '\0', maxpage);
224
225 if (pnul) {
226 nbytes = DIST (pnul, addr);
227 npages = nbytes / pgsz + 1;
228 break;
229 }
230 }
231 }
232
233 return _RWSTD_STATIC_CAST (_RWSTD_SSIZE_T, nbytes);
234
235#else // ifdef _WIN32
236
237 LPVOID const ptr = _RWSTD_CONST_CAST (LPVOID, addr);
238
239 if (_RWSTD_SIZE_MAX == nbytes) {
240
241 // treat the address as a pointer to a NUL-terminated string
242 if (IsBadStringPtr (_RWSTD_STATIC_CAST (LPCSTR, ptr), nbytes))
243 return -1;
244
245 // compute the length of the string
246 nbytes = strlen (_RWSTD_STATIC_CAST (const char*, addr));
247
248 // disable read checking below (since it was done above)
249 attr &= ~_RWSTD_PROT_READ;
250 }
251
252 if ((attr & _RWSTD_PROT_READ) && IsBadReadPtr (ptr, nbytes))
253 return -1;
254
255 if ((attr & _RWSTD_PROT_WRITE) && IsBadWritePtr (ptr, nbytes))
256 return -1;
257
258 return _RWSTD_STATIC_CAST (_RWSTD_SSIZE_T, nbytes);
259
260#endif // _RWSTD_NO_INCORE
261
262}
263
264}
const void * bad_address(size_t size)
Definition 0.printf.cpp:160
#define i
Definition 17.names.cpp:126
#define ptr
Definition 17.names.cpp:525
#define addr
Definition 17.names.cpp:446
#define _RWSTD_EXPORT
Definition _defs.h:485
#define _RWSTD_SSIZE_T
Definition _defs.h:1280
#define _RWSTD_REINTERPRET_CAST(T, x)
Definition _defs.h:535
#define _RWSTD_UNUSED(arg)
Definition _defs.h:972
#define _RWSTD_STATIC_CAST(T, x)
Definition _defs.h:534
#define _RWSTD_NAMESPACE(name)
Definition _defs.h:567
#define _RWSTD_CONST_CAST(T, x)
Definition _defs.h:536
#define _RWSTD_PROT_READ
Definition memattr.cpp:84
#define EFAULT
Definition memattr.cpp:36
#define ENOMEM
Definition memattr.cpp:78
#define _RWSTD_PROT_WRITE
Definition memattr.cpp:88
#define GETPAGESIZE()
Definition memattr.cpp:63
#define DIST(addr1, addr2)
Definition memattr.cpp:92
#define EINVAL
Definition cmdopt.cpp:40