Exercise the dynamic loading/unloading of libraries a bit more.
authorKen Raeburn <raeburn@mit.edu>
Wed, 9 Feb 2005 00:50:50 +0000 (00:50 +0000)
committerKen Raeburn <raeburn@mit.edu>
Wed, 9 Feb 2005 00:50:50 +0000 (00:50 +0000)
Athena's old IRIX systems fail this test now.

* t_loader.c (verbose): New variable.
(do_close_1): Drop filename argument.  Change messages accordingly, and only
display them if verbose.  Line up "done" messages vertically.
(do_open_1): Likewise.  Add library version argument, used when on AIX, in
combination with RTLD_MEMBER.
(do_open): Don't pass filename.  Do pass library version; callers changed.
(do_close): Don't pass filename.
(get_sym_1): Renamed from get_sym, added line number argument.  Print messages
if verbose.
(get_sym): New macro.
(xbasename): Function deleted.
(HORIZ): New macro.
(main): Turn off output buffering.  Print messages before and after calling
functions in loaded libraries.  Disable first set of tests, that don't call any
functions.  Test gssapi library without loading any other libraries, then test
it after loading com_err, and unload com_err first.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@17093 dc483132-0cff-0310-8789-dd5450dbe970

src/tests/shlib/ChangeLog
src/tests/shlib/t_loader.c

index 82a123eca3d090acb5fd2fed65767fdf7c4c27b1..32e9b48345fbbf1b090ad0a337ba0c4c37d38923 100644 (file)
@@ -1,3 +1,25 @@
+2005-02-08  Ken Raeburn  <raeburn@mit.edu>
+
+       * t_loader.c (verbose): New variable.
+       (do_close_1): Drop filename argument.  Change messages
+       accordingly, and only display them if verbose.  Line up "done"
+       messages vertically.
+       (do_open_1): Likewise.  Add library version argument, used when on
+       AIX, in combination with RTLD_MEMBER.
+       (do_open): Don't pass filename.  Do pass library version; callers
+       changed.
+       (do_close): Don't pass filename.
+       (get_sym_1): Renamed from get_sym, added line number argument.
+       Print messages if verbose.
+       (get_sym): New macro.
+       (xbasename): Function deleted.
+       (HORIZ): New macro.
+       (main): Turn off output buffering.  Print messages before and
+       after calling functions in loaded libraries.  Disable first set of
+       tests, that don't call any functions.  Test gssapi library without
+       loading any other libraries, then test it after loading com_err,
+       and unload com_err first.
+
 2005-02-02  Ken Raeburn  <raeburn@mit.edu>
 
        * Makefile.in: New file.
index 98c99682afba46a221a8d0774e07c1b85a63f8cc..ecd6a4e830f00bd6fff70e5ab8ef82c2c7096a61 100644 (file)
@@ -7,6 +7,8 @@
 #include "gssapi/gssapi.h"
 #define HAVE_DLOPEN 1
 
+static int verbose = 1;
+
 #ifdef HAVE_DLFCN_H
 # include <dlfcn.h>
 #endif
 
    Return value is the library handle.  On error, print a message and
    exit.  */
-#define do_open(LIB,FLAGS) do_open_1(LIB,FLAGS,__FILE__,__LINE__)
-static void *do_open_1(const char *libname, int lazy,
-                      const char *file, int line);
+#define do_open(LIB,REV,FLAGS) do_open_1(LIB,REV,FLAGS,__LINE__)
+static void *do_open_1(const char *libname, const char *rev, int lazy, int line);
 
 /* Look up a function symbol in the library and return a pointer.
 
    The return value may need casting to the correct type.  On error,
    print a message and exit.  */
-static void *get_sym(void *libhandle, const char *sym);
+static void *get_sym_1(void *libhandle, const char *sym, int line);
+#define get_sym(LIB, NAME) get_sym_1(LIB, NAME, __LINE__)
 #define GET_FSYM(TYPE, LIB, NAME) ((TYPE) get_sym(LIB, NAME))
 #define get_gfun(LIB, NAME) ((OM_uint32 KRB5_CALLCONV(*)()) get_sym(LIB, NAME))
 
@@ -33,17 +35,8 @@ static void *get_sym(void *libhandle, const char *sym);
 
    If the OS reports an error in doing so, print a message and
    exit.  */
-#define do_close(X) do_close_1(X, __FILE__, __LINE__)
-static void do_close_1(void *libhandle, const char *file, int line);
-
-static inline const char *xbasename(const char *path)
-{
-    const char *p = strrchr(path, '/');
-    if (p)
-       return p+1;
-    else
-       return path;
-}
+#define do_close(X) do_close_1(X, __LINE__)
+static void do_close_1(void *libhandle, int line);
 
 #ifdef HAVE_DLOPEN
 
@@ -53,15 +46,23 @@ static inline const char *xbasename(const char *path)
 # define SHLIB_SUFFIX ".so"
 #endif
 
-static void *do_open_1(const char *libname, int lazy,
-                      const char *file, int line)
+#define HORIZ 25
+
+static void *do_open_1(const char *libname, const char *rev,
+                      int lazy, int line)
 {
     void *p;
     char *namebuf;
+    size_t sz;
 
-    file = xbasename(file);
-    printf("from %s:%d: do_open(%s)\n", file, line, libname);
-    namebuf = malloc(strlen(SHLIB_SUFFIX) + strlen(libname) + 4);
+    if (verbose)
+       printf("from line %d: do_open(%s)...%*s", line, libname,
+              HORIZ-strlen(libname), "");
+    sz = strlen(SHLIB_SUFFIX) + strlen(libname) + 4;
+#ifdef _AIX
+    sz += strlen(rev) + 8;
+#endif
+    namebuf = malloc(sz);
     if (namebuf == 0) {
        perror("malloc");
        exit(1);
@@ -69,41 +70,62 @@ static void *do_open_1(const char *libname, int lazy,
     strcpy(namebuf, "lib");
     strcat(namebuf, libname);
     strcat(namebuf, SHLIB_SUFFIX);
+#ifdef _AIX
+    strcat(namebuf, "(shr.o.");
+    strcat(namebuf, rev);
+    strcat(namebuf, ")");
+#endif
 
-    p = dlopen(namebuf, lazy ? RTLD_LAZY : RTLD_NOW);
+#ifndef RTLD_MEMBER
+#define RTLD_MEMBER 0
+#endif
+    p = dlopen(namebuf, (lazy ? RTLD_LAZY : RTLD_NOW) | RTLD_MEMBER);
     if (p == 0) {
        fprintf(stderr, "dlopen of %s failed: %s\n", namebuf, dlerror());
        exit(1);
     }
     free(namebuf);
+    if (verbose)
+       printf("done: %p\n", p);
     return p;
 }
 
 #define SYM_PREFIX ""
-static void *get_sym(void *libhandle, const char *symname)
+static void *get_sym_1(void *libhandle, const char *symname, int line)
 {
     void *s;
 
     /* Bah.  Fix this later, if we care.  */
     assert(strlen(SYM_PREFIX) == 0);
 
+    if (verbose)
+       printf("from line %d: get_sym(%s)...%*s", line, symname,
+              HORIZ-strlen(symname), "");
+
     s = dlsym(libhandle, symname);
     if (s == 0) {
        fprintf(stderr, "symbol %s not found\n", symname);
        exit(1);
     }
+    if (verbose)
+       printf("done: %p\n", s);
     return s;
 }
 
-#define do_close(X) do_close_1(X, __FILE__, __LINE__)
-static void do_close_1(void *libhandle, const char *file, int line)
+static void do_close_1(void *libhandle, int line)
 {
-    file = xbasename(file);
-    printf("from %s:%d: do_close\n", file, line), fflush(stdout);
+    if (verbose) {
+       char pbuf[3*sizeof(libhandle)+4];
+       sprintf(pbuf, "%p", libhandle);
+       printf("from line %d: do_close(%s)...%*s", line, pbuf,
+              HORIZ-1-strlen(pbuf), "");
+    }
     if (dlclose(libhandle) != 0) {
        fprintf(stderr, "dlclose failed: %s\n", dlerror());
        exit(1);
     }
+    if (verbose)
+       printf("done\n");
 }
 
 #elif defined _WIN32
@@ -148,19 +170,24 @@ int main()
 {
     void *celib, *k5lib, *gsslib, *celib2;
 
-    celib = do_open("com_err", 0);
-    k5lib = do_open("krb5", 0);
-    gsslib = do_open("gssapi_krb5", 0);
-    celib2 = do_open("com_err", 0);
+    (void) setvbuf(stdout, 0, _IONBF, 0);
+
+#if 0
+    /* Simplest test: Load, then unload out of order.  */
+    celib = do_open("com_err", "3.0", 0);
+    k5lib = do_open("krb5", "3.2", 0);
+    gsslib = do_open("gssapi_krb5", "2.2", 0);
+    celib2 = do_open("com_err", "3.0", 0);
     do_close(celib);
     do_close(k5lib);
     do_close(celib2);
     do_close(gsslib);
+#endif
 
-    celib = do_open("com_err", 0);
-    k5lib = do_open("krb5", 0);
-    gsslib = do_open("gssapi_krb5", 0);
-    celib2 = do_open("com_err", 0);
+    celib = do_open("com_err", "3.0", 0);
+    k5lib = do_open("krb5", "3.2", 0);
+    gsslib = do_open("gssapi_krb5", "2.2", 0);
+    celib2 = do_open("com_err", "3.0", 0);
     do_close(celib2);
     {
        typedef krb5_error_code KRB5_CALLCONV (*ict)(krb5_context *);
@@ -171,22 +198,29 @@ int main()
        krb5_context ctx;
        krb5_error_code err;
 
+#define CALLING(S) (verbose ? printf("at   line %d: calling %s...%*s", __LINE__, #S, (int)(HORIZ+1-strlen(#S)), "") : 0)
+#define DONE() (verbose ? printf("done\n") : 0)
+
+       CALLING(krb5_init_context);
        err = init_context(&ctx);
+       DONE();
        if (err) {
            fprintf(stderr, "error 0x%lx initializing context\n",
                    (unsigned long) err);
            exit(1);
        }
+       CALLING(krb5_free_context);
        free_context(ctx);
+       DONE();
     }
-    celib2 = do_open("com_err", 0);
+    celib2 = do_open("com_err", "3.0", 0);
     do_close(celib);
     do_close(k5lib);
     do_close(celib2);
     do_close(gsslib);
 
-    celib = do_open("com_err", 1);
-    gsslib = do_open("gssapi_krb5", 1);
+    /* Test gssapi_krb5 without having loaded anything else.  */
+    gsslib = do_open("gssapi_krb5", "2.2", 1);
     {
        OM_uint32 KRB5_CALLCONV (*init_sec_context)(OM_uint32 *, gss_cred_id_t,
                                                    gss_ctx_id_t *, gss_name_t,
@@ -221,7 +255,9 @@ int main()
            10, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04"
        };
 
+       CALLING(gss_import_name);
        gmaj = import_name(&gmin, &target_name_buf, &service_name, &target);
+       DONE();
        if (gmaj != GSS_S_COMPLETE) {
            fprintf(stderr,
                    "import_name reports error major 0x%lx minor 0x%lx(%ld)\n",
@@ -234,15 +270,100 @@ int main()
           we're ignoring the error and testing whether we're doing
           cleanup properly.  (Though the internal cleanup needed in
           the two cases might be different.)  */
+       CALLING(gss_init_sec_context);
        gmaj = init_sec_context(&gmin, GSS_C_NO_CREDENTIAL, &gctx, target,
                                GSS_C_NULL_OID, 0, 0, NULL, GSS_C_NO_BUFFER,
                                NULL, &token, &retflags, NULL);
+       DONE();
        /* Ignore success/failure indication.  */
-       if (token.length)
+       if (token.length) {
+           CALLING(gss_release_buffer);
            release_buffer(&gmin, &token);
+           DONE();
+       }
+       CALLING(gss_release_name);
        release_name(&gmin, &target);
-       if (gctx != GSS_C_NO_CONTEXT)
+       DONE();
+       if (gctx != GSS_C_NO_CONTEXT) {
+           CALLING(gss_delete_sec_context);
            delete_sec_context(&gmin, gctx, GSS_C_NO_BUFFER);
+           DONE();
+       }
+    }
+    do_close(gsslib);
+
+    /* Test gssapi_krb5 with com_err already loaded, then unload
+       com_err first.  */
+    celib = do_open("com_err", "3.0", 1);
+    gsslib = do_open("gssapi_krb5", "2.2", 1);
+    {
+       OM_uint32 KRB5_CALLCONV (*init_sec_context)(OM_uint32 *, gss_cred_id_t,
+                                                   gss_ctx_id_t *, gss_name_t,
+                                                   gss_OID,
+                                                   OM_uint32, OM_uint32,
+                                                   gss_channel_bindings_t,
+                                                   gss_buffer_t, gss_OID *,
+                                                   gss_buffer_t,
+                                                   OM_uint32 *, OM_uint32 *)
+           = get_gfun(gsslib, "gss_init_sec_context");
+       OM_uint32 KRB5_CALLCONV (*import_name)(OM_uint32 *, gss_buffer_t,
+                                              gss_OID, gss_name_t *)
+           = get_gfun(gsslib, "gss_import_name");
+       OM_uint32 KRB5_CALLCONV (*release_buffer)(OM_uint32 *, gss_buffer_t)
+           = get_gfun(gsslib, "gss_release_buffer");
+       OM_uint32 KRB5_CALLCONV (*release_name)(OM_uint32 *, gss_name_t *)
+           = get_gfun(gsslib, "gss_release_name");
+       OM_uint32 KRB5_CALLCONV (*delete_sec_context)(OM_uint32 *,
+                                                     gss_ctx_id_t *,
+                                                     gss_buffer_t)
+           = get_gfun(gsslib, "gss_delete_sec_context");
+
+       OM_uint32 gmaj, gmin;
+       OM_uint32 retflags;
+       gss_ctx_id_t gctx = GSS_C_NO_CONTEXT;
+       gss_buffer_desc token;
+       gss_name_t target;
+       static gss_buffer_desc target_name_buf = {
+           9, "x@mit.edu"
+       };
+       static gss_OID_desc service_name = {
+           10, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04"
+       };
+
+       CALLING(gss_import_name);
+       gmaj = import_name(&gmin, &target_name_buf, &service_name, &target);
+       DONE();
+       if (gmaj != GSS_S_COMPLETE) {
+           fprintf(stderr,
+                   "import_name reports error major 0x%lx minor 0x%lx(%ld)\n",
+                   (unsigned long) gmaj, (unsigned long) gmin,
+                   (signed long) gmin);
+           exit(1);
+       }
+       /* This will probably get different errors, depending on
+          whether we have tickets at the time.  Doesn't matter much,
+          we're ignoring the error and testing whether we're doing
+          cleanup properly.  (Though the internal cleanup needed in
+          the two cases might be different.)  */
+       CALLING(gss_init_sec_context);
+       gmaj = init_sec_context(&gmin, GSS_C_NO_CREDENTIAL, &gctx, target,
+                               GSS_C_NULL_OID, 0, 0, NULL, GSS_C_NO_BUFFER,
+                               NULL, &token, &retflags, NULL);
+       DONE();
+       /* Ignore success/failure indication.  */
+       if (token.length) {
+           CALLING(gss_release_buffer);
+           release_buffer(&gmin, &token);
+           DONE();
+       }
+       CALLING(gss_release_name);
+       release_name(&gmin, &target);
+       DONE();
+       if (gctx != GSS_C_NO_CONTEXT) {
+           CALLING(gss_delete_sec_context);
+           delete_sec_context(&gmin, gctx, GSS_C_NO_BUFFER);
+           DONE();
+       }
     }
     do_close(celib);
     do_close(gsslib);