1 /*
2 * UNIX shell
3 *
4 * Stacked-storage allocation.
5 *
6 * Written by Geoff Collyer
7 * Rewritten by J. Schilling to match the SVr4 version of the Bourne Shell
8 *
9 *
10 * This replaces the original shell's stak.c. This implementation
11 * does not rely on memory faults to manage storage. See ``A Partial
12 * Tour Through the UNIX Shell'' for details. This implementation is
13 * newer than the one published in that paper, but differs mainly in
14 * just being a little more portable. In particular, it works on
15 * Ultrasparc and Alpha processors, which are insistently 64-bit processors.
16 *
17 * Maintains a linked stack (of mostly character strings), the top (most
18 * recently allocated item) of which is a growing string, which pushstak()
19 * inserts into and grows as needed.
20 *
21 * Each item on the stack consists of a pointer to the previous item
22 * (the "word" pointer; stk.topitem points to the top item on the stack),
23 * an optional magic number, and the data. There may be malloc overhead storage
24 * on top of this. Heap storage returned by alloc() lacks the "word" pointer.
25 *
26 * Pointers returned by these routines point to the first byte of the data
27 * in a stack item; users of this module should be unaware of the "word"
28 * pointer and the magic number. To confuse matters, stk.topitem points to the
29 * "word" linked-list pointer of the top item on the stack, and the
30 * "word" linked-list pointers each point to the corresponding pointer
31 * in the next item on the stack. This all comes to a head in tdystak().
32 *
33 * Geoff Collyer
34 */
35
36 /*
37 * see also stak.h
38 */
39 #include "defs.h"
40
41 /*
42 * Copyright Geoff Collyer 1987-2005
43 *
44 * @(#)stak.c 2.23 19/02/10 Copyright 2010-2019 J. Schilling
45 */
46 /*
47 * The contents of this file are subject to the terms of the
48 * Common Development and Distribution License, Version 1.0 only
49 * (the "License"). You may not use this file except in compliance
50 * with the License.
51 *
52 * See the file CDDL.Schily.txt in this distribution for details.
53 *
54 * When distributing Covered Code, include this CDDL HEADER in each
55 * file and include the License file CDDL.Schily.txt from this distribution.
56 */
57
58 #ifndef lint
59 static UConst char sccsid[] =
60 "@(#)stak.c 2.23 19/02/10 Copyright 2010-2019 J. Schilling";
61 #endif
62
63
64 #undef free /* refer to free(3) here */
65 #define stakend brkend /* SVr4 Shell uses brkend */
66 #define USED(x) /* Built in from Plan-9 compiler */
67
68 /*
69 * was (10*1024) for testing; must be >= sizeof (struct fileblk) always.
70 * must also be >= 2*(CPYSIZ in io.c [often 512])
71 */
72 #undef BRKINCR
73 #define BRKINCR 1024
74
75 #ifdef NO_TOSSGROWING_MACRO
76 #undef TOSSGROWING_MACRO
77 #endif
78
79 #define UC (unsigned char *)
80
81 #ifdef STAK_DEBUG
82 #define TPRS(s) do { if (Tracemem) prs(UC s); } while (0)
83 #define TPRN(n) do { if (Tracemem) prln(n); } while (0)
84 #define TPRNN(n) do { if (Tracemem) prnln(n); } while (0)
85
86 #define STPRS(s) do { if (Stackdebug) prs(UC s); } while (0)
87 #define STPRN(n) do { if (Stackdebug) prln(n); } while (0)
88 #define STPRNN(n) do { if (Stackdebug) prnln(n); } while (0)
89 #else
90
91 #define debugsav(a)
92
93 #define TPRS(s)
94 #define TPRN(n)
95 #define TPRNN(n)
96
97 #define STPRS(s)
98 #define STPRN(n)
99 #define STPRNN(n)
100 #endif
101
102 #ifndef TRACEMEM
103 #define TRACEMEM 0
104 #endif
105 #ifndef STACKDEBUG
106 #define STACKDEBUG 0
107 #endif
108
109 enum {
110 Tracemem = TRACEMEM,
111 Stackdebug = STACKDEBUG,
112
113 STMAGICNUM = 0x1235, /* stak item magic */
114 STNMAGICNUM = 0x1237, /* stak null item magic */
115 HPMAGICNUM = 0x4276, /* heap item magic */
116 };
117
118 /*
119 * to avoid relying on features of the Plan 9 C compiler, these structs
120 * are expressed rather awkwardly.
121 */
122 typedef struct stackblk Stackblk;
123
124 typedef struct {
125 Stackblk *word; /* pointer to previous stack item */
126 ULlong magic; /* force pessimal alignment */
127 } Stackblkhdr;
128
129 struct stackblk {
130 Stackblkhdr h;
131 char userdata[1];
132 };
133
134 typedef struct {
135 ULlong magic; /* force pessimal alignment */
136 } Heapblkhdr;
137
138 typedef struct {
139 Heapblkhdr h;
140 char userdata[1];
141 } Heapblk;
142
143 typedef struct {
144 unsigned char *base;
145 /*
146 * A chain of ptrs of stack blocks that have become covered
147 * by heap allocation. `tdystak' will return them to the heap.
148 */
149 Stackblk *topitem;
150 } Stack;
151
152 unsigned brkincr = BRKINCR; /* used in stak.h only */
153
154 static Stack stk;
155 static char *stklow; /* Lowest known addr on stak */
156 static char *stkhigh; /* Highest known addr on stak */
157
158 /*
159 * Global variables stakbas, staktop, stakbot, stakbsy, brkend see defs.c
160 */
161
162 static void *xmalloc __PR((size_t size));
163 #ifndef TOSSGROWING_MACRO
164 static void tossgrowing __PR((void));
165 #endif
166 static char *stalloc __PR((int size));
167 static void grostalloc __PR((void));
168 unsigned char *getstak __PR((Intptr_t asize));
169 #ifdef STAK_DEBUG
170 static void prnln __PR((long));
171 #endif
172 #if defined(STAK_DEBUG) || defined(FREE_DEBUG) || defined(TOSSCHECK)
173 static void prln __PR((long));
174 #endif
175 unsigned char *locstak __PR((void));
176 unsigned char *savstak __PR((void));
177 unsigned char *endstak __PR((unsigned char *argp));
178 void tdystak __PR((unsigned char *sav, struct ionod *iosav));
179 #ifdef STAK_DEBUG
180 void *debugstak __PR((void));
181 static void debugsav __PR((unsigned char *sav));
182 #endif
183 void stakchk __PR((void));
184 static unsigned char *__growstak __PR((int incr));
185 unsigned char *growstak __PR((unsigned char *newtop));
186 void addblok __PR((unsigned reqd));
187 void *alloc __PR((size_t size));
188 void shfree __PR((void *ap));
189 unsigned char *cpystak __PR((unsigned char *newstak));
190 unsigned char *movstrstak __PR((unsigned char *a,
191 unsigned char *b));
192 unsigned char *memcpystak __PR((unsigned char *s1,
193 unsigned char *s2, int n));
194 /*
195 * Call malloc() and keep track of stklow / stkhigh to be able to skip
196 * unallocated space in shfree():
197 */
198 static void *
xmalloc(size)199 xmalloc(size)
200 register size_t size;
201 {
202 register char *ret = malloc(size);
203
204 if (ret == NULL)
205 return ((void *)ret);
206
207 if (ret < stklow)
208 stklow = ret;
209
210 if ((ret + size) > stkhigh)
211 stkhigh = ret + size;
212
213 return ((void *)ret);
214 }
215
216 #ifdef TOSSGROWING_MACRO
217 #ifdef TOSSCHECK
218 #define tosscheck(stk) \
219 /* verify magic before freeing */ \
220 if (stk.topitem->h.magic != STMAGICNUM && \
221 stk.topitem->h.magic != STNMAGICNUM) { \
222 prs((unsigned char *) \
223 "tossgrowing: stk.topitem->h.magic "); \
224 prln((long)stk.topitem->h.magic); \
225 prs((unsigned char *)"\n"); \
226 error("tossgrowing: bad magic on stack"); \
227 }
228 #else
229 #define tosscheck(stk)
230 #endif
231 #define tossgrowing() \
232 if (stk.topitem != 0) { /* any growing stack? */ \
233 Stackblk *nextitem; \
234 \
235 tosscheck(stk); \
236 \
237 TPRS("tossgrowing freeing "); \
238 TPRN((long)stk.topitem); \
239 TPRS("\n"); \
240 \
241 stk.topitem->h.magic = 0; /* erase magic */ \
242 \
243 /* \
244 * about to free the ptr to next, so copy it first \
245 */ \
246 nextitem = stk.topitem->h.word; \
247 free(stk.topitem); \
248 stk.topitem = nextitem; \
249 }
250 #endif /* TOSSGROWING_MACRO */
251
252 #ifndef tossgrowing
253 static void
tossgrowing()254 tossgrowing() /* free the growing stack */
255 {
256 if (stk.topitem != 0) { /* any growing stack? */
257 Stackblk *nextitem;
258
259 #ifdef TOSSCHECK
260 /* verify magic before freeing */
261 if (stk.topitem->h.magic != STMAGICNUM &&
262 stk.topitem->h.magic != STNMAGICNUM) {
263 prs((unsigned char *)
264 "tossgrowing: stk.topitem->h.magic ");
265 prln((long)stk.topitem->h.magic);
266 prs((unsigned char *)"\n");
267 error("tossgrowing: bad magic on stack");
268 }
269 #endif /* TOSSCHECK */
270
271 TPRS("tossgrowing freeing ");
272 TPRN((long)stk.topitem);
273 TPRS("\n");
274
275 stk.topitem->h.magic = 0; /* erase magic */
276
277 /*
278 * about to free the ptr to next, so copy it first
279 */
280 nextitem = stk.topitem->h.word;
281 free(stk.topitem);
282 stk.topitem = nextitem;
283 }
284 }
285 #endif /* !tossgrowing */
286
287 static char *
stalloc(size)288 stalloc(size) /* allocate requested stack space (no frills) */
289 int size;
290 {
291 Stackblk *nstk;
292
293 TPRS("stalloc allocating ");
294 TPRN(sizeof (Stackblkhdr) + size);
295 TPRS(" user bytes ");
296
297 if (size < sizeof (Llong))
298 size = sizeof (Llong);
299 nstk = xmalloc(sizeof (Stackblkhdr) + size);
300 if (nstk == 0)
301 error(nostack);
302
303 TPRS("@ ");
304 TPRN((long)nstk);
305 TPRS("\n");
306
307 /* stack this item */
308 nstk->h.word = stk.topitem; /* point back @ old stack top */
309 stk.topitem = nstk; /* make this new stack top */
310
311 nstk->h.magic = STMAGICNUM; /* add magic number for verification */
312 return (nstk->userdata);
313 }
314
315 static void
grostalloc()316 grostalloc() /* allocate growing stack */
317 {
318 int size = BRKINCR;
319
320 /*
321 * fiddle global variables to point into this (growing) stack
322 */
323 staktop = stakbot = stk.base = (unsigned char *)stalloc(size);
324 stakend = stk.base + size;
325 }
326
327 /*
328 * allocate requested stack.
329 * movstrstak() assumes that getstak just realloc's the growing stack,
330 * so we must do just that. Grump.
331 * Return new address of stak base.
332 */
333 unsigned char *
getstak(asize)334 getstak(asize)
335 Intptr_t asize;
336 {
337 int staklen;
338 unsigned char *nstk;
339
340 staklen = stakend - stk.base; /* # of usable bytes */
341
342 TPRS("getstak(");
343 TPRN(asize);
344 TPRS(") calling __growstak(");
345 TPRNN(asize - staklen);
346 TPRS("):\n");
347
348 /* grow growing stack to requested size */
349 nstk = __growstak(asize - staklen);
350 grostalloc(); /* allocate new growing stack */
351 return (nstk);
352 }
353
354 #ifdef STAK_DEBUG
355 static void
prnln(l)356 prnln(l)
357 long l;
358 {
359 if (l < 0) {
360 prs((unsigned char *)"-");
361 l = -l;
362 }
363 prln(l);
364 }
365 #endif
366
367 #if defined(STAK_DEBUG) || defined(FREE_DEBUG) || defined(TOSSCHECK)
368 static void
prln(l)369 prln(l)
370 long l;
371 {
372 prs(&numbuf[ltos(l)]);
373 }
374 #endif
375
376 /*
377 * set up stack for local use (i.e. make it big).
378 * should be followed by `endstak'
379 * Return new address of stak base.
380 */
381 unsigned char *
locstak()382 locstak()
383 {
384 if (stakend - stakbot < BRKINCR) {
385 TPRS("locstak calling __growstak(");
386 TPRNN(BRKINCR - (stakend - stakbot));
387 TPRS("):\n");
388 (void) __growstak(BRKINCR - (stakend - stakbot));
389 }
390 return (stakbot);
391 }
392
393 /*
394 * return an address to be used by tdystak later,
395 * so it must be returned by getstak because it may not be
396 * a part of the growing stack, which is subject to moving.
397 * Return new address of stak base.
398 */
399 unsigned char *
savstak()400 savstak()
401 {
402 unsigned char *ostk;
403 Stackblk *blk;
404
405 assert(staktop == stakbot); /* assert empty stack */
406 ostk = getstak(1);
407 blk = (Stackblk *)(ostk - sizeof (Stackblkhdr));
408 blk->h.magic = STNMAGICNUM; /* Mark as null stak item */
409 return (ostk);
410 }
411
412 /*
413 * tidy up after `locstak'.
414 * make the current growing stack a semi-permanent item and
415 * generate a new tiny growing stack.
416 * Return new address of stak base.
417 *
418 * As currently all endstak()/tdystak() pairs in the shell leave a non-zero
419 * block on the current growing stack, we did not create code to set
420 * blk->h.magic = STNMAGICNUM in case of an empty block.
421 */
422 unsigned char *
endstak(argp)423 endstak(argp)
424 unsigned char *argp;
425 {
426 unsigned char *ostk;
427 UIntptr_t argoff = argp - stakbot;
428
429 if (argp >= stakend) { /* Space for null byte */
430 __growstak(argp - stakend + 1); /* stakend is off space */
431 argp = stakbot + argoff;
432 }
433 *argp++ = 0; /* terminate the string */
434 TPRS("endstak calling __growstak(");
435 TPRNN(-(stakend - argp));
436 TPRS("):\n");
437 ostk = __growstak(-(stakend - argp)); /* reduce growing stack size */
438 grostalloc(); /* alloc. new growing stack */
439
440 return (ostk); /* perm. addr. of old item */
441 }
442
443 /*
444 * Try to bring the "stack" back to sav (the address of userdata[0] in some
445 * Stackblk, returned by __growstak()), and bring iotemp's stack back to iosav
446 * (an old copy of iotemp, which may be zero).
447 */
448 void
tdystak(sav,iosav)449 tdystak(sav, iosav)
450 unsigned char *sav;
451 struct ionod *iosav;
452 {
453 Stackblk *blk = (Stackblk *)NIL;
454
455 rmtemp(iosav); /* pop temp files */
456
457 if (sav == 0) {
458 /* EMPTY */
459 STPRS("tdystak(0)\n");
460 } else {
461 blk = (Stackblk *)(sav - sizeof (Stackblkhdr));
462 if (blk->h.magic == STMAGICNUM ||
463 blk->h.magic == STNMAGICNUM) {
464 /* EMPTY */
465 STPRS("tdystak(data ptr: ");
466 STPRN((long)sav);
467 STPRS(")\n");
468 } else {
469 STPRS("tdystak(garbage: ");
470 STPRN((long)sav);
471 STPRS(")\n");
472 error("tdystak: bad magic in argument");
473 }
474 }
475
476 /*
477 * pop stack to sav (if zero, pop everything).
478 * stk.topitem points at the ptr before the data & magic.
479 */
480 while (stk.topitem != 0 && (sav == 0 || stk.topitem != blk)) {
481 debugsav(sav);
482 tossgrowing(); /* toss the stack top */
483 }
484 /*
485 * This is not the default call tdystak(0, 0) from main.c
486 * If the stak top "blk" was retrieved via savstak(), it is
487 * a null item that needs to be freed as well.
488 * If the stak top was retrieved via fixstak()/endstak()
489 * it usually contains data from the previous environment and
490 * thus must not be freed.
491 */
492 if (blk && stk.topitem == blk &&
493 blk->h.magic == STNMAGICNUM)
494 tossgrowing(); /* toss the stack top */
495
496 debugsav(sav);
497 STPRS("tdystak: done popping\n");
498 grostalloc(); /* new growing stack */
499 STPRS("tdystak: exit\n");
500 }
501
502 #ifdef STAK_DEBUG
503 void *
debugstak()504 debugstak()
505 {
506 Stack s;
507 int i = 0;
508
509 s.topitem = stk.topitem;
510
511 while (s.topitem) {
512 prs((unsigned char *)"Topitem: ");
513 prln((long)s.topitem);
514 prs((unsigned char *)"\n");
515 i++;
516 s.topitem = s.topitem->h.word;
517 }
518 prs((unsigned char *)"Number of topitems: ");
519 prn(i);
520 prs((unsigned char *)"\n");
521 return (stk.topitem);
522 }
523
524 static void
debugsav(sav)525 debugsav(sav)
526 unsigned char *sav;
527 {
528 if (stk.topitem == 0) {
529 /* EMPTY */
530 STPRS("tdystak: stk.topitem == 0\n");
531 } else if (sav != 0 &&
532 stk.topitem == (Stackblk *)(sav - sizeof (Stackblkhdr))) {
533 /* EMPTY */
534 STPRS("tdystak: stk.topitem == link ptr of arg: ");
535 STPRN((long)stk.topitem);
536 STPRS("\n");
537 } else {
538 /* EMPTY */
539 STPRS("tdystak: stk.topitem == link ptr of item above arg: ");
540 STPRN((long)stk.topitem);
541 STPRS("\n");
542 }
543 }
544 #endif
545
546 /*
547 * Reduce the growing-stack size if possible
548 */
549 void
stakchk()550 stakchk()
551 {
552 if (stakend - staktop > 2*BRKINCR) { /* lots of unused stack headroom */
553 TPRS("stakchk calling __growstak(");
554 TPRNN(-(stakend - staktop - BRKINCR));
555 TPRS("):\n");
556 (void) __growstak(-(stakend - staktop - BRKINCR));
557 }
558 }
559
560 /*
561 * Return new address of grown stak base,
562 * grow the growing stack by "incr".
563 */
564 static unsigned char *
__growstak(incr)565 __growstak(incr)
566 int incr;
567 {
568 int staklen;
569 unsigned int topoff;
570 unsigned int botoff;
571 unsigned int basoff;
572 unsigned char *oldbsy;
573
574 if (stk.topitem == 0) /* paranoia */
575 grostalloc(); /* make a trivial stack */
576
577 /*
578 * paranoia: during realloc, point @ previous item in case of signals
579 */
580 oldbsy = (unsigned char *)stk.topitem;
581 stk.topitem = stk.topitem->h.word;
582
583 topoff = staktop - oldbsy;
584 botoff = stakbot - oldbsy;
585 basoff = stk.base - oldbsy;
586
587 /*
588 * stakend points past the last valid byte of the growing stack
589 */
590 staklen = stakend + incr - oldbsy;
591
592 if (staklen < sizeof (Stackblkhdr)) /* paranoia */
593 staklen = sizeof (Stackblkhdr);
594
595 TPRS("__growstak growing ");
596 TPRN((long)oldbsy);
597 TPRS(" from ");
598 TPRN(stakend - oldbsy);
599 TPRS(" bytes; ");
600
601 #if !defined(HAVE_REALLOC_NULL) || defined(pdp11)
602 if (incr < 0) {
603 /*
604 * V7 realloc wastes the memory given back when
605 * asked to shrink a block, so we malloc new space
606 * and copy into it in the hope of later reusing the old
607 * space, then free the old space.
608 */
609 unsigned char *new = xmalloc((unsigned)staklen);
610
611 if (new == (unsigned char *)NIL)
612 error(nostack);
613 if (staklen >= 16) {
614 memcpy(new, oldbsy, staklen);
615 } else {
616 register int amt = staklen;
617 register unsigned char *to = new;
618 register unsigned char *fr = oldbsy;
619
620 while (amt--)
621 *to++ = *fr++;
622 }
623 free(oldbsy);
624 oldbsy = new;
625 } else
626 #endif
627 /*
628 * get realloc to grow the stack to match the stack top
629 */
630 if ((oldbsy = realloc(oldbsy, (unsigned)staklen)) ==
631 (unsigned char *)NIL) {
632 error(nostack);
633 }
634
635 #ifdef STAK_DEBUG
636 TPRS("now @ ");
637 TPRN((long)oldbsy);
638 TPRS(" of ");
639 TPRN(staklen);
640 TPRS(" bytes (");
641 if (incr < 0) {
642 /* EMPTY */
643 TPRN(-incr);
644 TPRS(" smaller");
645 } else {
646 /* EMPTY */
647 TPRN(incr);
648 TPRS(" bigger");
649 }
650 TPRS(")\n");
651 #endif
652
653 stakend = oldbsy + staklen; /* see? points at the last byte */
654 staktop = oldbsy + topoff;
655 stakbot = oldbsy + botoff;
656 stk.base = oldbsy + basoff;
657
658 stk.topitem = (Stackblk *)oldbsy; /* restore after realloc */
659 return (stk.base); /* addr of 1st usable byte */
660 }
661
662 /*
663 * Grow stak so "newtop" becomes part of the valid stak.
664 * Return new corrected address for "newtop".
665 */
666 unsigned char *
growstak(newtop)667 growstak(newtop)
668 unsigned char *newtop;
669 {
670 UIntptr_t incr;
671 UIntptr_t newoff = newtop - stakbot;
672
673 incr = (UIntptr_t)round(newtop - brkend + 1, BYTESPERWORD);
674 if (brkincr > incr)
675 incr = brkincr; /* Grow at least by brkincr */
676 __growstak(incr);
677
678 return (stakbot + newoff); /* New value for newtop */
679 }
680
681 /* ARGSUSED reqd */
682 void
addblok(reqd)683 addblok(reqd) /* called from main at start only */
684 unsigned reqd;
685 {
686 USED(reqd);
687 if (stakbot == 0) {
688 grostalloc(); /* allocate initial arena */
689 stklow = (char *)stk.topitem;
690 }
691 }
692
693 /*
694 * Heap allocation.
695 */
696 void *
alloc(size)697 alloc(size)
698 size_t size;
699 {
700 Heapblk *p = xmalloc(sizeof (Heapblkhdr) + size);
701
702 if (p == (Heapblk *)NIL)
703 error(nospace);
704
705 p->h.magic = HPMAGICNUM;
706
707 TPRS("alloc allocated ");
708 TPRN(size);
709 TPRS(" user bytes @ ");
710 TPRN((long)p->userdata);
711 TPRS("\n");
712 return (p->userdata);
713 }
714
715 /*
716 * the shell's private "free" - frees only heap storage.
717 * only works on non-null pointers to heap storage
718 * (below the data break and stamped with HPMAGICNUM).
719 * so it is "okay" for the shell to attempt to free data on its
720 * (real) stack, including its command line arguments and environment,
721 * or its fake stak.
722 * this permits a quick'n'dirty style of programming to "work".
723 */
724 void
shfree(ap)725 shfree(ap)
726 void *ap;
727 {
728 char *p = ap;
729 Heapblk *blk;
730
731 if (p == 0) /* Required by POSIX */
732 return; /* Ignore any NULL pointer */
733
734 if (p < stklow) { /* Below heap addresses */
735 #ifdef FREE_DEBUG
736 prs((unsigned char *)"free(");
737 prln((long)ap);
738 prs((unsigned char *)"): arg is below heap.\n");
739 #endif
740 return;
741 }
742 if (p > stkhigh) { /* Above heap addresses */
743 #ifdef FREE_DEBUG
744 prs((unsigned char *)"free(");
745 prln((long)ap);
746 prs((unsigned char *)"): arg is above heap.\n");
747 #endif
748 return;
749 }
750
751 blk = (Heapblk *)(p - sizeof (Heapblkhdr));
752
753 TPRS("shfree freeing user data @ ");
754 TPRN((long)p);
755 TPRS("\n");
756 /*
757 * ignore attempts to free non-heap storage
758 */
759 if (blk->h.magic == HPMAGICNUM) {
760 blk->h.magic = 0; /* erase magic */
761 free(blk);
762 #ifdef FREE_DEBUG
763 } else if (blk->h.magic == STMAGICNUM ||
764 blk->h.magic == STNMAGICNUM) {
765 prs((unsigned char *)"free(");
766 prln((long)ap);
767 prs((unsigned char *)"): arg is from stak.\n");
768 } else {
769 prs((unsigned char *)"free(");
770 prln((long)ap);
771 prs((unsigned char *)"): arg is unknown type.\n");
772 #endif
773 }
774 }
775
776 void
libc_free(ap)777 libc_free(ap)
778 void *ap;
779 {
780 free(ap);
781 }
782
783 #ifdef DO_SYSALLOC
784 void
chkmem()785 chkmem()
786 {
787 prs_buff((unsigned char *)"stklow: "); /* Do not translate */
788 prull_buff((UIntmax_t)(UIntptr_t)stklow);
789 prs_buff((unsigned char *)" stkhigh: "); /* Do not translate */
790 prull_buff((UIntmax_t)(UIntptr_t)stkhigh);
791 prs_buff((unsigned char *)" total: "); /* Translate this? */
792 prull_buff((UIntmax_t)(stkhigh-stklow));
793 prc_buff(NL);
794 flushb();
795 }
796 #endif
797
798 /* -------------------------------------------------------------------------- */
799 /*
800 * The code below has been taken from the historical stak.c
801 *
802 * Copyright 2008-2016 J. Schilling
803 */
804
805 /*
806 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
807 * Use is subject to license terms.
808 */
809
810 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
811 /* All Rights Reserved */
812
813 /*
814 * Copy the string in "x" to the stack and make it semi-permanent.
815 * The current local stack is assumed to be empty.
816 * Return new address of stak base.
817 */
818 unsigned char *
cpystak(x)819 cpystak(x)
820 unsigned char *x;
821 {
822 return (endstak(movstrstak(x, locstak())));
823 }
824
825 /*
826 * Append the string in "a" to the string pointed to by "b".
827 * "b" must be on the current local stack.
828 * Return the address of the nul character at the end of the new string.
829 *
830 * The stack is kept growable.
831 */
832 unsigned char *
movstrstak(a,b)833 movstrstak(a, b)
834 unsigned char *a;
835 unsigned char *b;
836 {
837 do {
838 if (b >= brkend)
839 b = growstak(b);
840 } while ((*b++ = *a++) != '\0');
841 return (--b);
842 }
843
844 /*
845 * Append the string in "s2" to the string pointed to by "s1".
846 * "s1" must be on the current local stack.
847 * Always copy n bytes from s2 to s1.
848 * Return "old value" of s1,
849 * taking care of that s1 may have been relocated by growstak().
850 *
851 * The stack is kept growable.
852 */
853 unsigned char *
memcpystak(s1,s2,n)854 memcpystak(s1, s2, n)
855 unsigned char *s1;
856 unsigned char *s2;
857 int n;
858 {
859 int amt = n > 0 ? n : 0;
860
861 while (--n >= 0) {
862 if (s1 >= brkend)
863 s1 = growstak(s1);
864 *s1++ = *s2++;
865 }
866 return (s1 - amt);
867 }
868