Advertisement
Guest User

Untitled

a guest
Aug 16th, 2015
476
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.89 KB | None | 0 0
  1. /**--------------------------------------------------------------------------**\
  2. ===================================
  3. Y Sever Includes - Malloc Functions
  4. ===================================
  5. Description:
  6. Functions for using malloc/calloc/free type functions in PAWN.
  7. Legal:
  8. Version: MPL 1.1
  9.  
  10. The contents of this file are subject to the Mozilla Public License Version
  11. 1.1 (the "License"); you may not use this file except in compliance with
  12. the License. You may obtain a copy of the License at
  13. http://www.mozilla.org/MPL/
  14.  
  15. Software distributed under the License is distributed on an "AS IS" basis,
  16. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  17. for the specific language governing rights and limitations under the
  18. License.
  19.  
  20. The Original Code is the YSI malloc include.
  21.  
  22. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  23. Portions created by the Initial Developer are Copyright (C) 2011
  24. the Initial Developer. All Rights Reserved.
  25.  
  26. Contributors:
  27. ZeeX, koolk, JoeBullet/Google63, g_aSlice/Slice
  28.  
  29. Thanks:
  30. JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
  31. ZeeX - Very productive conversations.
  32. koolk - IsPlayerinAreaEx code.
  33. TheAlpha - Danish translation.
  34. breadfish - German translation.
  35. Fireburn - Dutch translation.
  36. yom - French translation.
  37. 50p - Polish translation.
  38. Zamaroht - Spanish translation.
  39. Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes
  40. for me to strive to better.
  41. Pixels^ - Running XScripters where the idea was born.
  42. Matite - Pestering me to release it and using it.
  43.  
  44. Very special thanks to:
  45. Thiadmer - PAWN, whose limits continue to amaze me!
  46. Kye/Kalcor - SA:MP.
  47. SA:MP Team past, present and future - SA:MP.
  48.  
  49. Version:
  50. 0.1
  51. Changelog:
  52. 02/12/11:
  53. Added variable argument functions.
  54. 22/12/08:
  55. First version.
  56. Functions:
  57. Public
  58. -
  59. Core:
  60. -
  61. Stock:
  62. malloc - Allocate a block of memory (may be inline).
  63. calloc - Allocate a block of memory and blank.
  64. free - Free an allocated block of memory (may be inline).
  65. Malloc_Set - Set a value in an allocated array (may be inline).
  66. Malloc_Get - Get a value in an allocated array (may be inline).
  67. Malloc_SetS - Set a string in an allocated array.
  68. Malloc_GetS - Get a string in an allocated array.
  69. Malloc_Allocate - Do the memory allocation (may be static).
  70. Malloc_Free - Do the memory freeing (may be static).
  71. Malloc_SlotSize - Get the size of an allocated block (may be inline).
  72. Malloc_NewS - Allocate for and store a given string.
  73. Static:
  74. Malloc_Allocate - Do the memory allocation (may be stock).
  75. Malloc_Free - Do the memory freeing (may be stock).
  76. Inline:
  77. mget - Get data from an allocation unit.
  78. mset - Set data in an allocation unit.
  79. mgets - Get a string from an allocation unit.
  80. msets - Set a string in an allocation unit.
  81. malloc - Allocate a block of memory (may be stock).
  82. free - Free an allocated block of memory (may be stock).
  83. Malloc_Set - Set a value in an allocated array (may be stock).
  84. Malloc_Get - Get a value in an allocated array (may be stock).
  85. Malloc_NextSlot - Get the next free data block.
  86. Malloc_GetSlotSize - Get the size of a slot.
  87. Malloc_SetSlotSize - Set the size of a block.
  88. Malloc_GetData - Direct data access getter.
  89. Malloc_SetData - Direct data access setter.
  90. Malloc_SlotSize - Get the size of an allocated block (may be stock).
  91. API:
  92. -
  93. Callbacks:
  94. -
  95. Definitions:
  96. MALLOC_KB_TO_CELL - Multiplication value to convert kb to cells.
  97. NO_ALLOC - A failed allocation (NULL, but YSI already has NULL).
  98. Enums:
  99. -
  100. Macros:
  101. -
  102. Tags:
  103. Alloc - An allocated block handle variable.
  104. Variables:
  105. Global:
  106. YSI_gMallocMemory - Stores the data (may be static).
  107. Static:
  108. YSI_gMallocMemory - Stores the data (may be global).
  109. YSI_g_sUnusedStart - Start of free memory.
  110. Commands:
  111. -
  112. Compile options:
  113. MALLOC_MEMORY - Number of cells to reserve.
  114. MALLOC_MEMORY_KB - Number of killobytes to reserve.
  115. MALLOC_MEMORY_B - Number of bytes to reserve.
  116. MALLOC_MEMORY_MB - Number of megabytes to reserve.
  117. YSI_MALLOC_SECURE - Use enhanced bounds checking.
  118. YSI_MALLOC_NO_SHORT - Avoid conflicts with mget/mset.
  119. Operators:
  120. -
  121. \**--------------------------------------------------------------------------**/
  122.  
  123. main()
  124. {
  125. P:1("Malloc_main called");
  126. Malloc_TrySetup();
  127. #if defined Malloc_main
  128. Malloc_main();
  129. #endif
  130. return 1;
  131. //return MALLOC_SOLIDIFYHEAP(3);
  132. }
  133.  
  134. #if defined _ALS_main
  135. #undef main
  136. #else
  137. #define _ALS_main
  138. #endif
  139. #define main() forward Malloc_main();public Malloc_main()
  140.  
  141.  
  142. /**--------------------------------------------------------------------------**\
  143. <summary>Malloc_FindStackTop</summary>
  144. <returns>
  145. -
  146. </returns>
  147. <remarks>
  148. Loop back up through the stack and find the start of the current stack. If
  149. it doesn't equal the top of the true stack then we've been called via
  150. "CallLocalFunction" at some point and thus MAY get some memory corruption.
  151.  
  152. Based on ZeeX's GetStackTrace, but gets frames instead of returns.
  153. </remarks>
  154. \**--------------------------------------------------------------------------**/
  155.  
  156. static Malloc_FindStackTop()
  157. {
  158. new
  159. frm_addr;
  160. #emit LCTRL 5
  161. #emit STOR.S.pri frm_addr
  162. // Loop until we hit a return address of 0.
  163. while (GetFrameReturn(frm_addr))
  164. {
  165. #emit LREF.S.pri frm_addr
  166. #emit STOR.S.pri frm_addr
  167. }
  168. // We can't accurately get the number or parameters because of y_hooks :(.
  169. return frm_addr + 12;
  170. }
  171.  
  172. /**--------------------------------------------------------------------------**\
  173. <summary>OnScriptInit</summary>
  174. <returns>
  175. -
  176. </returns>
  177. <remarks>
  178. Finds all "BOUNDS 0" OpCodes in the AMX and rewrites them to "NOP NOP". The
  179. byte pattern for this code is "OP_BOUNDS 0", which (AFAIK) can not appear
  180. anywhere else in the DAT segment. You can have "OP_BOUNDS" as a parameter
  181. to something, but it would then be followed by an OpCode of "0", which is
  182. never valid (OP_NONE).
  183.  
  184. I've tried to make this as resiliant as possible to being called via
  185. "CallLocalFunction" as not the first callback in the script but there may
  186. still be a few problems - we won't see till people start testing I guess...
  187. </remarks>
  188. \**--------------------------------------------------------------------------**/
  189.  
  190. public OnScriptInit()
  191. {
  192. P:1("Malloc_OnScriptInit called");
  193. // First ever LEGITIMATE call to "heapspace"!
  194. if (heapspace() < MALLOC_MEMORY + 4 * 1024)
  195. {
  196. P:E("heapspace too low for y_malloc: Did you use \"#pragma dynamic\"?");
  197. }
  198. new
  199. Opcode:bounds = RelocateOpcode(OP_BOUNDS),
  200. nop = _:RelocateOpcode(OP_NOP);
  201. for (new i = AMX_HEADER_COD, end = AMX_HEADER_DAT - 4; i < end; i += 4)
  202. {
  203. // Make sure this isn't just something that LOOKS like "bounds 0",
  204. // although I don't think there can be because "0" is not a valid
  205. // opcode.
  206. if (AMX_Read(i) == _:bounds && AMX_Read(i + 4) == 0)
  207. {
  208. // Found a bounds code.
  209. AMX_Write(i, nop);
  210. AMX_Write(i += 4, nop);
  211. }
  212. }
  213. Malloc_TrySetup();
  214. #if defined Malloc_OnScriptInit
  215. Malloc_OnScriptInit();
  216. #endif
  217. SetTimer("Malloc_SolidifyTimer", 0, 0);
  218. SetTimer("Malloc_SolidifyTimer", 0, 0);
  219. return 1;
  220. }
  221.  
  222. #undef OnScriptInit
  223. #define OnScriptInit Malloc_OnScriptInit
  224. #if defined Malloc_OnScriptInit
  225. forward Malloc_OnScriptInit();
  226. #endif
  227.  
  228. /**--------------------------------------------------------------------------**\
  229. <summary>Malloc_TrySetup</summary>
  230. <returns>
  231. -
  232. </returns>
  233. <remarks>
  234. Move the heap pointer up a load. This is called multiple times at the start
  235. of the mode because we need to beat protections added in by the virtual
  236. machine to steal away its heap area.
  237. </remarks>
  238. \**--------------------------------------------------------------------------**/
  239.  
  240. static Malloc_TrySetup()
  241. {
  242. P:1("Malloc_TrySetup called");
  243. new
  244. temp;
  245. #emit LCTRL 3
  246. #emit STOR.S.pri temp
  247. if (temp > Malloc_FindStackTop() + 4)
  248. {
  249. P:W("y_malloc set up via \"CallLocalFunction\", memory corruption is a remote possibility");
  250. }
  251. temp = MALLOC_MEMORY * 4;
  252. // Allocate a ton of space on the heap.
  253. #emit LCTRL 2
  254. #emit LOAD.S.alt temp
  255. #emit ADD
  256. #emit STOR.S.pri temp
  257. // Now there's only the normal bit of the stack and heap left.
  258. if (temp == AMX_HEADER_HEA + MALLOC_MEMORY * 4 * 2)
  259. {
  260. // Already allocated and now trying to double allocate.
  261. return;
  262. }
  263. if (temp != AMX_HEADER_HEA + MALLOC_MEMORY * 4)
  264. {
  265. P:F("y_malloc: Not the first HEAP allocation!");
  266. return;
  267. }
  268. else
  269. {
  270. #emit LOAD.S.pri temp
  271. #emit SCTRL 2
  272. if (YSI_g_sHeapStart) return;
  273. }
  274. YSI_g_sHeapStart = temp - MALLOC_MEMORY * 4;
  275. P:2("Malloc_OnScriptInit: %d %d %d", YSI_g_sHeapStart, MALLOC_MEMORY * 4, AMX_HEADER_HEA);
  276. #emit CONST.alt YSI_gMallocMemory
  277. #emit LOAD.pri __YSI_g_sHeapStart
  278. #emit SUB
  279. #emit SHR.C.pri 2 // Divide by 4 to get cells.
  280. #emit STOR.pri __YSI_g_sHeapStart
  281. YSI_gMallocMemory[YSI_g_sHeapStart] = MALLOC_MEMORY - 1;
  282. YSI_g_sUnusedStart = YSI_g_sHeapStart + 1;
  283. // Blank the whole memory. Maybe required if the heap has been used
  284. // already (better to be safe than sorry).
  285. memset(YSI_gMallocMemory[YSI_g_sHeapStart + 1], 0, MALLOC_MEMORY - 1);
  286. #if _DEBUG > 3
  287. // The "#if" is actually ignored by these "#emit" codes, as always.
  288. #emit CONST.alt YSI_gMallocMemory
  289. #emit STOR.S.alt temp
  290. printf("Malloc_OnScriptInit: AMX_HEADER_HEA = %d, YSI_gMallocMemory = %d, YSI_g_sHeapStart = %d", _:AMX_HEADER_HEA, temp, YSI_g_sHeapStart);
  291. printf("Malloc_OnScriptInit: YSI_gMallocMemory + 4 * YSI_g_sHeapStart = %d", temp + 4 * YSI_g_sHeapStart);
  292. #endif
  293. // This is never read, but we now have a spare cell because we HAD to
  294. // allocate an array of some size.
  295. YSI_gMallocMemory[0] = MALLOC_MEMORY;
  296. }
  297.  
  298. static
  299. //YSI_g_sSolidifyHeap,
  300. YSI_g_sHeapSetup = 0;
  301.  
  302. static const
  303. // Split in to three because of line length limits.
  304. YSI_g_scErrorMessage1[] =
  305. " \n" \
  306. " \n" \
  307. " ============================================================================\n" \
  308. " | |\n" \
  309. " | ****************** |\n" \
  310. " | * VERY IMPORTANT * |\n" \
  311. " | ****************** |",
  312. YSI_g_scErrorMessage2[] =
  313. " | |\n" \
  314. " | Your \"crashdetect\" plugin is out of date, ignore the \"error 12\" above! |\n" \
  315. " | |\n" \
  316. " | [debug] Run time error 12: \"(sleep mode)\" |\n" \
  317. " | [debug] AMX backtrace: |",
  318. //" | [debug] #0 <SOME ADDRESS> in %s () from <FILE>%s|\n"
  319. YSI_g_scErrorMessage3[] =
  320. " | [debug] #0 <HEX NUMBER> in public Malloc_SolidifyTimer () |\n" \
  321. " | |\n" \
  322. " | For more information, see the YSI.tl release topic. |\n" \
  323. " | |\n" \
  324. " ============================================================================\n" \
  325. " \n";
  326.  
  327. forward OnRuntimeError(code);
  328.  
  329. public OnRuntimeError(code)
  330. {
  331. // This is called if the "crashdetect" plugin is installed.
  332. if (code == 12)
  333. {
  334. P:0(YSI_g_scErrorMessage1);
  335. P:0(YSI_g_scErrorMessage2);
  336. P:0(YSI_g_scErrorMessage3);
  337. }
  338. #if defined Malloc_OnRuntimeError
  339. Malloc_OnRuntimeError(code);
  340. #endif
  341. if (code == 12)
  342. {
  343. // Make sure our heap is correctly set still...
  344. return Malloc_SolidifyHeap();
  345. }
  346. else return 0;
  347. }
  348. #if defined _ALS_OnRuntimeError
  349. #undef OnRuntimeError
  350. #else
  351. #define _ALS_OnRuntimeError
  352. #endif
  353. #define OnRuntimeError Malloc_OnRuntimeError
  354. #if defined Malloc_OnRuntimeError
  355. forward Malloc_OnRuntimeError(code);
  356. #endif
  357.  
  358. forward Malloc_SolidifyTimer();
  359.  
  360. public Malloc_SolidifyTimer()
  361. {
  362. P:1("Malloc_SolidifyTimer called");
  363. Malloc_TrySetup();
  364. Malloc_SolidifyHeap();
  365. }
  366.  
  367. static Malloc_SolidifyHeap()
  368. {
  369. if (YSI_g_sHeapSetup == 2) return 1;
  370. ++YSI_g_sHeapSetup;
  371. #emit LCTRL 3
  372. #emit MOVE.alt
  373. #emit SCTRL 5
  374. #emit SCTRL 4 // Set the original stack pointer.
  375. // Call to save "stk" and "frm", since they aren't in early builds.
  376. #emit PUSH.C 0
  377. #emit SYSREQ.C heapspace // The pre-processor can't touch this.
  378. #emit STACK 4
  379. // Unfortunately, "heapspace" has a parameter pushed first so it saves the
  380. // wrong stack value (the value 4 below where it should be). The only other
  381. // opcode that reliably saves "stk" in "amx->stk" without trying to call a
  382. // native function is "OP_RETN", so let's BADLY invoke it! Note that we
  383. // still need the "heapspace" call (or any function call) to save "hea" and
  384. // "frm", which are NOT saved by "OP_RETN" but are by "OP_SYSREQ_C".
  385. #emit PUSH.C 0 // No parameters
  386. #emit LCTRL 6 // Return to the next instruction...
  387. #emit ADD.C 20
  388. #emit PUSH.pri
  389. #emit PUSH.alt // Same frame.
  390. #emit RETN
  391. // "return" to here...
  392. #emit HALT 12
  393. return 0;
  394. }
  395.  
  396. /**--------------------------------------------------------------------------**\
  397. <summary>Malloc_OnPlayerConnect</summary>
  398. <param name="playerid">Player that just connected.</param>
  399. <returns>
  400. -
  401. </returns>
  402. <remarks>
  403. This is the only callback that can be called before our timers when the mode
  404. starts. Make sure the heap is set up correctly.
  405. </remarks>
  406. \**--------------------------------------------------------------------------**/
  407.  
  408. forward Malloc_DoPlayerConnect(playerid);
  409.  
  410. public Malloc_DoPlayerConnect(playerid)
  411. {
  412. if (YSI_g_sHeapSetup != 2) Malloc_TrySetup();
  413. // Ensure we only call the originsl.
  414. return call OnPlayerConnect(playerid);
  415. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement