Replace remaining sprintf with snprintf #9867

pull laanwj wants to merge 2 commits into bitcoin:master from laanwj:2017_02_snprintf changing 2 files +4 −7
  1. laanwj commented at 8:14 PM on February 26, 2017: member

    Use of sprintf is seen as a red flag as many of its uses are insecure. OpenBSD warns about it while compiling, and some modern platforms, e.g. cloudlibc from cloudabi don't even provide it anymore.

    Although our uses of these functions are secure, it can't hurt to replace them anyway. There are only 4 occurences of which 3 in the tests.

  2. laanwj added the label Refactoring on Feb 26, 2017
  3. gmaxwell approved
  4. gmaxwell commented at 8:27 PM on February 26, 2017: contributor

    utACK.

  5. in src/uint256.cpp:None in d9b6b874c9 outdated
      21 | @@ -22,7 +22,7 @@ std::string base_blob<BITS>::GetHex() const
      22 |  {
      23 |      char psz[sizeof(data) * 2 + 1];
      24 |      for (unsigned int i = 0; i < sizeof(data); i++)
      25 | -        sprintf(psz + i * 2, "%02x", data[sizeof(data) - i - 1]);
      26 | +        snprintf(psz + i * 2, 3, "%02x", data[sizeof(data) - i - 1]);
    


    JeremyRubin commented at 9:43 PM on February 26, 2017:

    This is a little bit sketchy. Could it not safely be 2 here, not 3?


    kallewoof commented at 3:50 AM on February 27, 2017:

    NUL term needs a 3rd byte.


    dcousens commented at 3:58 AM on February 27, 2017:

    For others http://www.cplusplus.com/reference/cstdio/snprintf/

    A terminating null character is automatically appended after the content written.

    Hence, 2 hex characters + 1 null character.


    gmaxwell commented at 4:13 AM on February 27, 2017:

    It's correct, and it's also why snprintf isn't an especially safe function call. (replaces one class of issue with another more subtle one)


    laanwj commented at 6:22 AM on February 27, 2017:

    It's correct, and it's also why snprintf isn't an especially safe function call. (replaces one class of issue with another more subtle one)

    Indeed, that's why we never use it. The go-to function we have for this is "strprintf". However, it's kind of high overhead for formatting two hex characters. Especially as this function is called a lot.

    I'll just replace this with use of HexDigit instead.

  6. TheBlueMatt commented at 9:43 PM on February 26, 2017: member

    Concept ACK for general sanity, though I'm pretty sure there is no reason we should go out of our way to support libcs that are deliberately broken.

  7. laanwj commented at 6:26 AM on February 27, 2017: member

    Concept ACK for general sanity, though I'm pretty sure there is no reason we should go out of our way to support libcs that are deliberately broken.

    Somewhat tend to agree, though there is something to be said for deprecating unsafe functions that have caused so much pain since the 80's. They do the same with system calls, trying to keep the API (anda attack surface) as minimalist as possible.

  8. laanwj force-pushed on Feb 27, 2017
  9. laanwj commented at 6:49 AM on February 27, 2017: member

    Force-pushed into two commits:

    • uint256: replace use of sprintf with per-digit hex conversion
    • test: Replace remaining sprintf with snprintf
  10. in src/uint256.cpp:None in 30dc47717c outdated
      25 | -        sprintf(psz + i * 2, "%02x", data[sizeof(data) - i - 1]);
      26 | -    return std::string(psz, psz + sizeof(data) * 2);
      27 | +    static const char *hex_chars = "0123456789abcdef";
      28 | +    std::string retval;
      29 | +    retval.reserve(sizeof(data) * 2);
      30 | +    for (unsigned int i = 0; i < sizeof(data); i++) {
    


    dcousens commented at 6:51 AM on February 27, 2017:

    why not size_t?


    laanwj commented at 6:54 AM on February 27, 2017:

    Meh. For loop counters it's generally enough to use a 32-bit type. Especially if you know you're only going to count to 64, ever.

  11. dcousens approved
  12. in src/uint256.cpp:None in 30dc47717c outdated
      28 | +    std::string retval;
      29 | +    retval.reserve(sizeof(data) * 2);
      30 | +    for (unsigned int i = 0; i < sizeof(data); i++) {
      31 | +        uint8_t value = data[sizeof(data) - i - 1];
      32 | +        retval.push_back(hex_chars[value >> 4]);
      33 | +        retval.push_back(hex_chars[value & 0xf]);
    


    dcousens commented at 6:53 AM on February 27, 2017:

    edit: fail


    laanwj commented at 6:54 AM on February 27, 2017:

    But incorrect.


    JeremyRubin commented at 8:51 AM on February 27, 2017:

    nit: maybe emplace rather than push (potentially saves an initialization) @dcousens can you not delete your feedback? I had to dig in my emails to see that I wasn't repeating your feedback.


    laanwj commented at 8:56 AM on February 27, 2017:

    Do you really think there's anything to be gained by emplacing a char? I'd say something has to be really wrong for that to make a difference.


    laanwj commented at 8:58 AM on February 27, 2017:

    Anyhow I have a better solution based on reverse_iterator coming, so no need to discuss this further.


    sipa commented at 9:02 AM on February 27, 2017:

    I'm pretty sure that the copy constructor and move constructor for a char are the same, so emplace wouldn't make a difference.


    dcousens commented at 10:36 AM on February 27, 2017:

    @JeremyRubin I made a woefully incorrect suggestion in regards to the bitmasking.

    retval.push_back(hex_chars[value & 0xf0]);
    retval.push_back(hex_chars[value & 0x0f]);
    

    laanwj commented at 11:28 AM on February 27, 2017:

    @dcousens no worries we all have our dumb moments.

  13. in src/uint256.cpp:None in 30dc47717c outdated
      19 | @@ -20,10 +20,15 @@ base_blob<BITS>::base_blob(const std::vector<unsigned char>& vch)
      20 |  template <unsigned int BITS>
      21 |  std::string base_blob<BITS>::GetHex() const
    


    laanwj commented at 8:34 AM on February 27, 2017:

    Possibly we could even use HexStr here with a reverse_iterator, though I don't know how to do that for a C-style array. All the variations I can think of are much worse than just replicating this functionality here. Edit: found it out, it's simple!


    JeremyRubin commented at 9:09 AM on February 27, 2017:
    #include "stdio.h"
    #include <iterator>
    int main() {
        char a[2] = {'a', 'b'};
        auto start = std::reverse_iterator<char *>(&a[2]);
        auto end = std::reverse_iterator<char *>(&a[0]);
        while (start != end)
            printf("%c", *(start++));
    }
    

    Outputs:

    ba


    laanwj commented at 9:14 AM on February 27, 2017:

    Yes, thanks, I'm aware, see the new version of this patch.


    JeremyRubin commented at 9:15 AM on February 27, 2017:

    ha -- and here I was thinking you coded it after I commented and I was like "wow, @laanwj is a god amongst men in code response times" ;)


    laanwj commented at 9:35 AM on February 27, 2017:

    Yes, I implemented it in minus 3 minutes! Truly godlike :-)

  14. uint256: replace sprintf with HexStr and reverse-iterator
    Instead of calling sprintf for every byte, format the hex bytes
    ourselves by help of HexStr and a reverse_iterator.
    0a177148e7
  15. test: Replace remaining sprintf with snprintf
    Use of `sprintf` is seen as a red flag as many of its uses are insecure.
    OpenBSD warns about it while compiling, and some modern platforms, e.g.
    [cloudlibc from cloudabi](https://github.com/NuxiNL/cloudlibc) don't
    even provide it anymore.
    
    Although our uses of these functions are secure, it can't hurt to
    replace them anyway. There are only 3 occurences left, all in the
    tests.
    19cafc6239
  16. laanwj force-pushed on Feb 27, 2017
  17. laanwj commented at 9:04 AM on February 27, 2017: member

    There you go, a one-liner now.

  18. JeremyRubin commented at 9:19 AM on February 27, 2017: contributor

    utACK 19cafc6

  19. dcousens approved
  20. practicalswift commented at 10:17 PM on February 27, 2017: contributor

    utACK 19cafc6

  21. sipa commented at 11:23 PM on February 27, 2017: member

    utACK

  22. gmaxwell approved
  23. gmaxwell commented at 11:29 PM on February 27, 2017: contributor

    re-utACK.

  24. kallewoof commented at 12:10 AM on February 28, 2017: member

    utACK 19cafc6

  25. jonasschnelli approved
  26. jonasschnelli commented at 9:29 AM on February 28, 2017: contributor

    utACK 19cafc6239abd14f2b9c3d883dc7df0472cac52b

  27. laanwj merged this on Feb 28, 2017
  28. laanwj closed this on Feb 28, 2017

  29. laanwj referenced this in commit f5ef8e9dd2 on Feb 28, 2017
  30. zkbot referenced this in commit 564a229927 on Apr 4, 2018
  31. zkbot referenced this in commit dc57d6a7bc on Apr 4, 2018
  32. PastaPastaPasta referenced this in commit 848c8b3b59 on Dec 28, 2018
  33. PastaPastaPasta referenced this in commit 362a03e054 on Dec 29, 2018
  34. PastaPastaPasta referenced this in commit f9585160ad on Dec 29, 2018
  35. PastaPastaPasta referenced this in commit f841834e87 on Dec 31, 2018
  36. PastaPastaPasta referenced this in commit 9fbceb74d0 on Jan 2, 2019
  37. PastaPastaPasta referenced this in commit 3659d7d804 on Jan 3, 2019
  38. PastaPastaPasta referenced this in commit a68035dfd8 on Jan 5, 2019
  39. PastaPastaPasta referenced this in commit ada878b3d6 on Jan 7, 2019
  40. PastaPastaPasta referenced this in commit 6cf5e7a959 on Jan 7, 2019
  41. PastaPastaPasta referenced this in commit 3e10ff63f8 on Jan 23, 2019
  42. PastaPastaPasta referenced this in commit 6861a43c81 on Jan 25, 2019
  43. Krekeler referenced this in commit 6a72789f65 on Jun 14, 2020
  44. zkbot referenced this in commit caed4adf50 on Nov 10, 2020
  45. random-zebra referenced this in commit d1210fa46e on Apr 23, 2021
  46. MarcoFalke locked this on Sep 8, 2021

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-04-13 15:15 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me