compiler demands not used operator delete

Hello!
I created test class with public operator new and private operator delete(not implemented, just declared). I have code that creates class instance with operator new. delete never used.
However I get compilation error C2248: ‘delete_class::operator delete’: cannot access private member declared in class ‘delete_class’.
If I explicitly delete operator delete (= delete) compilation ok.
This code compiles no problem as user mode program in Visual Studio.

Why compiler requires not used function ?
Does anyone know why this is happening?

Minimal code to reproduce:

#include <wdm.h>

class delete_class
{
public:
  void* operator new(size_t) { return nullptr; }
private:
  void operator delete(void*);
};

extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT, PUNICODE_STRING)
{
  delete_class* d{ new delete_class };
  UNREFERENCED_PARAMETER(d);
  return STATUS_UNSUCCESSFUL;
}

Make it a public. UNREFERENCED_PARAMETER is referencing the parameter
and the code is thus trying to access the delete member.
In user mode, all of that is optimized away, and the variable is not
even created, thus delete is not accessed.

If you attempt to access it in user mode, you would get the same error.

D.

On 4/26/20, Sergey_Pisarev wrote:
> OSR https://community.osr.com/
>
> Sergey_Pisarev started a new discussion: compiler demands not used operator
> delete
>
> Hello!
>
> I created test class with public operator new and private operator
> delete(not implemented, just declared). I have code that creates class
> instance with operator new. delete never used.
>
> However I get compilation error C2248: ‘delete_class::operator delete’:
> cannot access private member declared in class ‘delete_class’.
>
> If I explicitly delete operator delete (= delete) compilation ok.
>
> This code compiles no problem as user mode program in Visual Studio.
>
> Why compiler requires not used function ?
>
> Does anyone know why this is happening?
>
> Minimal code to reproduce:
>
> #include <wdm.h>
>
> class delete_class
> {
> public:
> void* operator new(size_t) { return nullptr; }
> private:
> void operator delete(void*);
> };
>
> extern “C” NTSTATUS DriverEntry(PDRIVER_OBJECT, PUNICODE_STRING)
> {
> delete_class* d{ new delete_class };
> UNREFERENCED_PARAMETER(d);
> return STATUS_UNSUCCESSFUL;
> }
>
> –
> Reply to this email directly or follow the link below to check it out:
> https://community.osr.com/discussion/292051/compiler-demands-not-used-operator-delete
>
> Check it out:
> https://community.osr.com/discussion/292051/compiler-demands-not-used-operator-delete
></wdm.h>

Thank you for trying to help Dejan. But unfortunately all you have said is wrong :frowning:

Try a debug build of a user mode app, and if that does compile, add some code that actually runs for the class (e.g. ::member_function() {printf(“here\n”); } )

I am getting the same C2248 error in user mode then.
Changing it to public instead of private removes the error in both cases.

Changing it to public instead of private removes the error in both cases.

That’s what I would have suggested too.

Peter

If you do a new of the object the compiler will try to find the related
delete operator. It can’t in your case. because there is no available
delete operator. In user mode it can find the global delete operator from
the C++ runtime and will be happy. In kernel mode that doesn’t exist,
because and , so it barfs. Some old git once wrote a
suitable C++ runtime for the kernel and put it in the public domain. It
should still work and should still be available.

Mark Roddy

@Dejan_Maksimovic said:
Try a debug build of a user mode app, and if that does compile, add some code that actually runs for the class (e.g. ::member_function() {printf(“here\n”); } )

I am getting the same C2248 error in user mode then.
Changing it to public instead of private removes the error in both cases.

class delete_test
{
public:
  void* operator new(size_t) { return nullptr; }
private:
  void operator delete(void*);
};

int main()
{
  auto d{ new delete_test };
  d;
  return 0;
}

This code compiles in debug mode as um app with /W4 /WX. intellisense complains about private delete though.

@“Peter_Viscarola_(OSR)” said:

Changing it to public instead of private removes the error in both cases.

That’s what I would have suggested too.

Peter

Thank you guys.
I guess I wasn’t clear about what I want.
I know how to make this compile. This is not my first c++ project, I promise :slight_smile:

I am confused because this contradicts my understanding of c++ itself. In my understanding compiler shouldn’t care about function that not used. And it doesn’t actually care if I define any other unused function, private or not. but somehow it does care about operator delete.

I would like to understand what’s going on. This doesn’t block my work, but I hate to not understand what’s happening.

PS. operator delete not used in um app, I promise. delete declared but not defined, the project wouldn’t link if delete was used. plus I checked this in IDA - no operator delete in binary .

@Mark_Roddy said:
If you do a new of the object the compiler will try to find the related
delete operator. It can’t in your case. because there is no available
delete operator. In user mode it can find the global delete operator from
the C++ runtime and will be happy. In kernel mode that doesn’t exist,
because and , so it barfs. Some old git once wrote a
suitable C++ runtime for the kernel and put it in the public domain. It
should still work and should still be available.

Mark Roddy

Thank you Mark!
Yes I thought about that and defined global operator delete - still doesn’t compile for KM.
Interesting that if member operator delete not declared at all or declared as explicitly deleted - everything compiles just fine in KM. And if compiler tries to find related delete it should’ve complain.

If your binary in UM does not have delete symbols, then it is not using it.

The driver is.

I tried compiling your class into a WDK UM main() app, and it fails to
compile, with the same error.

Whether yours finds a global delete (should not, when you overrode it!), or
your UM code does not even allocare the class is the question.

My bet is still the latter.

@Dejan_Maksimovic said:
If your binary in UM does not have delete symbols, then it is not using it.

The driver is.

I tried compiling your class into a WDK UM main() app, and it fails to
compile, with the same error.

Whether yours finds a global delete (should not, when you overrode it!), or
your UM code does not even allocare the class is the question.

My bet is still the latter.

I create generic console project, not wdk app.
operator new generated and actually called. it is easy to check and I did it before starting this discussion. it is not a bet but a fact.

additional facts:
llvm doesn’t compile with private operator delete.
g++ compile with no errors or warnings.

OK. I now officially have no idea what Mr. Pisarev is asking. Though his sort of rude attitude his clear, the point of his question is not. At least to me.

Peter

I think I found the answer.
According to standard:
“If the new-expression creates an object or an array of objects of class type, access and ambiguity control are done for the allocation function, the deallocation function (15.5), and the constructor (15.1).”

So operator delete is special case and access checked by compiler even if delete itself never used. Thus this is not vs compiler idiosyncrasy but standard-compliant behaviour.

As a point of reference, your code gets an error in GCC, even without the unreferenced parameter.

[timr@Tims-Pro-14:~/src]$ g++  --std=c++11 -o x x.cpp
x.cpp:14:20: error: 'operator delete' is a private member of 'delete_class'
  delete_class* d{ new delete_class };
                   ^
x.cpp:9:8: note: declared private here
  void operator delete(void*);
       ^
1 error generated.
[timr@Tims-Pro-14:~/src]$ 
#include <cstdio>

class delete_test
{
  public:
  void* operator new(size_t) noexcept {return nullptr;}
  private:
  void operator delete(void*);
};

int main()
{
  delete_test* d{new delete_test};
  printf("%p\n", d);
  return 0;
}

this exact code successfully builds for me with g++ --std=c++11 -o x x.cpp

my g++ version:

ps@linuxdev:~/projects/delete_test$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:hsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: …/src/configure -v --with-pkgversion=‘Ubuntu 9.2.1-9ubuntu2’ --with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,gm2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-9 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none,hsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 9.2.1 20191008 (Ubuntu 9.2.1-9ubuntu2)

@Tim_Roberts said:

As a point of reference, your code gets an error in GCC, even without the unreferenced parameter.

[timr@Tims-Pro-14:~/src]$ g++  --std=c++11 -o x x.cpp
x.cpp:14:20: error: 'operator delete' is a private member of 'delete_class'
  delete_class* d{ new delete_class };
                   ^
x.cpp:9:8: note: declared private here
  void operator delete(void*);
       ^
1 error generated.
[timr@Tims-Pro-14:~/src]$ 

why does anyone think that C++ is a good idea for anything?

why does anyone think that C++ is a good idea for anything?

Well, THAT’S an awesome trolling good way to get the thread locked.

Peter