4

In linux kernel (version 4.8), "struct pid" is defined as following (from file: http://lxr.free-electrons.com/source/include/linux/pid.h). Here "numbers[1]" (at line 64) is a static array which can have only one element (because of array size is mentioned as 1).

 57 struct pid
 58 {
 59         atomic_t count;
 60         unsigned int level;
 61         /* lists of tasks that use this pid */
 62         struct hlist_head tasks[PIDTYPE_MAX];
 63         struct rcu_head rcu;
 64         struct upid numbers[1];
 65 };

But then, in the following code at line 319 and 320 (from file: http://lxr.free-electrons.com/source/kernel/pid.c), array "numbers" is inside a for loop as 'numbers[i]'. How is it even correct because variable 'i' cannot have any value other than zero without causing segmentation fault? I have checked the value of 'i' during the loops to see if it ever goes more than 1. Yes it goes but still i don't see any segmentation fault. Am i missing something here?

297 struct pid *alloc_pid(struct pid_namespace *ns)
298 {
299         struct pid *pid;
300         enum pid_type type;
301         int i, nr;
302         struct pid_namespace *tmp;
303         struct upid *upid;
304         int retval = -ENOMEM;
305 
306         pid = kmem_cache_alloc(ns->pid_cachep, GFP_KERNEL);
307         if (!pid)
308                 return ERR_PTR(retval);
309 
310         tmp = ns;
311         pid->level = ns->level;
312         for (i = ns->level; i >= 0; i--) {
313                 nr = alloc_pidmap(tmp);
314                 if (nr < 0) {
315                         retval = nr;
316                         goto out_free;
317                 }
318 
319                 pid->numbers[i].nr = nr;
320                 pid->numbers[i].ns = tmp;
321                 tmp = tmp->parent;
322         }
psin
  • 59
  • 8
  • 1
    it's not "correct" as far as the C standard is concerned, but that is of little interest to Linux kernel developers. It probably "works" for them. (The backing memory is allocated dynamically of course.) C99 supports this construction properly with `numbers[]`, but Linux doesn't use C99.) – Kerrek SB Dec 11 '16 at 00:14
  • Hi Kerrek, thanks for your quick reply. If it is not correct, then why does it not give any seg fault? – psin Dec 11 '16 at 01:17
  • @psin: Nothing in C guarantees you a segfault. An incorrect program can happen to behave as expected. The code will presumably be built only with tools that are known to behave as intended. – Kerrek SB Dec 11 '16 at 02:20
  • 1
    The technique shown is the 'struct hack' which was rendered unnecessary by the addition of _flexible array members_ to C99. It was never guaranteed to work by the standard, but was widely used so compilers didn't see fit to break code using it. See [Struct Hack](http://wiki.c2.com/?StructHack), [Struct Hack](http://www.geeksforgeeks.org/struct-hack/) for a 0-size array variant, and [C struct hack at work](http://stackoverflow.com/questions/16553542/c-struct-hack-at-work). – Jonathan Leffler Dec 11 '16 at 20:09

1 Answers1

0

Is it possible to have number of elements in an array more than array's size which is defined at compile time?

Yes. It is call undefined behavior and code should not be written to allow that.

How is it even correct because variable 'i' cannot have any value other than zero without causing segmentation fault?

It is possible; because code broke the contract. Writing outside an array's bounds may work. It may crash the program. It is undefined behavior.


C is not specified to prevent array access outside its bounds nor cause a seg fault. Such an access may be caught or not. Code itself needs to be responsible for insuring access is within bounds.
There are no training wheels and few safety nets specified in C

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Thanks chux. I find it hard to comprehend that kernel mainline stable code is buggy. In kernel version 3.16, the array "numbers" was declared as "numbers[0]" which is an array with no elements allowed and yet it was used to access the elements in that array. Is "numbers" being used as struct pointer instead of a static struct array? – psin Dec 11 '16 at 01:29
  • An array `numbers[0]` is not portable C. Typically the memory for `struct pid` is allocated with additional memory to allow the last field (an array) more than 1 element, up to the needed size. A more modern way is to use a _flexible array_ . See http://stackoverflow.com/q/11733981/2410359 This is likely more of what is happening rather than incorrect kernel code. – chux - Reinstate Monica Dec 11 '16 at 01:41
  • ... or http://stackoverflow.com/q/14643406/2410359 – chux - Reinstate Monica Dec 11 '16 at 01:47
  • 1
    adding this related link to help with array size 1. http://stackoverflow.com/questions/16553542/c-struct-hack-at-work – psin Dec 11 '16 at 03:51