Compiler Error: Function call with parameters that may be unsafe - c++

Got some code that is not mine and its producing this warning atm:
iehtmlwin.cpp(264) : warning C4996: 'std::basic_string<_Elem,_Traits,_Ax>::copy': 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'
with
[
_Elem=char,
_Traits=std::char_traits<char>,
_Ax=std::allocator<char>
]
c:\program files (x86)\microsoft visual studio 8\vc\include\xstring(1680) : see declaration of 'std::basic_string<_Elem,_Traits,_Ax>::copy'
with
[
_Elem=char,
_Traits=std::char_traits<char>,
_Ax=std::allocator<char>
]
this is the code in question:
HRESULT STDMETHODCALLTYPE Read(void __RPC_FAR *pv, ULONG cb, ULONG __RPC_FAR *pcbRead)
{
if (prepend.size() > 0)
{
int n = min(prepend.size(), cb);
prepend.copy((char *) pv, n);
prepend = prepend.substr(n);
if (pcbRead)
*pcbRead = n;
return S_OK;
};
int rc = Read((char *) pv, cb);
if (pcbRead)
*pcbRead = rc;
return S_OK;
};
and the warning refers to the prepend.copy line. I have tried googling the warning but cant work out what it is on about. Can some one help me solve this please.
Visual Studio 2005 SP1
Windows 7 RC1
.
Edit: prepend is a string which is typedefed
typedef basic_string<char, char_traits<char>, allocator<char> > string;

The warning is telling you that you risk a buffer overflow if n is too large -- which you know can't happen because of the way you just computed with a min, but the poor commpiler doesn't. I suggest you take the compiler's own advice and use -D_SCL_SECURE_NO_WARNINGS for this one source file...

Check out this MSDN page for documentation on the warning
http://msdn.microsoft.com/en-us/library/ttcz0bys.aspx
The MS C++ compiler decided to deprecate the method std::string::copy because it is potentially unsafe to use and can lead to a buffer overrun. This deprecation is Microsoft specific and you will likely not see it on other compiler platforms.

Related

Scary warnings in ancient code converting wstring to string

An old method contains code like the following (anonymised):
std::wstring wstr = ...;
std::string str(wstr.begin(), wstr.end());
Previously this all compiled without warnings but as we update to C++17 and VS2019 (v142) and tidy project settings, it now gives these big scary warnings:
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29333\include\xstring(2468,23): warning C4244: 'argument': conversion from 'wchar_t' to 'const _Elem', possible loss of data
with
[
_Elem=char
]
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29333\include\xstring(2479): message : see reference to function template instantiation 'void std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Construct<wchar_t*>(_Iter,const _Iter,std::input_iterator_tag)' being compiled
with
[
_Iter=wchar_t *
]
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29333\include\xstring(2479): message : see reference to function template instantiation 'void std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Construct<wchar_t*>(_Iter,const _Iter,std::input_iterator_tag)' being compiled
with
[
_Iter=wchar_t *
]
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29333\include\xstring(2459): message : see reference to function template instantiation 'void std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Construct<wchar_t*>(const _Iter,const _Iter,std::forward_iterator_tag)' being compiled
with
[
_Iter=wchar_t *
]
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29333\include\xstring(2459): message : see reference to function template instantiation 'void std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Construct<wchar_t*>(const _Iter,const _Iter,std::forward_iterator_tag)' being compiled
with
[
_Iter=wchar_t *
]
message : see reference to function template instantiation 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string<std::_String_iterator<std::_String_val<std::_Simple_types<_Elem>>>,0>(_Iter,_Iter,const _Alloc &)' being compiled
with
[
_Elem=wchar_t,
_Iter=std::_String_iterator<std::_String_val<std::_Simple_types<wchar_t>>>,
_Alloc=std::allocator<char>
]
message : see reference to function template instantiation 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string<std::_String_iterator<std::_String_val<std::_Simple_types<_Elem>>>,0>(_Iter,_Iter,const _Alloc &)' being compiled
with
[
_Elem=wchar_t,
_Iter=std::_String_iterator<std::_String_val<std::_Simple_types<wchar_t>>>,
_Alloc=std::allocator<char>
]
I am pretty sure this code pre-dates use of UNICODE in our codebase - it seems to work but I don't really understand the warnings or what I should do about it.
I found this question: UTF8 to/from wide char conversion in STL but the nice neat solution has comments saying it's deprecated in C++17! It's somewhat a mystery why this code mixes string and wstring in the first place, is there an easy solution? Or is this a case "just leave it if it works?!"
The issue is that you are converting from a 16 bit string to an 8 bit string. Since 16 bits hold more data than 8, data will then get lost. If you are converting between UTF-16 and UTF-8, you need to do it properly with a conversion library.
C++ does provide conversion library in the form of: codecvt (Deprecated in C++17 but still there for a while).
If you are sure the string only contains ASCII, you can suppress the warning.
See https://en.cppreference.com/w/cpp/locale/codecvt_utf8_utf16 for details
The warning is quite clear on its own.
warning C4244: 'argument': conversion from 'wchar_t' to 'const _Elem',
possible loss of data
Which means, this line std::string str(wstr.begin(), wstr.end()) involves a type casting from wchar_t to a narrower data type const _Elem a.k.a char. Since any narrowing cast may lead to data loss, hence the warning.
Consider an example as following:
#include <cstddef>
#include <iostream>
#include <string>
int main() {
std::wstring ws{};
auto c = (wchar_t)0x41'42'43'44; // A'B'C'D in ASCII
for (int i = 0; i < 3; ++i)
ws.push_back(c);
std::string str{ws.begin(), ws.end()};
std::cout << str.c_str() << std::endl;
}
The code above run and print DDD.
On 64 bit machine, the constructor of str move 4 bytes at a time to read a wchar_t. However, string type can only accept element as char ==> the constructor must perform a narrowing cast from wchar_t to char which results in a loss of 3 byte A B C for each wchar_t element.

Two code bases with the same code but one is generating an overload resolution compilation error and the other isn't

I'm following Jonno Robson's source code for a Vulkan App that can be found on github here: Vulkan-Terrain-Generator. I'm using Visual Studio 2017 on a Window's 7 64bit machine.
I have my own solution and project where everything has been typed by hand, but I also have a downloaded clone to their project so that I can use it side by side in my attempt to learn and better understand the Vulkan API.
In the Renderer class's initPipelines() function we are setting up all of the different pipelines for the rendered scene. In the section where we are setting up the TerrainRenderingPipeline there is a call to addTextureArray() that the inherited class invokes from its base class member. The TerrainRenderingPipeline class inherits from the Pipeline base class.
This is how it is being called in the Render class's initPipelines() method:
terrain_rendering_pipeline_->addTextureArray(VK_SHADER_STAGE_VERTEX_BIT, 3, terrain_generator_->getHeightmaps());
In my solution; this fails to compile and Visual Studio is generating a C2664 error complaining about overload resolution. However; when I compile and build Jonno's project there are no issues.
These are the function declarations for the addTextureArray(...) functions
that are found in pipeline.h:
void addTextureArray(VkShaderStageFlags stage_flags, uint32_t binding_location, std::vector<Texture*>& textures);
void addTextureArray(VkShaderStageFlags stage_flags, uint32_t binding_location, std::vector<VkImageView>& textures);
and these are the definitions that are found in pipeline.cpp
void VulkanPipeline::addTextureArray(VkShaderStageFlags stage_flags, uint32_t binding_location, std::vector<Texture*>& textures) {
Descriptor texture_descriptor = {};
// setup image info
for (Texture* texture : textures) {
VkDescriptorImageInfo image_info = {};
image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
image_info.imageView = texture->getImageView();
image_info.sampler = VK_NULL_HANDLE;
texture_descriptor.image_infos.push_back(image_info);
}
// setup descriptor layout info
texture_descriptor.layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
texture_descriptor.layout_binding.descriptorCount = texture_descriptor.image_infos.size();
texture_descriptor.layout_binding.binding = binding_location;
texture_descriptor.layout_binding.stageFlags = stage_flags;
texture_descriptor.layout_binding.pImmutableSamplers = nullptr;
descriptor_infos_.push_back(texture_descriptor);
}
void VulkanPipeline::addTextureArray(VkShaderStageFlags stage_flags, uint32_t binding_location, std::vector<VkImageView>& textures) {
Descriptor texture_descriptor = {};
// setup image info
for (VkImageView texture : textures) {
VkDescriptorImageInfo image_info = {};
image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
image_info.imageView = texture;
image_info.sampler = VK_NULL_HANDLE;
texture_descriptor.image_infos.push_back(image_info);
}
// setup descriptor layout info
texture_descriptor.layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
texture_descriptor.layout_binding.descriptorCount = texture_descriptor.image_infos.size();
texture_descriptor.layout_binding.binding = binding_location;
texture_descriptor.layout_binding.stageFlags = stage_flags;
texture_descriptor.layout_binding.pImmutableSamplers = nullptr;
descriptor_infos_.push_back(texture_descriptor);
}
Finally for the TerrainGenerator class's getHeightmaps() function that returns a std::vector<VkImageView> is found in terrain_generator.h:
inline std::vector<VkImageView> getHeightmaps() { return heightmap_image_views_; }
I believe this is all of the relevant code that involves this issue.
Here is the generated Visual Studio Compiler Error:
1>c:\users\skilz99\source\repos\vulkan terrain generator\vulkan terrain generator\renderer.cpp(522): error C2664: 'void VulkanPipeline::addTextureArray(VkShaderStageFlags,uint32_t,std::vector<VkImageView,std::allocator<_Ty>> &)': cannot convert argument 3 from 'std::vector<VkImageView,std::allocator<_Ty>>' to 'std::vector<Texture *,std::allocator<_Ty>> &'
1> with
1> [
1> _Ty=VkImageView
1> ]
1> and
1> [
1> _Ty=VkImageView
1> ]
1> and
1> [
1> _Ty=Texture *
1> ]
1>c:\users\skilz99\source\repos\vulkan terrain generator\vulkan terrain generator\renderer.cpp(545): warning C4305: 'argument': truncation from 'double' to 'T'
1> with
1> [
1> T=float
1> ]
What I don't understand is why is it failing to compile in my project-solution, but not in his... Any kind of tips or suggestions would be very helpful. If you need anymore information about the code please don't hesitate to ask. I tried to post the minimal possible amount of code as this is a decent size project.
When you use the getHeightmaps function in the call to addTextureArray, the object it returns is a temporary object. Temporary objects can't be bound to non-const references. And the addTextureArray take a non-const reference argument for the vector.
Either the addTextureArray function have to be modified to accept a const reference as the third argument:
void addTextureArray(VkShaderStageFlags, uint32_t, std::vector<Texture*> const&);
void addTextureArray(VkShaderStageFlags, uint32_t, std::vector<VkImageView> const&);
Or you have to modify the getHeightmaps function to return a reference:
inline std::vector<VkImageView>& getHeightmaps() { return heightmap_image_views_; }
After taking Some programmer dude's answer into consideration which would be the appropriate way to fix such an issue in conformance to modern C++ best practices. It was still making me wonder why the code would compile under Jonno's solution and not mine. Then Some programmer dude had mentioned in a comment,
Different build flags? Or something else that differs from your build. It's impossible to tell really.
So I went back and check the project settings and to my surprise there was one single compiler flag that I had over looked that was different.
In my solution by default when originally creating it under:
Configuration Properties
C/C++
Language -> Conformance mode
mine was set to Yes (/permissive-) by default and under Jonno's project his was set to no.
Once I changed this in my project's properties, it now compiles.

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

I got this warning message.. but i dont know what/where the problem is..!
includes
#pragma warning(push)
#pragma warning(disable:4996)
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/insert_linebreaks.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/archive/iterators/ostream_iterator.hpp>
#pragma warning(pop)
and the warning
1>c:\program files (x86)\microsoft visual studio 10.0\vc\include\xutility(2227): warning 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'
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\xutility(2212): Siehe Deklaration von 'std::_Copy_impl'
1> c:\users\perlig\documents\visual studio 2010\projects\restmanager\restmanager\**http.cpp(257)**: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "_OutIt std::copy<boost::archive::iterators::insert_linebreaks<Base,N>,boost::archive::iterators::ostream_iterator<Elem>>(_InIt,_InIt,_OutIt)".
1> with
1> [
1> _OutIt=boost::archive::iterators::ostream_iterator<char>,
1> Base=boost::archive::iterators::base64_from_binary<boost::archive::iterators::transform_width<const char *,6,8>>,
1> N=76,
1> Elem=char,
1> _InIt=boost::archive::iterators::insert_linebreaks<boost::archive::iterators::base64_from_binary<boost::archive::iterators::transform_width<const char *,6,8>>,76>
1> ]
the code occur in line 257 as the warning message says. but i´m not able to fix it because i not know what is wrong..
string data contains a "user:password" string for basic auth via http.
http.cpp(257):
// typdef, prepare
using namespace boost::archive::iterators;
stringstream os;
typedef
insert_linebreaks< // insert line breaks every 72 characters
base64_from_binary< // convert binary values ot base64 characters
transform_width< // retrieve 6 bit integers from a sequence of 8 bit bytes
const char *,
6,
8
>
>
,76
>
base64_text; // compose all the above operations in to a new iterator
// encrypt
#pragma warning(push)
#pragma warning(disable:4996)
copy( //<<<<<------ LINE 257
base64_text(data.c_str()),
base64_text(data.c_str() + data.size()),
boost::archive::iterators::ostream_iterator<char>(os)
);
#pragma warning(pop)
anybody got any idea?
I think you know what is the meaning of the warning but first I describe the warning and then say what to do to get rid of it. Microsoft implemented a new security enabled set of function in its CRT, STL, MFC, ... and mark old version of those functions as deprecated to provide a hint for you that you should migrate to new secure version. so it say std::copy is unsafe!! how? as follow:
char storage[ 10 ], *p = storage;
std::copy( std::istream_iterator<int>(std::cin), std::istream_iterator<int>(), p );
Now what will happened if user input more than 10 int? the memory will be overwritten and you corrupted your memory.
Using boost::archive::iterators::ostream_iterator is perfectly safe but since it does not follow the design of safe iterators in MSVC it will considered as unsafe.
Now you should either disable this warning by -D_SCL_SECURE_NO_WARNINGS to cl input flags or add a pragma to disable this warning( as you do ), but why pragma don't work?
the reason is obvious, this pragma work on scope and the scope that you use pragma on it have nothing wrong, you must guard xutility with this pragma and every thing will work as expected.

Does C++11 std::function limit the number of arguments a function pointer can have?

I'm using the Visual Studio 11 beta and I'm curious about a compilation error i'm getting storing a std::function object in my class.
typedef std::function<void (int, const char*, int, int, const char*)> MyCallback;
In my class I have,
MyCallback m_callback;
This compiles just fine. If I add one more argument to the list it fails.
typedef std::function<void (int, const char*, int, int, const char*, int)> MyCallback;
The failure is:
>c:\program files (x86)\microsoft visual studio 11.0\vc\include\functional(535): error C2027: use of undefined type 'std::_Get_function_impl<_Tx>'
1> with
1> [
1> _Tx=void (int,const char *,int,int,const char *,int)
1> ]
1> f:\development\projects\applications\my.h(72) : see reference to class template instantiation 'std::function<_Fty>' being compiled
1> with
1> [
1> _Fty=void (int,const char *,int,int,const char *,int)
1> ]
1>c:\program files (x86)\microsoft visual studio 11.0\vc\include\functional(536): error C2504: 'type' : base class undefined
1>c:\program files (x86)\microsoft visual studio 11.0\vc\include\functional(539): error C2027: use of undefined type 'std::_Get_function_impl<_Tx>'
1> with
1> [
1> _Tx=void (int,const char *,int,int,const char *,int)
1> ]
1>c:\program files (x86)\microsoft visual studio 11.0\vc\include\functional(539): error C2146: syntax error : missing ';' before identifier '_Mybase'
1>c:\program files (x86)\microsoft visual studio 11.0\vc\include\functional(539): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
This is a dynamically linked library which is preparing data to pass to another application. I can certainly rework the format of the data so that it can be passed with fewer arguments, but I was wondering why I see this limit?
Switching back to the c-style function pointer,
typedef void (*MyCallback)(int, const char*, int, int, const char*, int);
seems to work fine.
This limit is set by the implementation in Visual Studio.
The C++ specification for std::function does not place any limit. std::function uses variadic templates to work with any number of arguments. Implementations may have a limit based on, e.g., template instantiation nesting limits, but it should be large. The spec suggests 1024 as a good minimum supported nesting depth, and 256 as a good minimum for arguments allowed in one function call, for example.
Visual Studio (as of VS11) does not have variadic templates. They simulate them up to 5 arguments in VS11, though you can change it to up to 10. Do this by defining _VARIADIC_MAX in your project. This can increase compile times greatly.
Update: The VS 2012 Nov CTP adds support for variadic templates, but the standard library has not yet been updated to use them. Once it is updated you should be able to use as many arguments as you want with std::function.

Sending raw data with write() in boost::asio

I've recently decided to use boost::asio for my sockets, but now I'm running into a problem: documentation seems to be lacking.
What I want to do is write a function that will send a message consisting of the following structure:
2 bytes of an unsigned integer (uint16_t) for an opcode all bytes
all bytes after that (a flexible amount) being any type of data (cast to void*). This data will be operated upon based on the opcode
For example, if the opcode is 1, perhaps defined as OPCODE_LOGIN, then the bytes following the opcode could contain a string containing login information, etc.
bool sendMessage(tcp::socket* sock, uint16_t opcode, void* data)
{
void* fullData = malloc(sizeof(uint16_t) + sizeof(data));
memcpy(fullData, (void*)opcode, sizeof(opcode));
memcpy(&fullData + sizeof(uint16_t), data, sizeof(data));
boost::asio::write(sock, boost::asio::buffer(fullData, sizeof(fullData)));
// by the way, at this point, is it safe to delete fullData to prevent memory leaks?
return true;
}
This does not compile, however. I get a cryptic compilation error regarding the call to write:
1>------ Build started: Project: client, Configuration: Debug Win32 ------
1> main.cpp
1>c:\boost\boost_1_47\boost\asio\impl\write.hpp(46): error C2228: left of '.write_some' must have class/struct/union
1> type is 'boost::asio::basic_stream_socket<Protocol> '
1> with
1> [
1> Protocol=boost::asio::ip::tcp
1> ]
1> did you intend to use '->' instead?
1> c:\boost\boost_1_47\boost\asio\impl\write.hpp(59) : see reference to function template instantiation 'size_t boost::asio::write<SyncWriteStream,ConstBufferSequence,boost::asio::detail::transfer_all_t>(SyncWriteStream &,const ConstBufferSequence &,CompletionCondition,boost::system::error_code &)' being compiled
1> with
1> [
1> SyncWriteStream=boost::asio::ip::tcp::socket *,
1> ConstBufferSequence=boost::asio::mutable_buffers_1,
1> CompletionCondition=boost::asio::detail::transfer_all_t
1> ]
1> c:\users\josh\documents\visual studio 2010\projects\client\client\main.cpp(53) : see reference to function template instantiation 'size_t boost::asio::write<boost::asio::ip::tcp::socket*,boost::asio::mutable_buffers_ 1>(SyncWriteStream &,const ConstBufferSequence &)' being compiled
1> with
1> [
1> SyncWriteStream=boost::asio::ip::tcp::socket *,
1> ConstBufferSequence=boost::asio::mutable_buffers_1
1> ]
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
As you can see, the error message points directly into Boost's write.hpp file, and not to any of my own code.. I believe I'm calling write() incorrectly in some way, but after a solid hour of googling and researching references and examples (all of which either use another overloaded write() or are using data with specifically defined sizes/structures), I haven't been able to determine what exactly I'm doing wrong here.
Can someone help me debug this compilation error?
documentation seems to be lacking
The highest voted question in boost-asio is about documentation, start there :-)
Can someone help me debug this compilation error?
The write() free function expects a reference type as the first parameter. Not a pointer as you have in your example
bool sendMessage(tcp::socket* sock, uint16_t opcode, void* data)
{
void* fullData = malloc(sizeof(uint16_t) + sizeof(data));
memcpy(fullData, (void*)opcode, sizeof(opcode));
memcpy(&fullData + sizeof(uint16_t), data, sizeof(data));
boost::asio::write(*sock, boost::asio::buffer(fullData, sizeof(fullData)));
// ^^^^ correct type now
// by the way, at this point, is it safe to delete fullData to prevent memory leaks?
return true;
}
at this point, is it safe to delete fullData to prevent memory leaks?
Yes, write() is a blocking call. It is done with your buffer when the call returns. I strongly suggest making this code exception safe however, look into using new and a boost::scoped_array if you wish to create your buffer with dynamic storage duration.