bug-make
[Top][All Lists]
Advanced

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

[bug #64295] Detect plugin binary compatibility at load time


From: Dmitry Goncharov
Subject: [bug #64295] Detect plugin binary compatibility at load time
Date: Sun, 11 Jun 2023 10:44:48 -0400 (EDT)

Follow-up Comment #1, bug #64295 (project make):

This patch implements make abi versioning for loadable plugins.

The proposed patch is binary compatible with existing plugins.
This patch allows make to detect if a plugin is binary compatible and exit
with an error in the case of a binary incompatible plugin.

The patch embeds the version of make abi to the plugin in the form of a strong
symbol at build time.
Then at load time make can know which version of abi each plugin was built
with.  This allows make to compare the needed abi version against its
load-time version and exit with an error message, if the pluging was built
with an incompatible version.

The patch sets the initial version of make abi to 1.0.

Suppose have mk_temp.so plugin built with make abi 1.0.


$ ls
makefile  mk_temp.c
$ cat mk_temp.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include <gnumake.h>
#include <gnumake_abi_version.h>

int plugin_is_GPL_compatible;

struct tmpfile {
  struct tmpfile *next;
  char *name;
};
static struct tmpfile *files = NULL;

static char *
gen_tmpfile(const char *nm, unsigned int argc, char **argv)
{
  int fd;

  /* Compute the size of the filename and allocate space for it.  */
  int len = strlen (argv[0]) + 6 + 1;
  char *buf = gmk_alloc (len);

  strcpy (buf, argv[0]);
  strcat (buf, "XXXXXX");

  fd = mkstemp(buf);
  if (fd >= 0)
    {
      struct tmpfile *new = malloc (sizeof (struct tmpfile));
      new->name = strdup (buf);
      new->next = files;
      files = new;

      /* Don't leak the file descriptor.  */
      close (fd);
      return buf;
    }

  /* Failure.  */
  fprintf (stderr, "mkstemp(%s) failed: %s\n", buf, strerror (errno));
  gmk_free (buf);
  return NULL;
}
int
mk_temp_gmk_setup (unsigned int abi, const gmk_floc *floc)
{
  printf ("mk_temp plugin abi %u loaded from %s:%lu, needed abi %d.%d\n",
          abi, floc->filenm, floc->lineno, GMK_ABI_VERSION, GMK_ABI_AGE);
  /* Register the function with make name "mk-temp".  */
  gmk_add_function ("mk-temp", gen_tmpfile, 1, 1, 1);
  return 1;
}

void
mk_temp_gmk_unload ()
{
  while (files)
    {
      struct tmpfile *f = files;
      files = f->next;
      printf ("mk_temp removing %s\n", f->name);
      remove (f->name);
      free (f->name);
      free (f);
    }
  printf ("mk_temp plugin closed\n");
}

$ cat makefile
all:
        @echo Temporary file: $(mk-temp tmpfile.)
        @echo Temporary file: $(mk-temp tmpfile.)

-load mk_temp.so

mk_temp.so: mk_temp.c;  $(CC) -I ~/src/gmake/make/src -shared -fPIC -o $@ $^

$ make
cc -I ~/src/gmake/make/src -shared -fPIC -o mk_temp.so mk_temp.c
mk_temp plugin abi 1 loaded from makefile:5, needed abi 1.0
Temporary file: tmpfile.Uh53l3
Temporary file: tmpfile.7EQCH3
mk_temp removing tmpfile.7EQCH3
mk_temp removing tmpfile.Uh53l3
mk_temp plugin closed
$


The plugin included gnumake_abi_version.h.
mk_temp_gmk_setup uses macros GMK_VERSION, GMK_AGE.

Then we keep mk_temp.so intact and introduce a compatible change to make abi
and set the version to 2.1 and rebuild make.
At load time make reads 1.0 from mk_temp.so and compares its current abi 2.1
against 1.0 and proceeds with loading the plugin.


$ make --debug=v |tail -17
Loading symbol mk_temp_gmk_setup from mk_temp.so
Loaded shared object mk_temp.so
Make abi 2.1, mk_temp.so needed abi 1.0
Detected symbol mk_temp_gmk_unload in mk_temp.so
mk_temp plugin abi 2 loaded from makefile:5, needed abi 1.0
Updating makefiles....
Updating goal targets....
Considering target file 'all'.
 File 'all' does not exist.
Finished prerequisites of target file 'all'.
Must remake target 'all'.
Temporary file: tmpfile.mKD3cK
Temporary file: tmpfile.0fr5VI
Successfully remade target file 'all'.
mk_temp removing tmpfile.0fr5VI
mk_temp removing tmpfile.mKD3cK
mk_temp plugin closed
$



Now we introduce an incompatible change to make abi and set the version to 3.0
and rebuild make.
At load time make reads 1.0 from mk_temp.so and compares 3.0 against 1.0 and
exits with an error message.


$ make --debug=v 2>&1 |tail -6
Reading makefiles...
Reading makefile 'makefile'...
Loading symbol mk_temp_gmk_setup from mk_temp.so
Loaded shared object mk_temp.so
Make abi 3.0, mk_temp.so needed abi 1.0
makefile:5: *** mk_temp.so needed abi 1.0 is incompatible with make abi 3.0. 
Stop.


Tested on sunos (32 and 64 bit), linux (32 and 64 bit) and aix (64 bit).



    _______________________________________________________

Reply to this item at:

  <https://savannah.gnu.org/bugs/?64295>

_______________________________________________
Message sent via Savannah
https://savannah.gnu.org/




reply via email to

[Prev in Thread] Current Thread [Next in Thread]