From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Thread: 103376,ea88e33ca617708 X-Google-NewGroupId: yes X-Google-Attributes: gida07f3367d7,domainid0,public,usenet X-Google-Language: ENGLISH,ASCII Received: by 10.68.28.135 with SMTP id b7mr6951004pbh.8.1321652705013; Fri, 18 Nov 2011 13:45:05 -0800 (PST) Path: h5ni7008pba.0!nntp.google.com!news2.google.com!postnews.google.com!h30g2000pro.googlegroups.com!not-for-mail From: Adam Beneschan Newsgroups: comp.lang.ada Subject: Re: Calling Ada Procedure from C - how to handle a char ptr/array Date: Fri, 18 Nov 2011 13:38:09 -0800 (PST) Organization: http://groups.google.com Message-ID: <9a38b451-14d8-4449-97b8-7f040ea63498@h30g2000pro.googlegroups.com> References: <8e5541a3-cdd5-40af-a6fd-f7539ee61326@l19g2000yqc.googlegroups.com> NNTP-Posting-Host: 66.126.103.122 Mime-Version: 1.0 X-Trace: posting.google.com 1321652704 6146 127.0.0.1 (18 Nov 2011 21:45:04 GMT) X-Complaints-To: groups-abuse@google.com NNTP-Posting-Date: Fri, 18 Nov 2011 21:45:04 +0000 (UTC) Complaints-To: groups-abuse@google.com Injection-Info: h30g2000pro.googlegroups.com; posting-host=66.126.103.122; posting-account=duW0ogkAAABjRdnxgLGXDfna0Gc6XqmQ User-Agent: G2/1.0 X-Google-Web-Client: true X-Google-Header-Order: ARLUEHNKC X-HTTP-UserAgent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; WOW64; Trident/4.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.5.21022; .NET CLR 3.5.30729; .NET CLR 3.0.30618; .NET4.0C),gzip(gfe) Xref: news2.google.com comp.lang.ada:14460 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Date: 2011-11-18T13:38:09-08:00 List-Id: On Nov 18, 12:41=A0pm, awdorrin wrote: > Tried reworking the code into a function that returns a char_array, > but got a STORAGE_ERROR with a stack overflow/erroneous memory access. > > function Get_Label return Interfaces.C.Char_array is > =A0 Label : String(1..8); > begin > =A0 Label(1..8) :=3D "12345678"; > > =A0 return Interfaces.C.To_C(Label); > end; > > From the source code for To_C(), it allocates the char array, so I'm > not sure why this error would be raised... I just tried a small test case (written entirely in Ada) that declared this function just the way you wrote it, then called it. I compiled using GNAT. It didn't raise anything. Also, I don't see anything wrong with the function. So I suspect the problem isn't occurring in this function; it's occurring somewhere else. Are you calling Get_Label directly from C? If so, how is it declared in your C code? I don't agree with Jeff's suggestion to use a function that returns a Char_Array. The reason is that Char_Array is defined as an unconstrained array, and the language says that implementations don't have to support applying the C convention to functions that return unconstrained arrays. When I try this (writing a source that defines Get_Label as above, and applying Export(C) to it), GNAT gives a warning "foreign convention function Get_Label should not return unconstrained array". Are you using GNAT? If so, do you get the same warning? If so, that's a good indication that things aren't going to work. When an Ada function returns an unconstrained array, it has to arrange to return the bounds as well as the array data, and how it does that will vary from one implementation to another. Our compiler, for example, treats this kind of function as a procedure with an implicit OUT parameter that points to a record that will contain the data pointer and the bounds, which the caller will interpret as the function result. I don't know how GNAT handles it. Regardless, it will probably not be the way that a C program will expect, so you're likely to get mismatched parameters or something else that could easily lead to a bad memory access. >From the warning you described in your original post, and from my experience, I don't think GNAT handles an *unconstrained* char_array as an OUT parameter. But there are a couple ways to get around this. One is to declare your own constrained subtype: subtype constrained_char_array is Interfaces.C.Char_Array (Interfaces.C.Size_T); which declares a constrained array whose bounds are the entire range of Size_T. Of course, those won't be the actual bounds, but it will make GNAT think those are the actual bounds so that it doesn't complain about bounds not being passed in, and it doesn't try to check indexes against some bogus bound and get a Constraint_Error. procedure Get_Text (s : out constrained_char_array) is ... s :=3D Interfaces.C.To_C (Label); -- WRONG This is wrong, because it will try to assign to all of s from indexes Size_T'First to Size_T'Last. Remember, that's what it thinks the bounds are. (In your original attempt, it had no idea what the bounds were, so assigning "s :=3D" couldn't have worked either.) Since the C code isn't going to pass any bound information to Get_Text, you have to help it by telling it what index range you're setting: s(Size_T'First .. Size_T'First + Label'Length) :=3D Interfaces.C.To_C (Label); The length of the left-hand slice is Label'Length + 1, but that's what you want because To_C will stick a NUL character on the end of the string. Of course, if the character array in your C code isn't large enough to handle this result, you will be screwed, but that's par for the course in C. It might be better to have the C function pass in the sizeof() of the array as an extra parameter, which is how it's done in some of the Unix system calls. Then the Ada code could check to make sure that Label'Length + 1 <=3D [the Size parameter], or raise Constraint_Error if not. Another possibility is to use chars_ptr and Update in the Interfaces.C.Strings package. I'll let you look those up. Hope this helps, -- Adam