ibmi-brunch-learn

Announcement

Collapse
No announcement yet.

confusion about data structures passes as parms

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • confusion about data structures passes as parms

    we are working on a program that calls other programs and can't understand why it works correctly.
    (I haven't figured out to post code without destroying the spacing. this is still in fixed format.)


    this code in the calling program defines a data structure with one array:

    D* Data Structure for tags to be created.
    D TAG_ARRAY DS
    D TA_TAGNBR 6 DIM(99)

    this is the call:

    D* Prototypes for Detail Maintenance.
    D LIN40M36 PR EXTPGM('LIN40M36')
    D CONTROL_XFER LIKE(CONTROL_DATA)
    D TAG_XFER LIKE(TAG_ARRAY)
    D H1_XFER LIKE(H1_RECORD)​



    however, the called program LIN40M36 has tag_array defined as two arrays:

    D* Data Structure for tags to be created.
    D TAG_ARRAY DS
    D TA_TAGNBR 6 DIM(99)
    D TA_PRETAG 6 DIM(99)

    D LIN40M36 PR EXTPGM('LIN40M36')
    D CONTROL_XFER LIKE(CONTROL_DATA)
    D TAG_XFER LIKE(TAG_ARRAY)
    D H1_XFER LIKE(H1_RECORD)
    D
    D LIN40M36 PI
    D CONTROL_XFER LIKE(CONTROL_DATA)
    D TAG_XFER LIKE(TAG_ARRAY)
    D H1_XFER LIKE(H1_RECORD)


    if program LIN40m36 is expecting two arrays as that is how tag_array is defined, why does it work correctly when the calling program only sends 1 array?​
    ​​​

  • #2
    Oh boy ... where to begin. Let's start by telling you how to format source since that makes it _way_ easier to see what you are doing. To do this simply highlight the source section and press the # symbol in the tool bar above the edit window. This wraps the code in "code" tags.

    Your problem is not that it works - even if it does "work" now it may not continue to do so. You are lying to the compiler and that is always a bad idea.

    When you pass a parm to a program you are always _only_ passing the address of the first byte. How the data is interpreted is up to the called program. If the second array follows the fist in memory (which it will since it follows it in a DS) then it will "work".

    Couple of thoughts.
    1) A prototype should never be hard coded in a program. It should always be /COPY'd
    2) The same prototype should be /Copy'd into the called program so the compiler can ensure that the proto and the procedure interface match!

    You really need to decide which of the two is "right" and change the code to match.
    Last edited by JonBoy; October 3, 2022, 03:01 PM.

    Comment


    • #3
      It is actually worse than JonBoy writes.

      The called program refers to the memory in the calling program that is used by TAG_ARRAY ( 594 bytes )
      AND the 594 bytes following it via TA_PRETAG!!!
      This means that if you modify the array TA_PRETAG then you are modifying variables that are defined
      AFTER TAG_ARRAY. Then when you returns to the calling program you have a royal mess in the memory.
      Or alternatively the program crashes because it tries to refer to storage that is outside the job.


      The memory can be shown like this

      Memory in calling program
      XXXXXX... 594 bytes ...XXXXXXssssssssddddddfffffggggg ... 594 bytes used by variables ... hhhhhh


      Memory in called program ( referres to same adresses as above )
      XXXXXX... 594 bytes ...XXXXXXYYYYYY... 594 bytes ...YYYYYY

      So if you modify
      YYYYYY... 594 bytes ...YYYYYY
      then you are actually modifying
      ssssssssddddddfffffggggg ... 594 bytes used by variables ... hhhhhh​

      Comment


      • #4
        thanks for the quick confirmation of our suspicions. we are dropping the second array in all the called programs. I guess we were lucky that the code has been running for the past year or so and did not blow up or otherwise fail.

        The /copy of prototype is a good idea, hopefully we can incorporate in new programs. You know how hard it is to find time to enhance old code.

        Comment


        • #5
          The /copy of prototype is a good idea, hopefully we can incorporate in new programs. You know how hard it is to find time to enhance old code.
          But this is NOT an "enhancement" - it is a fix for already broken code.

          As Peder points out, the kind of memory corruption that can occur can be hard to debug. In some cases I have seen a bug of this type basically destroy a couple of a company's master files requiring days of backup restores, re-runs etc. They had no idea the files were being corrupted because the program output appeared correct. It was only during quarterly runs that the problem came to light.

          Comment


          • #6
            I'm sorry, I wasn't clear. we fixed the problem by dropping the second array in the called programs. Now caller and called match parms.


            what I was not planning on doing now is /copy of prototype.

            Comment


            • #7
              Understood - but until you have the /Copy in place you are always in danger of somebody making an incompatible change. The current issue, that you just fixed, didn't happen by magic. Someone screwed up - and apparently got away with it. Next time you might not be so lucky. Better to put the proper defences in place while it is fresh ion your mind.

              Comment


              • #8
                good point I hadn't considered. thanks.

                Comment


                • #9
                  One thing we are doing is to specify a length of the data structure.

                  For example your data structure

                  Code:
                  D TAG_ARRAY DS
                  D TA_TAGNBR 6 DIM(99)​
                  If you define it in your copy source with for example a length of 2000 bytes
                  Code:
                  D TAG_ARRAY DS 2000
                  D TA_TAGNBR 6 DIM(99)

                  then you can add new fields that are returning values without risking corruption of the memory.
                  And as long as they just returns values you don't have to recompile programs that are not using the returned values.

                  If you add a very big field that causes the size of the fields to exceed the size of 2000 bytes then the compiler returns an error.
                  Code:
                  D TAG_ARRAY DS 2000
                  D TA_TAGNBR 6 DIM(99)
                  D BIG_field    1800

                  Comment

                  Working...
                  X