Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[C++] Got rid of memset's in constructors #5938

Merged
merged 13 commits into from
Jun 2, 2020

Conversation

bakinovsky-m
Copy link
Contributor

Fixes #5930

There was a std::memset's in constructors of structs. GCC 10.1 failed to compile arrays_test_generated.h because of those memsets on array of non-trivial type NestedStruct

In this new code:

  • default constructor have no memset's now - it zero- or default-initialize all it's members
  • so does parametrized constructor
  • array of non-POD types are initializing by calling default-constructor for each of its object

@googlebot
Copy link

Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

📝 Please visit https://cla.developers.google.com/ to sign.

Once you've signed (or fixed any issues), please reply here with @googlebot I signed it! and we'll verify it.


What to do if you already signed the CLA

Individual signers
Corporate signers

ℹ️ Googlers: Go here for more info.

@bakinovsky-m bakinovsky-m changed the title [C++] Got rid of memset's in constuctors [C++] Got rid of memset's in constructors May 29, 2020
tests/arrays_test_generated.h Outdated Show resolved Hide resolved
{
(void)padding0__;
(void)padding1__;
(void)padding2__;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need these void casts?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unfortunately, yes
otherwise, compiler (clang 10.0) says something like

In file included from flatbuffers/tests/test.cpp:39:
flatbuffers/build/tests/arrays_test_generated.h:71:10: error: private field 'padding0__' is not used [-Werror,-Wunused-private-field]
  int8_t padding0__;  int32_t padding1__;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make a FLATBUFFERS_UNUSED() macro or something to better give intent to why we are using (void)?

tests/arrays_test_generated.h Show resolved Hide resolved
tests/test.cpp Outdated Show resolved Hide resolved
tests/test.cpp Outdated Show resolved Hide resolved
@bakinovsky-m
Copy link
Contributor Author

@googlebot I signed it!

@googlebot
Copy link

CLAs look good, thanks!

ℹ️ Googlers: Go here for more info.

// for each object in array it:
// * sets it as zeros for POD types (integral, floating point, etc)
// * calls default constructor for classes/structs
init_list += field_name + "()";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would move init_list += field_name out of the conditional, and just have the "()" : "(0)" part in a ternary conditional.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, i'll move field_name out
but it seems like if-else construction allows this case-specific comment to be more readable than in ternary conditional, what do you think?

init_list += (IsStruct(field->value.type) || IsArray(field->value.type))
              // this is either default initialization of struct
              // or
              // implicit initialization of array
              // for each object in array it:
              // * sets it as zeros for POD types (integral, floating point, etc)
              // * calls default constructor for classes/structs
             ? "()"
             : "(0)";

versus

if (IsStruct(field->value.type) || IsArray(field->value.type)) {
  // this is either default initialization of struct
  // or
  // implicit initialization of array
  // for each object in array it:
  // * sets it as zeros for POD types (integral, floating point, etc)
  // * calls default constructor for classes/structs
  init_list += "()";
} else {
  init_list += "(0)";
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either is fine with me, with a slight preference for the ternary.

src/idl_gen_cpp.cpp Outdated Show resolved Hide resolved
src/idl_gen_cpp.cpp Outdated Show resolved Hide resolved
src/idl_gen_cpp.cpp Outdated Show resolved Hide resolved
{
(void)padding0__;
(void)padding1__;
(void)padding2__;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make a FLATBUFFERS_UNUSED() macro or something to better give intent to why we are using (void)?

@bakinovsky-m
Copy link
Contributor Author

Can anybody help me with this Visual Studio build errors?

It looks like Visual Studio just wants to tell, that behaviour in this place changed from incorrect to correct (link). But due to warning-as-error setting build is failing. Maybe I can somehow suppress this particular warning?

https://ci.appveyor.com/project/google-admin/flatbuffers/builds/33204251/job/d535rfh8x87kyv1n

c:\projects\flatbuffers\tests\arrays_test_generated.h(84): error C2220: warning treated as error - no 'object' file generated [C:\projects\flatbuffers\flattests.vcxproj]
c:\projects\flatbuffers\tests\arrays_test_generated.h(84): warning C4351: new behavior: elements of array 'MyGame::Example::NestedStruct::a_' will be default initialized [C:\projects\flatbuffers\flattests.vcxproj]
c:\projects\flatbuffers\tests\arrays_test_generated.h(84): warning C4351: new behavior: elements of array 'MyGame::Example::NestedStruct::c_' will be default initialized [C:\projects\flatbuffers\flattests.vcxproj]
c:\projects\flatbuffers\tests\arrays_test_generated.h(84): warning C4351: new behavior: elements of array 'MyGame::Example::NestedStruct::d_' will be default initialized [C:\projects\flatbuffers\flattests.vcxproj]
c:\projects\flatbuffers\tests\arrays_test_generated.h(94): warning C4351: new behavior: elements of array 'MyGame::Example::NestedStruct::a_' will be default initialized [C:\projects\flatbuffers\flattests.vcxproj]
c:\projects\flatbuffers\tests\arrays_test_generated.h(94): warning C4351: new behavior: elements of array 'MyGame::Example::NestedStruct::c_' will be default initialized [C:\projects\flatbuffers\flattests.vcxproj]
c:\projects\flatbuffers\tests\arrays_test_generated.h(94): warning C4351: new behavior: elements of array 'MyGame::Example::NestedStruct::d_' will be default initialized [C:\projects\flatbuffers\flattests.vcxproj]
c:\projects\flatbuffers\tests\arrays_test_generated.h(161): warning C4351: new behavior: elements of array 'MyGame::Example::ArrayStruct::b_' will be default initialized [C:\projects\flatbuffers\flattests.vcxproj]
c:\projects\flatbuffers\tests\arrays_test_generated.h(161): warning C4351: new behavior: elements of array 'MyGame::Example::ArrayStruct::f_' will be default initialized [C:\projects\flatbuffers\flattests.vcxproj]
c:\projects\flatbuffers\tests\arrays_test_generated.h(177): warning C4351: new behavior: elements of array 'MyGame::Example::ArrayStruct::b_' will be default initialized [C:\projects\flatbuffers\flattests.vcxproj]
c:\projects\flatbuffers\tests\arrays_test_generated.h(177): warning C4351: new behavior: elements of array 'MyGame::Example::ArrayStruct::f_' will be default initialized [C:\projects\flatbuffers\flattests.vcxproj]
C:\projects\flatbuffers\tests\test.cpp(3232): error C2061: syntax error : identifier 'non_zero_memory' [C:\projects\flatbuffers\flattests.vcxproj]

@aardappel
Copy link
Collaborator

@bakinovsky-m yes, sounds like we can disable that warning: https://docs.microsoft.com/en-us/previous-versions/1ywe7hcy(v=vs.140)?redirectedfrom=MSDN

Sadly, that would mean this at the start of a generated code file:

#if defined(_MSC_VER)
  #pragma warning(push)
  #pragma warning(disable: 4351) // C4351: new behavior: elements of array 'array' will be default initialized
#endif

And this at the end:

#if defined(_MSC_VER)
  #pragma warning(pop)
#endif

Though frankly, I'd also be ok with just sticking this in base.h, without the push/pop, since this is really weird warning that apparently is only there for people "upgrading" their code, and is not a warning other compilers give. @dbaileychess ? @vglavnyy ?

As for non_zero_memory.. maybe needs an explicit & in front? Or failing that, &non_zero_memory[0] or something :(

@vglavnyy
Copy link
Contributor

vglavnyy commented Jun 1, 2020

Another possible solution:

struct Foo {
	int arr[10];

#ifdef _MSC_VER
	__pragma(warning(disable : 4351));  // C4351: new behavior: elements of array 'array' will be default initialized
#endif
	Foo() : arr()
	{}
};

@aardappel
Copy link
Collaborator

@vglavnyy yeah, but having that in each and every struct is a bit cluttered to read..

@aardappel
Copy link
Collaborator

aardappel commented Jun 1, 2020

Also, this is a warning given by VS2013, and the description says that this constructor didn't always cause zero-init in previous versions.. but we also still compile for VS2010! So in theory, it could not work there, and not give us zero-init. I guess our unit-test will catch that if that is case?

Like I said, I'd be fine to do it globally in base.h. The worst than can happen is that someone's code that sits in the same .cpp as FlatBuffers is included contains a datatype that has an explicit array constructor and relied on a very old C++ standard and non-initialization for.. performance? I find that exceedingly unlikely.

@aardappel
Copy link
Collaborator

The CI fail you just got is crtdbg.h clashing with placement new (see top of base.h), if we want to keep using it, you may need to #undef new before it, and #define new DEBUG_NEW after (if _WIN32 and !NDEBUG). Or maybe there's a way to do this test without placement new??

@aardappel
Copy link
Collaborator

Ok, awesome, thanks!

@aardappel aardappel merged commit 988164f into google:master Jun 2, 2020
ivannp pushed a commit to ivannp/flatbuffers that referenced this pull request Oct 2, 2020
* [C++] removed array's memsets from struct parametrized constructor

now POD-typed arrays are zero-initialized
and class-typed arrays are default-initialized

* [C++] memset -> zero/default initialization in default constructor

* [C++] Struct-type and array default initialization

* [C++] Newly generated tests

* [C++] forgotten test

* [C++] curly brace by code style

* [C++] test if memory is 0's after placement new

* [C++] memory leak fix

* [C++] simplifying and non-dynamic memory in test

* [C++] code cleanup

* [C++] disable old-compiler warning

* [C++] windows build fix (try)

* [C++] debug-new win build fix
charles1614 pushed a commit to charles1614/flatbuffers that referenced this pull request Dec 28, 2021
* [C++] removed array's memsets from struct parametrized constructor

now POD-typed arrays are zero-initialized
and class-typed arrays are default-initialized

* [C++] memset -> zero/default initialization in default constructor

* [C++] Struct-type and array default initialization

* [C++] Newly generated tests

* [C++] forgotten test

* [C++] curly brace by code style

* [C++] test if memory is 0's after placement new

* [C++] memory leak fix

* [C++] simplifying and non-dynamic memory in test

* [C++] code cleanup

* [C++] disable old-compiler warning

* [C++] windows build fix (try)

* [C++] debug-new win build fix
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

"Class-memaccess" compilation error in test [C++, gcc 10.1.0, Flatbuffers 1.12.0/master]
5 participants