7

I know this question was asked numerous times in SO, but this is a variation from the rest.

Compiler Error: Function call with parameters that may be unsafe

Visual Studio Warning C4996

xutility(2227): warning C4996: 'std::_Copy_impl'

Failing Code Snippet

DWORD dwNumberOfNames = pExportDirectory->NumberOfNames;
LPDWORD dwNames = (LPDWORD)((LPBYTE)hDLL +  pExportDirectory->AddressOfNames);
std::vector< std::string > exports;
std::copy(
    dwNames, 
    dwNames + dwNumberOfNames, 
    [&exports, &hDLL](DWORD  dwFuncOffset)
{
    std::string fname = std::string((PCHAR)((PBYTE)hDLL + dwFuncOffset));
    exports.push_back(fname);
}
);

Compiler Error

Error 1 error C4996: 'std::_Copy_impl': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators' C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\xutility 2176

Question

Considering, C4996, means the function was marked to be deprecated Where is the problem?

  1. Is it the use of std::copy, that MS thinks is unsafe and would be deprecated?
  2. Is it because I have used std::copy with a C Array?
  3. Is it because of the way I am using Lambda expression?
  4. If std::copy is deprecated, what is the alternative, if I need to be portable.

Note

I know, how to suppress the warning, but I am curious to know, the root cause of the problem?

Also, equally important for me to know, the portable way to handle this issue without compromising code quality.

Community
  • 1
  • 1
Abhijit
  • 62,056
  • 18
  • 131
  • 204
  • 1
    The third parameter to std::copy is supposed to be an output iterator, but you have a lambda that doesn't return an iterator. – Adrian McCarthy Oct 15 '13 at 20:03
  • (1) : with `std::copy`, you are not sure that you have enough "place" for the outputIterator, so there is a possible buffer overflow. – Jarod42 Oct 21 '13 at 15:11
  • @Jarod42 See my answer below, and if you use a `std::back_inserter` with a standard container, you don't have the overflow issues. – Kevin Anderson Oct 21 '13 at 21:49

2 Answers2

6

You aren't calling std::copy according to msdn: http://msdn.microsoft.com/en-us/library/x9f6s1wf.aspx

That function signature is this:

template<class InputIterator, class OutputIterator> 
   OutputIterator copy( 
      InputIterator _First,  
      InputIterator _Last,  
      OutputIterator _DestBeg 
   );

There's no place for a functor/lambda there.

You're not calling std::copy_if either: http://msdn.microsoft.com/en-us/library/ee384415.aspx

template<class InputIterator, class OutputIterator, class BinaryPredicate>
   OutputIterator copy_if(
      InputIterator _First, 
      InputIterator _Last,
      OutputIterator _Dest,
      Predicate _Pred
    );

As you have no output iterator, nor does your predicate return a bool.

It looks like you want std::transform: http://msdn.microsoft.com/en-us/library/391xya49.aspx

template<class InputIterator, class OutputIterator, class UnaryFunction> 
   OutputIterator transform( 
      InputIterator _First1,  
      InputIterator _Last1,  
      OutputIterator _Result, 
      UnaryFunction _Func 
   ); 

And you should be returning the value you want in the output iterator. So it'll be something like this:

std::transform(
    dwNames, 
    dwNames + dwNumberOfNames,
    std::back_inserter(exports),
    [&hDLL](DWORD  dwFuncOffset) // This lambda is WRONG
{
    // THIS LINE IS WRONG 
    std::string fname = std::string((PCHAR)((PBYTE)hDLL + dwFuncOffset));
    return fname;
}
);

My lambda is wrong. You need the input of the ELEMENTS of your array (I'm not sure of the type) as the argument to the lambda, and return what you want inserted into the exports vector.

You probably also didn't know about back_inserter. It's in the <iterator> header. See here: http://msdn.microsoft.com/en-us/library/12awccbs.aspx and here: http://www.cplusplus.com/reference/iterator/back_inserter/

That may not be 100% of the answer, but with that, I think you can get to where you want to go.

Kevin Anderson
  • 6,850
  • 4
  • 32
  • 54
1

It is not std::copy itself, I think your problem is to use LPDWORD to do the copy which makes Visuall C++ thinks you are doing C string copy because LPDWORD is not a checked iterator.

http://msdn.microsoft.com/en-us/library/ttcz0bys(v=vs.120).aspx

CS Pei
  • 10,869
  • 1
  • 27
  • 46
  • I appreciate your answer. Do you have a reason for your speculation? The compiler error refers to std::_Copy_impl, not to a strcpy. And where are you seeing a call to strcpy? – Abhijit Sep 29 '13 at 15:08
  • The message, present in the question, strongly suggests that it *is* `std::copy` itself that is warned about, and also, the question does not use `char *` (not where the warning is, anyway). –  Sep 29 '13 at 15:08
  • I have this exactly warning before with strcpy, strlen, etc. I just checked, this warning is because you do not use a checked iterator. – CS Pei Sep 29 '13 at 15:15
  • @JohnSmith: Is `checked iterator` part of the C++ standard, or MS specific? Would that make my code portable? And what is the correct way to use `stdext::checked_array_iterator` with a lambda expression? – Abhijit Sep 29 '13 at 15:22
  • I think checked iterator is MS specific. `stdext` is from MS I believe. I don't know the answer to lambda part. – CS Pei Sep 29 '13 at 15:31