Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 17 May 2008 11:18:16 -0700
From:      Norbert Papke <fbsd-ml@scrapper.ca>
To:        freebsd-stable@freebsd.org
Subject:   Apache seg faults -- Possible problem with libc?
Message-ID:  <200805171118.16482.fbsd-ml@scrapper.ca>

next in thread | raw e-mail | index | archive | help
Environment:  FreeBSD 7.0 Stable (as of Apr 30), apache-2.0.63

I am experiencing Apache crashes on a fairly consistent and frequent basis.  
The crash occurs in strncmp().  To help with the diagnosis, I have rebuilt 
libc with debug symbols.  Here is a typical stack dump:

  #0  strncmp () at /usr/src/lib/libc/i386/string/strncmp.S:69
  #1  0x2832558c in getenv (name=0x28338648 "TZ") 
     at /usr/src/lib/libc/stdlib/getenv.c:144
  #2  0x2830ce3a in tzset_basic (rdlocked=0)
     at /usr/src/lib/libc/stdtime/localtime.c:1013
  #3  0x2830d42f in localtime (timep=0xbfbfc1d4)
     at /usr/src/lib/libc/stdtime/localtime.c:1158
  #4  0x28220e6c in explode_time () from /usr/local/lib/apache2/libapr-0.so.9
  #5  0x28220f13 in apr_time_exp_lt ()
     from /usr/local/lib/apache2/libapr-0.so.9
  #6  0x08070227 in cached_explode ()
  #7  0x28374519 in log_request_time ()
     from /usr/local/libexec/apache2/mod_log_config.so
  #8  0x2837358d in config_log_transaction ()
     from /usr/local/libexec/apache2/mod_log_config.so
  #9  0x28373654 in multi_log_transaction ()
     from /usr/local/libexec/apache2/mod_log_config.so
  #10 0x08074519 in ap_run_log_transaction ()
  #11 0x08063d62 in ap_process_request ()
  #12 0x0805e718 in ap_process_http_connection ()
  #13 0x08070817 in ap_run_process_connection ()
  #14 0x08064fde in child_main ()
  #15 0x08065283 in make_child ()
  #16 0x08065a51 in ap_mpm_run ()
  #17 0x0806bfb8 in main ()

Frames 0 - 4 are present in all crash scenarios.  However, similar crashes 
occur with different paths into explode_time().

  (gdb) frame 0
  #0  strncmp () at /usr/src/lib/libc/i386/string/strncmp.S:69
  69              movb    (%eax),%bl
  (gdb) p/x $eax
  $70 = 0x883a4bc
  (gdb) p/x *$eax
  Cannot access memory at address 0x883a4bc

eax contains the first string to be compared.  This is an invalid memory 
location.

  (gdb) frame 1
  #1  0x2832558c in getenv (name=0x28338648 "TZ")   
     at /usr/src/lib/libc/stdlib/getenv.c:144
  144             if (strncmp(nameValue, name, nameLen) == 0 && 
      nameValue[nameLen] == '=')
  Current language:  auto; currently c
  (gdb) p envVarsTotal
  $71 = 57
  (gdb) p envVars[56]
  $72 = {nameLen = 4294967295, valueSize = 4294967295, 
     name = 0x883a4bc <Address 0x883a4bc out of bounds>,
     value = 0x0, active = true, putenv = true}
  (gdb) p envVars[55]
  $73 = {nameLen = 16, valueSize = 4, 
     name =  0x8303f20 "KDE_FULL_SESSION=true", 
     value = 0x8303f31 "true",
     active = true, putenv = false}

Because of the inline functions used in getenv(), gdb's location information 
is somewhat incomplete.  However, I believe that line 144 was called by 
__findenv(),  The fault occurs when __findenv() tries to access what appears 
to be an invalid environment variable.  Most likely, envVarsTotal is too big 
by one.

For reference, here is the code for __findenv().  The calling line is marked.

static inline char *
__findenv(const char *name, size_t nameLen, int *envNdx, bool onlyActive)
{
	int ndx;

	/*
	 * Find environment variable from end of array (more likely to be
	 * active).  A variable created by putenv is always active or it is not
	 * tracked in the array.
	 */
	for (ndx = *envNdx; ndx >= 0; ndx--)
		if (envVars[ndx].putenv) {
/* ==> */		if (strncmpeq(envVars[ndx].name, name, nameLen)) {
				*envNdx = ndx;
				return (envVars[ndx].name + nameLen +
				    sizeof ("=") - 1);
			}
		} else if ((!onlyActive || envVars[ndx].active) &&
		    (envVars[ndx].nameLen == nameLen &&
		    strncmpeq(envVars[ndx].name, name, nameLen))) {
			*envNdx = ndx;
			return (envVars[ndx].value);
		}

	return (NULL);
}


which is called by

char *
getenv(const char *name)
{
	int envNdx;
	size_t nameLen;

	/* Check for malformed name. */
	if (name == NULL || (nameLen = __strleneq(name)) == 0) {
		errno = EINVAL;
		return (NULL);
	}

	/*
	 * Find environment variable via environ if no changes have been made
	 * via a *env() call or environ has been replaced by a running program,
	 * otherwise, use the rebuilt environment.
	 */
	if (envVars == NULL || environ != intEnviron)
		return (__findenv_environ(name, nameLen));
	else {
		envNdx = envVarsTotal - 1;
/* ==> */		return (__findenv(name, nameLen, &envNdx, true));
	}
}



Any suggestions on how I could nail down the cause?  

Cheers,

-- Norbert.





Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200805171118.16482.fbsd-ml>