COBOL

COBOL

COBOL

COBOL is responsible for the efficient, reliable, secure, and unseen day-to-day operations of the world's economy.

 View Only
Expand all | Collapse all

NULL value in pointer

Discussion Topic

Discussion TopicThu January 28, 2016 02:41 AM

  • 1.  NULL value in pointer

    Posted Wed January 27, 2016 12:06 PM

    Program A calls program B with 1 parameter. Program B has 3 areas, (p1, p2, p3), defined in it's linkage section. Shouldn't the address of p2 and p3 be NULL when B is called from A, when A calls with only 1 parameter?

    Evalute address of p2 when not null perform p2-handle-second-parm end-evaluate. This is not the case at our site, now using Cobol v5.2.     

    ILPAPA


  • 2.  Re: NULL value in pointer

    Posted Wed January 27, 2016 06:50 PM

    Although I've not used V5.2, I'm going to boldly say No.

    The CALLing program and the CALLed program "pass" no other information than a parameter list. The length of the parameter list understood by the CALLed program is not known to the CALLing program, either at compile-time or run-time.

    If you pass a variable number of parameters to a program, the program must have means to determine from the data which parameters can be used on any given execution of the CALLed program.

    There is a way that you can get "NULL" to appear, which is by using OMITTED in place of each parameter you don't want to pass. You can then use your test. I'd just not recommend the test or taking action on the test for a business program. If you determine some action in your CALLed program by the number of parameters... how do you expect your program to work when it is given the wrong number of parameters in error?

    Either use the data to determine how many parameters there should be. Or use OMITTED, to be able to test, accurately, for NULL.

    In COBOL, getting the order and number of parameters correct in both CALLer and CALLed is down to the programmer.

     

    Second similar-ish question on this topic I've seen today. Was the other one you? :-)

    BillWoodger


  • 3.  Re: NULL value in pointer

    Posted Wed January 27, 2016 07:32 PM

    Another way to look at it. Consult the V5.2 Language Reference. Find Appendix B on Compiler Limits and discover how many identifiers there can be on the PROCEDURE DIVISION USING ... It is 32,767. Each of those represents four bytes of storage. In it's entirety, that would have to be initialised to binary zeros on each CALL for your suggested method to work. OK, sometimes the compiler/optimizer could "know" not to initialise everything, but by no means always. So you'd have a small shed-load of useless storage and useless initialisation just so you could do your check for NULL. And even then you'd only know whether a parameter was present or not, you'd not know (without knowledge from the data, anyway) whether the number of parameters is correct, or whether the parameters are in the correct order.

    Use the data, Luke. Use the data. Rely on the coder. Rely on the testers. If you can't know parameters are in the correct order, knowing how many parameters there are is no help, and nothing to make business decisions on. Expending CPU to get a false sense of security, or a (potentially) false indication of data state is not a good thing to do.

    BillWoodger


  • 4.  Re: NULL value in pointer

    Posted Thu January 28, 2016 02:41 AM

    See my latest post... :-) /Par P

    ILPAPA


  • 5.  Re: NULL value in pointer

    Posted Thu January 28, 2016 01:41 AM

    I apologise for mistyping the title to this issue. It was misleading. (But, my first coding example was correct). What I'm talking about is the ADDRESS OF the parameter, which I say should be null. Not the content.

    If I'm called with only 1 parameter but are prepared for 3, the ADDRESS OF 2nd and 3rd should be NULL. Example below. Is this a matter of configuration or is it a bug? I have consulted the manuals but haven't found anything yet.

    Best reg, Par P

    A.cbl

    Call B using by reference Datum end-call

    B.cbl

     Procedure Division                                          
                             using                               
                                by reference                     
                                             Datum               
                                             Dagnummer           
                                             Veckodag            
                                                     .           
                                                                 
     a00-start                                 section.          
    *-------------------------------------------------------------
    *-Gets: 1 to 3 parms from caller                             
    *.............................................................
    *-Does: Returning less or more depending on # of parameters  
    *.............................................................
    *-Give: 1 parm = YYMMDD                                      
    *-      2 parm = YYMMDD and YYMMDDD                          
    *-      3 parm = YYMMDD, YYMMDDD and day-of-week (ex: Monday)
    *-------------------------------------------------------------
         Perform x00-initiera                                    
    * eyecathing pointers                                        
         Set ptr1                         to address of Datum    
         Set ptr2                         to address of Dagnummer
         Set ptr3                         to address of Veckodag 
                                                                 
         Evaluate address of Datum                               
            when not null                                        
               add +001                   to binTeger            
         end-evaluate                                            
         Evaluate address of Dagnummer                           
            when not null                                        
               add +001                   to binTeger            
         end-evaluate                                            
                                                                 
         Evaluate binTeger                                       
            when +001                                            
               move txtccyymmdd           to Datum               
            when +002                                            
               perform s02-2parm                                 
               move txtccyymmdd           to Datum               
               move numDagnummer          to Dagnummer           
            when +003                                            
               perform s02-2parm                                 
               perform s03-3parm                                 
    ...
     

    ILPAPA


  • 6.  Re: NULL value in pointer

    Posted Thu January 28, 2016 03:38 AM

    Well, I understood your post originally, and everything I wrote here is relevant to your issue.

     

    A couple of other discussions, both from yesterday(!), that may help in understanding:

    http://stackoverflow.com/q/35042906/1927206

    http://ibmmainframes.com/viewtopic.php?p=333501#333501

    Perhaps if I say referencing the ADDRESS OF an item which appears on the USING of the PROCEDURE DIVISION is "undefined behaviour" if the number of items on that USING is greater than the number of the items on the CALL ... USING.

    That is a COBOL thing, although there are probably two-three compilers which have switches which would allow parameter-checking - which would be to guard against what you are attempting to do.

    Include an extra parameter as the first item. That will tell you how many parameters to expect (it indicates the function of the CALL, and the particular function in the code will only use data from the appropriate parameters - I'm using function in an English-language sense).

    BillWoodger


  • 7.  Re: NULL value in pointer

    Posted Thu January 28, 2016 04:07 AM

    Hmm... I know this is working with COBOL v4 and earlier COBOL versions. So for me, this "undefined behaviour" have been around for very many years at various sites. Are you sure about this?

    Unfortunately I have several thousands of old application-programs calling subroutines varying the number of parameters like I have described. Today my assembler code finds the parameterlist through the savearea and looks for the high-order bit, set. I want to replace the assembler code with a cobol program. And, as I have used the "address of if null-tactic" for very many years, at different sites, I'm hoping it to work also with COBOL V5.     

    ILPAPA


  • 8.  Re: NULL value in pointer

    Posted Thu January 28, 2016 04:47 AM

    You are describing undefined behaviour, are you not? "It does this, which is what I want, when I stand on one leg, but when I lift up both legs I just fall over, which is what I don't want".

    Where, in the Language Reference, Programming Guide, Installation or Migration documents, does it define the behaviour of CALL ... USING ... and PROCEDURE DIVISION USING .../ENTRY ... USING ...? Exactly what is described? That is the defined behaviour.

    How the defined behaviour is implemented in one compiler or another can be entirely different.

    If your site, or other places you have worked, have been relying on the undefined behaviour, they should have immediately raised a PMR to attempt to get IBM to formalise that behaviour, so it proceeds into a future compiler release.

    You could PMR IBM now, and argue the case, especially if IBM has used the technique in sample code provided publicly.

    You may get comment here form IBM personnel as well.

    If you'd like to contact me off-line to make a fuller description of the issue, and how many CALLed programs and how many CALLs it affects, I do have an ugly solution you could consider which is better than the Assembler one. In fact, it is a neat solution, it is the issue which is ugly. But no, I'd not expect your management to want to change thousands of programs for this.

    BillWoodger


  • 9.  Re: NULL value in pointer

    Posted Thu January 28, 2016 08:05 AM

    Ha ha... you are probably right! I may contact you... a bit later. 

    ILPAPA


  • 10.  Re: NULL value in pointer

    Posted Thu January 28, 2016 08:19 AM

    Bill, here is the code/debug-info from my friend at the V4 site.

     

    ------------------------- XPEDITER/TSO - SOURCE --------------------------OPT-

    COMMAND ===>                                                  SCROLL ===> CSR 

    PROGRAM: CBV4       MODULE: CBV4     COMP DATE:  01/27/2016 COMP TIME:20:24:35

    000011 K 01 PTR                             >  00000000                 POINTER

             ** END **                                                            

    ------   ------------------------------------------ Before CBV4:32/AMODE 31 <>

    000017 B  PROCEDURE DIVISION                                                  

    000018              USING                                                      

    000019              BY REFERENCE DATUM                                        

    000020                           DAGNUMMER                                    

    000021                           VECKODAG                                     

    000022                           .                                            

    000023         SET PTR TO ADDRESS OF DATUM                                    

    000024         EVALUATE ADDRESS OF DATUM                                      

    000025            WHEN NOT NULL                                               

    000026               ADD  +001                  TO BINTEGER                   

    000027            WHEN OTHER                                                  

    000028               CONTINUE                                                  

    000029         END-EVALUATE                                                   

    000030                                                                        

    000031         SET PTR TO ADDRESS OF DAGNUMMER                                 

    =====>         EVALUATE ADDRESS OF DAGNUMMER                                  

    000033            WHEN NOT NULL                                               

    000034               ADD  +001                  TO BINTEGER                    

    000035            WHEN OTHER                                                  

    000036               CONTINUE                                                 

    000037         END-EVALUATE                                                  

    ILPAPA


  • 11.  Re: NULL value in pointer

    Posted Thu January 28, 2016 08:24 AM

    Bill, can you provide me with your email address? To send a sample code...

    ILPAPA


  • 12.  Re: NULL value in pointer

    Posted Thu January 28, 2016 06:20 AM

    Perhaps you could show a minimal example which works for you in V4. I have this, which doesn't work how you describe:

           ID DIVISION.
           PROGRAM-ID. STAB01.
                                                                    
           DATA DIVISION.
           01  PARM-1                               PIC X VALUE "A".
           01  PARM-2                               PIC X VALUE "B".
           01  PARM-3                               PIC X VALUE "C".
           PROCEDURE DIVISION.
                                                                    
               CALL "STAB01A"               USING PARM-1
                                                  PARM-2
                                                  PARM-3
               CALL "STAB01B"               USING PARM-1
                                                                    
               GOBACK
               .

    STAB01B has access to PARM-1, expected, PARM-2 expected by me, unexpected by you, and when attempting to access PARM-3 I get a S0C4, Protection Exception. Unexpected.

    OS/VS COBOL behaved differently from this, in that I would have been able to access PARM-3 in STAB01B without an abend for certain.

    I am not aware of any IBM Mainframe COBOL compiler that reliably works the way you describe/expect.

    If you can provide a realiably-working minimal example, I'd be interested, but I'd expect to be able to explain why that works, and why a general example will not, with V4.

    I've not used V5, but I'd certainly not expect it to work the way you expect.

    Your Assembler routine will work reliably. Be aware there is an APAR for OMITTED on CALL in relation to the high-bit being set for the last parameter. If any new code using OMITTED when CALLing your subroutine comes into existence, both your Assembler routine and the check for NULL would work.

    Bear in mind that program-logic depending on identifying the number of parameters is a bad (my opinion) way to do things. A program that should be passing three parameters and erroneously passing only two will dictate that the incorrect logic is used in the CALLed program. Of course, testing should find it, but it's just wasted time.

    BillWoodger


  • 13.  Re: NULL value in pointer

    Posted Fri January 29, 2016 11:34 AM

    Problem Statement

    This is, in a CALLed program, testing the address of a parameter being NULL to know how many parameters were passed on a particular CALL.

    The technique is something that has worked in V4 and does not work in V5. Not only does it work in V4, but the technique has been used in various places over a number of years.

    Initial Answer

    No, you can't do that, the behaviour is undefined

    I provided a sample program of my own, which happily fell over with a S0C4 (and also had access to an address for the second parameter from the previous CALL)

    Investigation

    A minimal sample working program was obtained. It failed when I ran it.

    I usually investigate with NOOPT, so I tried with OPT. The provided sample program worked.

    Compiled mine with OPT. Still refused to work.

    Reviewed working program. It used CALL indentifier, which would be a dynamic CALL. Mine used CALL literal with compiler option DYNAM. The generated code had dissimilarities.

    Changed mine to use CALL identifier, and it ran without a S0C4.

    When does it work?

    There are generally three ways a COBOL program can be CALLed by another COBOL program:

    CALL literal, compile NODYNAM

    CALL literal, compile DYNAM

    CALL identifier, generates code for dynamic CALL not matter the compile option

     

    In V4 you can have the optimizer on (OPT(STD) or OPT(FULL), no difference to the generated code) or off (NOOPT).  That gives six combinations. Of those six combinations, only one, CALL identifier with OPT(STD) (or FULL), works.

    And it doesn't always work. My sample program, when it ceased to fall over, simply gave access to the previous parameters.

    The working example program, which had more code than just CALL statements in my example, didn't work if the second and third CALLs, with two and three parameters, were commented out, leaving just a CALL with one parameter. That gets a S0C4.

    Conclusion

    With V4 the technique "works" with a subset of CALL/OPT combinations, the one used at the site in question.

    It only works in a subset of cases, due to the relationship of optimized code to the issue. It would seem that the larger the program doing the CALL, the more likely the technique in the CALLed program will work. However, I'd not like to have that as the epitaph for a 2am problem.

    Recommendation

    Use a reliable technique to identify the last parameter passed to a COBOL program via CALL. This can be done in Assembler with a short walk back up the search-chain and looking for, from the right, the high-order bit of the address of the parameter.

    I've left that technical. For readers who don't understand that, forget about doing it yourselves.

    To my mind, it is good never to attempt to access data which was not included on the current CALL, and that includes the address of the data, because it may not be the address: it may be invalid (S0C4); or a valid address, but the address of a different piece of data.

     

     

    BillWoodger


  • 14.  Re: NULL value in pointer

    Posted Thu April 21, 2016 04:55 PM

    Agreed Bill.

    It was never intended behavior for the BLL cells to be initially null.

    While under v4.2 and earlier where the BLL cells (for parameters and other linkage section items) were in the TGT and coincidentally set to null during compile unit initialization the first time the compile unit is called, moving to v5 and later, which no longer has a TGT, means the BLL cells may not start out null.

    And certainly as you point out, if you call say, a procedure that expects three parameters with three parameters, and then again with two, the third BLL will still be pointing to the third parameter from the previous call.

    Bernie

    brataj


  • 15.  Re: NULL value in pointer

    Posted Fri April 22, 2016 04:58 AM

    Bernie, it is interesting that you say in V5 and later that BLL cells may not start out as a NULL address of LINKAGE SECTION items other than those named on PROCEDURE DIVISION USING ...

    I would expect there to be code "out there" for those items which has:

        IF address of name-in-linkage-section equal to NULL
             do something...

       END-IF

    I can' see a reference in the Migration Guides to any change of behaviour for that.

    There is no real need for that code, a programmer just needs to ensure that any LINKAGE SECTION item is only referenced when it logically exists. But exposure to other languages may lead to the expectation that it is "good practice" (it is not) and that it "works" (which it won't if V5 onwards don't give an initial NULL address).

    BLL cells relating to items on the PROCEDURE DIVISION USING ... would never need to be initialised, as they get set to a value before any user-written code can get at them.

    The problem with initialisation of parameter addresses when there are a different number of parameters on the CALL ... USING ... than on the PROCEDURE DIVISION USING ... is that even at run-time the CALLer doesn't know how many parameters the CALLed program expects, so can't deliberately "initialise" any deficiency at compile-time. Although the CALLed program knows/could know how many parameters were passed (high-order bit set to 1 on last parameter passed), the compiler, intentionally (and correctly) doesn't make any use of this knowledge.

    On top of that, because it is an internal compiler thing, which programmers shouldn't rely on, there is different behaviour depending on OPT and whether CALL "literal" is used.

    The original code "works", most of the time, given OPT(STD or FULL) and CALL "literal". "most of the time" isn't good enough, and is not a useful behaviour to attempt to replicate in V5 or later.

     

    BillWoodger


  • 16.  Re: NULL value in pointer

    Posted Tue April 26, 2016 06:34 PM

    I've never expected "omitted" parms to give NULL results unless they're explicitly declared as OMITTED, so I haven't had this problem. I haven't written mainframe COBOL for over 30+ years, but the System/38 and AS/400 series COBOL has behaved the same.

    As noted earlier, there can be as many as 32,767 identifiers on each and every PROCEDURE DIVISION USING phrase in every COBOL program or module in the system that receives parameters. And on each and every CALL USING statement, in every COBOL program or module in the system, a similar number of identifiers can be listed. And beyond that, there are other languages that can call or be called by COBOL programs or procedures.

    With that in mind, what code should be expected to set parameter addresses to NULL for parameters that are implicitly "omitted"? The issue isn't restricted to the subset of COBOL objects that might be CALLed with fewer parms. It's a much bigger issue.

    Should it be code that is compiled into every COBOL program (or module) that executes a CALL statement? If so, how many parm addresses should be NULLed? Should it happen for every CALL USING statement? Or should it only happen when COBOL is the target of the CALL?

    Or should it be done by code compiled into the CALLed program/module? If so, similar questions should be answered.

    How should multiple languages handle this? Should the system run-time somehow do the work outside of the application programs/modules? When should it happen? Should it happen for each and every CALL with parms that runs in the entire system?

    In short, I understand the concern about non-NULL "omitted" parms. But I find it hard to accept that there is any good way for the system to handle it. IMO, it's just a fact that "omitted" parms can't be assumed NULL, and programmers should expect that.

    tomliotta