I'm trying to understand how extern variables work when using dynamic linking and dynamic loading of shared libraries, and whether or not a large codebase that I've inherited could have problems in it. Unfortunately I cannot share code from this codebase, and wish to figure out if there's a specific issue here. I would like to know if a variable that is part of a shared library can be mutated from multiple processes that dynamically loads the shared library.
This is the main.c file.
// main.c
#include <stdio.h>
#include <unistd.h>
#include "foo.h"
int main(void)
{
while(1){
printf("Value = %d\n", global);
foo();
}
return 0;
}
This is the foo.c file.
// foo.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int global = 0;
void foo(void)
{
global = global + 1;
sleep(1);
}
and this is the foo.h file.
// foo.h
#ifndef foo_h__
#define foo_h__
extern void foo(void);
extern int global;
#endif // foo_h__
This is the Makefile for compiling this program.
# Makefile
all: main
main:
gcc -c -Wall -Werror -fpic foo.c
gcc -shared -o libfoo.dylib foo.o
gcc -Wall -o test main.c -lfoo -L.
Since the global
variable has an extern definition, and since a shared library is created, I was expecting that code would break when run across multiple processes. However, if I open two terminals and run ./test
in both of them simultaneously, the counter increments independently and correctly (no common shared memory). I'm glad this is how it works, but I'm curious if there's a way to break this? Reading through these answers [1-2], I thought that the shared libraries memory was loaded just once into the virtual memory space and I was under the assumption that the above code would not work, i.e. when starting the second process the first process would reset back to zero. How do I force this code above to increment the value in the same memory address in different processes? Is this possible at all?