cancel
Showing results for 
Search instead for 
Did you mean: 

DECC LIBRTL

 
Robert Badar
Valued Contributor

DECC LIBRTL

In CXX program, I am calling system service
SYS$GETRMI and after this, program crashed on open function call.
Program is created with 64bit pointers
and $GETRMI requires 32bit pointers in args.
Pointers mismatch probably.

Here is output:
%SYSTEM-F-ACCVIO, access violation, reason mask=04, virtual address=00000000000A
4000, PC=FFFFFFFF8083D9E0, PS=0000001B
%TRACE-F-TRACEBACK, symbolic stack dump follows
image module routine line rel PC abs PC
LIBRTL 0 000000000000D9E0 FFFFFFFF8083D9E0
DECC$SHR_EV56 0 000000000005EBA4 FFFFFFFF80AF6BA4
DECC$SHR_EV56 0 00000000000291A4 FFFFFFFF80AC11A4
DECC$SHR_EV56 0 0000000000131D54 FFFFFFFF80BC9D54
DECC$SHR_EV56 0 0000000000133674 FFFFFFFF80BCB674
DECC$SHR_EV56 0 000000000000BD48 FFFFFFFF80AA3D48
DECC$SHR_EV56 0 000000000002258C FFFFFFFF80ABA58C
SPI_agent GI_CPU_SNAPUSAGE SaveAsBMP
3019 0000000000000B64 0000000000032324
SPI_agent SPI_AGENT main 24407 0000000000001228 0000000000031228
SPI_agent SPI_AGENT __MAIN 0 0000000000000070 0000000000030070
SPI_agent 0 0000000000041FCC 0000000000041FCC
0 FFFFFFFF8037BCE4 FFFFFFFF8037BCE4
%TRACE-I-END, end of TRACE stack dump
8 REPLIES 8
Kris Clippeleyr
Honored Contributor

Re: DECC LIBRTL


Robert,

The 'reason mask' in the signal:
%SYSTEM-F-ACCVIO, access violation, reason mask=04, virtual address=00000000000A
indicates a read/modify operation on address 00000000000A (10 decimal).
This is definitely not a valid address.
Is the item list for $GETRMI properly built?
(i.e. all data fields & return length variables are accessible). Any chance of a local variable getting corrupted?

Kris (aka Qkcl)
I'm gonna hit the highway like a battering ram on a silver-black phantom bike...
Robert Badar
Valued Contributor

Re: DECC LIBRTL


Thak you Kris,

The item list for $GETRMI is properly built, I mean. $GETRMI works fine alone and open()
works alone too, but when I call open() somewhere in program after $GETRMI return, it crashes.
ACCVIO occur inside of RTL, but why ?

Here is an output from analyzer:

$ anal /proc SPI_agent.DMP/image=SPI_agent.exe

OpenVMS Alpha Debug64 Version V8.3-009


%DEBUG-I-NOGLOBALS, some or all global symbols not accessible
%SYSTEM-F-ACCVIO, access violation, reason mask=04, virtual address=00000000000A
4000, PC=FFFFFFFF8083D9E0, PS=0000001B
break on unhandled exception at SHARE$LIBRTL_CODE0+55776
%DEBUG-I-SOURCESCOPE, source lines not available for %PC in scope number 0
Displaying source for 7\%PC
Willem Grooters
Honored Contributor

Re: DECC LIBRTL

Properly initialized???
It wouldn't be the first time that a variable is used and filled in one call and after that, used in another activity witout alteration - casuing havoc :). If applicaible: check overlay and slack-bytes (due to alighnment).

Also be sure that the expectation on what you received from the $GETRMI call is correct. If this requires 32-bit pointers, using a 64 bit pointer may cause problems.

Can you create a small reproducer and publish it with building instuctions, it would be of help.

WG
Willem Grooters
OpenVMS Developer & System Manager
Robert Badar
Valued Contributor

Re: DECC LIBRTL

Partial code of:

#pragma required_pointer_size 32

typedef struct
{
word buffer_length;
word item_code;
void *buffer;
word *return_buffer_length;
} ITEM_LIST;

int buffer_size = sizeof(LWORD) + ActiveCPU_cnt * sizeof(CPU_Modes_buffer);
unsigned char *buffer = (unsigned char *)_malloc32(buffer_size);
struct _iosb iosb;
unsigned __int64 error_code;

ITEM_LIST _RMI$_item_list[] = { { buffer_size, RMI$_MODES, buffer, NULL },
{ 0, 0}};

/* system service */
error_code = SYS$GETRMI(EFN$C_ENF, // event flag number
0, 0, // reserved to HP
(_void_ptr32)_RMI$_item_list, // item list
&iosb, // I/O status block
NULL, // AST function address
0 ); // AST parameter

if(error_code == SS$_NORMAL)
error_code = SYS$SYNCH(EFN$C_ENF,&iosb);
#pragma required_pointer_size 64


Robert Badar
Valued Contributor

Re: DECC LIBRTL

Building instruct.:

$ CXX /POINTER_SIZE=64 SPI_agent.cpp
$ CXXLINK SPI_agent
Hoff
Honored Contributor

Re: DECC LIBRTL

A rule of thumb I tend to follow: don't point at the RTLs until you have far more proof. (I learned lesson the hard way. RTLs see way more use than the code calling them.)

In all but a vanishingly small number of cases, the calling code contains one or more bugs. Sure, the RTLs can and do sometimes have bugs, but Occam points to the caller's code.

Probably a heap or stack corruption, but that's very far from certain.

I'd probably build the 32-bit code into one or more module(s) separate from the 64-bit code, but that's me. Add in fenceposts, some instrumentation, and related debugging.

Please post a full-source reproducer, or at least the full source of your $getrmi. CPU_Modes_buffer, _iosb and a bunch of stuff is missing here.

Here's Jim Duff's C example:
http://www.eight-cubed.com/examples/framework.php?file=sys_getrmi.c

And FWIW, the dollar sign in _RMI$_item_list... That's a reserved character; don't use dollars in any object that you own or that is unique to your code, unless you've registered the prefix with HP.

And FWIW, SS$_NORMAL is only one of many of the potential successful status codes that can be returned. Take a look at $VMS_STATUS_SUCCESS() macro or test the low bit, as I expect you want to issue the $synch for any successful status return.

Seeing in-line malloc calls tends to concern me. I've noticed that applications having these calls scattered around tend to also have run-time stability issues. I'd suggest that you centralize and instrument these calls. This class of bug can be difficult to locate and quite transient, too.

I've had a half-dozen complex applications over the years that had weird transient errors and irreproducible crashes; failures that I could never replicate nor successfully instrument. So I switched tactics. In all the cases, I found that ripping out the existing memory management and replacing it with centralized and instrumented handling resolved the bugs. Since then, I've found that the centralized memory handling has also exposed latent bugs in these and other applications.

Stephen Hoffman
HoffmanLabs LLC
John Gillings
Honored Contributor

Re: DECC LIBRTL

Robert,

Your code looks OK to me. I wouldn't expect $GETRMI to go beyond the stated buffer size, and your buffer certainly isn't smaller than what you've stated.

However, I've learnt not to trust what the code appears to do when dealing with item lists and other system structures. I'd recommend running your program under DEBUG and STEP/INTO the $GETRMI call (obviously you can't step through the system service, BUT you can get into the dispatch vector, so you're at least in the call frame of the service and can examine the actual arguments). Examine your item list in HEX to make sure you can see all the fields in the correct places. So

DBG> STEP/INTO
DBG> EXAMINE/HEX/LONG @R19 ! 4th arg
DBG> EXAMINE/HEX/LONG
...

This will help detect any alignment issues, typos and other oddities. Note that examining the structure symbolically from DEBUG will hide automatic alignment of fields.

If you want to find out which LIBRTL routine is being called, and what it was passed, use FAKE_RTL to build a fake LIBRTL.
A crucible of informative mistakes
Robert Badar
Valued Contributor

Re: DECC LIBRTL

To all,

many thanks for Your interest at first,
I provide some source for testing

HW = ALPHA
OS = OpenVMS 8.3
CXX = 7.3-009

$ CXX /POINTER_SIZE=64 test2.cxx
$ CXXLINK test2
$ ru test2

here is

/* to uncomment one of this - program will run correctly */
// #define MODE_$GETRMI_ONLY
// #define MODE_OPEN_ONLY

/* pure 64-bit application */
#if defined(__VMS) && (defined(__ALPHA) || defined(__ia64))
/* test for compilation option /POINTER_SIZE=64 */
#if !defined(__INITIAL_POINTER_SIZE) || __INITIAL_POINTER_SIZE != 64
#pragma message ("Module require compilation option /POINTER_SIZE=64")
#error __INITIAL_POINTER_SIZE
#endif
#pragma required_pointer_size 64
#endif

/* software identifier */
char SoftwareID[] = "SPI TEST";

typedef unsigned char byte;
typedef unsigned short int word;
typedef unsigned long int lword;
typedef unsigned long int LWORD;
typedef unsigned long int longword;
typedef unsigned __int64 quadword;
typedef unsigned __int64 QWORD;

// --------------------------------------------------------------------------------------

/* NULL pointer value */
#ifndef NULL
#ifdef __cplusplus
#define NULL 0L
#else /* __cplusplus */
#define NULL ((void *)0L)
#endif /* __cplusplus */
#endif /* NULL */

// --------------------------------------------------------------------------------------

#pragma required_pointer_size save
#pragma required_pointer_size 32

typedef void *_void_ptr32;

#pragma required_pointer_size restore

/* header files */
#define __NEW_STARLET 1

#include
#include
#include
#include
#include
#include

#include
#include
#include
#include
#include

#pragma member_alignment save
#pragma nomember_alignment

// --------------------------------------------------------------------------------------
//
// *********************
// * IO_STATUS_BLOCK *
// *********************
//
// I/O status block

typedef struct
{
word status;
word counter;
longword info;

} IO_STATUS_BLOCK;

// --------------------------------------------------------------------------------------
//
// ***************
// * ITEM_LIST *
// ***************
//
// 32-bit item list

#pragma required_pointer_size save
#pragma required_pointer_size 32

typedef struct
{
word buffer_length;
word item_code;
void *buffer;
word *return_length_address;

} ITEM_LIST;

#pragma required_pointer_size restore

// --------------------------------------------------------------------------------------
//
// ******************
// * ITEM_LIST_64 *
// ******************
//
// 64-bit item list

typedef struct
{
word MBO;
word item_code;
longword MBMO;
quadword buffer_length;
void *buffer_address;
word *return_length_address;

} ITEM_LIST_64;

// --------------------------------------------------------------------------------------
//
// *******************
// * RMI_CPU_MODES *
// *******************
//
// Resource monitor information data for individual CPU

typedef struct RMI_CPU_Modes
{
byte ID; // physical CPU ID
longword interrupt; // actually sum of interrupt and idle modes !
longword MP_synchro; // multi-processor synchronization
longword kernel; // kernel mode
longword executive; // executive mode
longword supervisor; // supervisor mode
longword user; // user mode
longword reserved; // reserved, will be zero
longword idle; // CPU idle

} RMI_CPU_MODES;

// --------------------------------------------------------------------------------------

#pragma member_alignment restore

/* macro definitions */
#define IL64_MBO 1
#define IL64_MMBO -1

#define COLLECT_INTERVAL "WAIT 00:00:03"


//#define TIME_STOTCK(t) (quadword)(t * 10000000) // seconds conversion to 100ns ticks

/* global variables */
//_TIMER *CollectTimer = NULL; // collection timer

/* function and routine prototypes */
//void CollectTimerASTR (...); // AST routine for collection timer






// --------------------------------------------------------------------------------------

/* error codes */
enum
{
NOERROR,
ERROR_GETSYIW,
ERROR_GETRMIW

};

// --------------------------------------------------------------------------------------

/* 64-bit error code macro */
#define ERRQWORD(f,s) ((unsigned __int64) f << sizeof(unsigned __int32) * 8) | \
(unsigned __int32) s

// --------------------------------------------------------------------------------------

static const char *_f_name_output = "CPU_Usage.bmp";

// --------------------------------------------------------------------------------------
//
// *****************
// * GetCPU_Info *
// *****************
//
// Informations about CPUs in boot instance

quadword GetCPU_Info(longword *_active_cnt,
longword *_potential_cnt = NULL,
longword *_available_cnt = NULL)
{
ITEM_LIST_64 _SYI$_item_list[4];
IO_STATUS_BLOCK iosb;
quadword error_code;
int i = 0;

/* item list initialization */
_SYI$_item_list[i].MBO = IL64_MBO;
_SYI$_item_list[i].item_code = SYI$_ACTIVECPU_CNT;
_SYI$_item_list[i].MBMO = (lword)IL64_MMBO;
_SYI$_item_list[i].buffer_length = sizeof(*_active_cnt);
_SYI$_item_list[i].buffer_address = _active_cnt;
_SYI$_item_list[i].return_length_address = NULL;
i++;

if(_potential_cnt)
{
_SYI$_item_list[i].MBO = _SYI$_item_list[0].MBO;
_SYI$_item_list[i].item_code = SYI$_POTENTIALCPU_CNT;
_SYI$_item_list[i].MBMO = _SYI$_item_list[0].MBMO;
_SYI$_item_list[i].buffer_length = sizeof(*_potential_cnt);
_SYI$_item_list[i].buffer_address = _potential_cnt;
_SYI$_item_list[i].return_length_address = _SYI$_item_list[0].
return_length_address;
i++;
}

if(_available_cnt)
{
_SYI$_item_list[i].MBO = _SYI$_item_list[0].MBO;
_SYI$_item_list[i].item_code = SYI$_AVAILCPU_CNT;
_SYI$_item_list[i].MBMO = _SYI$_item_list[0].MBMO;
_SYI$_item_list[i].buffer_length = sizeof(*_available_cnt);
_SYI$_item_list[i].buffer_address = _available_cnt;
_SYI$_item_list[i].return_length_address = _SYI$_item_list[0].
return_length_address;
i++;
}

/* item list terminator (only first 8 bytes must be zero) */
_SYI$_item_list[i].MBO = 0;
_SYI$_item_list[i].item_code = 0;
_SYI$_item_list[i].MBMO = 0;
_SYI$_item_list[i].buffer_length = 0;

/* system service */
error_code = SYS$GETSYIW(EFN$C_ENF,
NULL,
NULL,
_SYI$_item_list,
(struct _iosb *)&iosb,
NULL,
0 );

/* error testing */
if(error_code != SS$_NORMAL)
error_code = ERRQWORD(ERROR_GETSYIW,(longword)error_code);
else
if(iosb.status == SS$_NORMAL)
error_code = ERRQWORD(ERROR_GETSYIW,(longword)iosb.status);
else
error_code = 0;

/* return */
return(error_code);
}

// --------------------------------------------------------------------------------------
//
// *******************
// * GetCPU_Modes *
// *******************
//
// Informations about active CPUs load

quadword GetCPU_Modes(_void_ptr32 buffer, int buffer_size)
{
#pragma required_pointer_size save
#pragma required_pointer_size 32

IO_STATUS_BLOCK iosb;
quadword error_code;
ITEM_LIST _RMI$_item_list[] = { { buffer_size, RMI$_MODES, buffer, NULL },
{ 0, 0 } };


/* system service */
error_code = SYS$GETRMI(EFN$C_ENF,
0, 0,
(void *)_RMI$_item_list,
(struct _iosb *)&iosb,
NULL,
0 );

#pragma required_pointer_size restore

if(error_code == SS$_NORMAL)
error_code = SYS$SYNCH(EFN$C_ENF, (struct _iosb *)&iosb);

if(error_code != SS$_NORMAL)
error_code = ERRQWORD(ERROR_GETRMIW,(longword)error_code);
else
if(iosb.status == SS$_NORMAL)
error_code = ERRQWORD(ERROR_GETRMIW,(longword)iosb.status);
else
error_code = 0;

/* return */
return(error_code);
}

// --------------------------------------------------------------------------------------
//
// ***************
// * SaveAsBMP *
// ***************
//
// Member method of some class for bitmap creation

void SaveAsBMP(void)
{
int _h_file;
int file_flags = O_WRONLY | O_CREAT;
int file_mode = 0x0777;

// error after open() call
// %SYSTEM-F-ACCVIO, access violation, reason mask=04, virtual address=000000000009
// 4000, PC=FFFFFFFF8083D9F0, PS=0000001B
// %TRACE-F-TRACEBACK, symbolic stack dump follows
// image module routine line rel PC abs PC
// LIBRTL 0 000000000000D9F0 FFFFFFFF8083D9F0
// DECC$SHR_EV56 0 000000000005EBA4 FFFFFFFF80AF6BA4
// DECC$SHR_EV56 0 00000000000291A4 FFFFFFFF80AC11A4
// DECC$SHR_EV56 0 0000000000131D54 FFFFFFFF80BC9D54
// DECC$SHR_EV56 0 0000000000133674 FFFFFFFF80BCB674
// DECC$SHR_EV56 0 000000000000BD48 FFFFFFFF80AA3D48
// DECC$SHR_EV56 0 000000000002258C FFFFFFFF80ABA58C
// test2 TEST2 SaveAsBMP 24175 00000000000003B4 00000000000303B4
// test2 TEST2 main 24288 0000000000000EC4 0000000000030EC4
// test2 TEST2 __MAIN 0 0000000000000070 0000000000030070
// test2 0 000000000003B2CC 000000000003B2CC
// 0 FFFFFFFF8037BCE4 FFFFFFFF8037BCE4

_h_file = open(_f_name_output, file_flags, file_mode, "ctx=bin", "ctx=stm");

// ...
// to do something
// ...

close(_h_file);
}

// --------------------------------------------------------------------------------------
//
// **********
// * main *
// **********
//
// Main function

main(int argc, char *argv[])
{
longword PotentialCPU_cnt = 0;
longword ActiveCPU_cnt = 0;
quadword *CPU_load = NULL;
quadword *CPU_total_ticks = NULL;
byte *CPU_Modes_buffer = NULL;
RMI_CPU_MODES *CPU_ModesEntry;
int buffer_size;
word *_snap_vector = NULL;
int vector_size;
quadword load;
quadword total_ticks;
int i, j;

/* fake data */
#ifdef MODE_OPEN_ONLY
word _CPU_vector[] = { 5094,
6500, 8200, 7700, 6800, 5200, 4800, 4700, 3300,
3100, 3000, 2800, 6700, 5500, 4500, 4400, 4300 };
int CPU_vector_size = 17;
#endif


/* get informations about CPUs */
GetCPU_Info(&ActiveCPU_cnt, &PotentialCPU_cnt);

printf("\n ActiveCPU_cnt = %d", ActiveCPU_cnt );
printf("\nPotentialCPU_cnt = %d", PotentialCPU_cnt);
printf("\n");

/* buffer allocation in required size, system service accepts only 32 bit pointer */
buffer_size = sizeof(LWORD) + ActiveCPU_cnt * sizeof(CPU_Modes_buffer);
CPU_Modes_buffer = (byte *)_malloc32(buffer_size);
CPU_ModesEntry = (RMI_CPU_MODES *)(CPU_Modes_buffer + sizeof(LWORD));

CPU_load = new QWORD[ActiveCPU_cnt];
CPU_total_ticks = new QWORD[ActiveCPU_cnt];

vector_size = PotentialCPU_cnt + 1;
_snap_vector = new word[vector_size];
for(i = 0; i < vector_size; i++) _snap_vector[i] = 0;


/* collection init */
#ifndef MODE_OPEN_ONLY
GetCPU_Modes((_void_ptr32)CPU_Modes_buffer, buffer_size);
#endif

for( i = 0; i < (int)ActiveCPU_cnt; i++ )
{
/* sumarize */
CPU_total_ticks[i] = CPU_ModesEntry[i].interrupt +
CPU_ModesEntry[i].MP_synchro +
CPU_ModesEntry[i].kernel +
CPU_ModesEntry[i].executive +
CPU_ModesEntry[i].supervisor +
CPU_ModesEntry[i].user +
CPU_ModesEntry[i].reserved;
// CPU_ModesEntry[i].idle;

CPU_load[i] = CPU_total_ticks[i] - CPU_ModesEntry[i].idle;
}

/* collection */
for(j = 0; j < 10; j++)
{
/* wait */
system(COLLECT_INTERVAL);
#ifndef MODE_OPEN_ONLY
GetCPU_Modes((_void_ptr32)CPU_Modes_buffer, buffer_size);
#endif

_snap_vector[0] = 0;

for ( i = 0; i < (int)ActiveCPU_cnt; i++ )
{
#ifdef MODE_OPEN_ONLY
_snap_vector[i + 1] = _CPU_vector[j % CPU_vector_size];
#else
/* sumarize */
total_ticks = CPU_ModesEntry[i].interrupt +
CPU_ModesEntry[i].MP_synchro +
CPU_ModesEntry[i].kernel +
CPU_ModesEntry[i].executive +
CPU_ModesEntry[i].supervisor +
CPU_ModesEntry[i].user +
CPU_ModesEntry[i].reserved;
// CPU_ModesEntry[i].idle;

load = total_ticks - CPU_ModesEntry[i].idle;

/* current percentage load of CPU */
_snap_vector[i + 1] = (load - CPU_load[i]) * 10000 /
(total_ticks - CPU_total_ticks[i]);
_snap_vector[0] += _snap_vector[i + 1];

/* save data for next loop */
CPU_load[i] = load;
CPU_total_ticks[i] = total_ticks;
#endif

printf("\t %5d", _snap_vector[i + 1]);
}

_snap_vector[0] /= ActiveCPU_cnt;
printf("\n");

//
// ...
//

/* save created bitmap grah to BMP file */
#ifndef MODE_$GETRMI_ONLY
SaveAsBMP();
#endif
}

/* destruction of allocated memory */
if(CPU_Modes_buffer) delete(CPU_Modes_buffer);
if(CPU_load ) delete(CPU_load );
if(CPU_total_ticks ) delete(CPU_total_ticks );
if(_snap_vector ) delete(_snap_vector );
}