MIDRANGE dot COM Mailing List Archive



Home » RPG400-L » December 2006

Re: stat() function and sub-proc issue



fixed


Hi Tim,

Your question is more appropriate for the RPG400-L mailing list, so I'm
replying there.  I'm CCing you directly, in case you're not subscribed to
RPG400-L


I am trying to use the stat() function and getting a RNQ1211 message on my
printer file. The code is:

The stat() API has nothing to do with your printer file. However, any time you call a program or procedure improperly with mismatched parameters (no matter what the procedure does!) you can corrupt memory. Corrupting memory has unpredicable results -- and can cause strange things like the RNQ1211 error you describe, if the corrupted memory happens to be part of the internal work variables that the compiler generates when it generates your program.

Let's look at your code for the stat() API:

D stat            PR            10I 0 ExtProc('stat')
D path                            *   value options(*string)
D buf                             *   value

D p_statds        S               *
D statds          DS                   BASED(p_statds)
D st_mode                       10U 0
D MyStat          S                    like(statds)
[SNIP]
    stat(rootdir + '/00618':%addr(mystat));

The stat() API requires two parameters. The first is a null-terminated string, and it looks like you're passing that one very nicely.

The second parameter is a data structure that has to be 128 bytes long. The API will always set all 128 bytes of this data structure. It doesn't know how long the variable you've passed is (it can't see your source code!) so it always fills in all 128 bytes.

Your MyStat data structure, however, is only 4 bytes long! So the API will overwrite 124 extra bytes of memory that don't belong to the data structure.

Think about it... all you're passing to the API is the ADDRESS of the data structure. If, for example, the DS happens to have an address of 1000, then your MyStat data structure occupies memory from 1000 - 1003, since it's 4 bytes long.

If the API thinks it's 128 long, it'll overwrite locations 1000-1127! So whatever happens to occupy positions 1004-1127 of memory will get changed to a different value by the API -- even if they have nothing to do with the MyStat data structure.

What's stored in those positions? Who knows. It might happen to be unused memory. It might happen to be other variables in your program. It might even be variables in a different program, all of which would get changed by the stat() API.

In this case, I'm guessing that the internal variable that the RPG runtime uses to keep track of whether a file is open happens to be one of the variables in that area of memory. Just your luck :)

Anyway, the fix is to make MyStat be 128 bytes long, as it's supposed to be. Then the API will overwrite those 128 bytes, and nothing else, and all will be well.

Here's my definition of the stat() API and statds:

     D stat            PR            10I 0 ExtProc('stat')
     D   path                          *   value options(*string)
     D   buf                               likeds(statds)


     D statds          DS                  qualified
     D                                     BASED(Template)
     D  st_mode                      10U 0
     D  st_ino                       10U 0
     D  st_nlink                      5U 0
     D  st_reserved2                  5U 0
     D  st_uid                       10U 0
     D  st_gid                       10U 0
     D  st_size                      10I 0
     D  st_atime                     10I 0
     D  st_mtime                     10I 0
     D  st_ctime                     10I 0
     D  st_dev                       10U 0
     D  st_blksize                   10U 0
     D  st_allocsize                 10U 0
     D  st_objtype                   11A
     D  st_reserved3                  1A
     D  st_codepage                   5U 0
     D  st_ccsid                      5U 0
     D  st_rdev                      10U 0
     D  st_nlink32                   10U 0
     D  st_rdev64                    20U 0
     D  st_dev64                     20U 0
     D  st_reserved1                 36A
     D  st_ino_gen_id                10U 0


As you can see, I used likeds() instead of a pointer for the data structure in my definition. This'll help protect you against making the same mistake in the future.

I also used to use a pointer for the 2nd parameter, but I changed to this method about 2 years ago, because it just works better. With these definitions, you'll call the API with the following code:


     D mystat          ds                  likeds(statds)
          .
          .
         stat(rootdir + '/00618':mystat);

Note that %addr() is no longer necessary with the way I prototyped it.

Hope that helps





Return to Archive home page | Return to MIDRANGE.COM home page

This mailing list archive is Copyright 1997-2014 by MIDRANGE dot COM and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available here. If you have questions about this, please contact