0

How can I achieve or emulate private access behavior under ANSI C (that is only code from my software module can call functions "successfully"), when "static" declaration is not an option?

Background:

I am in a strange situation.

I have to develop a big software module, which operates as an abstraction on a huge number of inputs (some thousand) to our software, presented by access functions — I will call them signals further. The module does some similar mapping operations on most of these signals, like changing the representation from integer to float, changing physical units or remap nominal values to other ones — depending on semantics and nature of the signals. Also some validations (like input set/range checks) are done signal-wise, and some common error validation is also done for signals and groups of them (return values of the access functions).

Now our test department wants to test small groups of the functionality — the units(tm) — like for every input-signal-group, and of course testing input routines, mapping routines and regrouped output-routines individually from each other, which totally makes sense.

But due to rigid rules on what is tested, each testable unit must be represented as its own C object and tested as we will ship it. To allow this, any of the input, mapping and output routines need external interfaces. And we ship a library to be integrated in a bigger software system.

Now, any input and output-routine is highly special (to some degree) as it calls specific access routines; any mapping routine is highly special (to some degree) as it provides the (general) mapping with signal specific magic numbers ;and so on. To have more fun, the special I/O routines (and the used access routines) are not (under all conditions) reentrant. So ... these functions MUST be called (always) in a certain way by my module, and MUST NOT under any circumstances be called by any other part of the software.

How can I provide some safety and encapsulation for these functions, although a "static" declaration of the functions is not possible, because of the test procedures, and my requirements document says it is my job to ensure calling correctness.

Any ideas?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Mark A.
  • 579
  • 4
  • 13
  • declaring a function static make this function only access able from code that is within the same compilation unit, as it renders the function internal. This is as near a I can get to private functions in C, without doing some runtime stuff (AFAIK). – Mark A. May 03 '15 at 14:58
  • See [How do you unit test private methods?](http://stackoverflow.com/questions/250692) and [How to test a `static` function?](http://stackoverflow.com/questions/593414). However, it may be that the rules that are imposed are going to impede any such attempt to enforce access control — the functions that should not be accessed should be `static` but your testing rules may make that nearly impossible. They're too rigid. Testing the sub-groups separately isn't something that's going to happen in the release product; the testing requirement is different, and you can use other techniques. – Jonathan Leffler May 03 '15 at 15:02
  • Yes, I had some fights on this requirement already... the key argument is, that the testable units should be the same .obj-objects on unit-test level, as when the software is integrated to ensure that the target compiler in the target environment does not do bad stuff. And what the compiler does, depends on surrounding code. I already use the methods similar to the ones described in the related questions for developer tests. – Mark A. May 03 '15 at 15:14
  • To what extent is the testing department an adversary and to what extent are they allies? Are they going to directly call any and every externally visible function? Have you considered doing what SQLite does: package all the code for your module into a single humungous source file so that only the required external entry points are visible? That's what's going to be shipped so that external users can't abuse the internals, so that's what should be tested. Indeed, is what you're shipping going to be a library for external users, or part of an executable which external users can't modify? – Jonathan Leffler May 03 '15 at 15:15
  • 1
    Another option to consider is making the functions static, but providing pointers to those functions via structures. Those structures may themselves be static but obtainable by calling a suitable publicly accessible function. Your code can then present visibly only those functions that should be visible; you can access the other functions via function pointer when necessary. – Jonathan Leffler May 03 '15 at 15:17
  • Thank you Jonathan for the fast answers. Our interface to the software integrator is a well defined set of function to be called, and we are totally sure, that the integrator does not senselessly experiments just with every extern symbol only because it exists. However, functional safety agreements forcing us to ensure this, and testing has (also because of safety requirements) very strict requirements on handling the test subjects. We are quite a paranoid bunch. Your idea with the presented pointer sounds as a way. I will think about this. – Mark A. May 03 '15 at 15:22
  • Hmm... maybe I provide just every function with an unit32_t parameter, explicitly asking for a defined number, and if not provided by the caller, the function just does nothing but returning an error, at least for the not reentrant I/O. – Mark A. May 03 '15 at 15:28
  • #ifdef TEST #define STATIC #else #define STATIC static #endif; STATIC int f(...), compile tests with -DTEST. – user3125367 May 03 '15 at 15:50
  • The question is quite complete and thorough, btw. Fixed someone's downvote. – user3125367 May 03 '15 at 15:55
  • Thank you, user3125367. Well, this would not work, as the function shall be tested not "on code level" (do I have used C in the right way, and have I expressed the things I wanted to express, and does the compiler the right thing in the easy case), but in the state as it will be shipped ("Does the compiler do its job in this case"), (hoping the linker don't do horrible things). The compiler will generate different binary code, depending on the #define. However your method works fine for developer tests and normal levels of paranoia. – Mark A. May 03 '15 at 15:58
  • I know this may be law's letter vs spirit, but as last resort I'll try to suggest this: http://stackoverflow.com/questions/435352/limiting-visibility-of-symbols-when-linking-shared-libraries – user3125367 May 03 '15 at 16:11
  • ... I think you may inverse the solution, not hiding symbols after the test, but unhiding them *before/for* tests, leaving hidden otherwise. Idk whether it is possible with explicit statics at all though. – user3125367 May 03 '15 at 16:18
  • Hmm... that sounds possible. I have to check, if we can/may deliver a linked lib instead of objects, and if the target compiler provides an easy way to export only the agreed interface. Given that, I can completely fulfill both requirements according to the letter. And internally we will ensure calling correctness by reviews. Thx @user3125367. Do you like to provide this as answer? It seems correct enough regarding my questions background. – Mark A. May 03 '15 at 17:48
  • I'll upvote your efforts if you post back, too lazy myself. – user3125367 May 03 '15 at 19:13

1 Answers1

1

There is no way to strictly define a private / public function or variable in C. What you can do is either to "hide" some information or to define a function or a variable as static.

A way to hide the information is to have a header my_object.h like:

typedef struct my_object_struct my_object_t;

my_object_t * my_object_new(...);
void my_object_free(my_object_t * my_object);
type my_function1(my_object_t * my_object, ...)
type my_function2(my_object_t * my_object, ...)

And the implementation in a file my_object.c:

struct my_object_struct{
    type some_var
    type some_var2
    ...
};

struct some_hidden_state{
    ...
};

type __my_hidden_function(my_object_t * my_object, struct some_hidden_state * state, ...){

}

my_object_t * my_object_new(...){
    ...
}

void my_object_free(my_object_t * my_object){
    ...
}

type my_function1(my_object_t * my_object, ...){
    ...
}

type my_function2(my_object_t * my_object, ...){
    ...
}

The only visible way to create a my_object_t object is to use my_object_new, and its internal variables would be hidden (not to a debbuger though).

This way my_hidden_function and my_hidden_state are not visible but someone could still use the extern keyword and the correct prototype to use them; the only way to strictly encapsulate them is to use static.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
OAnt
  • 131
  • 1
  • 4
  • 1
    I think it's worth emphasizing that the header file **is the interface** provided to the external parties and they have no access to the rest of source code, only to the binaries (compiled or compiled and linked) – SomeWittyUsername May 03 '15 at 15:09