尝试将数字写入二进制文件时引发异常

时间:2018-10-04 15:26:09

标签: c++

我一直在尝试用c ++创建自己的二进制文件。我正在做的是定义了一个结构,该结构实际​​上与dds标头相同。因此,我要做的是首先向二进制文件中写入一个版本号,以查看我处于什么阶段,然后将整个结构写入文件,最后将一个简单的文本字符串写入文件。 但是,当我尝试将版本号写入文件时,会引发如下异常:“在TestApplication7.exe中,在0x0F377236(msvcp140d.dll)处引发了异常:0xC0000005:访问冲突读取位置0x499602DB。”

所以基本上我正在做的是像这样在cpp文件的顶部定义一个版本号:

@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
@Slf4j
public class SecurityConfig {
@Bean
    public SecurityWebFilterChain securitygWebFilterChain(ServerHttpSecurity http) {
        return http
                .csrf().disable()
                .httpBasic().disable()
                .formLogin().disable()
                .logout().disable()

                .authenticationManager(this.authenticationManager())
                .securityContextRepository(this.securityContextRepository())
                .authorizeExchange().pathMatchers("/public/**").permitAll()
                .and().authorizeExchange().anyExchange().authenticated()
                .and().build();
    }

    @Bean
    ReactiveAuthenticationManager authenticationManager() {
        return authentication -> {
            log.debug("Autentication: " + authentication.toString());
            if (authentication instanceof CustomPreAuthenticationToken) {
                authentication.setAuthenticated(true);
            }

            return Mono.just(authentication);
        };
    }

    @Bean
    ServerSecurityContextRepository securityContextRepository() {
        return new ServerSecurityContextRepository() {
            @Override
            public Mono<Void> save(ServerWebExchange serverWebExchange, SecurityContext securityContext) {
                return null;
            }

            @Override
            public Mono<SecurityContext> load(ServerWebExchange serverWebExchange) {
                Principal nonReactivePrincipal = getPrincipalFromExchangeUsingReflection(serverWebExchange);

            return Mono.just(new SecurityContextImpl(new CustomPreAuthenticationToken(nonReactivePrincipal.getName(), nonReactivePrincipal,  AuthorityUtils.createAuthorityList("ROLE_USER") )));
            }
        };
    }


    private Principal getPrincipalFromExchangeUsingReflection(ServerWebExchange serverWebExchange) {
        Principal principal = null;

        try {
            Field ServletServerHttpRequestField = serverWebExchange.getClass().getDeclaredField("request");
            ServletServerHttpRequestField.setAccessible(true);
            Object servletServerHttpRequest = ServletServerHttpRequestField.get(serverWebExchange);
            Field httpServletRequestField = servletServerHttpRequest.getClass().getDeclaredField("request");
            httpServletRequestField.setAccessible(true);
            HttpServletRequest httpServletRequest = (HttpServletRequest) httpServletRequestField.get(servletServerHttpRequest);

            principal = httpServletRequest.getUserPrincipal();

        } catch (IllegalAccessException | NoSuchFieldException e) {
            log.error(e.getMessage(), e);
        }

        return principal;
    }
}



public class CustomPreAuthenticationToken extends UsernamePasswordAuthenticationToken {        
    public CustomPreAuthenticationToken(String key, Object principal, Collection<? extends GrantedAuthority> authorities) {
        super(key, principal, authorities);
    }
}

然后我只是简单地尝试将此数字写入二进制文件。

这是我的示例代码:

#define VERSION_NR 0x499602DB

所以是这样的代码:

 void  MyFile::Save(std::string ddsPath, MyFile::FileHeader header, const std::string texturePath) {
     header.PathLen = texturePath.length();
     const char* buffer{reinterpret_cast<const char*>(&texturePath)};
     const char* version{reinterpret_cast<const char*>(VERSION_NR)};

     std::ofstream output(ddsPath, std::ios::binary);
     output.write(version, sizeof(VERSION_NR)); //Here is where the exception is thrown
     ext->WriteStruct(output, header); //Writing the hole header to the file
     output << texturePath; //Outputting a simple text to the file
}

这导致引发异常,我不知道自己在做什么错,因为我对C ++编程非常陌生。我确实尝试在“保存”方法中创建一个const DWORD而不是使用宏,但是我仍然遇到相同的异常。 我不知道这是否有帮助,但消息“访问冲突读取位置0x499602DB”与我的宏的值是相同的“位置”。

如果有人可以帮助我,或者只是将我指出正确的方向,我将不胜感激。 谢谢!

2 个答案:

答案 0 :(得分:2)

如果我们摆脱了宏和许多其他不相关的代码,我们将得到:

int version = 0x499602DB;
const char* ch = reinterpret_cast<const char*>(version);
std::ofstream output("out.bin", std::ios::binary);
output.write(ch, sizeof(version));

您是正确的,即错误消息中显示了您的版本值这一事实是一个线索。第二行将整数值转换为地址为0x499602DB的字符指针。由于output.write尝试访问该地址时,该地址未指向有效的内存地址,因此操作系统不允许该操作,并且引发和访问冲突。

正确的代码是:

int version = 0x499602DB;
const char* ch = reinterpret_cast<const char*>(&version);
std::ofstream output("out.bin", std::ios::binary);
output.write(ch, sizeof(version));

或者,无论如何,您都想编写一个字符串,只需避免全部强制转换:

const char version[4] = {'\xDB','\x02','\x96','\x49'};
std::ofstream output("out.bin", std::ios::binary);
output.write(version, sizeof(version));

还请注意,一旦我们解决了此崩溃问题,以下内容也不正确:

const char* buffer{reinterpret_cast<const char*>(&texturePath)};

并且应该简单地是:

const char* buffer = texturePath.c_str();

texturePath是一个std::string对象,指向它的指针不能转换为char*c_str()方法返回一个const char*指针,然后可以传递该指针到std::ofstream::write的位置,或者只需像现在一样使用output << texturePath,然后删除buffer变量即可。

答案 1 :(得分:1)

VERSION_NR不是变量,因此char *指向随机存储器。 不要像处理其他数据那样使用宏,创建变量,在其上获取指针。