Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. _tcscpy_s and unused buffer part

_tcscpy_s and unused buffer part

Scheduled Pinned Locked Moved C / C++ / MFC
debugging
14 Posts 5 Posters 1 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • L leon de boer

    If anyone has a minute can they confirm a weird behaviour of _tcscpy_s which caught me totally off guard that it trashes the unused part of the return buffer. The code I would like you to test follows, you will need include TCHAR.H for the standard _tcscpy_s function

    #include

    TCHAR szFilter[512];

    memset(szFilter, 0, sizeof(szFilter)); // Zero szFilter
    _tcscpy_s(szFilter, _countof(szFilter), _T("All files"));
    int i = _tcslen(szFilter);
    TCHAR Ch1 = szFilter[i + 2]; // Place a debug here .. Ch1 will be trash .. my nice zeroed buffer is toast

    memset(szFilter, 0, sizeof(szFilter)); // Zero szFilter
    _tcscpy_s(szFilter, _tcslen(_T("All files"))+1, _T("All files"));
    TCHAR Ch2 = szFilter[i + 2]; // Place a debug here .. Ch2 will be 0 as expected

    What I am interested in is the part of the buffer the result is not written in. What stunned me was it was all trashed. Okay the function does not define what it does with the unused parts of the buffer but it seems a waste of time to play with it. The stranger part is if you lie to the function and make it have just the right size buffer it doesn't trash the buffer. It's so quirky I am trying to work out if it is a machine/processor dependent implementation of the function.

    In vino veritas

    L Offline
    L Offline
    Lost User
    wrote on last edited by
    #2

    I have seen this before and I think it is to do with the fact that the _s variants are "safe" mode functions. The first thing they do is to overwrite the buffer with some known pattern (hex FEFE in my Unicode test), before doing the copy - at least in Debug mode. You could try a Release mode version and add some code to examine the buffer at each point. A 16 character buffer will be big enough.

    L 1 Reply Last reply
    0
    • L leon de boer

      If anyone has a minute can they confirm a weird behaviour of _tcscpy_s which caught me totally off guard that it trashes the unused part of the return buffer. The code I would like you to test follows, you will need include TCHAR.H for the standard _tcscpy_s function

      #include

      TCHAR szFilter[512];

      memset(szFilter, 0, sizeof(szFilter)); // Zero szFilter
      _tcscpy_s(szFilter, _countof(szFilter), _T("All files"));
      int i = _tcslen(szFilter);
      TCHAR Ch1 = szFilter[i + 2]; // Place a debug here .. Ch1 will be trash .. my nice zeroed buffer is toast

      memset(szFilter, 0, sizeof(szFilter)); // Zero szFilter
      _tcscpy_s(szFilter, _tcslen(_T("All files"))+1, _T("All files"));
      TCHAR Ch2 = szFilter[i + 2]; // Place a debug here .. Ch2 will be 0 as expected

      What I am interested in is the part of the buffer the result is not written in. What stunned me was it was all trashed. Okay the function does not define what it does with the unused parts of the buffer but it seems a waste of time to play with it. The stranger part is if you lie to the function and make it have just the right size buffer it doesn't trash the buffer. It's so quirky I am trying to work out if it is a machine/processor dependent implementation of the function.

      In vino veritas

      L Offline
      L Offline
      Lost User
      wrote on last edited by
      #3

      Just confirmed this using ordinary strcpy_s, so nothing to do with TCHARs. Also when I run it in Release mode the buffer is not filled with the xFE characters.

      1 Reply Last reply
      0
      • L leon de boer

        If anyone has a minute can they confirm a weird behaviour of _tcscpy_s which caught me totally off guard that it trashes the unused part of the return buffer. The code I would like you to test follows, you will need include TCHAR.H for the standard _tcscpy_s function

        #include

        TCHAR szFilter[512];

        memset(szFilter, 0, sizeof(szFilter)); // Zero szFilter
        _tcscpy_s(szFilter, _countof(szFilter), _T("All files"));
        int i = _tcslen(szFilter);
        TCHAR Ch1 = szFilter[i + 2]; // Place a debug here .. Ch1 will be trash .. my nice zeroed buffer is toast

        memset(szFilter, 0, sizeof(szFilter)); // Zero szFilter
        _tcscpy_s(szFilter, _tcslen(_T("All files"))+1, _T("All files"));
        TCHAR Ch2 = szFilter[i + 2]; // Place a debug here .. Ch2 will be 0 as expected

        What I am interested in is the part of the buffer the result is not written in. What stunned me was it was all trashed. Okay the function does not define what it does with the unused parts of the buffer but it seems a waste of time to play with it. The stranger part is if you lie to the function and make it have just the right size buffer it doesn't trash the buffer. It's so quirky I am trying to work out if it is a machine/processor dependent implementation of the function.

        In vino veritas

        C Offline
        C Offline
        Chris Losinger
        wrote on last edited by
        #4

        maybe _CrtSetDebugFillThreshold[^] can help?

        image processing toolkits | batch image processing

        L 1 Reply Last reply
        0
        • L leon de boer

          If anyone has a minute can they confirm a weird behaviour of _tcscpy_s which caught me totally off guard that it trashes the unused part of the return buffer. The code I would like you to test follows, you will need include TCHAR.H for the standard _tcscpy_s function

          #include

          TCHAR szFilter[512];

          memset(szFilter, 0, sizeof(szFilter)); // Zero szFilter
          _tcscpy_s(szFilter, _countof(szFilter), _T("All files"));
          int i = _tcslen(szFilter);
          TCHAR Ch1 = szFilter[i + 2]; // Place a debug here .. Ch1 will be trash .. my nice zeroed buffer is toast

          memset(szFilter, 0, sizeof(szFilter)); // Zero szFilter
          _tcscpy_s(szFilter, _tcslen(_T("All files"))+1, _T("All files"));
          TCHAR Ch2 = szFilter[i + 2]; // Place a debug here .. Ch2 will be 0 as expected

          What I am interested in is the part of the buffer the result is not written in. What stunned me was it was all trashed. Okay the function does not define what it does with the unused parts of the buffer but it seems a waste of time to play with it. The stranger part is if you lie to the function and make it have just the right size buffer it doesn't trash the buffer. It's so quirky I am trying to work out if it is a machine/processor dependent implementation of the function.

          In vino veritas

          D Offline
          D Offline
          David Crow
          wrote on last edited by
          #5

          I reckon it has something to do with _tcscpy_s() internally calling _FILL_STRING() for the balance of the destination string. If you can live without the safe version, _tcscpy() will work as expected. It looks like you may need to use memcpy() instead.

          "One man's wage rise is another man's price increase." - Harold Wilson

          "Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons

          "You can easily judge the character of a man by how he treats those who can do nothing for him." - James D. Miles

          L 1 Reply Last reply
          0
          • D David Crow

            I reckon it has something to do with _tcscpy_s() internally calling _FILL_STRING() for the balance of the destination string. If you can live without the safe version, _tcscpy() will work as expected. It looks like you may need to use memcpy() instead.

            "One man's wage rise is another man's price increase." - Harold Wilson

            "Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons

            "You can easily judge the character of a man by how he treats those who can do nothing for him." - James D. Miles

            L Offline
            L Offline
            leon de boer
            wrote on last edited by
            #6

            You are correct the FILL_STRING is the culprit and no I need the function so will just do the buffer fill long handed. As Richard worked out it isn't there in release mode so it's something to do with debug mode display functions. My guess is it's a pattern for there watch for change implementation. It did however totally catch me out :-) Update: Chris correctly identified why it's doing it and how you control it.

            In vino veritas

            D 1 Reply Last reply
            0
            • L Lost User

              I have seen this before and I think it is to do with the fact that the _s variants are "safe" mode functions. The first thing they do is to overwrite the buffer with some known pattern (hex FEFE in my Unicode test), before doing the copy - at least in Debug mode. You could try a Release mode version and add some code to examine the buffer at each point. A 16 character buffer will be big enough.

              L Offline
              L Offline
              leon de boer
              wrote on last edited by
              #7

              Yes it's hex FEFE pattern for me as well. I tried release and it's not there .. must be something to do with debug mode. That is what was doing my head in a code that would run in release mode but not in debug mode ... now that is a turn up. Update: David Crowe got the weirdness there is a FILL_STRING call put on the balance of the buffer. I can't for the life of me think why they do it so have referred it to Microsoft as to why debug mode does it, and will work around the behaviour.

              In vino veritas

              1 Reply Last reply
              0
              • C Chris Losinger

                maybe _CrtSetDebugFillThreshold[^] can help?

                image processing toolkits | batch image processing

                L Offline
                L Offline
                leon de boer
                wrote on last edited by
                #8

                A good catch that does the job. Setting it to zero and then putting the value back after the code solves my problem. Well you learn something everyday, I was completely unaware they had added that functionality into the safe routines but at least they do realize the problem and allow control of it.

                In vino veritas

                1 Reply Last reply
                0
                • L leon de boer

                  You are correct the FILL_STRING is the culprit and no I need the function so will just do the buffer fill long handed. As Richard worked out it isn't there in release mode so it's something to do with debug mode display functions. My guess is it's a pattern for there watch for change implementation. It did however totally catch me out :-) Update: Chris correctly identified why it's doing it and how you control it.

                  In vino veritas

                  D Offline
                  D Offline
                  David Crow
                  wrote on last edited by
                  #9

                  leon de boer wrote:

                  ...so will just do the buffer fill long handed.

                  Just curious but what does it matter what's after the \0 value in the buffer?

                  "One man's wage rise is another man's price increase." - Harold Wilson

                  "Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons

                  "You can easily judge the character of a man by how he treats those who can do nothing for him." - James D. Miles

                  L 1 Reply Last reply
                  0
                  • D David Crow

                    leon de boer wrote:

                    ...so will just do the buffer fill long handed.

                    Just curious but what does it matter what's after the \0 value in the buffer?

                    "One man's wage rise is another man's price increase." - Harold Wilson

                    "Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons

                    "You can easily judge the character of a man by how he treats those who can do nothing for him." - James D. Miles

                    L Offline
                    L Offline
                    leon de boer
                    wrote on last edited by
                    #10

                    I was try to make a filter for OPENFILENAME OPENFILENAME structure (Windows)[^] It's not a great structure from MS and it look something like this "DXF Files\0*.dxf\0PLT Files\0*.plt\0\0 " You can't string copy that in because of the terminating 0 characters in it. For me it's worse "DXF files", "PLT files" is the English version I have German, French etc strings to replace it so the string changes. So I have to build that structure and the old code basically relied on the buffer being zeroed and it just wrote the string bits in without having to track all the string lengths. It was assumed strcpy doesn't play with parts of the buffer it isn't writing the result into. So the correct way to write it would be strcpy + strcat + strcat + strcat + strcat(\0).... which I did. The safe functions mean you have to track the amount of buffer left to pass in and so it becomes a lot of code for a very trivial thing ... BUT IT'S GUARANTEED TO WORK :-) So basically while I was trying to debug the program the code was failing because the code relied on something not guaranteed. For such a simple string structure its a pain to have to make code track multiple string pointers just to create it but I should have done it .. lesson 1 never assume anything not actually specified!!!! The bigger issue for me and why I went after it was performance. If they are playing around with stuff they don't need to they are wasting time. String functions are used often and everywhere and on very large memory blocks and I was concerned about the impact.

                    In vino veritas

                    D 1 Reply Last reply
                    0
                    • L leon de boer

                      I was try to make a filter for OPENFILENAME OPENFILENAME structure (Windows)[^] It's not a great structure from MS and it look something like this "DXF Files\0*.dxf\0PLT Files\0*.plt\0\0 " You can't string copy that in because of the terminating 0 characters in it. For me it's worse "DXF files", "PLT files" is the English version I have German, French etc strings to replace it so the string changes. So I have to build that structure and the old code basically relied on the buffer being zeroed and it just wrote the string bits in without having to track all the string lengths. It was assumed strcpy doesn't play with parts of the buffer it isn't writing the result into. So the correct way to write it would be strcpy + strcat + strcat + strcat + strcat(\0).... which I did. The safe functions mean you have to track the amount of buffer left to pass in and so it becomes a lot of code for a very trivial thing ... BUT IT'S GUARANTEED TO WORK :-) So basically while I was trying to debug the program the code was failing because the code relied on something not guaranteed. For such a simple string structure its a pain to have to make code track multiple string pointers just to create it but I should have done it .. lesson 1 never assume anything not actually specified!!!! The bigger issue for me and why I went after it was performance. If they are playing around with stuff they don't need to they are wasting time. String functions are used often and everywhere and on very large memory blocks and I was concerned about the impact.

                      In vino veritas

                      D Offline
                      D Offline
                      David Crow
                      wrote on last edited by
                      #11

                      leon de boer wrote:

                      You can't string copy that in because of the terminating 0 characters in it.

                      Why would you want to? The lpstrFilter member is a pointer not an "array". You should have something like:

                      OPENFILENAME ofn = {0};
                      ofn.lStructSize = sizeof(OPENFILENAME);
                      ofn.lpstrFilter = "DXF Files\0*.dxf\0PLT Files\0*.plt\0"; // string literals are already nul terminated
                      ...

                      Now if you are wanting a dynamic filter (one that changes at runtime), that's a horse of a different color, although still do-able.

                      "One man's wage rise is another man's price increase." - Harold Wilson

                      "Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons

                      "You can easily judge the character of a man by how he treats those who can do nothing for him." - James D. Miles

                      L 1 Reply Last reply
                      0
                      • D David Crow

                        leon de boer wrote:

                        You can't string copy that in because of the terminating 0 characters in it.

                        Why would you want to? The lpstrFilter member is a pointer not an "array". You should have something like:

                        OPENFILENAME ofn = {0};
                        ofn.lStructSize = sizeof(OPENFILENAME);
                        ofn.lpstrFilter = "DXF Files\0*.dxf\0PLT Files\0*.plt\0"; // string literals are already nul terminated
                        ...

                        Now if you are wanting a dynamic filter (one that changes at runtime), that's a horse of a different color, although still do-able.

                        "One man's wage rise is another man's price increase." - Harold Wilson

                        "Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons

                        "You can easily judge the character of a man by how he treats those who can do nothing for him." - James D. Miles

                        L Offline
                        L Offline
                        leon de boer
                        wrote on last edited by
                        #12

                        Edit: Correction yes that works as a static. But yes that is a static create but my strings are coming from memory the user can switch language on the fly and the number of types of file that can be loaded depends on version purchased. Bascially I can't possible do it with static strings I have to build the string into an array and pass the pointer to the array. The array is created and disposed of by the dialog and all very normal when doing multilingual dialog functions. Many of the string bits are coming from windows via the locale API and heaven only knows how long they are and where they are coming from in memory. I need the array because I have to assemble all the string somewhere. I would like to see a dynamic form of your code without allocating an array on the heap or local stack :-) Anyhow it's all working now, the performance was more the issue to me and that is resolved.

                        In vino veritas

                        D 1 Reply Last reply
                        0
                        • L leon de boer

                          Edit: Correction yes that works as a static. But yes that is a static create but my strings are coming from memory the user can switch language on the fly and the number of types of file that can be loaded depends on version purchased. Bascially I can't possible do it with static strings I have to build the string into an array and pass the pointer to the array. The array is created and disposed of by the dialog and all very normal when doing multilingual dialog functions. Many of the string bits are coming from windows via the locale API and heaven only knows how long they are and where they are coming from in memory. I need the array because I have to assemble all the string somewhere. I would like to see a dynamic form of your code without allocating an array on the heap or local stack :-) Anyhow it's all working now, the performance was more the issue to me and that is resolved.

                          In vino veritas

                          D Offline
                          D Offline
                          David Crow
                          wrote on last edited by
                          #13

                          leon de boer wrote:

                          I need the array because I have to assemble all the string somewhere.

                          Like was previously mentioned, you may need to use memcpy().

                          "One man's wage rise is another man's price increase." - Harold Wilson

                          "Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons

                          "You can easily judge the character of a man by how he treats those who can do nothing for him." - James D. Miles

                          1 Reply Last reply
                          0
                          • L leon de boer

                            If anyone has a minute can they confirm a weird behaviour of _tcscpy_s which caught me totally off guard that it trashes the unused part of the return buffer. The code I would like you to test follows, you will need include TCHAR.H for the standard _tcscpy_s function

                            #include

                            TCHAR szFilter[512];

                            memset(szFilter, 0, sizeof(szFilter)); // Zero szFilter
                            _tcscpy_s(szFilter, _countof(szFilter), _T("All files"));
                            int i = _tcslen(szFilter);
                            TCHAR Ch1 = szFilter[i + 2]; // Place a debug here .. Ch1 will be trash .. my nice zeroed buffer is toast

                            memset(szFilter, 0, sizeof(szFilter)); // Zero szFilter
                            _tcscpy_s(szFilter, _tcslen(_T("All files"))+1, _T("All files"));
                            TCHAR Ch2 = szFilter[i + 2]; // Place a debug here .. Ch2 will be 0 as expected

                            What I am interested in is the part of the buffer the result is not written in. What stunned me was it was all trashed. Okay the function does not define what it does with the unused parts of the buffer but it seems a waste of time to play with it. The stranger part is if you lie to the function and make it have just the right size buffer it doesn't trash the buffer. It's so quirky I am trying to work out if it is a machine/processor dependent implementation of the function.

                            In vino veritas

                            J Offline
                            J Offline
                            Joe Woodbury
                            wrote on last edited by
                            #14

                            _tcscpy_s and it's variants only guarantee that the string will be copied IF it fits. I suspect that the compiler "figured out" that it could safely optimize the copy using 32 or 64 bit chunks. This would result in satisfying the condition that the string be null terminated, but would also end up copying random data stored after the original string.

                            1 Reply Last reply
                            0
                            Reply
                            • Reply as topic
                            Log in to reply
                            • Oldest to Newest
                            • Newest to Oldest
                            • Most Votes


                            • Login

                            • Don't have an account? Register

                            • Login or register to search.
                            • First post
                              Last post
                            0
                            • Categories
                            • Recent
                            • Tags
                            • Popular
                            • World
                            • Users
                            • Groups