• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nasa / trick / 21535377179

31 Jan 2026 12:27AM UTC coverage: 55.623% (+0.02%) from 55.607%
21535377179

Pull #2033

github

web-flow
Merge a80bb9572 into d49130d35
Pull Request #2033: Updated to always record data at time 0 and also updated the print message accordingly for hexfloat checkpoint.

6 of 7 new or added lines in 3 files covered. (85.71%)

162 existing lines in 4 files now uncovered.

12523 of 22514 relevant lines covered (55.62%)

305082.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

68.63
/trick_source/sim_services/CheckPointAgent/ClassicCheckPointerAgent.cpp
1
#include "trick/MemoryManager.hh"
2
#include "trick/parameter_types.h"
3
#include "trick/io_alloc.h"
4
#include "trick/wcs_ext.h"
5
#include "trick/bitfield_proto.h"
6
#include "trick/message_proto.h"
7
#include "trick/message_type.h"
8

9
#include "trick/ClassicCheckPointAgent.hh"
10
#include "trick/ChkPtParseContext.hh"
11

12
#include <string>
13
#include <iostream>
14
#include <iomanip>
15
#include <sstream>
16
#include <stdlib.h>
17
#include <math.h>
18
#include <string.h>
19

20
const int Trick::ClassicCheckPointAgent::array_elements_per_line[TRICK_NUMBER_OF_TYPES] = {
21
     5, /** TRICK_VOID (for pointers) */
22
    20, /** TRICK_CHARACTER */
23
    20, /** TRICK_UNSIGNED_CHARACTER */
24
     1, /** TRICK_STRING */
25
    10, /** TRICK_SHORT */
26
    10, /** TRICK_UNSIGNED_SHORT */
27
     5, /** TRICK_INTEGER */
28
     5, /** TRICK_UNSIGNED_INTEGER */
29
     5, /** TRICK_LONG */
30
     5, /** TRICK_UNSIGNED_LONG */
31
     5, /** TRICK_FLOAT */
32
     5, /** TRICK_DOUBLE */
33
     5, /** TRICK_BITFIELD */
34
     5, /** TRICK_UNSIGNED_BITFIELD */
35
     5, /** TRICK_LONG_LONG */
36
     5, /** TRICK_UNSIGNED_LONG_LONG */
37
     5, /** TRICK_FILE_PTR */
38
    10, /** TRICK_BOOLEAN */
39
    10, /** TRICK_WCHAR */
40
     1, /** TRICK_WSTRING */
41
     5, /** TRICK_VOID_PTR */
42
    10, /** TRICK_ENUMERATED */
43
     5, /** TRICK_STRUCTURED (for pointers) */
44
     5, /** TRICK_OPAQUE_TYPE */
45
     1  /** TRICK_STL */
46
};
47

48
// MEMBER FUNCTION
49
Trick::ClassicCheckPointAgent::ClassicCheckPointAgent( Trick::MemoryManager *MM) {
629✔
50

51
   mem_mgr = MM;
629✔
52
   reduced_checkpoint = 1;
629✔
53
   hexfloat_checkpoint = 0;
629✔
54
   debug_level = 0;
629✔
55
}
629✔
56

57
// MEMBER FUNCTION
58
Trick::ClassicCheckPointAgent::~ClassicCheckPointAgent() { }
1,256✔
59

60
// MEMBER FUNCTION
61
bool Trick::ClassicCheckPointAgent::input_perm_check(ATTRIBUTES * attr) {
124,347✔
62
    return (attr->io & TRICK_CHKPNT_INPUT) ;
124,347✔
63
}
64

65
bool Trick::ClassicCheckPointAgent::output_perm_check(ATTRIBUTES * attr) {
171,516✔
66
    return (attr->io & TRICK_CHKPNT_OUTPUT) ;
171,516✔
67
}
68

69
// MEMBER FUNCTION
70
std::string Trick::ClassicCheckPointAgent::left_side_name() {
58,764✔
71

72
    std::string name ;
117,528✔
73
    int ii;
74
    int n_elements = leftside_stack.size();
58,764✔
75

76
    for (ii = 0; ii < n_elements ; ii++) {
227,719✔
77

78
        VarNameElement & element = leftside_stack[ii];
168,955✔
79

80
        switch( element.type) {
168,955✔
81

82
            case BASE_NAME: {
58,764✔
83
                name = element.name;
58,764✔
84
            } break;
58,764✔
85

86
            case ELEM_NAME: {
63,189✔
87
                name += '.' + element.name;
63,189✔
88
            } break;
63,189✔
89

90
            case ARRAY_INDEX: {
47,002✔
91
                std::stringstream index_string;
94,004✔
92
                index_string << element.index;
47,002✔
93
                name += '[';
47,002✔
94
                name += index_string.str();
47,002✔
95
                name += ']';
47,002✔
96
            } break;
47,002✔
97

98
            default: {
×
99
                message_publish(MSG_ERROR, "Checkpoint Agent ERROR: Left side name-stack appears to be corrupted.\n") ;
×
100
            }
101
        }
102
    }
103
    return( name);
117,528✔
104
}
105

106
// MEMBER FUNCTION
107
void Trick::ClassicCheckPointAgent::write_decl(std::ostream& chkpnt_os, ALLOC_INFO *info) {
2,696✔
108

109
    const char *type_spec;
110

111
    // Safety check for NULL info pointer or NULL name
112
    if (info == NULL || info->name == NULL) {
2,696✔
113
        return;
116✔
114
    }
115

116
    type_spec = trickTypeCharString(info->type, info->user_type_name);
2,580✔
117

118
    if (info->stcl == TRICK_EXTERN) {
2,580✔
UNCOV
119
        chkpnt_os << "// extern ";
×
120
    }
121

122
    if ( info->num_index == 0 ) {
2,580✔
123

124
        chkpnt_os << type_spec << " " << info->name << ";\n";
94✔
125

126
    } else if ((info->num_index > 0) && (info->num_index <= TRICK_MAX_INDEX)) {
2,486✔
127
        int ii;
128

129
        chkpnt_os << type_spec;
2,486✔
130

131
        ii = info->num_index-1;
2,486✔
132
        while ((ii >= 0) && (info->index[ii] == 0)) {
2,595✔
133
            chkpnt_os << "*";
109✔
134
            ii --;
109✔
135
        }
136

137
        chkpnt_os << " " << info->name ;
2,486✔
138

139
        ii = 0;
2,486✔
140
        while ((ii < info->num_index) && (info->index[ii] != 0)) {
4,971✔
141
            chkpnt_os << "[" << info->index[ii] << "]" ;
2,485✔
142
            ii ++;
2,485✔
143
        }
144
          chkpnt_os << ";" << std::endl;
2,486✔
145

146
    } else {
147
        // ERROR - num_index cant be negative.
148
    }
149
}
150

151

152
// STATIC FUNCTION
153
/* 
154
   Given an offset, that is within the bounds of a composite
155
   object (i.e., a struct or class instance), return the corresponding 
156
   ATTRIBUTES pointer (singular).
157

158
   Helper function for getCompositeSubReference.
159
.
160
*/
161

162
static ATTRIBUTES* findMember(ATTRIBUTES* A, long referenceOffset) {
714✔
163
    int i = 0;
714✔
164
    int j;
165
    int temp_size;
166
    /* Find the member which contains the address pointed to by rAddr */
167
    while ((A[i].name[0] != '\0')) {
5,080✔
168

169
        // if mod bit 0 is set, A[i] is a reference. Width of reference is stored
170
        // in mod bits 3-8. We could use sizeof(void*), but that is implementation
171
        // specific and not required by C++ standard.
172
        if ((A[i].mods & 1) == 1) {
4,523✔
173
          temp_size = ((A[i].mods >> 3) & 0x3F);
5✔
174
          // Calculate the size (temp_size) of the referenced member variable.
175
        } else if (A[i].num_index != 0) {
4,518✔
176
            // if size of last valid index is 0, then we are looking at a pointer
177
            if (A[i].index[A[i].num_index - 1].size == 0) {
407✔
178
                temp_size = sizeof(void*);
344✔
179
            } else {
180
                temp_size = A[i].size;
63✔
181
            }
182
            for (j = 0; j < A[i].num_index; j++) {
471✔
183
                if (A[i].index[j].size != 0) {
408✔
184
                    temp_size *= A[i].index[j].size;
64✔
185
                } else {
186
                    break;
344✔
187
                }
188
            }
189
        } else {
190
            temp_size = A[i].size;
4,111✔
191
        }
192

193
        // if the reference is not to this member variable, move on to the next member variable.
194
        if ( ( referenceOffset <  (long) ( A[i].offset)   ) ||
4,523✔
195
             ( referenceOffset >= (long) ( A[i].offset + temp_size))
1,007✔
196
           ) {
197
            i++;
4,366✔
198
        } else {
199
            break;
200
        }
201
    }
202

203
    return &(A[i]);
714✔
204
}
205

206
// STATIC FUNCTION
207
/*
208
   Given an address, that is within the bounds of a composite
209
   object (i.e., a struct or class instance), store the corresponding sub-name
210
   in reference_name buffer and return.
211

212
   A return value of 1 indicates an error occured. A return value of 0 indicates
213
   success.
214

215
   The following BNF production describes a valid sub-reference:
216

217
   <sub_reference> --> ""
218
                     | "+" + <offset>
219
                     | "[" + <index>+ "]" + <sub_reference>
220
                     | "." + <member_name> + <sub_reference>
221

222
   <offset> is an integer. It is the the reference offset minus the offset of
223
   the last data member.
224
   <index> is an integer. It is an array index.
225
   <member_name> is a name of a member of the given composite type.
226
*/
227

228
static int getCompositeSubReference(
714✔
229
    void*        reference_address, /* Address we are looking for */
230
    ATTRIBUTES** left_type,         /* Attributes of type we are looking for */
231
    void*        structure_address, /* Address of struct we are in */
232
    ATTRIBUTES*  A,                 /* Attributes of current struct we are in */
233
    char* reference_name            /* destination buffer of composite subreference */
234
    ) {
235

236
    int   j, m;
237
    long  offset;
238
    int   my_index[9];
239
    int   ret;
240
    int   size, last_size;
241

242
    char* rAddr = (char*)reference_address;
714✔
243
    char* sAddr = (char*)structure_address;
714✔
244

245
    long referenceOffset = (long)rAddr - (long)sAddr;
714✔
246

247
    // selected ATTRIBUTES stucture from A (singular)
248
    ATTRIBUTES* Ai;
249

250

251
    if ( referenceOffset < 0) {
714✔
UNCOV
252
        message_publish(MSG_ERROR, "Checkpoint Agent ERROR: Address to find is less than struct address.\n") ;
×
UNCOV
253
        return 1;
×
254
    }
255

256
    // Find the structure member that corresponds to the reference address.
257
    // If name is empty, we have failed. 
258
    Ai = findMember(A, referenceOffset);
714✔
259

260
/******If failed to find member, set reference_name to offset only and return ****/
261
    if (Ai->name[0] == '\0') {
714✔
262
        /* If we fail to find a member corresponding to the reference address,
263
           it must mean that the ATTRIBUTES don't contain a description for
264
           that particular member, i.e., it was **'ed out. In this case, we can only
265
           represent the reference_address as a byte offset into the structure.
266
         */
267
        if (referenceOffset == 0) {
557✔
268
            reference_name[0] = '\0' ;
547✔
269
        } else if (referenceOffset > 0) {
10✔
270
            snprintf(reference_name, (size_t)256, " + %ld" , referenceOffset);
10✔
271
        } else {
UNCOV
272
            return 1; // ERROR
×
273
        }
274
        return 0;
557✔
275
    }
276

277
/******************************************************************************/
278
    
279
/* We found a member corresponding to the reference address, so print it's name. */
280
    snprintf(reference_name, (size_t)256, ".%s", Ai->name);
157✔
281

282
/* If the referenced member variable is an intrinsic type */
283
    if (Ai->type != TRICK_STRUCTURED) {
157✔
284

285
/* If the reference address is non-array or a pointer, return reference_name as is */
286
        if((Ai->num_index == 0) || (Ai->index[0].size == 0)) {
14✔
287
            return 0;
14✔
288
        }
289

290
/* else, rAddr is pointing to an array, determine its dimensions and determine 
291
   the element pointed to by rAddr. Then print the index and return */
292

293
        offset = (long) rAddr - ((long) sAddr + Ai->offset);
×
294
        size = last_size = Ai->size;
×
295

296
        /* Calculate the number of fixed dimensions. */
UNCOV
297
        int num_fixed_dims = 0;
×
UNCOV
298
        for (j = 0; j < Ai->num_index; j++) {
×
UNCOV
299
            if (Ai->index[j].size > 0) {
×
300
                num_fixed_dims++;
×
301
            }
302
        }
303

304
        // Calculate the array indices for the right-side.
UNCOV
305
        for (j = num_fixed_dims - 1; j >= 0; j--) {
×
306
            size *= Ai->index[j].size;
×
307
            if(!size) {
×
308
              std::cerr << "Checkpoint Agent " << __FUNCTION__ << " ERROR: divide by zero during array indices calculation" << std::endl;
×
UNCOV
309
              return 1;
×
310
            }
311
            my_index[j] = (int) ((offset % size) / last_size);
×
312
            offset -= last_size * my_index[j];
×
313
            last_size = size;
×
314
        }
315

316
        for (j = 0; j < num_fixed_dims; j++) {
×
UNCOV
317
            size_t len = strlen(reference_name);
×
UNCOV
318
            size_t rem = (size_t)256 - len;
×
UNCOV
319
            snprintf(&reference_name[len], rem, "[%d]", my_index[j]);
×
320
        }
UNCOV
321
    return 0;
×
322
    }
323
/******** TRICK_STRUCTURED ****************************************************/
324
    /* if it is a reference, do nothing and return */
325
    if ((Ai->mods & 1) == 1) { // Ai->type == TRICK_STRUCTURED
143✔
326
        return 0;
1✔
327
    }
328
/*if member is an unarrayed struct, continue to call getCompositeSubReference.*/
329
    if (Ai->num_index == 0) {
142✔
330
        /* if left_type specifies the current member, stop here */
331
        if ( (left_type != NULL) && (*left_type != NULL) && (Ai->attr == (*left_type)->attr)) {
139✔
UNCOV
332
            return 0;
×
333
        }
334

335
        char buf[256];
336
        ret = getCompositeSubReference( rAddr, left_type, sAddr + Ai->offset, (ATTRIBUTES *) Ai->attr, buf);
139✔
337

338
        if (ret == 0) {
139✔
339
            size_t len = strlen(reference_name);
139✔
340
            size_t rem = (size_t)256 - len;
139✔
341
            snprintf(&reference_name[len], rem, "%s", buf);
139✔
342
        } else {
UNCOV
343
            return 1; // ERROR.
×
344
        }
345
    return 0;
139✔
346
    }
347

348
/***** If the member is not a pointer do nothing and return *******************/
349
    if (Ai->index[0].size == 0) {
3✔
350
        return 0;
2✔
351
    }
352

353
/*********** Member is an arrayed struct **************************************/ 
354

355
    offset = (long) rAddr - ((long) sAddr + Ai->offset);
1✔
356
    size = last_size = Ai->size;
1✔
357

358
    /* Calculate the indices into the array */
359
    for (j = Ai->num_index - 1; j >= 0; j--) {
3✔
360
        if (Ai->index[j].size != 0) {
2✔
361
            size *= Ai->index[j].size;
2✔
362
        }
363
        my_index[j] = (int) ((offset % size) / last_size);
2✔
364
        offset -= last_size * my_index[j];
2✔
365
        last_size = size;
2✔
366
    }
367

368

369
    for (j = 0; j < Ai->num_index; j++) {
3✔
370
        size_t len = strlen(reference_name);
2✔
371
        size_t rem = (size_t)256 - len;
2✔
372
        snprintf(&reference_name[len], rem, "[%d]", my_index[j]);
2✔
373
    }
374

375
    /* if left_type specifies the current member, stop here */
376
    if ( (left_type != NULL) && (*left_type != NULL) && (Ai->attr == (*left_type)->attr)) {
1✔
UNCOV
377
        return 0;
×
378
    } 
379

380
/**** Go find the subreference for the arrayed struct member and append *********/
381

382
    /* get the offset into the array that rAddr points to */
383
    offset = 0;
1✔
384
    for (j = 0; j < Ai->num_index; j++) {
3✔
385
      m = my_index[j];
2✔
386
      for(int k = j + 1; m && (k < Ai->num_index); k++) {
3✔
387
        m *= Ai->index[k].size;
1✔
388
      }
389
      offset += m*Ai->size;
2✔
390
    }
391

392
    {
393
        char buf[256];
394
        ret = getCompositeSubReference( rAddr, left_type, sAddr + Ai->offset + offset, (ATTRIBUTES *) Ai->attr, buf);
1✔
395

396
        if (ret == 0) {
1✔
397
            size_t len = strlen(reference_name);
1✔
398
            size_t rem = (size_t)256 - len;
1✔
399
            snprintf(&reference_name[len], rem, "%s", buf);
1✔
400
        } else {
UNCOV
401
            return 1; // ERROR
×
402
        }
403
    }
404

405
    return 0;
1✔
406
}
407

408

409
// MEMBER FUNCTION
410
// Get the fully qualified varible name of the Allocation, given the address.
411

412
std::string Trick::ClassicCheckPointAgent::get_var_name( void* addr,
574✔
413
                                                         ATTRIBUTES* A,
414
                                                         void* struct_addr,
415
                                                         std::string name,
416
                                                         ATTRIBUTES** left_type) {
417
    char reference_name[256];
418
    int ret;
419
    std::string var_name;
1,148✔
420

421
    var_name = name;
574✔
422
    ret = getCompositeSubReference( addr, left_type, struct_addr, A, reference_name );
574✔
423

424
    if (ret == 0) {
574✔
425
        var_name += reference_name;
574✔
426
    } else {
UNCOV
427
          std::stringstream ss;
×
UNCOV
428
          ss << "Checkpoint Agent ERROR: Unable to create a subreference of variable \"" << name << "\"."
×
UNCOV
429
             << std::endl;
×
UNCOV
430
          message_publish(MSG_ERROR, ss.str().c_str() );
×
431
    }
432
    return (var_name);
1,148✔
433
}
434

435
// MEMBER FUNCTION
436
int Trick::ClassicCheckPointAgent::restore( std::istream* checkpoint_stream) {
23✔
437

438
    ChkPtParseContext* context = new ChkPtParseContext( mem_mgr, checkpoint_stream);
23✔
439
    int status = 0;
23✔
440

441
    if ( CCP_parse( context)) {
23✔
442
        status = 1;
×
443
    } else if ((context->bad_declaration_count > 0) ||
23✔
444
               (context->bad_assignment_count > 0)) {
23✔
445
        std::stringstream ss;
×
UNCOV
446
        ss << "Checkpoint Agent ERROR: " << context->bad_declaration_count << " invalid declaration(s) "
×
UNCOV
447
           << "and " << context->bad_assignment_count << " invalid assignment(s)."
×
UNCOV
448
           << std::endl;
×
449
        message_publish(MSG_ERROR, ss.str().c_str() );
×
450
        status = 1;
×
451
    }
452

453
    if (status) {
23✔
UNCOV
454
        std::stringstream ss;
×
UNCOV
455
        ss << "Checkpoint Agent ERROR: Checkpoint restore failed."
×
UNCOV
456
           << std::endl;
×
UNCOV
457
        message_publish(MSG_INFO, ss.str().c_str() );
×
458
    }
459
    delete context ;
23✔
460
    return (status);
23✔
461
}
462

463
// MEMBER FUNCTION
464
int Trick::ClassicCheckPointAgent::is_nil_valued( void* address,
67,886✔
465
                                                  ATTRIBUTES* attr,
466
                                                  int curr_dim,
467
                                                  int offset
468
                                                ) {
469

470
    char* test_addr;
471
    int remaining_dimensions = attr->num_index - curr_dim;
67,886✔
472

473
    /** @par Detailed Description: */
474

475
    /** @par
476
        If we're referencing a singleton then calculate the test-address
477
        from the (base) address, the offset and the data-type. Then
478
        test that calculated address (with the given type) for nil.
479
        If it's nil return 1, otherwise return 0.
480
     */
481
    if (remaining_dimensions ==0) {
67,886✔
482

483
        switch (attr->type) {
63,682✔
484
           case TRICK_CHARACTER :
6,860✔
485
           case TRICK_UNSIGNED_CHARACTER :
486
               test_addr = (char*)address + offset * sizeof(char);
6,860✔
487
               if (*(char*)test_addr == '\0') return(1);
6,860✔
488
               break;
52✔
489
           case TRICK_BOOLEAN:
13,557✔
490
               test_addr = (char*)address + offset * sizeof(bool);
13,557✔
491
               if (*(bool*)test_addr == false) return(1);
13,557✔
492
               break;
2,629✔
UNCOV
493
           case TRICK_WCHAR :
×
UNCOV
494
               test_addr = (char*)address + offset * sizeof(wchar_t);
×
UNCOV
495
               if (*(wchar_t*)test_addr == 0) return(1);
×
UNCOV
496
               break;
×
497
           case TRICK_SHORT :
2,241✔
498
           case TRICK_UNSIGNED_SHORT :
499
               test_addr = (char*)address + offset * sizeof(short);
2,241✔
500
               if (*(short*)test_addr == 0) return(1);
2,241✔
501
               break;
1,885✔
502
           case TRICK_INTEGER :
13,144✔
503
           case TRICK_UNSIGNED_INTEGER :
504
               test_addr = (char*)address + offset * sizeof(int);
13,144✔
505
               if (*(int*)test_addr == 0) return(1);
13,144✔
506
               break;
6,949✔
507
           case TRICK_ENUMERATED :
380✔
508
               if ((size_t)attr->size == sizeof(int)) {
380✔
509
                   test_addr = (char*)address + offset * sizeof(int);
380✔
510
                   if (*(int*)test_addr == 0) return(1);
380✔
UNCOV
511
               } else if ((size_t)attr->size == sizeof(short)) {
×
UNCOV
512
                   test_addr = (char*)address + offset * sizeof(short);
×
UNCOV
513
                   if (*(short*)test_addr == 0) return(1);
×
514
               } else {
UNCOV
515
                   return(-1);
×
516
               }
517
               break;
80✔
518
           case TRICK_LONG :
97✔
519
           case TRICK_UNSIGNED_LONG :
520
               test_addr = (char*)address + offset * sizeof(long);
97✔
521
               if (*(long*)test_addr == 0) return(1);
97✔
522
               break;
48✔
523
           case TRICK_FLOAT :
2✔
524
               test_addr = (char*)address + offset * sizeof(float);
2✔
525
               if (fpclassify( *(float*)test_addr) == FP_ZERO) return(1);
2✔
526
               break;
2✔
527
           case TRICK_DOUBLE :
7,526✔
528
               test_addr = (char*)address + offset * sizeof(double);
7,526✔
529
               if (fpclassify( *(double*)test_addr) == FP_ZERO) return(1);
7,526✔
530
               break;
4,805✔
531
           case TRICK_LONG_LONG :
9,392✔
532
           case TRICK_UNSIGNED_LONG_LONG :
533
               test_addr = (char*)address + offset * sizeof(long long);
9,392✔
534
               if (*(long long*)test_addr == 0) return(1);
9,392✔
535
               break;
863✔
536
           case TRICK_BITFIELD :
×
537
           case TRICK_UNSIGNED_BITFIELD :
538
               test_addr = (char*)address + offset * (size_t)attr->size;
×
539
               if (attr->size == sizeof(int)) {
×
UNCOV
540
                   if (*(int*)test_addr == 0) return(1);
×
541
               } else if (attr->size == sizeof(short)) {
×
UNCOV
542
                   if (*(short*)test_addr == 0) return(1);
×
543
               } else if (attr->size == sizeof(char)) {
×
UNCOV
544
                   if (*(char*)test_addr == 0) return(1);
×
545
               } else {
546
                   message_publish(MSG_ERROR, "Checkpoint Agent INTERNAL ERROR:\n"
×
547
                                              "Unhandled bitfield struct size (%d) in bitfield assignment.\n", attr->size) ;
548
                   return(-1);
×
549
               }
UNCOV
550
               break;
×
UNCOV
551
           case TRICK_FILE_PTR :
×
552
               // FIXME
UNCOV
553
               return(0);
×
554
               break;
555
           case TRICK_STRING :
8,101✔
556
               test_addr = (char*)address + offset * sizeof(void*);
8,101✔
557
               if (*(std::string*)test_addr == "") return(1);
8,101✔
558
               break;
7,598✔
559
           case TRICK_STL :
2,382✔
560
               // Can't test properly, always return 0 to indicate the STL is not empty.
561
               return(0);
2,382✔
562
               break;
UNCOV
563
           default :
×
UNCOV
564
               message_publish(MSG_ERROR, "Checkpoint Agent file %s: Unhandled Type (%d).\n", __FILE__, attr->type) ;
×
UNCOV
565
               return(-1);
×
566
               break;
567
        }
568
        return(0);
24,911✔
569

570
    /** @par
571
        If on the otherhand we are referencing an array, then we must consider two cases.
572
     */
573
    } else if (remaining_dimensions > 0) {
4,204✔
574
       int curr_dim_size;
575
       curr_dim_size = attr->index[curr_dim].size ;
4,204✔
576

577
       /**  @par
578
            If the array is unconstrained (i.e., it's a pointer) then we just need to check
579
            whether the pointer is NULL.
580
        */
581
       if ( curr_dim_size == 0) {
4,204✔
582
           test_addr = ((char*)address) + (offset*sizeof(void *));
1,783✔
583
           if (*(char**)test_addr == NULL) return(1);
1,783✔
584

585
       /** @par
586
           If the array (at this dimension) is constrained (i.e., it's a fixed array )
587
           then it is nil if and only if each of it's sub-elements (at the next dimension,
588
           which can themselves be arrays) are nil. So, for each of the elements in current
589
           dimension, we recursively call is_nil_valued() on each of the sub-elements to
590
           find out whether this array is nil valued and return the result.
591
           */
592
       } else {
593
           int ii;
594
           int zerotest;
595

596
           for (ii=0; ii < curr_dim_size; ii++) {
9,204✔
597
               zerotest = is_nil_valued( address, attr, curr_dim+1, offset*curr_dim_size+ii);
9,122✔
598
               if (!(zerotest == 1)) return(zerotest);
9,122✔
599
           }
600
           return(1);
82✔
601
       }
602

603
    } else {
UNCOV
604
        return(-1);
×
605
    }
606
    return(0);
865✔
607
}
608

609
// STATIC FUNCTION
610
static void write_quoted_str( std::ostream& os, const char* s) {
8,074✔
611
    int ii;
612
    int len = strlen(s);
8,074✔
613
    os << "\"" ;
8,074✔
614
    for (ii=0 ; ii<len ; ii++) {
139,414✔
615
        switch ((s)[ii]) {
131,340✔
616
        case '\n': os << "\\n"; break;
54✔
UNCOV
617
        case '\t': os << "\\t"; break;
×
UNCOV
618
        case '\b': os << "\\b"; break;
×
619
        case '\"': os << "\\\""; break;
44✔
620
        default  : os << s[ii] ; break;
131,242✔
621
        }
622
    }
623
    os << "\"" ;
8,074✔
624
}
8,074✔
625

626
void Trick::ClassicCheckPointAgent::write_singleton( std::ostream& chkpnt_os, void* address, ATTRIBUTES* attr, int offset ) {
26,499✔
627

628
    void* src_addr;
629

630
    switch(attr->type) {
26,499✔
UNCOV
631
        case TRICK_VOID:
×
UNCOV
632
            chkpnt_os << std::endl << "// ERROR - VOID data type cannot be checkpointed." << std::endl;
×
UNCOV
633
            message_publish(MSG_ERROR, "Checkpoint Agent ERROR: VOID data type cannot be checkpointed.\n") ;
×
UNCOV
634
        break;
×
635
        case TRICK_UNSIGNED_CHARACTER:
1✔
636
            src_addr = (char*)address + offset * sizeof(unsigned char);
1✔
637
            chkpnt_os << std::dec << (int)*(unsigned char*)src_addr ;
1✔
638
        break;
1✔
639
        case TRICK_BOOLEAN:
2,630✔
640
            src_addr = (char*)address + offset * sizeof(bool);
2,630✔
641
            if (*(bool*)src_addr) {
2,630✔
642
                chkpnt_os << "true" ;
2,629✔
643
            } else {
644
                chkpnt_os << "false" ;
1✔
645
            }
646
        break;
2,630✔
647
        case TRICK_CHARACTER:
1,057✔
648
            src_addr = (char*)address + offset * sizeof(char);
1,057✔
649
            if (isprint( *(char*)src_addr) ) {
1,057✔
650
                chkpnt_os << "'" << *(char*)src_addr << "'" ;
642✔
651
            } else {
652
                unsigned int ch = *(unsigned char*)src_addr;
415✔
653
                  chkpnt_os << "'\\x" << std::hex << ch << "'" ;
415✔
654
            }
655
        break;
1,057✔
UNCOV
656
        case TRICK_WCHAR: {
×
657
            src_addr = (char*)address + offset * sizeof(wchar_t);
×
UNCOV
658
            char buff[16] = {0};
×
UNCOV
659
            wctomb(buff,*(wchar_t*)src_addr);
×
UNCOV
660
            chkpnt_os << std::dec << buff;
×
661
            }
UNCOV
662
            break;
×
663
        case TRICK_SHORT:
8✔
664
            src_addr = (char*)address + offset * sizeof(short);
8✔
665
            chkpnt_os << std::dec << *(short*)src_addr;
8✔
666
            break;
8✔
667
        case TRICK_UNSIGNED_SHORT:
1,881✔
668
            src_addr = (char*)address + offset * sizeof(unsigned short);
1,881✔
669
            chkpnt_os << std::dec << *(unsigned short*)src_addr;
1,881✔
670
            break;
1,881✔
671
        case TRICK_ENUMERATED: {
84✔
672
                int ii = 0;
84✔
673
                int found = 0;
84✔
674
                int value;
675
                ENUM_ATTR* enum_attr;
676

677
                if ((size_t)attr->size == sizeof(int)) {
84✔
678
                    src_addr = (char*)address + offset * sizeof(int);
84✔
679
                    value =  *(int*)src_addr;
84✔
680
                } else if ((size_t)attr->size == sizeof(short)) {
×
681
                    src_addr = (char*)address + offset * sizeof(short);
×
UNCOV
682
                    value =  *(short*)src_addr;
×
683
                } else {
UNCOV
684
                    std::cerr << __FUNCTION__ << ": enumeration size error." << std::endl;
×
UNCOV
685
                    std::cerr.flush();
×
UNCOV
686
                    value = -1;
×
687
                }
688

689
                enum_attr = (ENUM_ATTR*)attr->attr;
84✔
690

691
                while ( !found && (enum_attr[ii].label[0] != '\0')) {
318✔
692
                   if (value == enum_attr[ii].value) {
234✔
693
                       chkpnt_os << enum_attr[ii].label;
84✔
694
                       found = 1;
84✔
695
                   }
696
                   ii++;
234✔
697
                }
698
                if (!found) {
84✔
UNCOV
699
                    chkpnt_os << std::dec << value;
×
700
                }
701

702
            } break;
84✔
703
        case TRICK_INTEGER:
6,980✔
704
            src_addr = (char*)address + offset * sizeof(int);
6,980✔
705
            chkpnt_os << std::dec << *(int*)src_addr;
6,980✔
706
            break;
6,980✔
707
        case TRICK_UNSIGNED_INTEGER:
306✔
708
            src_addr = (char*)address + offset * sizeof(unsigned int);
306✔
709
            chkpnt_os << std::dec << *(unsigned int*)src_addr;
306✔
710
            break;
306✔
711
        case TRICK_LONG:
39✔
712
            src_addr = (char*)address + offset * sizeof(long);
39✔
713
            chkpnt_os << std::dec << *(long*)src_addr;
39✔
714
            break;
39✔
715
        case TRICK_UNSIGNED_LONG:
14✔
716
            src_addr = (char*)address + offset * sizeof(unsigned long);
14✔
717
            chkpnt_os << std::dec << *(unsigned long*)src_addr;
14✔
718
            break;
14✔
719
        case TRICK_FLOAT:
4✔
720
            src_addr = (char*)address + offset * sizeof(float);
4✔
721
            if (fpclassify( *(float*)src_addr) != FP_NAN) {
4✔
722
                if (hexfloat_checkpoint) {
4✔
UNCOV
723
                    double temp_dbl = *(float*)src_addr;
×
UNCOV
724
                    unsigned char* byte_p = (unsigned char*)&temp_dbl;
×
UNCOV
725
                    chkpnt_os << "0g";
×
UNCOV
726
                    for (int ii=sizeof(double)-1 ; ii>= 0 ; ii--) {
×
UNCOV
727
                        chkpnt_os << std::hex << std::setw(2) << std::setfill('0') << (unsigned int)byte_p[ii];
×
728
                    }
729
                } else {
730
                    chkpnt_os << std::setprecision(8) << *(float*)src_addr;
4✔
731
                }
732
            } else {
UNCOV
733
                chkpnt_os << "NAN";
×
734
            }
735
            break;
4✔
736
        case TRICK_DOUBLE:
4,942✔
737
            src_addr = (char*)address + offset * sizeof(double);
4,942✔
738
            if (fpclassify( *(double*)src_addr) != FP_NAN) {
4,942✔
739
                if (hexfloat_checkpoint) {
4,942✔
740
                    double temp_dbl = *(double*)src_addr;
4✔
741
                    unsigned char* byte_p = (unsigned char*)&temp_dbl;
4✔
742
                    chkpnt_os << "0g";
4✔
743
                    for (int ii=sizeof(double)-1 ; ii>= 0 ; ii--) {
36✔
744
                        chkpnt_os << std::hex << std::setw(2) << std::setfill('0') << (unsigned int)byte_p[ii];
32✔
745
                    }
746
                } else {
747
                    chkpnt_os << std::setprecision(16) << *(double*)src_addr;
4,938✔
748
                }
749
            } else {
750
                chkpnt_os << "NAN";
×
751
            }
752
            break;
4,942✔
753
        case TRICK_BITFIELD: {
×
754
                int sbf = 0;
×
755
                src_addr = (char*)address + offset * (size_t)attr->size;
×
756
                if (attr->size == sizeof(int)) {
×
UNCOV
757
                     sbf = extract_bitfield_any( *(int*)src_addr, attr->size, attr->index[0].start, attr->index[0].size);
×
758
                } else if (attr->size == sizeof(short)) {
×
UNCOV
759
                     sbf = extract_bitfield_any( *(short*)src_addr, attr->size, attr->index[0].start, attr->index[0].size);
×
UNCOV
760
                } else if (attr->size == sizeof(char)) {
×
761
                     sbf = extract_bitfield_any( *(char*)src_addr, attr->size, attr->index[0].start, attr->index[0].size);
×
762
                } else {
763
                     message_publish(MSG_ERROR, "Checkpoint Agent INTERNAL ERROR:\n"
×
764
                                                "Unsupported bitfield size (%d) bytes.\n", attr->size) ;
765
                }
766
                chkpnt_os << std::dec << sbf;
×
767
            } break;
×
768
        case TRICK_UNSIGNED_BITFIELD: {
×
769
                int bf = 0;
×
770
                src_addr = (char*)address + offset * (size_t)attr->size;
×
771
                if (attr->size == sizeof(int)) {
×
UNCOV
772
                     bf = extract_unsigned_bitfield_any( *(unsigned int*)src_addr, attr->size, attr->index[0].start, attr->index[0].size);
×
773
                } else if (attr->size == sizeof(short)) {
×
UNCOV
774
                     bf = extract_unsigned_bitfield_any( *(unsigned short*)src_addr, attr->size, attr->index[0].start, attr->index[0].size);
×
UNCOV
775
                } else if (attr->size == sizeof(char)) {
×
776
                     bf = extract_unsigned_bitfield_any( *(unsigned char*)src_addr, attr->size, attr->index[0].start, attr->index[0].size);
×
777
                } else {
UNCOV
778
                     message_publish(MSG_ERROR, "Checkpoint Agent INTERNAL ERROR:\n"
×
779
                                                "Unsupported bitfield size (%d) bytes.\n", attr->size) ;
780
                }
UNCOV
781
                chkpnt_os << std::dec << bf;
×
UNCOV
782
            } break;
×
783
        case TRICK_LONG_LONG:
850✔
784
            src_addr = (char*)address + offset * sizeof(long long);
850✔
785
            chkpnt_os << std::dec << *(long long*)src_addr;
850✔
786
            break;
850✔
787
        case TRICK_UNSIGNED_LONG_LONG:
17✔
788
            src_addr = (char*)address + offset * sizeof(unsigned long long);
17✔
789
            chkpnt_os << std::dec << *(unsigned long long*)src_addr;
17✔
790
            break;
17✔
UNCOV
791
        case  TRICK_FILE_PTR:
×
UNCOV
792
            src_addr = (char*)address + offset * sizeof(void*);
×
UNCOV
793
            chkpnt_os << *(void**)src_addr;
×
794
            break;
×
795
        case TRICK_STRING:
7,686✔
796
            src_addr = (char*)address + offset * sizeof(std::string);
7,686✔
797
            write_quoted_str(chkpnt_os, (*(std::string*)src_addr).c_str());
7,686✔
798
            break;
7,686✔
799
        case TRICK_OPAQUE_TYPE:
×
800
            chkpnt_os << std::endl << "// ERROR - OPAQUE data type (" << attr->type_name << ") cannot be checkpointed." << std::endl;
×
801
            message_publish(MSG_ERROR, "Checkpoint Agent ERROR: OPAQUE data type (%s) cannot be checkpointed.\n", attr->type_name) ;
×
UNCOV
802
        break;
×
UNCOV
803
        default:
×
UNCOV
804
            chkpnt_os << "0";
×
UNCOV
805
            message_publish(MSG_ERROR, "Checkpoint Agent file %s: Unhandled Type (%d).\n", __FILE__, attr->type) ;
×
UNCOV
806
            break;
×
807
    }
808
}
26,499✔
809

810
// MEMBER FUNCTION
811
// Get the variable-name associated with the given variable-address and data-type.
812
// If no data-type is specified, (i.e., if attr == NULL), then the name will refer
813
// to the (inner-most) primitive data-type associated with the address.
814

815
// attr and curr_dim together specify the expected data-type.
816
// If (attr == NULL) then type checking can't and won't be performed.
817

818
std::string Trick::ClassicCheckPointAgent::
960✔
819
    ref_string_from_ptr( void* pointer, ATTRIBUTES* attr, int curr_dim) {
820

821
    std::string reference_string;
1,920✔
822

823
    if ((attr != NULL) && ((curr_dim >= attr->num_index) || (attr->index[curr_dim].size != 0))) {
960✔
UNCOV
824
        message_publish(MSG_ERROR, "Checkpoint Agent ERROR: ref_string_from_ptr called with a non-pointer type.\n") ;
×
825
    }
826

827
    if (pointer == NULL) {
960✔
UNCOV
828
        reference_string = "NULL";
×
829
    } else {
830
        ALLOC_INFO *alloc_info;
831

832
        /** Find the allocation that contains the pointer-address. */
833
        alloc_info = mem_mgr->get_alloc_info_of( pointer);
960✔
834

835
        if (alloc_info != NULL) {
960✔
836
            // Special handling for character strings: prefer string literal format over allocation reference
837
            // The following info for "char *" is for reference purpose:
838
            // curr_dim = 0
839
            // attr.type = TRICK_CHARACTER (base type)
840
            // attr.num_index = 1 (1D array)
841
            // attr.index[0].size = 0 (not static array)
842
            // attr.size = sizeof(char)
843
            // This prevents anonymous allocations from appearing in subsequent checkpoints
844
            if ((attr != NULL) && (attr->type == TRICK_CHARACTER || attr->type == TRICK_UNSIGNED_CHARACTER) && ((curr_dim + 1) == attr->num_index)) {
925✔
845
                std::stringstream ss;
97✔
846
                write_quoted_str( ss, (const char*)pointer);
97✔
847
                reference_string = ss.str();
97✔
848
            } else {
849
                int alloc_elem_size;
850
                int alloc_elem_index;
851
                int misalignment;
852

853
                alloc_elem_size = alloc_info->size;
828✔
854
                alloc_elem_index = (int) (((long) pointer - (long) alloc_info->start) / alloc_elem_size);
828✔
855
                misalignment = (int) (((long) pointer - (long) alloc_info->start) % alloc_elem_size);
828✔
856

857
                // If type-checking AND the type specifiers match AND  the type we're looking for
858
                // is either not structured or if it is, the attr-list that describes the contents
859
                // of the structure is the same.
860

861
                if ( (attr != NULL) && (attr->type == alloc_info->type) &&
828✔
862
                     ( (attr->type != TRICK_STRUCTURED) || (attr->attr == alloc_info->attr))) {
816✔
863

864
                int ii;
865
                int n_l_ptrs, n_r_ptrs;
866

867
                // Calculate the number of pointers (asterisks) on the left side of the assignment.
868
                n_l_ptrs = attr->num_index - curr_dim;
253✔
869

870
                // Calculate the number of pointers (asterisks) on the right side of the assignment.
871
                n_r_ptrs = 0;
253✔
872
                for (ii=0 ; ii <alloc_info->num_index ; ii++) {
480✔
873
                    if (alloc_info->index[ii] == 0) n_r_ptrs++;
227✔
874
                }
875

876
                if (n_l_ptrs != (n_r_ptrs + 1)) {
253✔
UNCOV
877
                    reference_string = "NULL /*ERROR: # asterisks disagree.*/";
×
878
                } else {
879
                    if (misalignment == 0) {
253✔
880
                        std::stringstream workss;
506✔
881
                        if (alloc_info->name != NULL) {
253✔
882
                            workss << "&" << alloc_info->name;
253✔
883
                            if (alloc_info->num_index != 0) {
253✔
884
                                workss << "[" << alloc_elem_index << "]";
163✔
885
                            }
886
                            reference_string = workss.str();
253✔
887
                        } else {
UNCOV
888
                            std::stringstream ss;
×
UNCOV
889
                            ss << "Checkpoint Agent ERROR: The name of the allocation at " << alloc_info->start << " is NULL."
×
UNCOV
890
                               << "Therefore, Trick::ClassicCheckPointAgent::ref_string_from_ptr() can't generate a textual reference to it."
×
UNCOV
891
                               << std::endl;
×
UNCOV
892
                            message_publish(MSG_ERROR, ss.str().c_str() );
×
UNCOV
893
                            reference_string = "ERROR - Allocation name is NULL";
×
894
                        }
895

896
                    } else {
UNCOV
897
                        message_publish(MSG_ERROR, "Checkpoint Agent ERROR: Badly aligned pointer.\n"
×
898
                                                   "   It is not aligned with the data object\n"
899
                                                   "   (of the same type) into which it is pointing.\n") ;
UNCOV
900
                        reference_string = "ERROR - Badly aligned pointer";
×
901
                    }
902
                }
253✔
903
            } else if (alloc_info->type == TRICK_STRUCTURED) {
575✔
904
                // The type specifications don't match, but the right-side is structured,
905
                // so we apparently the matching type is buried in the right hand side structure.
906

907
                if (alloc_info->name != NULL) {
574✔
908
                    std::string rightside;
1,148✔
909
                    std::stringstream element_name;
1,148✔
910
                    element_name << "&" << alloc_info->name;
574✔
911
                    if (alloc_info->num_index != 0) {
574✔
912
                        element_name << '[' << alloc_elem_index << ']';
54✔
913
                    }
914
                    rightside = get_var_name( pointer,
574✔
915
                                              alloc_info->attr,
916
                                              (char *) alloc_info->start + (alloc_elem_index * alloc_info->size),
574✔
917
                                              element_name.str(),
1,148✔
918
                                              &attr
919
                                            );
574✔
920
                    reference_string = rightside;
574✔
921
                } else {
UNCOV
922
                    std::stringstream ss;
×
UNCOV
923
                    ss << "Checkpoint Agent ERROR: The name of the allocation at " << alloc_info->start << " is NULL."
×
UNCOV
924
                       << "Therefore, Trick::ClassicCheckPointAgent::ref_string_from_ptr() can't generate a textual reference to it."
×
UNCOV
925
                       << std::endl;
×
UNCOV
926
                    message_publish(MSG_ERROR, ss.str().c_str() );
×
UNCOV
927
                    reference_string = "ERROR - Allocation name is NULL";
×
928
                }
929
            } else { // The type specifications don't match, and the right hand side is not structured
930

931
                if (attr != NULL) {
1✔
932
                    const char* left_type_spec  = trickTypeCharString(attr->type, "");
×
933
                    const char* right_type_spec = trickTypeCharString(alloc_info->type, alloc_info->user_type_name);
×
934
                    message_publish(MSG_ERROR, "Checkpoint Agent ERROR: Type mismatch. Type specifications disagree.\n"
×
935
                                               "   The left side type specifier is \"%s\" but the right side is \"%s\".\n",
936
                                    left_type_spec, right_type_spec) ;
937
                    reference_string = "ERROR - Type specifications disagree";
×
938
                } else {
939

940
                    if (misalignment == 0) {
1✔
941
                        std::stringstream workss;
2✔
942

943
                        if (alloc_info->name != NULL) {
1✔
944
                            workss << "&" << alloc_info->name;
1✔
945
                            if (alloc_info->num_index != 0) {
1✔
UNCOV
946
                                workss << "[" << alloc_elem_index << "]";
×
947
                            }
948
                            reference_string = workss.str();
1✔
949
                        } else {
UNCOV
950
                            std::stringstream ss;
×
UNCOV
951
                            ss << "Checkpoint Agent ERROR: The name of the allocation at " << alloc_info->start << " is NULL."
×
UNCOV
952
                               << "Therefore, Trick::ClassicCheckPointAgent::ref_string_from_ptr() can't generate a textual reference to it."
×
UNCOV
953
                               << std::endl;
×
UNCOV
954
                            message_publish(MSG_ERROR, ss.str().c_str() );
×
955
                            reference_string = "ERROR - Allocation name is NULL";
×
956
                        }
957

958
                    } else {
959
                        message_publish(MSG_ERROR, "Checkpoint Agent ERROR: Badly aligned pointer.\n"
×
960
                                                   "   It is not aligned with the data object\n"
961
                                                   "   (of the same type) into which it is pointing.\n") ;
962
                        reference_string = "ERROR - Badly Aligned Pointer";
×
963
                    }
964
                }
965

966
                }
967
            }
968
        } else if ((attr != NULL) && ((curr_dim + 1) == attr->num_index)) {
35✔
969

970
            if (attr->type == TRICK_CHARACTER) {
35✔
971
                std::stringstream ss;
35✔
972
                write_quoted_str( ss, (const char*)pointer);
35✔
973
                reference_string = ss.str();
35✔
UNCOV
974
            } else if (attr->type == TRICK_WCHAR) {
×
UNCOV
975
                message_publish(MSG_ERROR, "Checkpoint Agent ERROR: TRICK_WCHAR not fully supported yet.\n") ;
×
UNCOV
976
                reference_string = "ERROR: TRICK_WCHAR not fully supported yet.";
×
977
            } else {
UNCOV
978
                std::string lname = left_side_name();
×
UNCOV
979
                message_publish(MSG_ERROR, "Checkpoint Agent ERROR: Pointer <%p> in \"%s\" is not in Trick managed memory\n"
×
980
                                           "nor is it a character pointer.\n", pointer, lname.c_str()) ;
UNCOV
981
                reference_string = "ERROR - Pointer not in Trick managed memory";
×
982
            }
35✔
983

984
        } else {
UNCOV
985
            std::string lname = left_side_name();
×
UNCOV
986
            message_publish(MSG_ERROR, "Checkpoint Agent ERROR: Pointer <%p> in \"%s\" is not in Trick managed memory\n"
×
987
                                       "nor is it a character pointer.\n", pointer, lname.c_str()) ;
UNCOV
988
            reference_string = "ERROR - Pointer not in Trick managed memory";
×
989
        }
990
    }
991
    return( reference_string);
1,920✔
992
}
993

994
// MEMBER FUNCTION
995
void Trick::ClassicCheckPointAgent::write_rvalue( std::ostream& chkpnt_os, void* address, ATTRIBUTES* attr, int curr_dim, int offset) {
30,046✔
996

997
    // If the variable that we are pointing to is Un-arrayed
998
    if (curr_dim == attr->num_index) {
30,046✔
999

1000
        write_singleton( chkpnt_os, address, attr, offset);
26,499✔
1001

1002
    // If the variable that we are pointing to is Arrayed
1003
    } else if (curr_dim < attr->num_index) {
3,547✔
1004

1005
        // If the variable is a pointer
1006
        if (attr->index[curr_dim].size == 0) {
3,547✔
1007
            std::string ref_string;
1,902✔
1008

1009
            void* pointer = *(void**)((char*)address + offset * sizeof(void*));
951✔
1010

1011
            ref_string = ref_string_from_ptr( pointer, attr, curr_dim);
951✔
1012

1013
            chkpnt_os << ref_string.c_str() ;
951✔
1014

1015
        } else { // Fixed dimension
1016

1017
            char* src_addr;
1018

1019
            // If this is the final, fixed dimension
1020
            if (((curr_dim + 1) == attr->num_index) ||
2,596✔
1021
                (attr->index[curr_dim + 1].size == 0)) {
47✔
1022

1023
                int use_quoted_string;
1024

1025
                // If ALL but the last of the elements of a character array
1026
                // "isprintable" AND the last is '\0' then print out the array
1027
                // as a quoted string. Otherwise print out each of the characters.
1028

1029
                use_quoted_string = 1;
2,592✔
1030
                if (attr->type == TRICK_CHARACTER) {
2,592✔
1031

1032
                    int array_len = attr->index[curr_dim].size;
301✔
1033
                    int ii = array_len - 1;
301✔
1034
                    src_addr = (char*)address + offset * array_len * sizeof(char);
301✔
1035
                    if (src_addr[ii] != '\0') {
301✔
1036
                        use_quoted_string = 0;
20✔
1037
                    }
1038
                    ii--;
301✔
1039
                    while ( use_quoted_string && (ii >= 0) ) {
1,093✔
1040
                        use_quoted_string = isprint( src_addr[ii]);
792✔
1041
                        ii--;
792✔
1042
                    }
1043
                }
1044

1045

1046
                // This is necessary due to https://github.com/nasa/trick/issues/1399
1047
                // If there is a string array where the memory is not initialized, the code above
1048
                // can incorrectly decide to write it as a quoted string when it should be an
1049
                // empty array, causing a segfault when the checkpoint is reloaded.
1050
                if (attr->index[curr_dim + 1].size == 0 && ((curr_dim + 1) != attr->num_index)) {
2,592✔
1051
                    use_quoted_string = 0;
43✔
1052
                } 
1053

1054

1055
                if ((attr->type == TRICK_CHARACTER) && use_quoted_string)  {
2,592✔
1056

1057
                    write_quoted_str(chkpnt_os, src_addr);
256✔
1058

1059
                } else {
1060

1061
                    int ii, jj;
1062
                    int array_len;
1063

1064
                    // Determine the number of array elements we need to print out
1065
                    // to get all of the non-zero values.
1066

1067
                    array_len = attr->index[curr_dim].size ;
2,336✔
1068

1069
                    chkpnt_os << "\n";
2,336✔
1070

1071
                    for (ii=0 ; ii < curr_dim+1 ; ii++) {
4,677✔
1072
                        chkpnt_os << "    ";
2,341✔
1073
                    }
1074
                    chkpnt_os << "{";
2,336✔
1075

1076
                    for (ii = 0; ii < array_len ; ii++ ) {
6,345✔
1077

1078
                        if (ii > 0) {
4,009✔
1079
                            chkpnt_os << ", ";
1,673✔
1080

1081
                            // Conditionally line-break and indent.
1082
                            if (( (ii+1) % array_elements_per_line[attr->type]) == 0 ) {
1,673✔
1083
                                // Line-break.
1084
                                chkpnt_os << "\n";
195✔
1085
                                // Indent.
1086
                                for (jj=0 ; jj < curr_dim+1 ; jj++) {
390✔
1087
                                    chkpnt_os << "    ";
195✔
1088
                                }
1089
                                chkpnt_os << " ";
195✔
1090
                            }
1091
                        }
1092
                        write_rvalue( chkpnt_os, address, attr, curr_dim + 1, offset * attr->index[curr_dim].size + ii);
4,009✔
1093
                    }
1094
                    chkpnt_os << "}";
2,336✔
1095

1096
                }
2,592✔
1097

1098
            } else { // Not the final fixed dimension.
1099

1100
                int ii;
1101

1102
                chkpnt_os << "\n";
4✔
1103
                for (ii=0 ; ii < curr_dim+1 ; ii++) {
8✔
1104
                    chkpnt_os << "    ";
4✔
1105
                }
1106
                chkpnt_os << "{";
4✔
1107

1108
                for (ii=0 ; ii< attr->index[curr_dim].size ; ii++) {
265✔
1109
                    if (ii > 0) {
261✔
1110
                        chkpnt_os << ",";
257✔
1111
                    }
1112
                    write_rvalue( chkpnt_os, address, attr, curr_dim + 1, offset * attr->index[curr_dim].size + ii);
261✔
1113
                }
1114

1115
                chkpnt_os << "\n";
4✔
1116

1117
                for (ii=0 ; ii < curr_dim+1 ; ii++) {
8✔
1118
                    chkpnt_os << "    " ;
4✔
1119
                }
1120
                chkpnt_os << "}";
4✔
1121
            }
1122
        }
1123

1124
    } else {
UNCOV
1125
        chkpnt_os << "/*ERROR*/";
×
1126

UNCOV
1127
        message_publish(MSG_ERROR, "Checkpoint Agent ERROR: The specified current dimension \"%d\" is greater\n"
×
1128
                                   "than the number of dimensions specified in the type ATTRIBUTES.\n", curr_dim) ;
1129

UNCOV
1130
        return;
×
1131
    }
1132
}
1133

1134
// MEMBER FUNCTION
1135
// Create an assignment statement.
1136
void Trick::ClassicCheckPointAgent::assign_rvalue(std::ostream& chkpnt_os, void* address, ATTRIBUTES* attr, int curr_dim, int offset) {
58,764✔
1137

1138
    std::string lname = left_side_name();
58,764✔
1139

1140
    if (!output_perm_check(attr)) {
58,764✔
UNCOV
1141
        if (debug_level) {
×
UNCOV
1142
            message_publish(MSG_DEBUG, "Checkpoint Agent INFO: No assignment generated for \"%s\" "
×
1143
                                       "because its io specification does not allow it.\n", lname.c_str()) ;
1144
        }
UNCOV
1145
        return;
×
1146
    }
1147

1148
    if ((reduced_checkpoint && is_nil_valued( (void*)address, attr, curr_dim, offset ) ) ) {
58,764✔
1149
        if (debug_level) {
30,606✔
UNCOV
1150
            message_publish(MSG_DEBUG, "Checkpoint Agent INFO: No assignment generated for \"%s\" "
×
1151
                                       "because its value is nil and the reduced_checkpoint flag is set.\n", lname.c_str()) ;
1152
        }
1153
        return;
30,606✔
1154
    }
1155

1156
    if (debug_level) {
28,158✔
UNCOV
1157
        message_publish(MSG_DEBUG, "Checkpoint Agent INFO: Generating assignment for [%p] %s.\n",(void*)address, lname.c_str()) ;
×
1158
    }
1159

1160
    if (!input_perm_check(attr)) {
28,158✔
1161
        chkpnt_os << "/* OUTPUT-ONLY: ";
22✔
1162
    }
1163
    if ( attr->type == TRICK_STL ) {
28,158✔
1164
        chkpnt_os << "// STL: " << lname ;
2,382✔
1165
    } else {
1166
        chkpnt_os << lname << " = ";
25,776✔
1167

1168
        write_rvalue( chkpnt_os, (void*)address, attr, curr_dim, offset);
25,776✔
1169
        chkpnt_os << ";";
25,776✔
1170

1171
        // Check if we need to add decimal comments for hexfloat values
1172
        bool should_add_decimal_comment = hexfloat_decimal_comment_checkpoint && hexfloat_checkpoint && (attr->type == TRICK_FLOAT || attr->type == TRICK_DOUBLE);
25,776✔
1173

1174
        // Add decimal comment for hexfloat values
1175
        if (should_add_decimal_comment) {
25,776✔
1176
            // Temporarily disable hexfloat to get decimal representation
1177
            bool saved_hexfloat = hexfloat_checkpoint;
×
UNCOV
1178
            hexfloat_checkpoint = false;
×
1179

1180
            // Capture decimal output to string stream
UNCOV
1181
            std::stringstream decimal_ss;
×
UNCOV
1182
            write_rvalue( decimal_ss, (void*)address, attr, curr_dim, offset);
×
1183

1184
            // Restore hexfloat setting
UNCOV
1185
            hexfloat_checkpoint = saved_hexfloat;
×
1186

1187
            // Add // to each line of the decimal output
UNCOV
1188
            std::string decimal_str = decimal_ss.str();
×
UNCOV
1189
            std::istringstream iss(decimal_str);
×
UNCOV
1190
            std::string line;
×
UNCOV
1191
            bool first_line = true;
×
1192
            
UNCOV
1193
            while (std::getline(iss, line)) {
×
UNCOV
1194
                if (first_line) {
×
UNCOV
1195
                    chkpnt_os << std::endl << "// " << lname << " = " << line;
×
UNCOV
1196
                    first_line = false;
×
1197
                } else {
UNCOV
1198
                    chkpnt_os << std::endl << "//" << line;
×
1199
                }
1200
            }
1201
        }
1202
    }
1203
    if (!input_perm_check(attr)) {
28,158✔
1204
        chkpnt_os << "*/";
22✔
1205
    }
1206
    chkpnt_os << std::endl;
28,158✔
1207
    chkpnt_os.flush();
28,158✔
1208

1209
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc