Hirdetés

Új hozzászólás Aktív témák

  • dobragab

    addikt

    Napi Májkroszoft. Alapszituáció: az strerror nem thread safe, lehet, hogy valami globális memóriaterületen van a buffer, amit az strerror ír (!), és két threadről hívva minden szétrohad. Már ez is Microsoft-specifikus, mert *IX-eken az strerror semmit nem ír, csak kikeresi a sztringek közül az aktuálisat.

    Erre a C11 szabvány megoldása:

    errno_t strerror_s(char *buf, rsize_t bufsz, errno_t errnum);
    size_t strerrorlen_s(errno_t errnum);

    Tök frankó, lekéred a hosszát előre, allokálsz valamit neki, majd beleíratod.

    Ehhez képest a Microsoft (néhány wide verzió mellett) ezt nyújtja:

    errno_t strerror_s(char *buffer, size_t numberOfElements, int errnum);
    errno_t _strerror_s(char *buffer, size_t numberOfElements, const char *strErrMsg);

    Jól látható, hogy az strerrorlen_s függvényt sikeresen kifelejetették, és használhatatlan az egész. Az strerror_s nem tudja visszaadni sehogy a méretet, ha nem fér bele.

    És akkor a dokumentáció, ami miatt a maradék hajamat is kitépem:

    If strErrMsg is NULL, _strerror_s returns a string in buffer containing the system error message for the last library call that produced an error. The error-message string is terminated by the newline character ('\n'). If strErrMsg is not equal to NULL, then _strerror_s returns a string in buffer containing (in order) your string message, a colon, a space, the system error message for the last library call producing an error, and a newline character. Your string message can be, at most, 94 characters long.

    - Miért zárja le sorvéggel? :W
    - Miért pont Unixos sorvéggel?
    - Hogy sikerült kitalálni, hogy pont 94 karakteres lehet a saját üzenet? Nem annyi lenne a dolga, hogy ráhív egy strlcpy-t? Miért kell felesleges limitációt bevezetni ide is?

    These functions validate their parameters. If buffer is NULL or if the size parameter is 0, the invalid parameter handler is invoked, as described in Parameter Validation. If execution is allowed to continue, the functions return EINVAL and set errno to EINVAL.

    Ha a buffer csak simán kicsi, akkor is EINVAL-lal tér vissza, és ez sehol nincs ledokumentálva. És hogy miért pont EINVAL, az is rejtély, amikor ott van pont erre, szabványosítva az E2BIG és az ENAMETOOLONG.

    _strerror_s, _wcserror_s, and __wcserror_s are not part of the ANSI definition but are instead Microsoft extensions to it. Do not use them where portability is desired; for ANSI compatibility, use strerror_s instead.

    Mivan? ANSI kompatibilitás? Az strerror_s sose volt ANSI szabvány része, de az ISO C11-é igen. És - ahogy a Macskafogóban elhangzott - a műsort itt tetszették felejteni. Az a függvény, ami ezt a foshányást használhatóvá teszi, nincs implementálva.

    template <size_t size>
    errno_t strerror_s( char (&buffer)[size], int errnum); // C++ only

    In C++, using these functions is simplified by template overloads; the overloads can infer buffer length automatically, eliminating the need to specify a size argument. For more information, see Secure Template Overloads.

    Miééééhéhéhéhéért? Ha már C++, lehetne mondjuk std::string-gel visszatérő, ami az egész buffer nyavalyát feleslegessé teszi, az APIt pedig használhatóvá. De nem, a C++ template magic-et arra kell használni, hogy a hetvenes évekbeli borzalmasan szar API fényesebb legyen.

    Szóval nekem így sikerült használhatóbbá tennem. Tudtok ajánlani valami jobbat esetleg?

    std::string const& stdc_error::strerror(int no)
    {
    static thread_local std::string result(BUFSIZ, '\0');
    // Let's hope strerror_s can't fail unless buffer is too small.
    // Anyway, if buffer is small, it returns EINVAL (?)
    int err;
    while ((err = strerror_s(&result[0], result.size(), no)) == EINVAL)
    result.resize(result.size() * 2);

    if (err != EINVAL) // should not happen
    result = "An unknown error occured in strerror_s.";

    // Removing trailing '\n'. Assuming that if it contains a newline,
    // it won't be in the middle of the string.
    // Looking at this wonderful API, this assumption is risky.
    auto pos = result.find_last_of('\n');
    if (pos != std::string::npos)
    result[pos] = '\0';

    return result;
    }

Új hozzászólás Aktív témák