Re: PL/I and C (was Re: Simple (?) C question)
See below ... Am 21.06.2017 um 22:13 schrieb Frank Swarbrick: Interesting! Is this (1 and 2) actually addressed anywhere official that discusses PL/I and C ILC? One would hope so... I imagine that PL/I could simply call the C free() function itself, in any case. in fact, I don't know if this is documented anywhere. I realized it last year only when we had a storage lead in a PL/1 batch job which involved C too, and I observed after some checking, that there was no increase in the LE User Heaps. The culprit turned out to be some PL/1 routines, and their ALLOCs used up the LE Anywhere Heap, so I had to add support for the LE Anywhere and Below Heap to my tools; I thought up until then that they are only used by LE itself, but not by the "user" routines. Wrong ... Don't know if you can call the C free() function directly from C, but there are LE functions doing the storage allocation and free business (I don't recall their names, must be in the LE Vendor interface book), and they should work regardless of the heap type. Maybe even PL/1 FREE doesn't care if the area is User heap or LE Anywhere heap ... the layout of the control blocks is the same ... but I don't know; if PL/1 FREE simply calls the aforementioned LE function, all will be OK. This presentation is very interesting: http://www-03.ibm.com/systems/resources/Stack+and+Heap.pdf I'm not looking to make anything in particular work in PL/I, but rather thinking about how the new "dynamic-length elementary items" supported by the latest COBOL standard (2014) could work when interfacing with C strings (and PL/I variable length strings, for that matter). I thought it would be useful to know what PL/I does in this regard. Frank From: IBM Mainframe Discussion List <IBM-MAIN@LISTSERV.UA.EDU> on behalf of Bernd Oppolzer <bernd.oppol...@t-online.de> Sent: Wednesday, June 21, 2017 2:04 PM To: IBM-MAIN@LISTSERV.UA.EDU Subject: Re: PL/I and C (was Re: Simple (?) C question) Hi Frank, 1.) yes, the C area acquired by malloc must be freed by someone 2.) unfortunately, the PL/1 FREE statement cannot do it, because, as I recently observed while checking some PL/1 modules for storage leaks, PL/1 stores its heap areas (allocated by PL/1 ALLOC / FREE) in the LE ANYWHERE HEAP, but C - with malloc - uses one of the (in theory many) LE USER HEAPs, so PL/1 FREE will not be able to FREE the C malloc areas. At least, that's what I think. You will IMO have to provide a C function that frees the area on behalf of the PL/1 caller (using C free). At least, I believe that's what you should do. 3.) at one of my former customer's site, we decided to write our own storage management, callable from all languages. Of course, it is based on normal GETMAIN / FREEMAIN. If you do this carefully, you will even be able to outperform the LE storage management (to some small percent values). With this solution, you don't have such problems as outlined above. 4.) for my private Stanford Pascal compiler project (the compiler runs on MVS and CMS on Hercules, but even on today's z/OS), I rewrote the LE storage management in Pascal, from some descriptions and presentations available from IBM. This took me some weeks last year, but it works without problems. Look here: http://bernd-oppolzer.de/job9.htm Oppolzer - Informatik / Stanford Pascal Compiler<http://bernd-oppolzer.de/job9.htm> bernd-oppolzer.de Updated version of the Stanford Pascal Compiler designed to run on VM/370 Rel. 6 under the Hercules emulator. It should also run on today's z/VM and some, or all ... 5.) I also wrote some diagnose routines (for LE on z/OS) that check for storage leaks on the fly (while the programs run). Please call me offline, if you want to know more. Kind regards Bernd Am 21.06.2017 um 21:01 schrieb Frank Swarbrick: I know we have some PL/I experts here, and I can't seem to subscribe to the PL/I listserv, so I'll ask here. I am not a PL/I programmer, but I've studied it to some degree. I believe the following is a valid PL/I program that would invoke the C language get_static_string() function (as well as one called get_dynamic_string() that does a malloc() and returns it's result). pli_calling_C: procedure dcl s_strext('get_static_string') entry( entry returns( byvalue pointer ) ) options( byvalue nodescriptor ); dcl d_strext('get_dynamic_string') entry( entry returns( byvalue pointer ) ) options( byvalue nodescriptor ); dcl str1 char(*) varz based(str1ptr), str1ptr pointer; dcl str2 char(*) varz based(str2ptr), str2ptr pointer; str1ptr = s_str(); display(str1); str2ptr = d_str(); display(str2); end; My question is, can/must the PL/I program do free(str2ptr) in order to release the storage for the dynamically allocated string? (And obviously NOT do this for str1ptr.) Side
Re: PL/I and C (was Re: Simple (?) C question)
Interesting! Is this (1 and 2) actually addressed anywhere official that discusses PL/I and C ILC? One would hope so... I imagine that PL/I could simply call the C free() function itself, in any case. I'm not looking to make anything in particular work in PL/I, but rather thinking about how the new "dynamic-length elementary items" supported by the latest COBOL standard (2014) could work when interfacing with C strings (and PL/I variable length strings, for that matter). I thought it would be useful to know what PL/I does in this regard. Frank From: IBM Mainframe Discussion List <IBM-MAIN@LISTSERV.UA.EDU> on behalf of Bernd Oppolzer <bernd.oppol...@t-online.de> Sent: Wednesday, June 21, 2017 2:04 PM To: IBM-MAIN@LISTSERV.UA.EDU Subject: Re: PL/I and C (was Re: Simple (?) C question) Hi Frank, 1.) yes, the C area acquired by malloc must be freed by someone 2.) unfortunately, the PL/1 FREE statement cannot do it, because, as I recently observed while checking some PL/1 modules for storage leaks, PL/1 stores its heap areas (allocated by PL/1 ALLOC / FREE) in the LE ANYWHERE HEAP, but C - with malloc - uses one of the (in theory many) LE USER HEAPs, so PL/1 FREE will not be able to FREE the C malloc areas. At least, that's what I think. You will IMO have to provide a C function that frees the area on behalf of the PL/1 caller (using C free). At least, I believe that's what you should do. 3.) at one of my former customer's site, we decided to write our own storage management, callable from all languages. Of course, it is based on normal GETMAIN / FREEMAIN. If you do this carefully, you will even be able to outperform the LE storage management (to some small percent values). With this solution, you don't have such problems as outlined above. 4.) for my private Stanford Pascal compiler project (the compiler runs on MVS and CMS on Hercules, but even on today's z/OS), I rewrote the LE storage management in Pascal, from some descriptions and presentations available from IBM. This took me some weeks last year, but it works without problems. Look here: http://bernd-oppolzer.de/job9.htm Oppolzer - Informatik / Stanford Pascal Compiler<http://bernd-oppolzer.de/job9.htm> bernd-oppolzer.de Updated version of the Stanford Pascal Compiler designed to run on VM/370 Rel. 6 under the Hercules emulator. It should also run on today's z/VM and some, or all ... 5.) I also wrote some diagnose routines (for LE on z/OS) that check for storage leaks on the fly (while the programs run). Please call me offline, if you want to know more. Kind regards Bernd Am 21.06.2017 um 21:01 schrieb Frank Swarbrick: > I know we have some PL/I experts here, and I can't seem to subscribe to the > PL/I listserv, so I'll ask here. I am not a PL/I programmer, but I've > studied it to some degree. I believe the following is a valid PL/I program > that would invoke the C language get_static_string() function (as well as one > called get_dynamic_string() that does a malloc() and returns it's result). > > pli_calling_C: >procedure > >dcl s_strext('get_static_string') > entry( entry returns( byvalue pointer ) ) > options( byvalue nodescriptor ); >dcl d_strext('get_dynamic_string') > entry( entry returns( byvalue pointer ) ) > options( byvalue nodescriptor ); >dcl str1 char(*) varz based(str1ptr), str1ptr pointer; >dcl str2 char(*) varz based(str2ptr), str2ptr pointer; > >str1ptr = s_str(); >display(str1); >str2ptr = d_str(); >display(str2); > end; > > My question is, can/must the PL/I program do free(str2ptr) in order to > release the storage for the dynamically allocated string? (And obviously NOT > do this for str1ptr.) > > Side request... Could someone post the PL/I "JNI" copybook? > > Thanks, Frank > > ____________ > From: Frank Swarbrick > Sent: Tuesday, June 20, 2017 9:47 AM > To: IBM Mainframe Discussion List > Subject: Re: Simple (?) C question > > > Thanks John. I know of no code that does this, nor do I intend to implement > any. What I was really trying to determine is if a routine could possibly > (rightly or wrongly) return a pointer to a field that was statically > allocated rather than dynamically allocated. Which would mean that the > caller should not, for example, attempt a free() on that pointer. I've been > pondering the COBOL 2014 standard and how it might interact with C in this > regard. > > Thanks to everyone who answered. > > Frank > > > From: IBM Mainframe Discussion List <IBM-MAIN@LISTSERV.UA.EDU> on behalf of > John McKown <john.archie.mck...@gmail.com> > Sent: Monday, June
Re: PL/I and C (was Re: Simple (?) C question)
Hi Frank, 1.) yes, the C area acquired by malloc must be freed by someone 2.) unfortunately, the PL/1 FREE statement cannot do it, because, as I recently observed while checking some PL/1 modules for storage leaks, PL/1 stores its heap areas (allocated by PL/1 ALLOC / FREE) in the LE ANYWHERE HEAP, but C - with malloc - uses one of the (in theory many) LE USER HEAPs, so PL/1 FREE will not be able to FREE the C malloc areas. At least, that's what I think. You will IMO have to provide a C function that frees the area on behalf of the PL/1 caller (using C free). At least, I believe that's what you should do. 3.) at one of my former customer's site, we decided to write our own storage management, callable from all languages. Of course, it is based on normal GETMAIN / FREEMAIN. If you do this carefully, you will even be able to outperform the LE storage management (to some small percent values). With this solution, you don't have such problems as outlined above. 4.) for my private Stanford Pascal compiler project (the compiler runs on MVS and CMS on Hercules, but even on today's z/OS), I rewrote the LE storage management in Pascal, from some descriptions and presentations available from IBM. This took me some weeks last year, but it works without problems. Look here: http://bernd-oppolzer.de/job9.htm 5.) I also wrote some diagnose routines (for LE on z/OS) that check for storage leaks on the fly (while the programs run). Please call me offline, if you want to know more. Kind regards Bernd Am 21.06.2017 um 21:01 schrieb Frank Swarbrick: I know we have some PL/I experts here, and I can't seem to subscribe to the PL/I listserv, so I'll ask here. I am not a PL/I programmer, but I've studied it to some degree. I believe the following is a valid PL/I program that would invoke the C language get_static_string() function (as well as one called get_dynamic_string() that does a malloc() and returns it's result). pli_calling_C: procedure dcl s_strext('get_static_string') entry( entry returns( byvalue pointer ) ) options( byvalue nodescriptor ); dcl d_strext('get_dynamic_string') entry( entry returns( byvalue pointer ) ) options( byvalue nodescriptor ); dcl str1 char(*) varz based(str1ptr), str1ptr pointer; dcl str2 char(*) varz based(str2ptr), str2ptr pointer; str1ptr = s_str(); display(str1); str2ptr = d_str(); display(str2); end; My question is, can/must the PL/I program do free(str2ptr) in order to release the storage for the dynamically allocated string? (And obviously NOT do this for str1ptr.) Side request... Could someone post the PL/I "JNI" copybook? Thanks, Frank From: Frank Swarbrick Sent: Tuesday, June 20, 2017 9:47 AM To: IBM Mainframe Discussion List Subject: Re: Simple (?) C question Thanks John. I know of no code that does this, nor do I intend to implement any. What I was really trying to determine is if a routine could possibly (rightly or wrongly) return a pointer to a field that was statically allocated rather than dynamically allocated. Which would mean that the caller should not, for example, attempt a free() on that pointer. I've been pondering the COBOL 2014 standard and how it might interact with C in this regard. Thanks to everyone who answered. Frank From: IBM Mainframe Discussion List <IBM-MAIN@LISTSERV.UA.EDU> on behalf of John McKown <john.archie.mck...@gmail.com> Sent: Monday, June 19, 2017 7:59 PM To: IBM-MAIN@LISTSERV.UA.EDU Subject: Re: Simple (?) C question On Mon, Jun 19, 2017 at 4:25 PM, Frank Swarbrick < frank.swarbr...@outlook.com> wrote: I know there are at least a few C developers here, so I was wondering if you could answer a question. Is the following valid C? (I'm not asking if one should actually do it; only if its valid at all.) char *get_static_string(void) { static char str[81] = "This is a statically allocated C string"; return str; } printf("%s", get_static_string()); I don't have a C compiler available at work else I'd try it myself. Frank You have gotten some good answers. So I will just interject a bit of, perhaps off center, comment. Your code, as written compiles just fine. But it is basically very dangerous. The reason is that you are returning a pointer which could be used to overwrite storage. This is also known as "a bad thing" and is basically an attack vector by malicious code. I don't know the actual intent of your question. But I would suggest using the #pragma string(readonly) in your example. E.g. compile "get_static_string" in its own compilation unit (i.e. by itself) #pragma strings(readonly) const char *get_static_string() { const static char[] = "This is a statically allocated C string"; // let the compiler figure out the lengt
PL/I and C (was Re: Simple (?) C question)
I know we have some PL/I experts here, and I can't seem to subscribe to the PL/I listserv, so I'll ask here. I am not a PL/I programmer, but I've studied it to some degree. I believe the following is a valid PL/I program that would invoke the C language get_static_string() function (as well as one called get_dynamic_string() that does a malloc() and returns it's result). pli_calling_C: procedure dcl s_strext('get_static_string') entry( entry returns( byvalue pointer ) ) options( byvalue nodescriptor ); dcl d_strext('get_dynamic_string') entry( entry returns( byvalue pointer ) ) options( byvalue nodescriptor ); dcl str1 char(*) varz based(str1ptr), str1ptr pointer; dcl str2 char(*) varz based(str2ptr), str2ptr pointer; str1ptr = s_str(); display(str1); str2ptr = d_str(); display(str2); end; My question is, can/must the PL/I program do free(str2ptr) in order to release the storage for the dynamically allocated string? (And obviously NOT do this for str1ptr.) Side request... Could someone post the PL/I "JNI" copybook? Thanks, Frank From: Frank Swarbrick Sent: Tuesday, June 20, 2017 9:47 AM To: IBM Mainframe Discussion List Subject: Re: Simple (?) C question Thanks John. I know of no code that does this, nor do I intend to implement any. What I was really trying to determine is if a routine could possibly (rightly or wrongly) return a pointer to a field that was statically allocated rather than dynamically allocated. Which would mean that the caller should not, for example, attempt a free() on that pointer. I've been pondering the COBOL 2014 standard and how it might interact with C in this regard. Thanks to everyone who answered. Frank From: IBM Mainframe Discussion List <IBM-MAIN@LISTSERV.UA.EDU> on behalf of John McKown <john.archie.mck...@gmail.com> Sent: Monday, June 19, 2017 7:59 PM To: IBM-MAIN@LISTSERV.UA.EDU Subject: Re: Simple (?) C question On Mon, Jun 19, 2017 at 4:25 PM, Frank Swarbrick < frank.swarbr...@outlook.com> wrote: > I know there are at least a few C developers here, so I was wondering if > you could answer a question. Is the following valid C? (I'm not asking if > one should actually do it; only if its valid at all.) > char *get_static_string(void) { > static char str[81] = "This is a statically allocated C string"; > return str; > } > > > printf("%s", get_static_string()); > > > I don't have a C compiler available at work else I'd try it myself. > > Frank > > You have gotten some good answers. So I will just interject a bit of, perhaps off center, comment. Your code, as written compiles just fine. But it is basically very dangerous. The reason is that you are returning a pointer which could be used to overwrite storage. This is also known as "a bad thing" and is basically an attack vector by malicious code. I don't know the actual intent of your question. But I would suggest using the #pragma string(readonly) in your example. E.g. compile "get_static_string" in its own compilation unit (i.e. by itself) #pragma strings(readonly) const char *get_static_string() { const static char[] = "This is a statically allocated C string"; // let the compiler figure out the length; return str; } I can hear you saying: "But, really, I need up be able to update this string on occasion." If so, then I would greatly suggest that you create a "compilation unit" (single file containing source which is compiled independently ) such as: # file static_string.c #if ! defined(MAXSTRLEN) #define MAXSTRLEN 100 #endif #include static char str[MAXSTRLEN]; const char *get_static_string(void) { return str; } int set_static_string(char *set_to_value) { int len_to_set = strnlen(set_to_value,MAXSTRLEN); if (len_to_set >= MAXSTRLEN) // string too long! return 1; // tell caller NO GO! memcpy(str,set_to_value,len_to_set); // fast copy return 0; } Since the variable "str" is defined as "static" and outside of any function definition, it is "global" to the "compilation unit", but is not known outside of it (i.e. it is not an external name). You compile the above to "object" code. You may be able to bind it into a LOADLIB, but I think you'll get some "external reference not found" type messages for "main". Anyway, the above could be similar to: # file use_static_string.c #include #include #include #include const char *get_static_string(void); int set_static_string(char *); int main(int argc, char *argv[]){ char set_to_1[]="Set to this value"; char set_to_2[]="Set to another value";
Re: Simple (?) C question
On Tue, 20 Jun 2017 16:37:56 -0700, retired mainframer wrote: >Does MacOS run on any IBM mainframe? >> No, but I've used setvbuf() that I mentioned later in this thread to accomplish this purpose on z/OS xlc. If xlc doesn't conform to POSIX it ought to be APARable: On Tue, 20 Jun 2017 09:44:02 -0500, Paul Gilmartin wrote: >The programmer can alter this behavior to make it visible instantly with: >setvbuf( stdout, NULL, _IONBF, 0 ); Didn't work in xlc Enhanced ASCII mode untill IBM fixed my APAR. -- gil -- For IBM-MAIN subscribe / signoff / archive access instructions, send email to lists...@listserv.ua.edu with the message: INFO IBM-MAIN
Re: Simple (?) C question
Some additional remarks below ... Am 20.06.2017 um 22:56 schrieb Bernd Oppolzer: I tried the program, too, using my local Watcom C compiler. No problems, but I had to add some global definitions to make it run. Looks like this: #include #include #include char *get_static_string(void) { static char str[81] = "This is a statically allocated C string"; return str; } int main (void) { printf("%s", get_static_string()); } To improve the program a little bit, I would like to add some const directives: #include #include #include static const char *get_static_string(void) { static const char str[81] = "This is a statically allocated C string"; return str; } I would like to emphasize the difference between the two meanings of "static" in the function before: a) the first "static" before the function head only tells that the function name is not known outside the module (not known to the linker); it does not tell anything about the function result type, which is "const char *". This keyword should have been selected "local" by the C language designers. That they re-used "static" here, is kind of criminal in my opinion (all functions are "static" in the normal sense; same goes for all external variables, be they local to the module or not). b) the keyword "static" befor the variable str has the common meaning; it tells that the variable is "static" (as opposite to "auto", which is a C keyword, too, BTW). int main (void) { printf ("%s", get_static_string()); } using this, and the correct warning level, and a sensible C compiler, the program does not have any problem, IMO. (Assignments to the const static string should be flagged by the compiler; you even can force the str variable to be in the STATIC CSECT, even if you compile using RENT, if you use the ROCONST compiler option - there is even a #pragma NORENT, IIRC, which is crucial for VERY large const tables, which MUST be in the STATIC CSECT, even in the RENT case). (the remarks in the last paragraphs are mostly specific to the mainframe and the IBM C compilers, of course). Kind regards Bernd -- For IBM-MAIN subscribe / signoff / archive access instructions, send email to lists...@listserv.ua.edu with the message: INFO IBM-MAIN
Re: Simple (?) C question
I tried the program, too, using my local Watcom C compiler. No problems, but I had to add some global definitions to make it run. Looks like this: #include #include #include char *get_static_string(void) { static char str[81] = "This is a statically allocated C string"; return str; } int main (void) { printf("%s", get_static_string()); } To improve the program a little bit, I would like to add some const directives: #include #include #include static const char *get_static_string(void) { static const char str[81] = "This is a statically allocated C string"; return str; } int main (void) { printf ("%s", get_static_string()); } using this, and the correct warning level, and a sensible C compiler, the program does not have any problem, IMO. (Assignments to the const static string should be flagged by the compiler; you even can force the str variable to be in the STATIC CSECT, even if you compile using RENT, if you use the ROCONST compiler option - there is even a #pragma NORENT, IIRC, which is crucial for VERY large const tables, which MUST be in the STATIC CSECT, even in the RENT case). (the remarks in the last paragraphs are mostly specific to the mainframe and the IBM C compilers, of course). Kind regards Bernd Am 20.06.2017 um 19:36 schrieb Anthony Giorgio: That's entirely possible. The only pointers that should ever be freed are those that have been explicitly returned by one of the C heap functions, or a NULL pointer. Anything else can cause big problems. On 06/20/2017 11:47 AM, Frank Swarbrick wrote: Thanks John. I know of no code that does this, nor do I intend to implement any. What I was really trying to determine is if a routine could possibly (rightly or wrongly) return a pointer to a field that was statically allocated rather than dynamically allocated. Which would mean that the caller should not, for example, attempt a free() on that pointer. I've been pondering the COBOL 2014 standard and how it might interact with C in this regard. Thanks to everyone who answered. Frank From: IBM Mainframe Discussion List <IBM-MAIN@LISTSERV.UA.EDU> on behalf of John McKown <john.archie.mck...@gmail.com> Sent: Monday, June 19, 2017 7:59 PM To: IBM-MAIN@LISTSERV.UA.EDU Subject: Re: Simple (?) C question On Mon, Jun 19, 2017 at 4:25 PM, Frank Swarbrick < frank.swarbr...@outlook.com> wrote: I know there are at least a few C developers here, so I was wondering if you could answer a question. Is the following valid C? (I'm not asking if one should actually do it; only if its valid at all.) char *get_static_string(void) { static char str[81] = "This is a statically allocated C string"; return str; } printf("%s", get_static_string()); I don't have a C compiler available at work else I'd try it myself. Frank You have gotten some good answers. So I will just interject a bit of, perhaps off center, comment. Your code, as written compiles just fine. But it is basically very dangerous. The reason is that you are returning a pointer which could be used to overwrite storage. This is also known as "a bad thing" and is basically an attack vector by malicious code. I don't know the actual intent of your question. But I would suggest using the #pragma string(readonly) in your example. E.g. compile "get_static_string" in its own compilation unit (i.e. by itself) #pragma strings(readonly) const char *get_static_string() { const static char[] = "This is a statically allocated C string"; // let the compiler figure out the length; return str; } I can hear you saying: "But, really, I need up be able to update this string on occasion." If so, then I would greatly suggest that you create a "compilation unit" (single file containing source which is compiled independently ) such as: # file static_string.c #if ! defined(MAXSTRLEN) #define MAXSTRLEN 100 #endif #include static char str[MAXSTRLEN]; const char *get_static_string(void) { return str; } int set_static_string(char *set_to_value) { int len_to_set = strnlen(set_to_value,MAXSTRLEN); if (len_to_set >= MAXSTRLEN) // string too long! return 1; // tell caller NO GO! memcpy(str,set_to_value,len_to_set); // fast copy return 0; } Since the variable "str" is defined as "static" and outside of any function definition, it is "global" to the "compilation unit", but is not known outside of it (i.e. it is not an external name). You compile the above to "object" code. You may be able to bind it into a LOADLIB, but I think you'll get some "external reference not found" type messages for "main". Anyway, the above could be similar to: # file use_static_string.c #include #include #include #
Re: Simple (?) C question
It's thread safe in that sense that several processes (LE enclaves) running in parallel each get their own instance of the WSA, so there is no mixing of static variables in this case. Of course, if you use other variants of multi-threading which don't involve separate (that is, parallel) LE enclaves, you will not get separate WSAs for each of the parallel "threads". Kind regards Bernd Am 20.06.2017 um 14:16 schrieb David Crayford: That's not what I meant. It's not thread safe without locking. And even if you're not multi-threaded it may be better practice to copy the static C string into a buffer. Take strerror() for example. Once you've got the error you either print it immediately or copy the message into a buffer. strerror_r() is much better but still has the issue that your target buffer may be too small. Some platforms have macros that define the maximum length of a message returned from strerror(). IMO returning static C strings is bad practice and should be avoided when there are better alternatives. On 20/06/2017 7:12 PM, Don Poitras wrote: Not if you compile RENT. In that case the static is allocated in a separate area rather than being inside the load module. -- For IBM-MAIN subscribe / signoff / archive access instructions, send email to lists...@listserv.ua.edu with the message: INFO IBM-MAIN
Re: Simple (?) C question
Am 20.06.2017 um 13:12 schrieb Don Poitras: Not if you compile RENT. In that case the static is allocated in a separate area rather than being inside the load module. and: every invocation of the module from potentially parallel LE enclaves (for example, when used inside a DB2 stored proc environment) get its own instance of the WSA = writable storage area, that is, its own set of static variables. This is not true for the NORENT case, when the static variables are part of the module's CSECT. In article <32db4b0b-1271-18b1-574c-9cb6a37a2...@gmail.com> you wrote: If the string can be mutated either by the client or the runtime returning by reference is not re-entrant. -- For IBM-MAIN subscribe / signoff / archive access instructions, send email to lists...@listserv.ua.edu with the message: INFO IBM-MAIN
Re: Simple (?) C question
Thanks John. I know of no code that does this, nor do I intend to implement any. What I was really trying to determine is if a routine could possibly (rightly or wrongly) return a pointer to a field that was statically allocated rather than dynamically allocated. Which would mean that the caller should not, for example, attempt a free() on that pointer. I've been pondering the COBOL 2014 standard and how it might interact with C in this regard. Thanks to everyone who answered. Frank From: IBM Mainframe Discussion List <IBM-MAIN@LISTSERV.UA.EDU> on behalf of John McKown <john.archie.mck...@gmail.com> Sent: Monday, June 19, 2017 7:59 PM To: IBM-MAIN@LISTSERV.UA.EDU Subject: Re: Simple (?) C question On Mon, Jun 19, 2017 at 4:25 PM, Frank Swarbrick < frank.swarbr...@outlook.com> wrote: > I know there are at least a few C developers here, so I was wondering if > you could answer a question. Is the following valid C? (I'm not asking if > one should actually do it; only if its valid at all.) > char *get_static_string(void) { > static char str[81] = "This is a statically allocated C string"; > return str; > } > > > printf("%s", get_static_string()); > > > I don't have a C compiler available at work else I'd try it myself. > > Frank > > You have gotten some good answers. So I will just interject a bit of, perhaps off center, comment. Your code, as written compiles just fine. But it is basically very dangerous. The reason is that you are returning a pointer which could be used to overwrite storage. This is also known as "a bad thing" and is basically an attack vector by malicious code. I don't know the actual intent of your question. But I would suggest using the #pragma string(readonly) in your example. E.g. compile "get_static_string" in its own compilation unit (i.e. by itself) #pragma strings(readonly) const char *get_static_string() { const static char[] = "This is a statically allocated C string"; // let the compiler figure out the length; return str; } I can hear you saying: "But, really, I need up be able to update this string on occasion." If so, then I would greatly suggest that you create a "compilation unit" (single file containing source which is compiled independently ) such as: # file static_string.c #if ! defined(MAXSTRLEN) #define MAXSTRLEN 100 #endif #include static char str[MAXSTRLEN]; const char *get_static_string(void) { return str; } int set_static_string(char *set_to_value) { int len_to_set = strnlen(set_to_value,MAXSTRLEN); if (len_to_set >= MAXSTRLEN) // string too long! return 1; // tell caller NO GO! memcpy(str,set_to_value,len_to_set); // fast copy return 0; } Since the variable "str" is defined as "static" and outside of any function definition, it is "global" to the "compilation unit", but is not known outside of it (i.e. it is not an external name). You compile the above to "object" code. You may be able to bind it into a LOADLIB, but I think you'll get some "external reference not found" type messages for "main". Anyway, the above could be similar to: # file use_static_string.c #include #include #include #include const char *get_static_string(void); int set_static_string(char *); int main(int argc, char *argv[]){ char set_to_1[]="Set to this value"; char set_to_2[]="Set to another value"; const char *return_static_string; int retRC; retRC=set_static_string(set_to_1); if (retRC != 0) { printf("retRC=%d\n",retRC); exit(1); } return_static_string=get_static_string(); printf("%s\n",return_static_string); retRC=set_static_string(set_to_2); if (retRC != 0) { printf("retRC=%d\n",retRC); exit(1); } return_static_string=get_static_string(); printf("%s\n",return_static_string); } Please note that I did test the above, but not on z/OS. I did it on Linux/Intel at home. But it is fairly generic and so should work on z/OS with xlc as well. Also note the use of MAXSTRLEN. This is really a "preprocessor" value. Why did I use it as I did? Because if 100 is not correct, you can change the MAXSTRLEN value on the compile with the -D compile option. I don't remember how to do this with JCL, but on a UNIX shell prompt, you can do something like: xlc -c -DMAXSTRLEN=256 -o static_string.o static_string.c # MAX string length is 256 (255 chars + NUL ending) # compile, don't link xlc -o use_static_string use_static_string.c static_string.o # compile and link object from above -- Veni, Vidi
Re: Simple (?) C question
On Mon, 19 Jun 2017 17:13:00 -0700, retired mainframer wrote: > >Probably unrelated to your real question but the format string passed to >printf should also have a \n after the %s to insure the output is visible. > On MacOS, at least, buffers are flushed when the program exits, so the output will be visible sooner or later. The programmer can alter this behavior to make it visible instantly with: setvbuf( stdout, NULL, _IONBF, 0 ); -- gil -- For IBM-MAIN subscribe / signoff / archive access instructions, send email to lists...@listserv.ua.edu with the message: INFO IBM-MAIN
Re: Simple (?) C question
Not if you compile RENT. In that case the static is allocated in a separate area rather than being inside the load module. In article <32db4b0b-1271-18b1-574c-9cb6a37a2...@gmail.com> you wrote: > If the string can be mutated either by the client or the runtime > returning by reference is not re-entrant. > I would always prefer to use strings buffers: > int get_string(char * buf, size_t buflen); > Strings are s much easier in C++. > On 20/06/2017 9:59 AM, John McKown wrote: > > On Mon, Jun 19, 2017 at 4:25 PM, Frank Swarbrick < > > frank.swarbr...@outlook.com> wrote: > > > >> I know there are at least a few C developers here, so I was wondering if > >> you could answer a question. Is the following valid C? (I'm not asking if > >> one should actually do it; only if its valid at all.) > >> char *get_static_string(void) { > >> static char str[81] = "This is a statically allocated C string"; > >> return str; > >> } > >> > >> > >> printf("%s", get_static_string()); > >> > >> > >> I don't have a C compiler available at work else I'd try it myself. > >> > >> Frank > >> > >> > > ?You have gotten some good answers. So I will just interject a bit of, > > perhaps off center, comment. Your code, as written compiles just fine. But > > it is basically very dangerous. The reason is that you are returning a > > pointer which could be used to overwrite storage. This is also known as "a > > bad thing" and is basically an attack vector by malicious code. I don't > > know the actual intent of your question. But I would suggest using the > > #pragma string(readonly) in your example. E.g. compile "get_static_string" > > in its own compilation unit (i.e. by itself) > > > > #pragma strings(readonly) > > const char *get_static_string() { > > const static char[] = "This is a statically allocated C string"; // let > > the compiler figure out the length; > > return str; > > } > > > > > > ?I can hear you saying: "But, really, I need up be able to update this > > string on occasion."? If so, then I would greatly suggest that you create a > > "compilation unit" (single file containing source which is compiled > > independently ) such as: > > > > # > > ? file static_string.c > > ? > > #if ! defined(MAXSTRLEN) > > #define MAXSTRLEN 100 > > #endif > > #include > > > > static char str[MAXSTRLEN]; > > > > const char *get_static_string(void) { > > return str; > > } > > > > int set_static_string(char *set_to_value) { > > int len_to_set = strnlen(set_to_value,MAXSTRLEN); > > if (len_to_set >= MAXSTRLEN) // string too long! > > return 1; // tell caller NO GO! > > memcpy(str,set_to_value,len_to_set); // fast copy > > return 0; > > } > > > > ?Since the variable "str" is defined as "static" and outside of any > > function definition, it is "global" to the "compilation unit", but is not > > known outside of it (i.e. it is not an external name). You compile the > > above to "object" code. You may be able to bind it into a LOADLIB, but I > > think you'll get some "external reference not found" type messages for > > "main". > > > > Anyway, the above could be similar to: > > > > ?# file use_static_string.c? > > > > #include > > #include > > #include > > #include > > const char *get_static_string(void); > > int set_static_string(char *); > > int main(int argc, char *argv[]){ > > char set_to_1[]="Set to this value"; > > char set_to_2[]="Set to another value"; > > const char *return_static_string; > > int retRC; > > retRC=set_static_string(set_to_1); > > if (retRC != 0) { > > printf("retRC=%d\n",retRC); > > exit(1); > > } > > return_static_string=get_static_string(); > > printf("%s\n",return_static_string); > > retRC=set_static_string(set_to_2); > > if (retRC != 0) { > > printf("retRC=%d\n",retRC); > > exit(1); > > } > > return_static_string=get_static_string(); > > printf("%s\n",return_static_string); > > } > > > > ?Please note that I did test the above, but not on z/OS. I did it on > > Linux/Intel at home. But it is fairly generic and so should work on z/OS > > with xlc as well. > > > > Also note the use of MAXSTRLEN. This is really a "preprocessor" value. Why > > did I use it as I did? Because if 100 is not correct, you can change the > > MAXSTRLEN value? on the compile with the -D compile option. I don't > > remember how to do this with JCL, but on a UNIX shell prompt, you can do > > something like: > > > > xlc -c -DMAXSTRLEN=256 -o static_string.o static_string.c # MAX string > > length is 256 (255 chars + NUL ending) # compile, don't link > > xlc -o use_static_string use_static_string.c static_string.o # compile and > > link object from above > > > > > > > -- > For IBM-MAIN subscribe / signoff / archive access
Re: Simple (?) C question
If the string can be mutated either by the client or the runtime returning by reference is not re-entrant. I would always prefer to use strings buffers: int get_string(char * buf, size_t buflen); Strings are s much easier in C++. On 20/06/2017 9:59 AM, John McKown wrote: On Mon, Jun 19, 2017 at 4:25 PM, Frank Swarbrick < frank.swarbr...@outlook.com> wrote: I know there are at least a few C developers here, so I was wondering if you could answer a question. Is the following valid C? (I'm not asking if one should actually do it; only if its valid at all.) char *get_static_string(void) { static char str[81] = "This is a statically allocated C string"; return str; } printf("%s", get_static_string()); I don't have a C compiler available at work else I'd try it myself. Frank You have gotten some good answers. So I will just interject a bit of, perhaps off center, comment. Your code, as written compiles just fine. But it is basically very dangerous. The reason is that you are returning a pointer which could be used to overwrite storage. This is also known as "a bad thing" and is basically an attack vector by malicious code. I don't know the actual intent of your question. But I would suggest using the #pragma string(readonly) in your example. E.g. compile "get_static_string" in its own compilation unit (i.e. by itself) #pragma strings(readonly) const char *get_static_string() { const static char[] = "This is a statically allocated C string"; // let the compiler figure out the length; return str; } I can hear you saying: "But, really, I need up be able to update this string on occasion." If so, then I would greatly suggest that you create a "compilation unit" (single file containing source which is compiled independently ) such as: # file static_string.c #if ! defined(MAXSTRLEN) #define MAXSTRLEN 100 #endif #include static char str[MAXSTRLEN]; const char *get_static_string(void) { return str; } int set_static_string(char *set_to_value) { int len_to_set = strnlen(set_to_value,MAXSTRLEN); if (len_to_set >= MAXSTRLEN) // string too long! return 1; // tell caller NO GO! memcpy(str,set_to_value,len_to_set); // fast copy return 0; } Since the variable "str" is defined as "static" and outside of any function definition, it is "global" to the "compilation unit", but is not known outside of it (i.e. it is not an external name). You compile the above to "object" code. You may be able to bind it into a LOADLIB, but I think you'll get some "external reference not found" type messages for "main". Anyway, the above could be similar to: # file use_static_string.c #include #include #include #include const char *get_static_string(void); int set_static_string(char *); int main(int argc, char *argv[]){ char set_to_1[]="Set to this value"; char set_to_2[]="Set to another value"; const char *return_static_string; int retRC; retRC=set_static_string(set_to_1); if (retRC != 0) { printf("retRC=%d\n",retRC); exit(1); } return_static_string=get_static_string(); printf("%s\n",return_static_string); retRC=set_static_string(set_to_2); if (retRC != 0) { printf("retRC=%d\n",retRC); exit(1); } return_static_string=get_static_string(); printf("%s\n",return_static_string); } Please note that I did test the above, but not on z/OS. I did it on Linux/Intel at home. But it is fairly generic and so should work on z/OS with xlc as well. Also note the use of MAXSTRLEN. This is really a "preprocessor" value. Why did I use it as I did? Because if 100 is not correct, you can change the MAXSTRLEN value on the compile with the -D compile option. I don't remember how to do this with JCL, but on a UNIX shell prompt, you can do something like: xlc -c -DMAXSTRLEN=256 -o static_string.o static_string.c # MAX string length is 256 (255 chars + NUL ending) # compile, don't link xlc -o use_static_string use_static_string.c static_string.o # compile and link object from above -- For IBM-MAIN subscribe / signoff / archive access instructions, send email to lists...@listserv.ua.edu with the message: INFO IBM-MAIN
Re: Simple (?) C question
On Mon, Jun 19, 2017 at 4:25 PM, Frank Swarbrick < frank.swarbr...@outlook.com> wrote: > I know there are at least a few C developers here, so I was wondering if > you could answer a question. Is the following valid C? (I'm not asking if > one should actually do it; only if its valid at all.) > char *get_static_string(void) { > static char str[81] = "This is a statically allocated C string"; > return str; > } > > > printf("%s", get_static_string()); > > > I don't have a C compiler available at work else I'd try it myself. > > Frank > > You have gotten some good answers. So I will just interject a bit of, perhaps off center, comment. Your code, as written compiles just fine. But it is basically very dangerous. The reason is that you are returning a pointer which could be used to overwrite storage. This is also known as "a bad thing" and is basically an attack vector by malicious code. I don't know the actual intent of your question. But I would suggest using the #pragma string(readonly) in your example. E.g. compile "get_static_string" in its own compilation unit (i.e. by itself) #pragma strings(readonly) const char *get_static_string() { const static char[] = "This is a statically allocated C string"; // let the compiler figure out the length; return str; } I can hear you saying: "But, really, I need up be able to update this string on occasion." If so, then I would greatly suggest that you create a "compilation unit" (single file containing source which is compiled independently ) such as: # file static_string.c #if ! defined(MAXSTRLEN) #define MAXSTRLEN 100 #endif #include static char str[MAXSTRLEN]; const char *get_static_string(void) { return str; } int set_static_string(char *set_to_value) { int len_to_set = strnlen(set_to_value,MAXSTRLEN); if (len_to_set >= MAXSTRLEN) // string too long! return 1; // tell caller NO GO! memcpy(str,set_to_value,len_to_set); // fast copy return 0; } Since the variable "str" is defined as "static" and outside of any function definition, it is "global" to the "compilation unit", but is not known outside of it (i.e. it is not an external name). You compile the above to "object" code. You may be able to bind it into a LOADLIB, but I think you'll get some "external reference not found" type messages for "main". Anyway, the above could be similar to: # file use_static_string.c #include #include #include #include const char *get_static_string(void); int set_static_string(char *); int main(int argc, char *argv[]){ char set_to_1[]="Set to this value"; char set_to_2[]="Set to another value"; const char *return_static_string; int retRC; retRC=set_static_string(set_to_1); if (retRC != 0) { printf("retRC=%d\n",retRC); exit(1); } return_static_string=get_static_string(); printf("%s\n",return_static_string); retRC=set_static_string(set_to_2); if (retRC != 0) { printf("retRC=%d\n",retRC); exit(1); } return_static_string=get_static_string(); printf("%s\n",return_static_string); } Please note that I did test the above, but not on z/OS. I did it on Linux/Intel at home. But it is fairly generic and so should work on z/OS with xlc as well. Also note the use of MAXSTRLEN. This is really a "preprocessor" value. Why did I use it as I did? Because if 100 is not correct, you can change the MAXSTRLEN value on the compile with the -D compile option. I don't remember how to do this with JCL, but on a UNIX shell prompt, you can do something like: xlc -c -DMAXSTRLEN=256 -o static_string.o static_string.c # MAX string length is 256 (255 chars + NUL ending) # compile, don't link xlc -o use_static_string use_static_string.c static_string.o # compile and link object from above -- Veni, Vidi, VISA: I came, I saw, I did a little shopping. Maranatha! <>< John McKown -- For IBM-MAIN subscribe / signoff / archive access instructions, send email to lists...@listserv.ua.edu with the message: INFO IBM-MAIN
Re: Simple (?) C question
The static array will exist for the life of the program and is therefore accessible after the function returns. My compiler accepted it and execution produced the expected result when the printf statement was placed in main. Probably unrelated to your real question but the format string passed to printf should also have a \n after the %s to insure the output is visible. > -Original Message- > From: IBM Mainframe Discussion List [mailto:IBM-MAIN@LISTSERV.UA.EDU] On > Behalf Of Frank Swarbrick > Sent: Monday, June 19, 2017 2:26 PM > To: IBM-MAIN@LISTSERV.UA.EDU > Subject: Simple (?) C question > > I know there are at least a few C developers here, so I was wondering if you could answer a > question. Is the following valid C? (I'm not asking if one should actually do it; only if its > valid at all.) > char *get_static_string(void) { > static char str[81] = "This is a statically allocated C string"; > return str; > } > > > printf("%s", get_static_string()); > > > I don't have a C compiler available at work else I'd try it myself. -- For IBM-MAIN subscribe / signoff / archive access instructions, send email to lists...@listserv.ua.edu with the message: INFO IBM-MAIN
Re: Simple (?) C question
On Mon, 19 Jun 2017 21:25:50 +, Frank Swarbrick wrote: >I know there are at least a few C developers here, so I was wondering if you >could answer a question. Is the following valid C? (I'm not asking if one >should actually do it; only if its valid at all.) >char *get_static_string(void) { >static char str[81] = "This is a statically allocated C string"; >return str; >} > > >printf("%s", get_static_string()); > >I don't have a C compiler available at work else I'd try it myself. > What do you have on your desktop? OK. Trying as published: 536 $ gmake stati cc stati.c -o stati stati.c:7: error: expected declaration specifiers or ‘...’ before string constant stati.c:7: error: expected declaration specifiers or ‘...’ before ‘get_static_string’ stati.c:7: warning: data definition has no type or storage class stati.c:7: warning: conflicting types for built-in function ‘printf’ gmake: *** [stati] Error 1 537 $ So, repairing the problems: 537 $ diff -u stati.c stati2.c --- stati.c 2017-06-19 17:56:07.0 -0600 +++ stati2.c2017-06-19 18:01:27.0 -0600 @@ -3,5 +3,7 @@ return str; } - +#include +int main( void ) { printf("%s", get_static_string()); +} 538 $ And trying again: 538 $ gmake stati2 & ./stati2 cc stati2.c -o stati2 This is a statically allocated C string539 $ 539 $ -- gil -- For IBM-MAIN subscribe / signoff / archive access instructions, send email to lists...@listserv.ua.edu with the message: INFO IBM-MAIN
Re: Simple (?) C question
Looks good to me. Like Peter says, the function returns the pointer correctly, and the compiler should put that string in a static memory location instead of on the stack. Now if you were to do something like this: char * x; printf("%s\n", get_static_string()); x = get_static_string(); x[20] = 'X'; printf("%s\n", get_static_string()); The result should be this: This is a statically allocated C string This is a staticallyXallocated C string So we know we're pointing to the same static area with each call. But if you were to change the function to a local variable like this: char str[81] = "This is a statically allocated C string"; ... now we're allocating locally and that memory is gone (or maybe reused?) when the function returns the address. Not what you want probably. Frank Swarbrick wrote: I know there are at least a few C developers here, so I was wondering if you could answer a question. Is the following valid C? (I'm not asking if one should actually do it; only if its valid at all.) char *get_static_string(void) { static char str[81] = "This is a statically allocated C string"; return str; } printf("%s", get_static_string()); I don't have a C compiler available at work else I'd try it myself. Frank -- For IBM-MAIN subscribe / signoff / archive access instructions, send email to lists...@listserv.ua.edu with the message: INFO IBM-MAIN -- For IBM-MAIN subscribe / signoff / archive access instructions, send email to lists...@listserv.ua.edu with the message: INFO IBM-MAIN
Re: Simple (?) C question
Looks OK to me. "str" is an array of char's so the name by itself (without subscript brackets) is actually a pointer to that storage (IOW a char *). Someone well versed in C once told me to remember: str == [0] That is, the array name is equal to the address of the first array member. Peter -Original Message- From: IBM Mainframe Discussion List [mailto:IBM-MAIN@LISTSERV.UA.EDU] On Behalf Of Frank Swarbrick Sent: Monday, June 19, 2017 5:26 PM To: IBM-MAIN@LISTSERV.UA.EDU Subject: Simple (?) C question I know there are at least a few C developers here, so I was wondering if you could answer a question. Is the following valid C? (I'm not asking if one should actually do it; only if its valid at all.) char *get_static_string(void) { static char str[81] = "This is a statically allocated C string"; return str; } printf("%s", get_static_string()); I don't have a C compiler available at work else I'd try it myself. Frank -- This message and any attachments are intended only for the use of the addressee and may contain information that is privileged and confidential. If the reader of the message is not the intended recipient or an authorized representative of the intended recipient, you are hereby notified that any dissemination of this communication is strictly prohibited. If you have received this communication in error, please notify us immediately by e-mail and delete the message and any attachments from your system. -- For IBM-MAIN subscribe / signoff / archive access instructions, send email to lists...@listserv.ua.edu with the message: INFO IBM-MAIN