Re: variable length array (VLA) reference (global, extern access, etc)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 7/8/19 9:37 AM, phi gcc wrote:
> Hi All,
> 
> I have a need for a VLA reference to be saved globally so unrelatted
> functions could retrieve the VLA global ref (dim values along with scalar
> addr of the 1st array element) and could then 'construct' its own VLA for
> an 'elegant' multi-dimensional array access.
> 
> While storing a VLA reference a relativly easy (store the addr of
> a[0][0]... or simply &a), declaring a VLA in an unrelated function is more
> tricky but doable. I wanted to know if there is a way with gcc to kind of
> change a VLA base addr dynamically through an API.
> 
> I presented a solution I found to fit my need, that is sharing a
> multi-dimentional array between main() VLA creation, and init, then VLA
> reference publishing in the global scope, and finally spawing threads that
> can use the global VLA ref to setup their own VLA, all accessing the same
> VLA from main(). I ignored the synchro/cache access on purpose in the
> example because it is not relevant for the demo.
> 
> https://stackoverflow.com/questions/10360394/declaring-a-variable-length-array-as-a-global-variable-in-c/56924075#56924075
> 
> The code is like this /* (*N) */ are reference to comment I provide in the
> above document.
> 
> 
> #include <pthread.h>
> #include <stdio.h>
> #include <stdlib.h>
> 
> int gn, gm, *ga;                                                 /* (*2) */
> 
> void worker(int tndx, long n, long m, int a[n][m])               /* (*6) */
> { long *np=&n, *mp=&m, i=mp-np, *ap=mp+i;                        /* (*7) */
> 
>   *ap=(long)ga;
>   /* At this oint the worker can elegantly access the global dyn array.
>    * elegantly mean through a[i][j].
>    */
>   printf("worker %d started\n", tndx);
>   for(int j=0;j<m;j++)
>   { a[tndx][j]+=(tndx*1000);                                     /* (*8) */
>   }
> }
> 
> void *init_thread(void *v)
> { int x[1][1], tndx = (int)(long)v;                              /* (*4) */
>   printf("thread #%d started\n", tndx);
>   worker(tndx, (long)gn, (long)gm, x);                           /* (*5) */
> }
> 
> int main(int ac, char **av)
> { int n=atoi(av[1]), m=atoi(av[2]);
>   pthread_t tt[n];  /* thread table */                           /* (*1) */
>   int a[n][m];      /* dyn array    */                           /* (*1) */
> 
>   gn=n, gm=m, ga=&a[0][0]; /* globals setup shared by workers */ /* (*2) */
>   for(int i=0, k=0;i<n;i++)for(int j=0;j<m;j++)a[i][j]=k++;      /* (*3) */
> 
>   printf("Init  a[][]\n");
>   for(int i=0, k=0;i<n;i++)for(int j=0;j<m;j++)
>     printf("a[%d][%d]=%d\n",i,j,a[i][j]);
>   for(int i=0;i<n;i++)
>   { if(pthread_create(&tt[i], NULL, init_thread, (void *)(long)i))
>     { exit((printf("pthread_create %d failed\n",i),1));
>     }
>   }
>   printf("Draining threads\n");
>   for(int i=0;i<n;i++)
>   { pthread_join(tt[i],0);
>   }
>   printf("Final a[][]\n");
>   for(int i=0, k=0;i<n;i++)for(int j=0;j<m;j++)
>     printf("a[%d][%d]=%d\n",i,j,a[i][j]);
>   pthread_exit(NULL);
> }
> 
> So you see in the above example, I use a 'tiny' or 'moderate' hack to patch
> the base addr of the threads VLA, doing trivial stack inspection and patch.
> 
> So my question is about avoiding the hack, is there a way to have a
> gcc/glibc API to actually set the base addr of a VLA dynamically assuming
> the user knows what she is doing?
> 
> WIthout an API, at the compiler level accepting a cast like (int[*][*])
> could do the job, basically it would be identical to int* but would make
> the cast possible removing the need for base addr patch and the dummy array
> x[1][1] in my example the code would become
VLAs are allocated on the current function's stack and using them after
the current function returns is undefined behavior.  It will likely work
for toy programs, but it'll break in the real world at some point
because the stack space will end up being used for other objects,
clobbering the data you expect to find there.

Also note that you need to be more careful with shared objects in
multi-threaded programs.  You probably want to read-up on the C11/C++11
memory model and atomics.  Again, what you're doing will likely work
with toys, but will eventually break in the real world.


jeff





[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux