There is this function in the LibAIFF library:
AIFF_Ref AIFF_OpenFile(const char* name, int flags);
It accepts a const char* but for my use, name has to be of type a char* because I need to build it based on the location of my AIFF file on my directory (which I can properly accomplish) - specifically, in my case name is the AIFF file path.
But I think I'm running into some problems because of this (I'm not sure though). What happens when I send the function a char*? The bad behavior I'm noticing occurs with an associated AIFF_CloseFile function which runs into some problems what seems to be randomly based on the file path I send to it. For example, if I have the exact same AIFF file with two names with just one of the letters changed, the error (which has to do with AIFF_CloseFile trying to free a buffer defined within a structure which has either already been freed or hasn't been allocated) occurs with one of them but not the other. If I comment out the call to the close file function, everything works in that the AIFF file is successfully opened and read but I'm not supposed to do that.
Any help will be much appreciated. Thanks
It is fine to use a char * when a const char * is expected.
If a function accepts a const char * it just means that the function won't be changing the string contents at all.
The other way around is not good though.
EDIT:
I don't know the library you are using.. It could be a problem if the library is remembering the string you used, but is not making its own internal copy. This would be an awful library though..
Related
Normally, C file I/O is done using FILE* as this is what the standard library functions all take.
In C, one can also have a const pointer, where the address of the pointer cannot change (but the value it points to can be).
I wondered if this could be applied to FILE*, so wrote this small program to test this:
#include <stdio.h>
int main(void) {
FILE* const file = fopen("somefile.txt", "w");
if (file != NULL) {
fprintf(file, "%s\n", "So this works? That's just swell!");
}
return 0;
}
This compiles fine and works as intended on Ubuntu/Linux 16.04 using GCC (the file contains exactly the string I expected), but I'm not sure if this idiom is such a good idea —the FILE type is opaque by design and handling of it is implementation-specific.
Because there's no guarantee that any C library implementation won't try and change the address of the FILE pointer, is it safer to not use this approach when doing I/O in C?
Converting comments into an answer as requested.
You can use FILE * const sanely; you cannot use const FILE * sanely. There's a guarantee that none of the functions in the C library will modify the pointer part of the FILE * you pass to them in any way detectable by the calling code, because the pointer is always passed by value — never the address of the pointer. So there is no way for the calling code to modify your pointer — unless it goes to insanely complex steps in order to do so, and it won't because there is neither any need nor any benefit to doing so.
I'm aware of the difference between FILE * const and const FILE * (as well as why the latter doesn't make any sense). In my question I am seeking to clarify whether making the pointer const will have any negative impact on the standard library functions, as they don't take const pointers in their prototypes.
Also, for context of why I'm looking to do this — the same reasons why one might make any other pointer const: to stop an accidental re-assignment of what it points to.
It can't have any effect on the functions in the library; they are passed a copy of the value, and they won't modify the value, but won't be aware that the original value is non-modifiable anyway, and won't care. Using FILE * const fp = fopen(…); simply means you can't reuse that file pointer for anything else in the same function (or retry opening a different file name or calling a different 'open' function), and you can't reset it to NULL after you fclose() it. Of course, if the pointer goes out of scope because it is inside a loop, it can be reused when the scope is re-entered.
Otherwise, using FILE * const has no effect. I don't think it's useful. It isn't harmful except that it does nothing beneficial (and might confuse people). I recommend against using FILE * const.
I'm attempting to build a test framework in TCL that will allow me to perform scripted tests on a remote device over a TCP socket. There already exists a Visual Basic interface and with SWIG in Ubuntu I'm reusing the C functions that it calls to build a shared library that will work as an extension to TCL. I have had success at incorporating basic functions, such as opening/closing sockets, and basic read/writes to single memory addresses on the device using SWIG's typemaps.i to provide pointers (*OUTPUT) to the readAddress function to return address values to TCL.
The problem is that for this to be useful I am going to have to incorporate a large number of Remote Procedure Calls which pass complicated data types into (and back out of!) the device. As a proof of concept I'm attempting to get a relatively simple function working. This attempts to read default test parameters via an RPC; a pointer to a struct is provided for the function to use for the results: rpc_testDefaults ( testDefaults_t *testDefaults ).
The typedef for testDefaults_t is in testDefaults.h, which is in the style of the following:
// testDefaults.h
#include <stdint.h>
typedef uint32_t customType_t;
typedef struct
{
customType_t varName1; // Description
uint32_t varName2; // Description
// 13 more uint32_t elements
} testDefaults_t;
// Two more struct type definitions
testDefaults.c is along the lines of this:
// testDefaults.c
#include "testDefaults.h"
// #ifdefs to compile as 'client' OR 'server' (defaults to 'client')
rpc_testDefaults ( testDefaults_t, *testDefaults )
{
// function
}
My SWIG interface file looks like this:
// rpcTest.i
%module rpcTest
%include <cpointer.i>
%include "testDefaults.h"
%pointer_functions(testDefaults_t, testDefaults);
//%apply int *OUTPUT {testDefaults_t, *testDefaults};
%{
#include "testDefaults.h"
extern int rpc_testDefaults ( testDefaults_t, *testDefaults )
}%
extern int rpc_testDefaults ( testDefaults_t, *testDefaults )
There are many other .c and header files in the same folder which support this function and the others which I mentioned I got working.
I run swig -tcl -debug-typedef rpcTest.i which gives me rpcTest_wrap.c, I can see that the testDefaults_t has been recognised as a type/scope as is has a section in the debug output (it's also included in the unnamed scope section: testDefaults_t -> testDefaults_t).
I run gcc -fPIC -DCLIENT_FLAG -c *.c -I/usr/include/tcl8.5 and I get an error from a line in the SWIG output file: rpcTest_wrap.c:1803:3: error: unknown type name 'testDefaults_t' (plus a lot more errors derived from this). The line in question is the first line in this function:
static testDefaults_t *new_testDefaults() {
return (testDefaults_t *)malloc(sizeof(testDefaults_t));
}
Which I believe is cpointers.i creating a function for TCL to 'create' a pointer to that struct.
I have a feeling this is something to do with gcc including files in the wrong order, but I'm at a loss as to what to do next. I've tried many combinations of defining the header in various places in the interface file and this is the combination that gives the least errors :). You can see my commented-out partial attempt at using typemaps instead of cpointers but I'm even more clueless with these, I managed it for a pointer to a single value but it didn't seem to be working for a struct with it's own type. It did compile without error though.
So is it possible to get what I'm trying to achieve working using cpointers.i? Any suggestions on how to overcome the compiler issue? Would I be better off learning how to use typemaps? Let me know where I can provide more detail if it would help, I may be leaving out crucial information as I've had to summarize and change all the names as this is company stuff.
Any help/criticism would be greatly appreciated!
Looking into the rpcTest_wrap.c file I noticed that the include for testDefaults.h was right after the group of functions that were attempting to use it. I replaced "int" in the interface file with testDefaults_t (I think this is correct), ran SWIG, edited the output (dangerous I know!) so that the include happened just before these functions, and it compiles fine. I can load the shared library into TCL and run the new functions.
However, and this is perhaps a new question, [in TCL] using the new functions to create a pointer, feed it into rpc_testDefaults, and attempting to dereference the resulting pointer using testDefaults_value just returns another pointer. I realize that I can't just dereference a struct, but I have no idea how to dereference individual elements. Any tutorials I can find only refer to dereferencing non-structs (and none of these tutorials are for TCL). Something somewhere mentioned that there are similarities between structs and TK widgets so I'll have a look into this, but I'm still not sure is what I'm attempting to do even possible, and if it is is this the right way to do it.
Again, what I am attempting to do is in TCL, access individual elements of a struct which has been returned from (or fed into) a C function via a pointer.
UPDATE: I got this working in the end by using the functions SWIG generates which I discovered in the end of the wrapper file. cpointer.i wasn't needed at all. In TCL I first create a pointer using the new function new_testDefaults which returns a string with in the form of a TCL style pointer. I pass this pointer into rpc_testDefaults, which returns nothing as it was actually a void function. I can then access individual elements from the struct referenced by the above pointer by setting it as an argument to the elementName_get and elementName_set functions generated by SWIG. The next task is to get more complicated functions working, structs in structs etc, but now that I'm familiar with the methodology it shouldn't be too hard.
I am studying on "reading code" by reading pieces of NetBSD source code.
(for whoever is interested, it's < Code Reading: The Open Source Perspective > I'm reading)
And I found this function:
/* convert IP address to a string, but not into a single buffer
*/
char *
naddr_ntoa(naddr a)
{
#define NUM_BUFS 4
static int bufno;
static struct {
char str[16]; /* xxx.xxx.xxx.xxx\0 */
} bufs[NUM_BUFS];
char *s;
struct in_addr addr;
addr.s_addr = a;
strlcpy(bufs[bufno].str, inet_ntoa(addr), sizeof(bufs[bufno].str));
s = bufs[bufno].str;
bufno = (bufno+1) % NUM_BUFS;
return s;
#undef NUM_BUFS
}
It introduces 4 different temporary buffers to wrap inet_ntoa function since inet_ntoa is not re-entrant.
But seems to me this naddr_ntoa function is also not re-entrant:
the static bufno variable can be manipulated by other so the temporary buffers do not seem work as expected here.
So is it a potential bug?
Yes, this is a potential bug. If you want a similar function that most likely reentrant you could use e.g. inet_ntop (which incidentally handles IPv6 as well).
That code comes from src/sbin/routed/trace.c and it is not a general library routine, but just a custom hack used only in the routed program. The addrname() function in the same file makes use of the same trick, for the same reason. It's not even NetBSD code per se, but rather it comes from SGI originally, and is maintained by Vernon Schryver (see The Routed Page).
It's just a quick hack to allow use of multiple calls within the same expression, such as where the results are being used in one printf() call: E.g.:
printf("addr1->%s, addr2->%s, addr3->%s, addr4->%s\n",
naddr_ntoa(addr1), naddr_ntoa(addr2), naddr_ntoa(addr3), naddr_ntoa(addr4));
There are several examples of similar uses in the routed source files (if.c, input.c, rdisc.c).
There is no bug in this code. The routed program is not multi-threaded. Reentrancy is not being addressed at all in this hack. This trick has been done by design for a very specific purpose that has nothing to do with reentrancy. The Code Reading author(s) is wrong to associate this trick with reentrancy.
It's simply a way to hide the saving of multiple results in an array of static variables instead of having to individually copy those results from one static variable into separate storage in the calling function when multiple results are required for a single expression.
Remember that static variables have all the properties of global variables except for the limited scope of their identifier. It is of course true that unprotected use of global (or static) variables inside a function make that function non-reentrant, but that's not the only problem global variables cause. Use of a fully-reentrant function would not be appropriate in routed because it would actually make the code more complex than necessary, whereas this hack keeps the calling code clean and simple. It would though have been better for the hack to be properly documented such that future maintainers would more easily spot when NUM_BUFS has to be adjusted.
I have the following structure:
struct sys_config_s
{
char server_addr[256];
char listen_port[100];
char server_port[100];
char logfile[PATH_MAX];
char pidfile[PATH_MAX];
char libfile[PATH_MAX];
int debug_flag;
unsigned long connect_delay;
};
typedef struct sys_config_s sys_config_t;
I also have a function defined in a static library (let's call it A.lib):
sys_config_t* sys_get_config(void)
{
static sys_config_t config;
return &config;
}
I then have a program (let's call it B) and a dynamic library (let's call it C). Both B and C link with A.lib. At runtime B opens C via dlopen() and then gets an address to C's function func() via a call to dlsym().
void func(void)
{
sys_get_config()->connect_delay = 1000;
}
The above code is the body of C's func() function and it produces a segmentation fault when reached. The segfault only occurs while running outside of gdb.
Why does that happen?
EDIT: Making sys_config_t config a global variable doesn't help.
The solution is trivial. Somehow, by a header mismatch, the PATH_MAX constant was defined differently in B's and C's compilation units. I need to be more careful in the future. (facepalms)
There is no difference between the variable being a static-local, or a static-global variable. A static variable is STATIC, that means, it is not, on function-call demand, allocated on the stack within the current function frame, but rather it is allocated in one of the preexisting segments of the memory defined in the executable's binary headers.
That's what I'm 100% sure. The question, where in what segment they exactly placed, and whether they are properly shared - is an another problem. I've seen similar problems with sharing global/static variables between modules, but usually, the core of the problem was very specific to the exact setup..
Please take into consideration, that the code sample is small, and I worked on that platforms long time ago. What I've written above might got mis-worded or even be plainly wrong at some points!
I think, that the important thing is that you are getting that segfault in C when touching that line. Setting an integer field to a constant could not have failed, never, provided that target address is valid and not write-protected. That leaves two options:
- either your function sys_get_config() has crashed
- or it has returned an invalid pointer.
Since you say that the segfault is raised here, not in sys_get_config, the only thing left is the latter point: broken pointer.
Add to the sys_get_config some trivial printf that will dump the address-to-be-returned, then do the same in the calling function "func". Check whether it not-null, and also check if within sys_get_config it is the same as after being returned, just to be sure that calling conventions are proper, etc. A good idea for making a double/triple check is to also add inside the module "A" a copy of the function sys_get_config (with different name of course), and to check whether the addresses returned from sys_get_config and it's copy are the same. If they are not - something went very wrong during the linking
There is also a very very small chance that the module loading has been deferred, and you are trying to reference a memory of a module that was not fully initialized yet.. I worked on linux very long time ago, but I remember that dlopen has various loading options. But you wrote that you got the address by dlsym, so I suppose the module has loaded since you've got the symbol's final address..
I'm programming (and indeed close to completing) a CLI program to test the user on vocabulary, or indeed any set of questions and responses he/she would care to define.
Full source on github: https://github.com/megamasha/Vocab-Tester
Loading from a file and saving to a file are handled from separate functions, both outside of main(). At the moment they're in the same source file, but I'd like to know how to do this both a) within the file, and b) in the case that they end up in a separate database ops file.
I want to allow the user to save to the file he most recently loaded, so I want my loaddatabase() function to define a global char * to the filename, which the savedatabase() function can then access.
If I declare a char * outside of any function, it is read-only and trying to write a filename to it causes a segfault.
If I declare it within the loaddatabase() function, savedatabase() can't access it.
Will declaring the variable static allow other functions to access it, or if not, how can I allow two functions to access the same char *?
You can define a global variable by defining it in a single .c file:
char * database;
And by declaring it in a .h file:
extern char * database;
And by including the .h file in every file that uses the variable.
The extern keyword declares the variable without defining it. It says the compiler that the variable exists in an other file.
So for your problem, you can define char * database in the file of your load/save functions, and declare it (extern char * database) in the file of your main function.
You can do the same thing with char database[1024] instead of char * database if you don't want to bother allocating and freeing memory for the filename. This way you can directly write to database.
You need to declare a character array, i.e. char filename[260].