From b3f85abbd8dc93d14f18bf3fddf315e826e05b72 Mon Sep 17 00:00:00 2001 From: Ken Raeburn Date: Wed, 9 Feb 2005 00:50:50 +0000 Subject: [PATCH] Exercise the dynamic loading/unloading of libraries a bit more. 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 | 22 ++++ src/tests/shlib/t_loader.c | 199 +++++++++++++++++++++++++++++-------- 2 files changed, 182 insertions(+), 39 deletions(-) diff --git a/src/tests/shlib/ChangeLog b/src/tests/shlib/ChangeLog index 82a123eca..32e9b4834 100644 --- a/src/tests/shlib/ChangeLog +++ b/src/tests/shlib/ChangeLog @@ -1,3 +1,25 @@ +2005-02-08 Ken Raeburn + + * 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 * Makefile.in: New file. diff --git a/src/tests/shlib/t_loader.c b/src/tests/shlib/t_loader.c index 98c99682a..ecd6a4e83 100644 --- a/src/tests/shlib/t_loader.c +++ b/src/tests/shlib/t_loader.c @@ -7,6 +7,8 @@ #include "gssapi/gssapi.h" #define HAVE_DLOPEN 1 +static int verbose = 1; + #ifdef HAVE_DLFCN_H # include #endif @@ -17,15 +19,15 @@ 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); -- 2.26.2