William A. Rowe Jr. wrote on 2011-02-08:
> On 2/8/2011 8:29 AM, Steve Hay wrote:
>> +        int len = (int)strlen(newarr[arg]) + 1; +        *env =
>> (char*)_malloc_dbg(len * sizeof(char), _CRT_BLOCK, __FILE__, __LINE__);
>> +        strcpy_s(*env, len, newarr[arg]);
> 
> That's just sick ... It's inexcusable to use strcpy when len is already
> known :)
> 
> Very interesting observations, are you in a position to try this with
> the older
> C compilers?  Interested to know if we can just apply this to all
> flavors without
> any headaches.

I'm not sure if strcpy_s() is as sick as strcpy() would be, given that it takes 
a len argument anyway (?), but I've been looking at saving a little work in the 
function concerned anyway, by copying the new environment strings into place 
directly from the return value of the UTF-8 conversion function, rather than 
going through the intermediate newarr[] array as my quick hack currently does.

The function at the foot of this email is more along the lines of what I'm 
thinking, and is still working correctly. Would this approach be an improvement 
when suitably tidied up?

I wonder if the problem is that malloced data generally has heads and tails on 
it to catch buffer overruns when freeing and the free which the putenv() call 
does when *replacing* an existing environment variable is maybe unhappy at the 
absence of the expected heads and tails on that, given that the APR-ized 
environment is currently allocated in a single block (with only one head & 
tail), rather than string-by-string like stdenvp.c did it orignially (giving 
each string its own head & tail)? It doesn't explain why it still runs on 
XP/2003, or in debug mode, or with old compilers, though...

I have VC98 and VS2005/VS2008/VS2010 all handy and will try release and debug 
mode builds of my test program with each compiler, and run each binary on XP 
and 2008. I don't have VS2003 available.

I will also do full Apache/Perl/mod_perl tests as well, but since that'll 
obviously take rather longer maybe just a release mode build for each compiler 
would suffice?


static int warrsztoastr(char*** retarr, wchar_t* arrsz, int args) {
    const wchar_t* wch;
    size_t totlen;
    size_t newlen;
    size_t wsize;
    char** env;
        char* pstrs;
    char* strs;
    int arg;
    if (args < 0) {
        for (args = 1, wch = arrsz; wch[0] || wch[1]; ++wch)
            if (!*wch)
                ++args;
    }
    wsize = 1 + wch - arrsz;
    newlen = totlen = wsize * 3 + 1;
    pstrs = strs = (char*)_malloc_dbg(newlen * sizeof(char), _CRT_BLOCK, 
__FILE__, __LINE__);
    (void)ucs2toutf8(arrsz, &wsize, strs, &newlen);
    assert(newlen && !wsize);
    *retarr = env = (char **)_malloc_dbg((args + 1) * sizeof(char*), 
_CRT_BLOCK, __FILE__, __LINE__);
    for (arg = 0; arg < args; ++arg) {
        char* p = pstrs;
        int len = 0;
        while (*p++)
            ++len;
        len += 1;
        *env = (char*)_malloc_dbg(len * sizeof(char), _CRT_BLOCK, __FILE__, 
__LINE__);
        memcpy(*env, pstrs, len * sizeof(char));
        pstrs += len;
        ++env;
    }
    *env = NULL;
    _free_dbg(strs, _CRT_BLOCK);
    return args;
}

Reply via email to