Deutsch English Français Italiano |
<1046fbb$44e$1@reader1.panix.com> View for Bookmarking (what is this?) Look up another Usenet article |
Path: news.eternal-september.org!eternal-september.org!feeder3.eternal-september.org!uucp.gnuu.de!news.karotte.org!news.szaf.org!weretis.net!feeder9.news.weretis.net!panix!.POSTED.spitfire.i.gajendra.net!not-for-mail From: cross@spitfire.i.gajendra.net (Dan Cross) Newsgroups: comp.os.vms Subject: Re: FreeTDS port to VMS V9.x on x86? Date: Thu, 3 Jul 2025 17:40:59 -0000 (UTC) Organization: PANIX Public Access Internet and UNIX, NYC Message-ID: <1046fbb$44e$1@reader1.panix.com> References: <101n7gq$4m9b$1@dont-email.me> <103gp9h$2oqhd$1@dont-email.me> <1041eiv$2v6eo$1@dont-email.me> <68669c25$0$690$14726298@news.sunsite.dk> Injection-Date: Thu, 3 Jul 2025 17:40:59 -0000 (UTC) Injection-Info: reader1.panix.com; posting-host="spitfire.i.gajendra.net:166.84.136.80"; logging-data="4238"; mail-complaints-to="abuse@panix.com" X-Newsreader: trn 4.0-test77 (Sep 1, 2010) Originator: cross@spitfire.i.gajendra.net (Dan Cross) In article <68669c25$0$690$14726298@news.sunsite.dk>, Arne Vajhøj <arne@vajhoej.dk> wrote: >On 7/1/2025 3:57 PM, Arne Vajhøj wrote: >> On 6/25/2025 8:15 AM, Craig A. Berry wrote: >>> feel free to take a crack at it and submit a PR. To >>> work against current sources, you either need to use autoconf with a git >>> checkout or get a nightly snapshot from <https://www.freetds.org>. >> >> I may take a look. >> >> Submitting a PR may be a problem. I have never had a personal >> Github account and I suspect that my work Github account has >> been deactivated. But I will worry about that when/if I have >> a good fix. > >First take: > >https://www.vajhoej.dk/arne/temp/tds_vasprintf.c Instead of putting this on a web page on your private sever, you should consider putting it on github or similar in a place where people can comment directly on the code. >Total rewrite. I did not like the old code at all. Your code is incorrect. Note that `vsnprintf` et al do not include space for the NUL terminator in their return value, and you do not account for this when you malloc your destination buffer. Since you then use the (unsafe, unchecked) `vsprintf` function to actually format, you're writing off the end of the allocated buffer, resulting in undefined behavior. I get that you use `vsprintf` here for maximum portability, but it's a poor substitute for `vsnprintf`. Sufficiently so, that I think you're better off using it if you can. As the main logic is the same in each case (find out the buffer size, allocate, and then assign and return), and the only real difference is in finding out the buffer length, your code would be more readable with some helper functions that you delegated to. You refer to `_PATH_DEVNULL` but do not `#include <paths.h>`, as required by POSIX. Your standards matrix includes C90, but note that C90 is not (generally) going to be supported by your code, unless the system already supports `vasprintf` or `va_copy` as an extension. In particular, every option that does not include `vsnprintf` requires `va_copy`, so you may as well test for that once and error immediately. An obvious optimization, in the cases where you try `vsnprintf`, would be to observe that most strings are going to be fairly small (say, a K or less) and speculatively write into a stack-allocated buffer when determining the size; if the result fits, then simply `strdup` the result and return. This would avoid having to call into the (comparatively expensive) formatting code twice, but it hardly seems worth it; I didn't bother in my implementation (which is below). - Dan C. /* * SPDX-License-Identifier: LGPL 2.1 OR Apache 2.0 * * vasprintf implementation */ #include <stdarg.h> #include <stdio.h> #include <stdlib.h> //#include "config.h" static const size_t FAIL = ~(size_t)0; #ifdef HAVE_VASPRINTF int tds_vasprintf(char **outp, const char *fmt, va_list ap) { return vasprintf(outp, fmt, ap); } #else #ifndef va_copy #error "va_copy macro required" #endif #ifdef HAVE_VSNPRINTF static inline int tds_vsnprintf(char *dst, size_t len, const char *fmt, va_list ap) { return vsnprintf(dst, len, fmt, ap); } static inline size_t tds_vasprintf_bufsize(const char *fmt, va_list ap) { int ret = vsnprintf(NULL, 0, fmt, ap); if (ret < 0) return FAIL; return ret; } #else // Note: this is extremely dangerous, as `len` is mostly ignored. static inline int tds_vsnprintf(char *dst, size_t len, const char *fmt, va_list ap) { if (dst == NULL || len == 0) return -1; return vsprintf(dst, fmt, ap); } #include <paths.h> #ifdef REENTRANT #define neednull(fp) 1 #define putnull(fp) fclose(fp) #else #define neednull(fp) ((fp) == NULL) #define putnull(fp) #endif static inline size_t tds_vasprintf_bufsize(const char *fmt, va_list ap) { #ifdef HAVE_VSCPRINTF return _vscprintf(fmt, ap); #endif static FILE *fp = NULL; if (neednull(fp)) fp = fopen(_PATH_DEVNULL, "w"); if (fp == NULL) return FAIL; int len = vfprintf(fp, fmt, ap); if(len < 0) return FAIL; putnull(fp); return (size_t)len; } #endif int tds_vasprintf(char **outp, const char *fmt, va_list ap) { va_list save_ap; va_copy(save_ap, ap); size_t len = tds_vasprintf_bufsize(fmt, ap); if (len == ~(size_t)0) return -1; char *dst = malloc(len); if (dst == NULL) return -1; vsprintf(dst, fmt, save_ap); *outp = dst; return (int)len; } #endif #ifdef TEST #include <assert.h> #include <string.h> char * dovasprintf(const char *fmt, ...) { char *out = NULL; int rv = 0; va_list ap; va_start(ap, fmt); out = NULL; rv = tds_vasprintf(&out, fmt, ap); va_end(ap); ========== REMAINDER OF ARTICLE TRUNCATED ==========