Passing an array to a function which expects constant array elements

In C, I recently wanted to pass a pointer to an array of chars to a function, and since the function is not allowed to modify the array contents, I declared it as const. The rationale behind this is

char (*param)[20];

defines a pointer param to an array of non-constant chars, and

const char (*param)[20];

defines a pointer param to an array of constant chars. So, the straight forward definition of the function looked like this, and I also verified that the compiler properly catches attempts to write to the array elements:

void f(const char (*param)[20]) {
   /* (*param)[2] = 'A'; */ /* correctly catched by the compiler: assignment of read-only location '(*param)[2]' */
}

Then, I wanted to call the function as follows:

int main() {
   char (*data)[20] = calloc(20, 1);

   f(data);

   return 0;
}

But, I got the following warning when compiling this code:

$  gcc -Wall -pedantic -o so so.c
so.c: In function 'main':
so.c:15:4: warning: passing argument 1 of 'f' from incompatible pointer type [enabled by default]
    f(data);
    ^
so.c:3:6: note: expected 'const char (*)[20]' but argument is of type 'char (*)[20]'
 void f(const char (*param)[20]) {
      ^

Why does this happen? It should be possible to pass a pointer to any non-const data to a function which expects a pointer to const data – this is for example the way how the standard string functions are declared, like strcpy(). The source parameter is a const char*, but we can pass both a pointer to const or to non-const data. As long as the called function does not modify the contents the pointer points to, this should work well. While trying to understand why the above does not work, it turned out that “this is how C works”, and the GCC FAQ explains it: T (*)[n] is not assignment compatible to const T (*)[n] (note though that T* would be assignment compatible to const T* as described above). The C FAQ (if the site is down, use something like https://archive.today/mGvX7 instead) boils this down to the fact that it is not allowed to assign a char** pointer to a const char** pointer. It is only allowed for simple pointers to data (as in the strcpy() example above), but not for pointers to pointers (at any level, recursively). The FAQ also lists the steps which show how the unmodifiable data could be modified without using an explicit cast if this was allowed. Hence the reason that the compiler correctly prints this warning.

Solutions

The simplest solution is to remove the const from the function’s parameter list. However, this would not allow the compiler to catch write access to the array within the function anymore. If we want to keep the const, we need to cast when calling the function (but explicit casts especially between non-const and const usually indicates other deeper issues, so this should be avoided). A much better solution is to wrap the array in a structure. With this approach, it is possible to keep the const so that the compiler catches modifications of the array, and the function can be called without warning. The drawback is that accessing the data inside the function requires a bit more effort to reference the array structure member:

#include <stdlib.h>

typedef struct _arr11 { char data[11]; } arr11;

void f(const arr11* param) {
   /* error: assignment of read-only location 'param->data[3]' */
   /* param->data[3] = 'A';*/
}

int main() {
   arr11* data = calloc(sizeof(arr11), 1);

   f(data);    /* No warning! */

   return 0;
}

JCA code sample: encrypting data with AES

The following code fragments show how a text can be encrypted and decrypted with the JCA (Java Cryptography Architecture) API using the AES cryptographic algorithm. Lets assume that we have a text which we want to encrypt, and also a key which we want to use for the encryption (remember that AES is a symmetric encryption algorithm, so the same key is used for both encryption and decryption):

String text = "Sample String which we want to encrypt";
String key = "Bar12345Bar12345";

The first thing we need to do is to get the cipher (the cryptographic algorithm) we want to use, and we also need to create a Key which represents our String-based key we defined above so that it can be used in JCE API calls. Cryptographic algorithms are normally working on binary data, so we also need to get the binary representation of the key first, using an appropriate character set:

Cipher cipher = Cipher.getInstance("AES");
Key aesKey = new SecretKeySpec(key.getBytes(StandardCharsets.ISO_8859_1), "AES");

The Key class has a method getEncoded() which returns the binary representation of the key as a byte[] array. We can use this method do print a hexadecimal dump of the key, and we will get the following output:

0000: 42 61 72 31 32 33 34 35 42 61 72 31 32 33 34 35  Bar12345Bar12345

Note that the key which we created is exactly 16 bytes = 128 bits long. This is the minimum key size supported by AES – and with a default JDK installation, we can not use larger keys. See … for more information how to use larger keys (192 bit and 256 bit). Next, we also need to get the binary representation of the text we want to encrypt, so that it can be fed into the encryption algorithm:

byte[] plaintext = text.getBytes(StandardCharsets.ISO_8859_1);

The dump of the plaintext data looks like this:

0000: 53 61 6D 70 6C 65 20 53 74 72 69 6E 67 20 77 68  Sample String wh
0010: 69 63 68 20 77 65 20 77 61 6E 74 20 74 6F 20 65  ich we want to e
0020: 6E 63 72 79 70 74                                ncrypt

Now, we can use the Ciper.doFinal() method to encrypt the whole plaintext:

cipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] ciphertext = cipher.doFinal(plaintext);

The dump of the ciphertext (which is the encrypted data) looks like this:

0000: 29 0F 31 B5 7E D4 BD 02 69 8E C3 8E 87 C9 8A 4A  ).1µ~Ô½.i?Ã??É?J
0010: 2D C6 FB F9 E8 4E C9 F7 34 61 33 9B 46 27 57 49  -ÆûùèNÉ÷4a3?F'WI
0020: 31 44 53 5B 58 C6 1F 8A 99 A0 F5 18 5C EB 6A 05  1DS[XÆ.?? õ.\ëj.

One thing to mention is that the length of the ciphertext has been extended to a multiple of 128 bits – this is the block size which AES is using. Now we can use the ciphertext and decrypt it using the original key:

cipher.init(Cipher.DECRYPT_MODE, aesKey);
byte[] decrypted = cipher.doFinal(ciphertext);

The hexadecimal dump of the decrypted array shows that the data has been properly decrypted:

0000: 53 61 6D 70 6C 65 20 53 74 72 69 6E 67 20 77 68  Sample String wh
0010: 69 63 68 20 77 65 20 77 61 6E 74 20 74 6F 20 65  ich we want to e
0020: 6E 63 72 79 70 74                                ncrypt

The complete runnable sample is available at https://github.com/afester/CodeSamples/blob/master/Java/JCE/src/com/example/AESSample.java.

Google Chrome developer tip: extended reload button

When the “Developer Tools” console is open in Google Chrome, the reload button gets a drop down menu with some options which are quite useful when developing web applications:

  • Normal Reload: just reload the page, same as F5
  • Hard reload: reload the page, but do not use anything from the cache for this request
  • Empty Cache and Hard Reload: Empty the cache and reload (which is implicitly a hard reload then, since the cache is empty)
To actually open the menu, it is necessary to press and hold the reload button a short time, similar to the “back” button where chrome displays a page history then. Also, the functionality is only available when at the same time the developer console is open for the specific page – the developer console can be opened by pressing F12. See also What’s the difference between “Normal Reload”, “Hard Reload”, and “Empty Cache and Hard Reload” in chrome? for some additional information.

About the scope of definition objects

In Oracle ADF, each definition object (those objects which are used as the templates for actual objects) has a scope which can be either session based or application based (shared between sessions). The following diagram shows a rough (and probably somewhat incomplete) overview of the runtime structure of some of the most common objects (Entity object, View object, Application Module) and their corresponding definition objects:

Creating definition objects

Essentially, there are two possible ways how to create a definition object:

  • From an .xml file, as shown on the left side of the diagram. This is what the framework does automatically in the background. Each of the definition objects has a protected static loadFromXML() method which is used by the framework to load the corresponding .xml file.
  • Programmatically by calling the default (or single parameter name) constructor of a definition object, as shown on the right side of the diagram.
The important thing is: When the framework creates a definition object, it has application scope, and thus is shared between sessions. If the application modifies such a definition object, it has an impact on all objects which are derived from it afterwards! For example, if an application changes the query string of a ViewDefImpl object which has application scope, all ViewObjectImpl objects which will be created afterwards will inherit this changed query string. When creating a definition object programmatically, the scope can usually be defined by one of the constructor parameters. However, the general guideline in ADF is to use either the default constructor or the constructor which takes a single name parameter – these constructors ensure that the definition object has session scope.

The meta object manager

When a new definition object has been created, it should be registered with the meta object manager so that it can be looked up by its name later. This is done by calling the registerDefObject() method on the definition object:

ViewDefImpl mydef = new ViewDefImpl("view.DataVO");
...
mydef.registerDefObject();

The meta object manager is an application wide singleton, and it has a method dumpMOM() which can be used to dump the definition objects which are currently registered:

MetaObjectManager mom = MetaObjectManager.getSingleton(); 
mom.dumpMOM(new PrintWriter(System.err), true);

<< Shared DefinitionContext >>
-- oracle.jbo.mom.DefinitionContextAgeable.dumpMOM --
...
<< Session DefinitionContext >>
-- oracle.jbo.mom.DefinitionContextAgeable.dumpMOM --
...

Note that the parameter-less dumpMOM() overload prints to System.out, which might overlap with other ad-hoc debug output on System.err you might be using in your test application (you would never use System.out or System.err in production code anyway). Internally, the meta object manager uses entries in the ADFContext‘s applicationScope and sessionScope maps – so it is capable of managing session specific objects even though itself it is an application singleton.

Conclusion

When modifying definition objects at runtime, make sure that you are not modifying application scoped definition objects (unless your intention is that all objects in all sessions derived afterwards will inherit this modification). Instead, programmatically create a session scoped definition object, or use the instance specific methods for the modifications. For example, instead of modifying or creating a new ViewDefImpl object with a specific query string and then create a ViewObjectImpl based on it, it is also possible to set the query string directly on the ViewObjectImpl itself – it then only affects this particular view object instance.