Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1285 lines
34 KiB

  1. /***
  2. *shadow.cpp - RTC support
  3. *
  4. * Copyright (c) 1998-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *
  7. *Revision History:
  8. * 07-28-98 JWM Module incorporated into CRTs (from KFrei)
  9. * 08-13-98 KBF Changed address cache to be 'invalid' address cache
  10. * 08-13-98 KBF Turned on optimization, modified address calc functions
  11. * 10-13-98 KBF Added Shadow-Death notification capabilities
  12. * 11-03-98 KBF added pragma intrinsic to eliminate CRT code dependence
  13. * 11-03-98 KBF Also fixed bug with allocating blocks of 4K multiples
  14. * 12-01-98 KBF Fixed a bug in RTC_MSFreeShadow - MC 11029
  15. * 12-02-98 KBF Fixed _RTC_MSR0AssignPtr
  16. * 12-03-98 KBF Added CheckMem_API and APISet functions
  17. * 05-11-99 KBF Error if RTC support define not enabled
  18. * 05-14-99 KBF Requires _RTC_ADVMEM (it's been cut for 7.0)
  19. *
  20. ****/
  21. #ifndef _RTC
  22. #error RunTime Check support not enabled!
  23. #endif
  24. #include "rtcpriv.h"
  25. #ifdef _RTC_ADVMEM
  26. static const unsigned MEM_SIZE = 0x40000000;
  27. // This tag is valid?
  28. #define MEM_ISVALID(tag) (tag)
  29. // Both tags in this short are valid
  30. #define MEM_SHORTVALID(tag) (((tag) & 0xFF) && ((tag) & 0xFF00))
  31. // All 4 tags in this int are valid
  32. #define MEM_INTVALID(tag) (((tag) & 0xFF) && ((tag) & 0xFF00) && ((tag) & 0xFF0000) && ((tag) & 0xFF000000))
  33. // Given an address, get a shadow memory index
  34. #define MEM_FIXADDR(addr) ((addr) & (MEM_SIZE - 1))
  35. // An int's worth of unused values
  36. static const unsigned int MEM_EMPTYINT = 0;
  37. // An unused value
  38. static const shadowtag MEM_EMPTY = 0;
  39. // An untracked value
  40. static const shadowtag MEM_UNKNOWN = 0xFF;
  41. static const unsigned int MEM_UNKNOWNINT = 0xFFFFFFFF;
  42. #define MEM_NEXT_ID(a) ((shadowtag)((a) % 253 + 1))
  43. static const unsigned int PAGE_SIZE = 4096;
  44. /* Page Index Macros */
  45. static const unsigned int PAGES_PER_ELEM = 1;
  46. static const unsigned int MEM_PER_IDX = PAGE_SIZE; // 4K
  47. static const unsigned int IDX_SIZE = ((MEM_SIZE / MEM_PER_IDX) * sizeof(index_elem)) / PAGES_PER_ELEM;
  48. static const unsigned int IDX_STATE_TRACKED = 0x2; // bitmask
  49. #define SET_IDX_STATE(idx, st) (_RTC_pageidx[idx]=st)
  50. #define GET_IDX_STATE(idx) (_RTC_pageidx[idx])
  51. // Get the index number for a given address
  52. #define IDX_NUM(addr) (MEM_FIXADDR(addr) / MEM_PER_IDX)
  53. // Index align this address
  54. #define IDX_ALIGN(addr) ((addr) & ~(MEM_PER_IDX - 1))
  55. #ifdef _RTC_DEBUG
  56. // Debugging helper functions
  57. #define show(a, b) unsigned b(unsigned c) { return a(c); }
  58. show(GET_IDX_STATE, get_idx_state)
  59. show(IDX_NUM, idx_num)
  60. show(IDX_ALIGN, idx_align)
  61. #undef show
  62. #endif
  63. // This is the pseudo-address used for REG0 in the cache
  64. #define REG0 ((memref)1)
  65. static shadowtag blockID = 0;
  66. static void KillShadow();
  67. #ifdef __MSVC_RUNTIME_CHECKS
  68. #error Hey dufus, don't compile this file with runtime checks turned on
  69. #endif
  70. #pragma intrinsic(memset)
  71. struct cacheLine
  72. {
  73. memref pointer;
  74. memptr value;
  75. memptr base;
  76. void *assignment;
  77. };
  78. // Actual Cache Size is 2^CacheSize
  79. // Cache is 8x3 - 24 elements total
  80. #define CACHESIZE 3
  81. #define CACHELINESIZE 3
  82. static cacheLine cache[1<<CACHESIZE][CACHELINESIZE];
  83. static long readlocks[1<<CACHESIZE];
  84. static long writelocks[1<<CACHESIZE];
  85. static long cachePos[1<<CACHESIZE];
  86. #define READ_LOCK(line) \
  87. {\
  88. while(InterlockedIncrement(&readlocks[line]) <= 0)\
  89. {\
  90. InterlockedDecrement(&readlocks[line]);\
  91. Sleep(0);\
  92. }\
  93. }
  94. #define READ_UNLOCK(line) InterlockedDecrement(&readlocks[line])
  95. static void WRITE_LOCK(int line)
  96. {
  97. while (InterlockedExchange(&writelocks[line], 1))
  98. Sleep(0);
  99. long users = InterlockedExchange(&readlocks[line], -2000);
  100. while (readlocks[line] != -2000-users)
  101. Sleep(0);
  102. }
  103. #define WRITE_UNLOCK(line) {readlocks[line] = 0; writelocks[line] = 0;}
  104. #define CacheHash(value) (((1 << CACHESIZE) - 1) & (value >> 3))
  105. static void
  106. ClearCacheRange(memptr lo, memptr hi)
  107. {
  108. // Remove all pointers stored between lo and hi
  109. // We don't need to use locks, because this stuff is only
  110. // used for the stack, and if you're running on the same stack
  111. // you're in serious trouble...
  112. unsigned size = hi - lo;
  113. for (int i = 0; i < (1 << CACHESIZE); i++)
  114. {
  115. for (int j = 0; j < CACHELINESIZE; j++)
  116. {
  117. if (cache[i][j].pointer &&
  118. (unsigned)cache[i][j].pointer - (unsigned)lo < size)
  119. cache[i][j].pointer = 0;
  120. }
  121. }
  122. }
  123. static void
  124. AddCacheLine(void *retaddr, memref ptr, memptr base, memptr value)
  125. {
  126. if (!value)
  127. return;
  128. int loc = CacheHash((int)ptr);
  129. WRITE_LOCK(loc);
  130. int prefpos = 0;
  131. for (int i = 0; i < CACHELINESIZE; i++)
  132. {
  133. if (cache[loc][i].pointer == ptr)
  134. {
  135. prefpos = i+1;
  136. break;
  137. } else if (!prefpos && !cache[loc][i].pointer)
  138. prefpos = i+1;
  139. }
  140. if (!prefpos)
  141. prefpos = cachePos[loc];
  142. else
  143. prefpos--;
  144. cache[loc][prefpos].pointer = ptr;
  145. cache[loc][prefpos].value = value;
  146. cache[loc][prefpos].base = base;
  147. cache[loc][prefpos].assignment = retaddr;
  148. if (++prefpos == CACHELINESIZE)
  149. cachePos[loc] = 0;
  150. else
  151. cachePos[loc] = prefpos;
  152. WRITE_UNLOCK(loc);
  153. }
  154. static void
  155. ClearCacheLine(memref ptr)
  156. {
  157. int loc = CacheHash((int)ptr);
  158. READ_LOCK(loc);
  159. for (int i = 0; i < CACHELINESIZE; i++)
  160. {
  161. if (cache[loc][i].pointer == ptr)
  162. {
  163. READ_UNLOCK(loc);
  164. WRITE_LOCK(loc);
  165. cache[loc][i].pointer = 0;
  166. cachePos[loc] = i;
  167. WRITE_UNLOCK(loc);
  168. return;
  169. }
  170. }
  171. READ_UNLOCK(loc);
  172. }
  173. #define GetCacheLine(ptr, dst) {\
  174. int loc = CacheHash((int)ptr);\
  175. dst.pointer = 0;\
  176. READ_LOCK(loc);\
  177. for (int i = 0; i < CACHELINESIZE; i++)\
  178. {\
  179. if (cache[loc][i].pointer == ptr)\
  180. {\
  181. dst = cache[loc][i];\
  182. break;\
  183. }\
  184. }\
  185. READ_UNLOCK(loc);\
  186. }
  187. static void
  188. ClearCache()
  189. {
  190. for (int loc = 0; loc < 1 << CACHESIZE; loc++)
  191. {
  192. for (int i = 0; i < CACHELINESIZE; i++)
  193. cache[loc][i].pointer = 0;
  194. readlocks[loc] = writelocks[loc] = 0;
  195. cachePos[loc] = 0;
  196. }
  197. }
  198. // This is called before every function to allocate
  199. // locals in the shadow memory
  200. void __fastcall
  201. _RTC_MSAllocateFrame(memptr frame, _RTC_framedesc *v)
  202. {
  203. if (!_RTC_shadow)
  204. return;
  205. int i;
  206. int memsize = -v->variables[v->varCount-1].addr + sizeof(int);
  207. // Next, commit all required pages, initializing all unallocated portions
  208. // of newly committed memory to the proper state
  209. _RTC_MSCommitRange(frame - memsize, memsize, IDX_STATE_PARTIALLY_KNOWN);
  210. if (!_RTC_shadow)
  211. return;
  212. // Now step thru each variable, and allocate it within the shadow memory
  213. // While allocating, mark the buffer sections as invalid
  214. for (i = 0; i < v->varCount; i++)
  215. {
  216. *(unsigned*)(&_RTC_shadow[MEM_FIXADDR(frame + v->variables[i].addr - sizeof(int))]) = MEM_EMPTYINT;
  217. *(unsigned*)(&_RTC_shadow[MEM_FIXADDR(frame + v->variables[i].addr + v->variables[i].size)]) = MEM_EMPTYINT;
  218. blockID = MEM_NEXT_ID(blockID);
  219. memset(&_RTC_shadow[MEM_FIXADDR(frame + v->variables[i].addr)], blockID, v->variables[i].size);
  220. }
  221. }
  222. // Free the stack frame from shadow memory
  223. void __fastcall
  224. _RTC_MSFreeFrame(memptr frame, _RTC_framedesc *v)
  225. {
  226. // I'm not bothering to attempt to free any shadow memory pages
  227. // This might cause problems for certain really poorly written programs...
  228. if (_RTC_shadow)
  229. {
  230. int size = (sizeof(int) + sizeof(int) - 1 - v->variables[v->varCount - 1].addr);
  231. memset(&_RTC_shadow[MEM_FIXADDR(frame-size)], MEM_UNKNOWN, size);
  232. // Temporary hack until we handle parameters
  233. ClearCacheRange(frame - size, frame);
  234. }
  235. // Cheap Bounds Check, to be sure that no external functions trash the stack
  236. _RTC_CheckStackVars((void*)frame, v);
  237. }
  238. // The list of global variable descriptors is constructed by dummy
  239. // start and end descriptor here, in sections .rtc$MEA and .rtc$MEZ.
  240. // The compiler emits .rtc$MEB entries for each global, under -RTCm.
  241. // The linker sorts these together into the .rtc section. Note that the
  242. // linker, under /DEBUG, inserts zero padding into the section for
  243. // incremental compilation. We force the alignment of these descriptors,
  244. // and thus the sections, to be the size of the structure, so no odd padding
  245. // is inserted.
  246. //
  247. // The following is how the code *should* look:
  248. //
  249. // __declspec(align(8)) struct global_descriptor {
  250. // memptr addr;
  251. // unsigned size;
  252. // };
  253. //
  254. // #pragma section(".rtc$MEA", read)
  255. // #pragma section(".rtc$MEZ", read)
  256. //
  257. // __declspec(allocate(".rtc$MEA")) global_descriptor glob_desc_start = {0};
  258. // __declspec(allocate(".rtc$MEZ")) global_descriptor glob_desc_end = {0};
  259. //
  260. // However, __declspec(align()), #pragma section, and __declspec(allocate())
  261. // are all VC 6.1 features. It is a CRT requirement to compile the 6.1 CRT
  262. // using only 6.0 language features (because NT 5 only uses the 6.0 compiler,
  263. // I think). So here's how we do it:
  264. struct global_descriptor
  265. {
  266. union {
  267. double ___unused; // only here to force 8-byte alignment
  268. struct {
  269. memptr addr;
  270. unsigned size;
  271. };
  272. };
  273. };
  274. #pragma const_seg(".rtc$MEA")
  275. const global_descriptor glob_desc_start = {0};
  276. #pragma const_seg(".rtc$MEZ")
  277. const global_descriptor glob_desc_end = {0};
  278. #pragma const_seg()
  279. // We must start our loop at &glob_desc_start, not &glob_desc_start + 1,
  280. // because the pre-VC 6.1 compiler (specifically, the global optimizer)
  281. // treats &glob_desc_start + 1 as distinct (unaliased) from &glob_desc_end,
  282. // in the loop below. Thus, it gets rid of the loop test at the loop top.
  283. // This is a problem for cases where there are no globals. This is done
  284. // because it is expected that the 6.1 CRT will be compiled by pre-6.1
  285. // compilers.
  286. // Allocate the list of globals in shadow memory
  287. void __cdecl
  288. _RTC_MSAllocateGlobals(void)
  289. {
  290. if (!_RTC_shadow)
  291. return;
  292. // Just step thru every item, and call _RTC_MSAllocShadow
  293. const global_descriptor *glob = &glob_desc_start;
  294. for (; glob != &glob_desc_end; glob++)
  295. _RTC_MSAllocShadow(glob->addr, glob->size, IDX_STATE_PARTIALLY_KNOWN);
  296. }
  297. // This should initialize the shadow memory as appropriate,
  298. // committing all necessary pages
  299. // partial implies that the page is only partially known
  300. // so we need to be sure that all unallocated values on the
  301. // page are set as a single valid block
  302. short
  303. _RTC_MSAllocShadow(memptr real_addr, unsigned real_size, unsigned state)
  304. {
  305. // Ignore bogus zero address or size, possibly from globals linker padding
  306. if (!_RTC_shadow || !real_addr || !real_size)
  307. return 0;
  308. // Now allocate the shadow memory, if necessary
  309. if (state & IDX_STATE_TRACKED)
  310. {
  311. // Commit the shadow memory,
  312. // marking newly committed, but unallocated memory as appropriate
  313. _RTC_MSCommitRange(real_addr, real_size, state);
  314. if (!_RTC_shadow)
  315. return blockID;
  316. // Now initialize the shadow memory
  317. blockID = MEM_NEXT_ID(blockID);
  318. memset(&_RTC_shadow[MEM_FIXADDR(real_addr)], blockID, real_size);
  319. } else if (state == IDX_STATE_ILLEGAL)
  320. {
  321. // Initialize the page index stuff to the correct state
  322. // ASSERT(state == IDX_STATE_ILLEGAL)
  323. unsigned idx_start = IDX_NUM(real_addr);
  324. unsigned idx_end = IDX_NUM(real_addr + real_size - 1);
  325. for (unsigned i = idx_start; i <= idx_end; i++)
  326. SET_IDX_STATE(i, state);
  327. }
  328. return blockID;
  329. }
  330. // This sets the value of the shadow memory to be the value passed in
  331. void
  332. _RTC_MSRestoreShadow(memptr addr, unsigned size, short id)
  333. {
  334. if (!_RTC_shadow)
  335. return;
  336. memset(&_RTC_shadow[MEM_FIXADDR(addr)], id, size);
  337. }
  338. // This assigns a new blockID to the shadow memory
  339. // It will NOT be equal to the id passed in
  340. short
  341. _RTC_MSRenumberShadow(memptr addr, unsigned size, short notID)
  342. {
  343. if (!_RTC_shadow)
  344. return 0;
  345. blockID = MEM_NEXT_ID(blockID);
  346. if (blockID == notID)
  347. blockID = MEM_NEXT_ID(blockID);
  348. memset(&_RTC_shadow[MEM_FIXADDR(addr)], blockID, size);
  349. return blockID;
  350. }
  351. // This should de-initialize shadow memory
  352. // and decommit any unneeded pages
  353. void _RTC_MSFreeShadow(memptr addr, unsigned size)
  354. {
  355. if (!_RTC_shadow)
  356. return;
  357. // Low & Hi are the bounds of the freed memory region
  358. memptr low = MEM_FIXADDR(addr);
  359. memptr hi = (low + size) & ~(sizeof(unsigned)-1);
  360. // start and end are the page-aligned bounds;
  361. memptr start = IDX_ALIGN(low);
  362. memptr end = IDX_ALIGN(low + size + MEM_PER_IDX - 1);
  363. memptr tmp;
  364. int used;
  365. // First, clear the shadow memory that contained this stuff
  366. memset(&_RTC_shadow[low],
  367. (GET_IDX_STATE(IDX_NUM(low)) == IDX_STATE_PARTIALLY_KNOWN)
  368. ? MEM_UNKNOWN
  369. : MEM_EMPTY,
  370. size);
  371. // Now go thru and release the pages that have
  372. // been completely eliminated from use
  373. for (tmp = start, used = 0; !used && tmp < low; tmp += sizeof(unsigned))
  374. {
  375. unsigned val = *(unsigned *)&_RTC_shadow[tmp];
  376. used = val != MEM_EMPTYINT && val != MEM_UNKNOWNINT;
  377. }
  378. if (used)
  379. start += MEM_PER_IDX;
  380. for (tmp = hi, used = 0; !used && tmp < end; tmp += sizeof(unsigned))
  381. {
  382. unsigned val = *(unsigned *)&_RTC_shadow[tmp];
  383. used = val != MEM_EMPTYINT && val != MEM_UNKNOWNINT;
  384. }
  385. if (used)
  386. end -= MEM_PER_IDX;
  387. if (start < end)
  388. // Free the page in memory
  389. _RTC_MSDecommitRange(start, end-start);
  390. }
  391. void _RTC_MSCommitRange(memptr addr, unsigned size, unsigned state)
  392. {
  393. // Commit the page range
  394. if (!VirtualAlloc(&_RTC_shadow[MEM_FIXADDR(addr)], size, MEM_COMMIT, PAGE_READWRITE))
  395. KillShadow();
  396. else {
  397. // Now mark the range as committed in the page tables
  398. size += (addr - IDX_ALIGN(addr));
  399. int val = (state == IDX_STATE_PARTIALLY_KNOWN) ? MEM_UNKNOWNINT : MEM_EMPTYINT;
  400. while (size && !(size & 0x80000000))
  401. {
  402. // If this is a newly committed page, initialize it to the proper value
  403. if (GET_IDX_STATE(IDX_NUM(addr)) != state)
  404. {
  405. SET_IDX_STATE(IDX_NUM(addr), state);
  406. int *pg = (int*)&_RTC_shadow[MEM_FIXADDR(IDX_ALIGN(addr))];
  407. for (int i = 0; i < MEM_PER_IDX / sizeof(int); i++)
  408. pg[i] = val;
  409. }
  410. addr += MEM_PER_IDX;
  411. size -= MEM_PER_IDX;
  412. }
  413. }
  414. }
  415. void _RTC_MSDecommitRange(memptr addr, unsigned size)
  416. {
  417. // Decommit the page range
  418. VirtualFree(&_RTC_shadow[MEM_FIXADDR(addr)], size, MEM_DECOMMIT);
  419. // Now mark the range as decommited in the page tables
  420. size += (addr - IDX_ALIGN(addr));
  421. while (size && !(size & 0x80000000))
  422. {
  423. SET_IDX_STATE(IDX_NUM(addr), IDX_STATE_UNKNOWN);
  424. addr += MEM_PER_IDX;
  425. size -= MEM_PER_IDX;
  426. }
  427. }
  428. static shadowtag
  429. GetAddrTag(memptr addr)
  430. {
  431. shadowtag *loc = &_RTC_shadow[MEM_FIXADDR(addr)];
  432. if ((memptr)loc == addr)
  433. return MEM_EMPTY;
  434. if (addr & 0x80000000)
  435. return MEM_UNKNOWN;
  436. switch (GET_IDX_STATE(IDX_NUM(addr)))
  437. {
  438. case IDX_STATE_UNKNOWN:
  439. return MEM_UNKNOWN;
  440. case IDX_STATE_ILLEGAL:
  441. return MEM_EMPTY;
  442. case IDX_STATE_PARTIALLY_KNOWN:
  443. case IDX_STATE_FULLY_KNOWN:
  444. return *loc;
  445. default:
  446. __assume(0);
  447. }
  448. }
  449. static void
  450. MemCheckAdd(void *retaddr, memptr base, int offset, unsigned size)
  451. {
  452. // If base isn't really the base, don't assume offset is,
  453. // just be sure the memory is valid
  454. shadowtag baseTag;
  455. if (base < offset)
  456. baseTag = GetAddrTag(base + offset);
  457. else
  458. baseTag = GetAddrTag(base);
  459. // Step thru ever byte of the memory and verify that they're all the same
  460. for (unsigned i = 0; i < size; i++)
  461. {
  462. shadowtag newTag = GetAddrTag(base + offset + i);
  463. if (newTag != baseTag || newTag == MEM_EMPTY)
  464. {
  465. _RTC_Failure(retaddr, (newTag == MEM_EMPTY)
  466. ? _RTC_INVALID_MEM
  467. : _RTC_DIFF_MEM_BLOCK);
  468. return;
  469. }
  470. }
  471. }
  472. static void
  473. PtrMemCheckAdd(void *retaddr, memref base, int offset, unsigned size)
  474. {
  475. if (*base < offset)
  476. {
  477. // if *base isn't really the base, just do a MemCheckAdd
  478. MemCheckAdd(retaddr, *base, offset, size);
  479. return;
  480. }
  481. shadowtag baseTag;
  482. cacheLine cl;
  483. GetCacheLine(base, cl);
  484. if (cl.pointer && cl.value == *base)
  485. {
  486. baseTag = GetAddrTag(cl.base);
  487. } else
  488. baseTag = GetAddrTag(*base);
  489. for (unsigned i = 0; i < size; i++)
  490. {
  491. shadowtag newTag = GetAddrTag(*base + offset + i);
  492. if (newTag != baseTag || newTag == MEM_EMPTY)
  493. {
  494. if (cl.pointer && cl.value == *base && cl.base)
  495. _RTC_MemFailure(retaddr,
  496. (newTag == MEM_EMPTY) ? _RTC_INVALID_MEM : _RTC_DIFF_MEM_BLOCK,
  497. cl.assignment);
  498. else
  499. _RTC_Failure(retaddr,
  500. (newTag == MEM_EMPTY) ? _RTC_INVALID_MEM : _RTC_DIFF_MEM_BLOCK);
  501. return;
  502. }
  503. }
  504. }
  505. static void
  506. PtrMemCheck(void *retaddr, memref base, unsigned size)
  507. {
  508. shadowtag baseTag = GetAddrTag(*base);
  509. cacheLine cl;
  510. GetCacheLine(base, cl);
  511. if (cl.pointer && cl.value == *base)
  512. _RTC_MemFailure(retaddr,
  513. (baseTag == MEM_EMPTY) ? _RTC_INVALID_MEM : _RTC_DIFF_MEM_BLOCK,
  514. cl.assignment);
  515. else for (unsigned i = 1; i < size; i++)
  516. {
  517. shadowtag newTag = GetAddrTag(*base + i);
  518. if (newTag != baseTag)
  519. {
  520. _RTC_Failure(retaddr, (newTag == MEM_EMPTY) ? _RTC_INVALID_MEM : _RTC_DIFF_MEM_BLOCK);
  521. return;
  522. }
  523. }
  524. }
  525. memptr __fastcall
  526. _RTC_MSPtrPushAdd(memref dstoffset, memref base, int offset)
  527. {
  528. if (_RTC_shadow)
  529. {
  530. memptr src = *base;
  531. memref dst = dstoffset - 4;
  532. shadowtag dstTag = GetAddrTag(src + offset);
  533. shadowtag srcTag = GetAddrTag(src);
  534. cacheLine cl;
  535. GetCacheLine(base, cl);
  536. memptr origBase = src;
  537. if (cl.pointer)
  538. {
  539. if (cl.value == src)
  540. {
  541. srcTag = GetAddrTag(cl.base);
  542. origBase = cl.base;
  543. } else
  544. ClearCacheLine(base);
  545. }
  546. if (srcTag != MEM_EMPTY)
  547. {
  548. if (dstTag != srcTag)
  549. AddCacheLine(_ReturnAddress(), dst, origBase, src + offset);
  550. else
  551. ClearCacheLine(dst);
  552. }
  553. }
  554. return *base + offset;
  555. }
  556. void __fastcall
  557. _RTC_MSPtrAssignAdd(memref dst, memref base, int offset)
  558. {
  559. memptr src = *base;
  560. *dst = src + offset;
  561. if (!_RTC_shadow)
  562. return;
  563. // First, verify that the address is not in shadow memory
  564. shadowtag dstTag = GetAddrTag(*dst);
  565. shadowtag srcTag = GetAddrTag(src);
  566. cacheLine cl;
  567. GetCacheLine(base, cl);
  568. memptr origBase = src;
  569. if (cl.pointer)
  570. {
  571. if (cl.value == src)
  572. {
  573. srcTag = GetAddrTag(cl.base);
  574. origBase = cl.base;
  575. } else
  576. ClearCacheLine(base);
  577. }
  578. if (srcTag == MEM_EMPTY)
  579. return;
  580. if (dstTag != srcTag)
  581. AddCacheLine(_ReturnAddress(), dst, origBase, *dst);
  582. else
  583. ClearCacheLine(dst);
  584. }
  585. memptr __fastcall
  586. _RTC_MSPtrAssignR0(memref src)
  587. {
  588. if (_RTC_shadow)
  589. {
  590. cacheLine cl;
  591. GetCacheLine(src, cl);
  592. if (cl.pointer)
  593. {
  594. if (cl.value == *src)
  595. AddCacheLine(_ReturnAddress(), REG0, cl.base, *src);
  596. else
  597. ClearCacheLine(src);
  598. }
  599. }
  600. return *src;
  601. }
  602. memptr __fastcall
  603. _RTC_MSPtrAssignR0Add(memref src, int offset)
  604. {
  605. memptr dst = *src + offset;
  606. if (_RTC_shadow)
  607. {
  608. // First, verify that the address is tolerable
  609. shadowtag dstTag = GetAddrTag(dst);
  610. shadowtag srcTag = GetAddrTag(*src);
  611. cacheLine cl;
  612. GetCacheLine(src, cl);
  613. memptr origBase = *src;
  614. if (cl.pointer)
  615. {
  616. if (cl.value == *src)
  617. {
  618. srcTag = GetAddrTag(cl.base);
  619. origBase = cl.base;
  620. } else
  621. ClearCacheLine(src);
  622. }
  623. if (srcTag != MEM_EMPTY)
  624. {
  625. if (dstTag != srcTag)
  626. AddCacheLine(_ReturnAddress(), REG0, origBase, dst);
  627. else
  628. ClearCacheLine(REG0);
  629. }
  630. }
  631. return *src + offset;
  632. }
  633. void __fastcall
  634. _RTC_MSR0AssignPtr(memref dst, memptr src)
  635. {
  636. *dst = src;
  637. if (_RTC_shadow)
  638. {
  639. cacheLine cl;
  640. GetCacheLine(REG0, cl);
  641. if (cl.pointer)
  642. {
  643. if (cl.value == src)
  644. AddCacheLine(_ReturnAddress(), dst, cl.base, src);
  645. else
  646. ClearCacheLine(REG0);
  647. }
  648. }
  649. }
  650. void __fastcall
  651. _RTC_MSR0AssignPtrAdd(memref dst, memptr src, int offset)
  652. {
  653. *dst = src + offset;
  654. if (_RTC_shadow)
  655. {
  656. shadowtag dstTag = GetAddrTag(*dst);
  657. shadowtag srcTag = GetAddrTag(src);
  658. cacheLine cl;
  659. GetCacheLine(REG0, cl);
  660. memptr origBase = src;
  661. if (cl.pointer)
  662. {
  663. if (cl.value == src)
  664. {
  665. srcTag = GetAddrTag(cl.base);
  666. origBase = cl.base;
  667. } else
  668. ClearCacheLine(REG0);
  669. }
  670. if (srcTag == MEM_EMPTY)
  671. return;
  672. if (dstTag != srcTag)
  673. AddCacheLine(_ReturnAddress(), dst, origBase, *dst);
  674. else
  675. ClearCacheLine(dst);
  676. }
  677. }
  678. memptr __fastcall
  679. _RTC_MSAddrPushAdd(memref dstoffset, memptr base, int offset)
  680. {
  681. if (_RTC_shadow)
  682. {
  683. memref dst = dstoffset - 4;
  684. // First, verify that the address is not in shadow memory
  685. shadowtag dstTag = GetAddrTag(base + offset);
  686. shadowtag srcTag = GetAddrTag(base);
  687. if (dstTag == MEM_UNKNOWN &&
  688. (srcTag == MEM_EMPTY || srcTag == MEM_UNKNOWN))
  689. ClearCacheLine(dst);
  690. else if (dstTag == MEM_EMPTY ||
  691. (dstTag == MEM_UNKNOWN && srcTag != MEM_UNKNOWN) ||
  692. (srcTag == MEM_UNKNOWN && dstTag != MEM_UNKNOWN))
  693. AddCacheLine(_ReturnAddress(), dst, base, base + offset);
  694. else if (srcTag != MEM_EMPTY)
  695. {
  696. if (srcTag != dstTag)
  697. AddCacheLine(_ReturnAddress(), dst, base, base + offset);
  698. else
  699. ClearCacheLine(dst);
  700. }
  701. }
  702. return base + offset;
  703. }
  704. void __fastcall
  705. _RTC_MSAddrAssignAdd(memref dst, memptr base, int offset)
  706. {
  707. *dst = base + offset;
  708. if (!_RTC_shadow)
  709. return;
  710. // First, verify that the address is not in shadow memory
  711. shadowtag dstTag = GetAddrTag(*dst);
  712. shadowtag srcTag = GetAddrTag(base);
  713. if (dstTag == MEM_UNKNOWN &&
  714. (srcTag == MEM_EMPTY || srcTag == MEM_UNKNOWN))
  715. ClearCacheLine(dst);
  716. else if (dstTag == MEM_EMPTY ||
  717. (dstTag == MEM_UNKNOWN && srcTag != MEM_UNKNOWN) ||
  718. (srcTag == MEM_UNKNOWN && dstTag != MEM_UNKNOWN))
  719. AddCacheLine(_ReturnAddress(), dst, base, *dst);
  720. else if (srcTag == MEM_EMPTY)
  721. return;
  722. else if (srcTag != dstTag)
  723. AddCacheLine(_ReturnAddress(), dst, base, *dst);
  724. else
  725. ClearCacheLine(dst);
  726. }
  727. void __fastcall
  728. _RTC_MSPtrAssign(memref dst, memref src)
  729. {
  730. *dst = *src;
  731. if (!_RTC_shadow)
  732. return;
  733. cacheLine cl;
  734. GetCacheLine(src, cl);
  735. if (cl.pointer)
  736. {
  737. if (cl.value == *src)
  738. AddCacheLine(_ReturnAddress(), dst, cl.base, *src);
  739. else
  740. ClearCacheLine(src);
  741. }
  742. }
  743. memptr __fastcall
  744. _RTC_MSPtrPush(memref dstoffset, memref src)
  745. {
  746. if (_RTC_shadow)
  747. {
  748. cacheLine cl;
  749. GetCacheLine(src, cl);
  750. if (cl.pointer)
  751. {
  752. if (cl.value == *src)
  753. AddCacheLine(_ReturnAddress(), dstoffset - 4, cl.base, *src);
  754. else
  755. ClearCacheLine(src);
  756. }
  757. }
  758. return *src;
  759. }
  760. memval1 __fastcall
  761. _RTC_MSPtrMemReadAdd1(memref base, int offset)
  762. {
  763. memval1 res;
  764. __try
  765. {
  766. res = *(memval1*)(*base + offset);
  767. }
  768. __except(1)
  769. {
  770. _RTC_Failure(_ReturnAddress(), _RTC_INVALID_MEM);
  771. }
  772. if (_RTC_shadow)
  773. PtrMemCheckAdd(_ReturnAddress(), base, offset, 1);
  774. return res;
  775. }
  776. memval2 __fastcall
  777. _RTC_MSPtrMemReadAdd2(memref base, int offset)
  778. {
  779. memval2 res;
  780. __try
  781. {
  782. res = *(memval2*)(*base + offset);
  783. }
  784. __except(1)
  785. {
  786. _RTC_Failure(_ReturnAddress(), _RTC_INVALID_MEM);
  787. }
  788. if (_RTC_shadow)
  789. PtrMemCheckAdd(_ReturnAddress(), base, offset, 2);
  790. return res;
  791. }
  792. memval4 __fastcall
  793. _RTC_MSPtrMemReadAdd4(memref base, int offset)
  794. {
  795. memval4 res;
  796. __try
  797. {
  798. res = *(memval4*)(*base + offset);
  799. }
  800. __except(1)
  801. {
  802. _RTC_Failure(_ReturnAddress(), _RTC_INVALID_MEM);
  803. }
  804. if (_RTC_shadow)
  805. PtrMemCheckAdd(_ReturnAddress(), base, offset, 4);
  806. return res;
  807. }
  808. memval8 __fastcall
  809. _RTC_MSPtrMemReadAdd8(memref base, int offset)
  810. {
  811. memval8 res;
  812. __try
  813. {
  814. res = *(memval8*)(*base + offset);
  815. }
  816. __except(1)
  817. {
  818. _RTC_Failure(_ReturnAddress(), _RTC_INVALID_MEM);
  819. }
  820. if (_RTC_shadow)
  821. PtrMemCheckAdd(_ReturnAddress(), base, offset, 8);
  822. return res;
  823. }
  824. memval1 __fastcall
  825. _RTC_MSMemReadAdd1(memptr base, int offset)
  826. {
  827. memval1 res;
  828. __try
  829. {
  830. res = *(memval1*)(base + offset);
  831. }
  832. __except(1)
  833. {
  834. _RTC_Failure(_ReturnAddress(), _RTC_INVALID_MEM);
  835. }
  836. if (_RTC_shadow)
  837. MemCheckAdd(_ReturnAddress(), base, offset, 1);
  838. return res;
  839. }
  840. memval2 __fastcall
  841. _RTC_MSMemReadAdd2(memptr base, int offset)
  842. {
  843. memval2 res;
  844. __try
  845. {
  846. res = *(memval2*)(base + offset);
  847. }
  848. __except(1)
  849. {
  850. _RTC_Failure(_ReturnAddress(), _RTC_INVALID_MEM);
  851. }
  852. if (_RTC_shadow)
  853. MemCheckAdd(_ReturnAddress(), base, offset, 2);
  854. return res;
  855. }
  856. memval4 __fastcall
  857. _RTC_MSMemReadAdd4(memptr base, int offset)
  858. {
  859. memval4 res;
  860. __try
  861. {
  862. res = *(memval4*)(base + offset);
  863. }
  864. __except(1)
  865. {
  866. _RTC_Failure(_ReturnAddress(), _RTC_INVALID_MEM);
  867. }
  868. if (_RTC_shadow)
  869. MemCheckAdd(_ReturnAddress(), base, offset, 4);
  870. return res;
  871. }
  872. memval8 __fastcall
  873. _RTC_MSMemReadAdd8(memptr base, int offset)
  874. {
  875. memval8 res;
  876. __try
  877. {
  878. res = *(memval8*)(base + offset);
  879. }
  880. __except(1)
  881. {
  882. _RTC_Failure(_ReturnAddress(), _RTC_INVALID_MEM);
  883. }
  884. if (_RTC_shadow)
  885. MemCheckAdd(_ReturnAddress(), base, offset, 8);
  886. return res;
  887. }
  888. memval1 __fastcall
  889. _RTC_MSPtrMemRead1(memref base)
  890. {
  891. memval1 res;
  892. __try
  893. {
  894. res = *(memval1*)*base;
  895. }
  896. __except(1)
  897. {
  898. _RTC_Failure(_ReturnAddress(), _RTC_INVALID_MEM);
  899. }
  900. if (_RTC_shadow)
  901. PtrMemCheck(_ReturnAddress(), base, 1);
  902. return res;
  903. }
  904. memval2 __fastcall
  905. _RTC_MSPtrMemRead2(memref base)
  906. {
  907. memval2 res;
  908. __try
  909. {
  910. res = *(memval2*)*base;
  911. }
  912. __except(1)
  913. {
  914. _RTC_Failure(_ReturnAddress(), _RTC_INVALID_MEM);
  915. }
  916. if (_RTC_shadow)
  917. PtrMemCheck(_ReturnAddress(), base, 2);
  918. return res;
  919. }
  920. memval4 __fastcall
  921. _RTC_MSPtrMemRead4(memref base)
  922. {
  923. memval4 res;
  924. __try
  925. {
  926. res = *(memval4*)*base;
  927. }
  928. __except(1)
  929. {
  930. _RTC_Failure(_ReturnAddress(), _RTC_INVALID_MEM);
  931. }
  932. if (_RTC_shadow)
  933. PtrMemCheck(_ReturnAddress(), base, 4);
  934. return res;
  935. }
  936. memval8 __fastcall
  937. _RTC_MSPtrMemRead8(memref base)
  938. {
  939. memval8 res;
  940. __try
  941. {
  942. res = *(memval8*)*base;
  943. }
  944. __except(1)
  945. {
  946. _RTC_Failure(_ReturnAddress(), _RTC_INVALID_MEM);
  947. }
  948. if (_RTC_shadow)
  949. PtrMemCheck(_ReturnAddress(), base, 8);
  950. return res;
  951. }
  952. memptr __fastcall
  953. _RTC_MSPtrMemCheckAdd1(memref base, int offset)
  954. {
  955. if (_RTC_shadow)
  956. PtrMemCheckAdd(_ReturnAddress(), base, offset, 1);
  957. return *base + offset;
  958. }
  959. memptr __fastcall
  960. _RTC_MSPtrMemCheckAdd2(memref base, int offset)
  961. {
  962. if (_RTC_shadow)
  963. PtrMemCheckAdd(_ReturnAddress(), base, offset, 2);
  964. return *base + offset;
  965. }
  966. memptr __fastcall
  967. _RTC_MSPtrMemCheckAdd4(memref base, int offset)
  968. {
  969. if (_RTC_shadow)
  970. PtrMemCheckAdd(_ReturnAddress(), base, offset, 4);
  971. return *base + offset;
  972. }
  973. memptr __fastcall
  974. _RTC_MSPtrMemCheckAdd8(memref base, int offset)
  975. {
  976. if (_RTC_shadow)
  977. PtrMemCheckAdd(_ReturnAddress(), base, offset, 8);
  978. return *base + offset;
  979. }
  980. memptr __fastcall
  981. _RTC_MSPtrMemCheckAddN(memref base, int offset, unsigned size)
  982. {
  983. if (_RTC_shadow)
  984. PtrMemCheckAdd(_ReturnAddress(), base, offset, size);
  985. return *base + offset;
  986. }
  987. memptr __fastcall
  988. _RTC_MSMemCheckAdd1(memptr base, int offset)
  989. {
  990. if (_RTC_shadow)
  991. MemCheckAdd(_ReturnAddress(), base, offset, 1);
  992. return base + offset;
  993. }
  994. memptr __fastcall
  995. _RTC_MSMemCheckAdd2(memptr base, int offset)
  996. {
  997. if (_RTC_shadow)
  998. MemCheckAdd(_ReturnAddress(), base, offset, 2);
  999. return base + offset;
  1000. }
  1001. memptr __fastcall
  1002. _RTC_MSMemCheckAdd4(memptr base, int offset)
  1003. {
  1004. if (_RTC_shadow)
  1005. MemCheckAdd(_ReturnAddress(), base, offset, 4);
  1006. return base + offset;
  1007. }
  1008. memptr __fastcall
  1009. _RTC_MSMemCheckAdd8(memptr base, int offset)
  1010. {
  1011. if (_RTC_shadow)
  1012. MemCheckAdd(_ReturnAddress(), base, offset, 8);
  1013. return base + offset;
  1014. }
  1015. memptr __fastcall
  1016. _RTC_MSMemCheckAddN(memptr base, int offset, unsigned size)
  1017. {
  1018. if (_RTC_shadow)
  1019. MemCheckAdd(_ReturnAddress(), base, offset, size);
  1020. return base + offset;
  1021. }
  1022. memptr __fastcall
  1023. _RTC_MSPtrMemCheck1(memref base)
  1024. {
  1025. if (_RTC_shadow)
  1026. PtrMemCheck(_ReturnAddress(), base, 1);
  1027. return *base;
  1028. }
  1029. memptr __fastcall
  1030. _RTC_MSPtrMemCheck2(memref base)
  1031. {
  1032. if (_RTC_shadow)
  1033. PtrMemCheck(_ReturnAddress(), base, 2);
  1034. return *base;
  1035. }
  1036. memptr __fastcall
  1037. _RTC_MSPtrMemCheck4(memref base)
  1038. {
  1039. if (_RTC_shadow)
  1040. PtrMemCheck(_ReturnAddress(), base, 4);
  1041. return *base;
  1042. }
  1043. memptr __fastcall
  1044. _RTC_MSPtrMemCheck8(memref base)
  1045. {
  1046. if (_RTC_shadow)
  1047. PtrMemCheck(_ReturnAddress(), base, 8);
  1048. return *base;
  1049. }
  1050. memptr __fastcall
  1051. _RTC_MSPtrMemCheckN(memref base, unsigned size)
  1052. {
  1053. if (_RTC_shadow)
  1054. PtrMemCheck(_ReturnAddress(), base, size);
  1055. return *base;
  1056. }
  1057. static long enabled = 1;
  1058. void __fastcall
  1059. _RTC_CheckMem_API(memref addr, unsigned size)
  1060. {
  1061. if (enabled)
  1062. _RTC_MSPtrMemCheckN(addr, size);
  1063. }
  1064. void __fastcall
  1065. _RTC_APISet(int on_off)
  1066. {
  1067. if (on_off)
  1068. InterlockedIncrement(&enabled);
  1069. else
  1070. InterlockedDecrement(&enabled);
  1071. }
  1072. void _RTC_MS_Init()
  1073. {
  1074. _RTC_shadow = (shadowtag *)VirtualAlloc(NULL, MEM_SIZE, MEM_RESERVE, PAGE_READWRITE);
  1075. _RTC_pageidx = (index_elem*)VirtualAlloc(NULL, IDX_SIZE, MEM_COMMIT, PAGE_READWRITE);
  1076. _RTC_MSAllocShadow((memptr)_RTC_pageidx, IDX_SIZE, IDX_STATE_ILLEGAL);
  1077. ClearCache();
  1078. }
  1079. static void
  1080. KillShadow()
  1081. {
  1082. // This is called if a call to VirtualAlloc failed - we need to turn off shadow memory
  1083. bool didit = false;
  1084. _RTC_Lock();
  1085. if (_RTC_shadow)
  1086. {
  1087. VirtualFree(_RTC_shadow, 0, MEM_RELEASE);
  1088. VirtualFree(_RTC_pageidx, 0, MEM_RELEASE);
  1089. _RTC_shadow = 0;
  1090. _RTC_pageidx = 0;
  1091. MEMORY_BASIC_INFORMATION mbi;
  1092. if (VirtualQuery(&_RTC_SetErrorFunc, &mbi, sizeof(mbi)))
  1093. _RTC_NotifyOthersOfChange((void*)mbi.AllocationBase);
  1094. didit = true;
  1095. }
  1096. if (didit)
  1097. {
  1098. bool notify = true;
  1099. for (_RTC_Funcs *f = _RTC_globptr->callbacks; f; f = f->next)
  1100. if (f->shadowoff)
  1101. notify = notify && (f->shadowoff()!=0);
  1102. if (notify)
  1103. {
  1104. HINSTANCE user32 = LoadLibrary("USER32.DLL");
  1105. if (!user32)
  1106. return;
  1107. typedef int (*pMsgBoxProc)(HWND,LPCTSTR,LPCTSTR,UINT);
  1108. pMsgBoxProc pMsgBox = (pMsgBoxProc)GetProcAddress(user32, "MessageBoxA");
  1109. if (!pMsgBox)
  1110. return;
  1111. pMsgBox(NULL, "The Advanced Memory Checking subsystem has run out of virtual memory,"
  1112. " and is now disabled. The checks will no longer occur for this process. "
  1113. "Try freeing up hard drive space for your swap file.",
  1114. "RTC Subsystem Failure",
  1115. MB_OK | MB_ICONWARNING | MB_DEFBUTTON1 | MB_SETFOREGROUND | MB_TOPMOST);
  1116. }
  1117. }
  1118. _RTC_Unlock();
  1119. }
  1120. #endif // _RTC_ADVMEM