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