File: op_bindparm.c

package info (click to toggle)
fis-gtm 6.3-014-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 36,680 kB
  • sloc: ansic: 333,039; asm: 5,180; csh: 4,956; sh: 1,924; awk: 291; makefile: 66; sed: 13
file content (155 lines) | stat: -rw-r--r-- 6,068 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/****************************************************************
 *								*
 * Copyright (c) 2001-2018 Fidelity National Information	*
 * Services, Inc. and/or its subsidiaries. All rights reserved.	*
 *								*
 *	This source code contains the intellectual property	*
 *	of its copyright holder(s), and is made available	*
 *	under a license.  If you do not know the terms of	*
 *	the license, please stop and do not read further.	*
 *								*
 ****************************************************************/

#include "mdef.h"

#include <stdarg.h>
#include "gtm_stdio.h"
#include "gtm_string.h"

#include "gtmio.h"
#include "lv_val.h"
#include <rtnhdr.h>
#include "mv_stent.h"
#include "stack_frame.h"
#include "op.h"
#include "gdsroot.h"
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsbt.h"
#include "gdsfhead.h"
#include "alias.h"
#include "compiler.h"
#include "parm_pool.h"

GBLREF mv_stent			*mv_chain;
GBLREF unsigned char		*stackbase, *stacktop, *msp, *stackwarn;
GBLREF symval			*curr_symval;
GBLREF stack_frame		*frame_pointer;

error_def(ERR_ACTLSTTOOLONG);
error_def(ERR_STACKCRIT);
error_def(ERR_STACKOFLOW);

void op_bindparm(UNIX_ONLY_COMMA(int frmc) int frmp_arg, ...)
{
	va_list		var;
	uint4		mask;
	register lv_val *a;
	var_tabent	*parm_name;
	int		i;
	int		frmp;	/* formal argument pointer */
	VMS_ONLY(int	frmc;)	/* formal argument count */
	int		actc;
	unsigned int	*prev_count_ptr;
	unsigned int	prev_count;
	lv_val		**actp;		/* actual pointer */
	lv_val		*new_var;
	mvs_ntab_struct	*ntab;
	ht_ent_mname	*tabent, **htepp;
	parm_slot	*curr_slot;
	DBGRFCT_ONLY(mident_fixed vname;)
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	frmp = frmp_arg;
	VMS_ONLY(va_count(frmc);)
	if (TREF(parm_pool_ptr))
	{
		curr_slot = PARM_CURR_SLOT;
		prev_count_ptr = &((*(curr_slot - 1)).mask_and_cnt.actualcnt);
		prev_count = *prev_count_ptr;
		/* If we were dealing with a new job, then push_parm would not have been called if the number of
		 * actuals was 0; so, by checking for proper frame value stored in the parameter pool we ensure
		 * that we are not looking at some uninitialized value here. Note that although we protect against
		 * fall-throughs into labels with a formallist now, in case two consecutive invocations to
		 * op_bindparm happen without a push_parm in between, do not attempt to use a previously utilized
		 * parameter set.
		 */
		if ((0 == (TREF(parm_pool_ptr))->start_idx) || (SAFE_TO_OVWRT <= prev_count)
				|| (DBG_ASSERT(2 <= (TREF(parm_pool_ptr))->start_idx)
					(PARM_ACT_FRAME(curr_slot, prev_count) != frame_pointer)))
			actc = 0;
		else
		{	/* Acquire mask, actual count, and pointer to actual list from the parameter pool. */
			assert(1 <= (TREF(parm_pool_ptr))->start_idx);
			mask = (*(curr_slot - 1)).mask_and_cnt.mask;
			actc = prev_count;
			actp = &((*(curr_slot - SLOTS_NEEDED_FOR_SET(actc))).actuallist);
		}
	} else
		/* If the parameter pool is uninitialized, there are no parameters we can bind. */
		return;
	assert(0 <= frmc);
	/* This would also guarantee that actc > 0. */
	if (actc > frmc)
	{
		if (prev_count_ptr != &((TREF(parm_pool_ptr))->start_idx))
			*prev_count_ptr += SAFE_TO_OVWRT;
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ACTLSTTOOLONG);
	}
	VAR_START(var, frmp_arg);
	for (i = 0; i < frmc; i++, frmp = va_arg(var, int4), actp++)
	{
		if (i >= actc)
		{	/* "Extra" formallist parm, not part of actual list - Needs a PVAL (implicit NEW) as doesn't have one yet */
			PUSH_MV_STENT(MVST_PVAL);
			new_var = mv_chain->mv_st_cont.mvs_pval.mvs_val = lv_getslot(curr_symval);
			LVVAL_INIT(new_var, curr_symval);
			ntab = &mv_chain->mv_st_cont.mvs_pval.mvs_ptab;
			ntab->hte_addr = NULL;		/* In case table gets expanded before we set it below */
		} else if (!(mask & 1 << i))
		{	/* Actual list parm - already has PVAL built by push_parm() */
			ntab = &((mvs_pval_struct *)*actp)->mvs_ptab;
			new_var = ((mvs_pval_struct *)*actp)->mvs_val;
		} else
		{	/* Actual list parm - dotted pass-by-reference parm */
			PUSH_MV_STENT(MVST_NTAB);
			ntab = &mv_chain->mv_st_cont.mvs_ntab;
			ntab->hte_addr = NULL;		/* In case table gets expanded before we set it below */
			new_var = *actp;
			/* This sort of parameter is considered an alias */
			assert(0 < new_var->stats.trefcnt);
			INCR_TREFCNT(new_var);
		}
		htepp = (ht_ent_mname **)&frame_pointer->l_symtab[frmp];	/* address of l_symtab entry */
		parm_name = &(((var_tabent *)frame_pointer->vartab_ptr)[frmp]);
		assert(0 <= frmp && frmp < frame_pointer->vartab_len);
		if (add_hashtab_mname_symval(&curr_symval->h_symtab, parm_name, NULL, &tabent))
			lv_newname(tabent, curr_symval);
		assert(tabent->value);
		DEBUG_ONLY(ntab->nam_addr = parm_name);				/* address of var_tabent */
		ntab->hte_addr = tabent;					/* save hash table entry addr */
		ntab->save_value = (lv_val *)tabent->value;			/* address of original lv_val */
		DBGRFCT_ONLY(
			memcpy(vname.c, tabent->key.var_name.addr, tabent->key.var_name.len);
			vname.c[tabent->key.var_name.len] = '\0';
		);
		DBGRFCT((stderr, "op_bindparm: Resetting var '%s' with hte 0x"lvaddr" from 0x"lvaddr" to 0x"lvaddr"\n",
			 &vname.c, tabent, tabent->value, new_var));
		tabent->value = (char *)new_var;
		*htepp = tabent;
	}
	va_end(var);
	/* Incrementing the actual count in parameter pool by a special value, so that we know that it is safe to
	 * overwrite the current params and there is no need to save them; if an error occurred earlier or actc
	 * is 0, then this addition has already been taken care of above.
	 *
	 * When curr_slot == TREF(parm_pool_ptr)->parms, we risk setting prev_count_ptr equal
	 *  to TREF(parm_pool_ptr)->start_idx; if we add SAFE_TO_OVWRT to this value, we could access
	 *  uninit'd memory in push_parm. We check at each exit if this pointer is equal to
	 *  TREF(parm_pool_ptr)->start_idx as a way of preventing that from happening. This happens below
	 *  and in the error case above
	 */
	if ((0 == prev_count || actc) && prev_count_ptr != &((TREF(parm_pool_ptr))->start_idx))
		*prev_count_ptr += SAFE_TO_OVWRT;
}