View in English

  • Global Nav Open Menu Global Nav Close Menu
  • Apple Developer
Search
Cancel
  • Apple Developer
  • News
  • Discover
  • Design
  • Develop
  • Distribute
  • Support
  • Account
Only search within “”

Quick Links

5 Quick Links

Vídeos

Abrir menu Fechar menu
  • Coleções
  • Tópicos
  • Todos os vídeos
  • Sobre

Mais vídeos

  • Sobre
  • Resumo
  • Transcrição
  • Código
  • Combine C, C++ e Swift com segurança

    Saiba como combinar C, C++ e Swift enquanto aumenta a segurança de seus apps. Mostraremos como identificar onde APIs do C e C++ não seguras são chamadas no seu código Swift, como chamá-las com mais segurança e como deixar o código em C e C++ existente no seu app mais seguro por padrão.

    Capítulos

    • 0:00 - Introdução
    • 2:39 - Encontrar uma chamada não segura no Swift
    • 4:55 - Chamar C/C++ com segurança
    • 7:25 - Funções que usam ponteiros
    • 17:13 - Funções que retornam ponteiros
    • 20:16 - Importar tipos personalizados
    • 26:57 - Melhorar a segurança do C/C++
    • 30:48 - Conclusão

    Recursos

    • -fbounds-safety: Enforcing bounds safety for C
    • Safely Mixing Swift and C++
      • Vídeo HD
      • Vídeo SD

    Vídeos relacionados

    WWDC25

    • Melhore o uso da memória e o desempenho com o Swift
  • Buscar neste vídeo...

    Olá! Meu nome é Yeoul. Sou manager da equipe Secure Language Extension da Apple. Ao criar um app, é fundamental priorizar a segurança, ou seja, proteger as informações privadas dos seus usuários contra possíveis invasores. Esses agentes mal-intencionados exploram vulnerabilidades em código escrito em C e C++, que são linguagens inseguras. Pelo lado positivo, se o seu app já usa o Swift, essa linguagem é segura por padrão. É uma notícia fantástica.

    Mas mesmo que você escreva todo o novo código em Swift, o app ainda pode ter códigos em C e C++ em partes mais antigas da sua base de código. Ou pode usar bibliotecas externas. Ao combinar essas linguagens, é importante que as proteções do Swift não sejam comprometidas. Em alto nível, o problema é que as funções C e C++ que recebem ou retornam ponteiros brutos são difíceis de ser chamadas com segurança. Chamá-las incorretamente pode causar erros de segurança e estabilidade, como estouros de buffer e use-after-frees.

    Por causa disso, ponteiros em C e C++ são importados como tipos não seguros no Swift. Por exemplo, um ponteiro de número inteiro em C é importado como UnsafeMutablePointer. O Swift inclui Unsafe no nome do tipo de propósito. Isso mostra que não posso confiar nas garantias normais de segurança ao chamar a função. Mas sei que algumas funções podem ser chamadas com segurança no Swift. Até agora, não era possível fazer isso com C e C++. Esse é o assunto desta sessão.

    Primeiro, descreverei um novo recurso, segurança rígida da memória, que ajuda a identificar chamadas inseguras no Swift.

    Depois, mostrarei como anotar funções C e C++ para transmitir informações ausentes para o Swift chamá-las com segurança. Em seguida, explicarei como anotar tipos C++ personalizados para importação segura. Embora as linguagens baseadas em C nunca sejam tão seguras quanto o Swift, vou mostrar ferramentas para tornar códigos em C e C++ mais seguros.

    O Swift 6.2 tem um novo recurso para ajudar a identificar chamadas para funções em C e C++ não seguras. Demonstrarei isso em um app que criei, no qual os usuários podem compartilhar fotos de perfil fofas de seus animais de estimação. O app tem acesso a informações privadas muito confidenciais do usuário, como o sobrenome do cachorro, então deve ser seguro. Ele é escrito no Swift. Ele também chama códigos em C e C++ para aplicar filtros de imagem personalizados. Quero encontrar todas as chamadas não seguras de C e C++ dentro do app para torná-las seguras. A parte complicada é que encontrar essas chamadas pode ser difícil. O Swift é seguro por padrão, mas permite o uso de construções não seguras, especialmente ao interoperar com C e C++. Por exemplo, nos bastidores, &imageData cria um UnsafeMutablePointer, que eu posso ver pelo nome que não é seguro. Não é fácil notar isso ao ler esse código. Para detectar chamadas não seguras, posso usar o novo modo de segurança rígida da memória no Swift 6.2. Quando o modo está ativado, o compilador alerta em caso de códigos não seguros e nos explica o raciocínio. A segurança rígida da memória não está ativada por padrão, mas como meu app precisa de segurança, vou ativá-la. Vamos conferir isso no Xcode.

    Vou ativar a segurança rígida da memória nos ajustes do projeto.

    Quando eu recompilo, o compilador mostra avisos para ajudar a identificar construções não seguras.

    Vejo alguns novos avisos agora. A maioria desses códigos inseguros envolve ponteiros em C e C++.

    Mostrarei como chamar com segurança funções que usam esses ponteiros no Swift.

    Antes, vamos falar sobre o que dificulta o uso com segurança de ponteiros em C e C++.

    Os ponteiros são uma ferramenta eficiente e útil. Eles permitem fazer buscas na memória sem precisar copiá-la. Mas são muito difíceis de usar com segurança. Isso ocorre porque o C e o C++ não ajudam os programadores a evitar erros. Por exemplo, nada me impede de usar acidentalmente uma parte da memória depois que ela foi liberada ou de acessar além dos limites de um buffer.

    Temos boas notícias. O Swift 6.2 inclui um novo tipo de ponteiro seguro chamado Span que oferece os benefícios dos ponteiros e evita esses erros automaticamente. Um Span funciona como um ponteiro, mas tem segurança integrada. O Swift garante que você não consiga realizar ações não seguras com ele. E se você precisar modificar a memória, há um MutableSpan. Para saber mais sobre o Span, confira “Melhorias no desempenho e no uso da memória o Swift". Seria ótimo se o Swift importasse ponteiros em C e C++ como Spans em vez de ponteiros não seguros.

    Infelizmente, faltam duas informações importantes no compilador para que ele faça isso com segurança. Sem informações do C++ sobre os limites de um ponteiro, o Swift não pode impedir acessos fora dos limites. E sem informações do C++ sobre a vida útil do ponteiro, o Swift não consegue impedir que ele seja usado depois de liberado. A ideia é que, se o programador fornecer as informações que faltam, o Swift poderá tratar um ponteiro não seguro como um Span.

    No Swift 6.2, posso fornecer as informações ausentes ao compilador adicionando anotações aos meus códigos em C e C++. Isso não muda o modo como esse código funciona. Apenas torna suas suposições explícitas. Assim, o Swift pode chamar com segurança códigos em C e C++ que usam ponteiros. Vamos falar sobre como anotar funções que usam e retornam ponteiros. Para fazer isso, vamos voltar ao meu app.

    O primeiro aviso é sobre o uso da função invertImage que usa um ponteiro bruto.

    Mostrarei como chamar com segurança funções como essa, que usam ponteiros como parâmetros.

    Como mencionei, ponteiros brutos não têm informações sobre limites, então não há como verificar se acessam dentro dos limites. Se eu não usá-los com cuidado, eles podem causar erros de memória fora dos limites. Veja um exemplo. A função InvertImage é chamada no Swift. A função usa um ponteiro de imagem, que é um ponteiro bruto para a imagem, e o tamanho tem parâmetros separados.

    Como o ponteiro da imagem é só um ponteiro bruto, nada me impede de passar acidentalmente um tamanho muito grande. Se eu fizer isso, a função lerá e gravará além dos limites do buffer. E esse é exatamente um dos problemas que o Span resolve. Imagine se invertImage fosse importado como uma função do Swift que usa um Span. Eu poderia passar um Span diretamente em vez de passar um ponteiro bruto e o tamanho separadamente. Isso me protegerá automaticamente de erros como passar o tamanho errado, porque Spans sempre carregam as informações de limites corretas para a memória a que apontam. Então, nos bastidores, o compilador se encarregará de desempacotar o Span, extrair o ponteiro e o tamanho corretos e passá-los para a função em C para mim. Dessa forma, não haverá margem para erros.

    O compilador faz isso, mas falta a conexão entre o ponteiro bruto e o tamanho. A função invertImage presume que o ponteiro se refere a um buffer de elementos de imageSize, mas é apenas uma suposição implícita. Preciso expressar essa relação explicitamente para que tanto os humanos quanto o compilador entendam isso. Isso pode ser expresso com a anotação counted_by. Ela informa ao compilador o número de elementos na memória apontados pelo ponteiro. Então, o ponteiro também precisa de outra anotação chamada noescape para informações de vida útil ausentes. Mas você pode ignorá-la por enquanto. Vou mostrar isso mais tarde. Após fornecer as informações extras, posso chamar a função do Swift com segurança passando um Span diretamente. O compilador cuidará automaticamente do resto. Dessa forma, não é possível haver erros. Voltarei à função invertImage.

    Vou adicionar anotações counted_By e noescape à função invertImage.

    Vou acessar a decoração e adicionar as mesmas anotações.

    Voltarei ao local de chamadas no Swift.

    Agora vou passar a imageData diretamente para chamar a função do Swift.

    Agora não há um ponteiro não seguro envolvido, então o aviso desapareceu.

    O próximo aviso está na função applyGrayScale. Ele diz que a função usa um tipo em C++ não seguro.

    Vamos dar uma olhada na definição de C++ dessa função. Como o nome indica, applyGrayScale é uma função que aplica um efeito de escala de cinza na imagem de entrada. A função usa uma visualização da imagem, que é um tipo Span em C++. Até aqui, falamos sobre Spans no Swift. Mas o C++ também tem uma noção sobre Spans. Vemos o alerta porque o Swift considera os Spans do C++ não seguros, mesmo que estejam tentando resolver o mesmo problema. Assim como os Spans do Swift, os Spans do C++ são um tipo padrão usado para acessar a memória contígua de outra pessoa. Eles contêm um ponteiro para essa memória e seu tamanho. Como os Spans do C++ sabem o tamanho, podem verificar com segurança se há acessos fora dos limites, como os Spans do Swift. Ao contrário dos Spans do Swift, os Spans do C++ não têm informações de vida útil, portanto, não impedem o acesso à memória alocada. Usar um Span do C++ pode causar um erro use-after-free.

    Veja um exemplo. Imagine se a função ApplyGrayScale usasse um Span do C++ chamado imageView, que aponta para uma matriz criada pelo Swift.

    Em applyGrayscale, posso salvar o ponteiro em uma variável global como cachedView para outro código em C++ usar depois.

    Mas aqui está o problema. Depois que a função retorna, o Swift pode desalocar a matriz, porque supõe que não é mais usada. Agora, o código C++ mantém um ponteiro que não aponta para uma memória válida. É um ponteiro pendente. Acessá-lo é um erro clássico do tipo use-after-free.

    Por outro lado, um Span do Swift é seguro. Ele não é mais usado depois que a memória a qual ele aponta não é mais usada. Se uma função usa um Span do Swift, ela só pode usá-lo dentro da função. Não é permitido mantê-lo, como salvá-lo em um cachedView para uso posterior. Quando um ponteiro é mantido após o fim da função, isso é chamado de escape. E o compilador relata um erro como esse sempre que um Span tenta escapar de seu escopo.

    Não é possível que ponteiros fiquem pendentes com os Spans do Swift, e os erros use-after-free são evitados por padrão.

    Um Span do C++ não fornece o mesmo tipo de garantias. Para segurança, preciso auditar manualmente a função e garantir que não retenha imageView, evitando um ponteiro pendente.

    Depois de verificar se o parâmetro não escapa da função em C++, preciso lembrar essa informação na definição da função. Assim, os humanos e o compilador podem entender o comportamento da função. Adicionar a anotação noescape me ajuda a fazer isso. A anotação noescape também pode ser aplicada a ponteiros e referências brutos.

    A partir do Swift 6.2, um parâmetro Span do C++ com a anotação noescape poderá ser tratado como um Span do Swift. Agora posso passar um Span do Swift diretamente para applyGrayscale, o que é conveniente e evita código boilerplate inseguro. É incrível como chamar uma função em C++ pode ser algo tão seguro e fácil.

    Vou para a definição de applyGrayScale

    e adicionar noescape ao parâmetro imageView

    e também à decoração.

    Agora, voltarei ao local principal no Swift.

    Posso remover o acesso temporário ao ponteiro de buffer mutável não salvo e passar diretamente o Span do Swift retirado de imageData.

    O aviso desapareceu, pois chamei applyGrayscale com segurança.

    O próximo aviso é sobre o uso de scanImageRow, que usa um Span do C++ e retorna outro Span do C++.

    Como chamo com segurança uma função que retorna um ponteiro como o Span do C++?

    Retornar um Span do C++ pode ser perigoso porque ele não monitora se a memória para a qual aponta ainda é válida. Veja um exemplo. ScanImageRow usa imageView como um Span do C++ e retorna outro Span do C++ apontando para uma linha selecionada de imageData. Quando a função retornar, os dados serão desalocados. Retornar Span do C++ ainda aponta para tal memória, criando um ponteiro pendente. Isso resulta em um acesso use-after-free. Esse erro seria evitado se o valor retornado fosse tratado como um Span do Swift em vez de um Span do C++. Isso ocorre porque o compilador não deixa retornar um Span do Swift, a menos que saiba que a memória retornada ainda é válida e que ainda é seguro usá-la. Então, quando é realmente seguro usar o Span de retorno? Ele aponta para parte da mesma memória que o parâmetro imageView. Isso significa que a vida útil dele acompanha a do imageView.

    Essa relação é chamada de lifetimebound.

    Essa é a informação que falta para o Swift importar um Span de retorno do C++ como um Span do Swift. Posso expressar isso com a anotação lifetimebound. Assim, o compilador garante que ele seja usado com segurança.

    Vou para a definição de scanImageRow.

    Vou adicionar lifetimebound ao parâmetro imageView da função scanImageRow.

    E farei o mesmo na declaração.

    Com a anotação lifetimebound, a função pode usar um Span do Swift e retornar outro Span do Swift. Vou para a parte principal no Swift.

    Posso remover o acesso não seguro do ponteiro e passar o Span do Swift.

    A função agora retorna um Span do Swift, em vez de um ponteiro não seguro. Assim que eu recompilar, o aviso desaparecerá.

    Agora que resolvi as chamadas não seguras do código em códigos C e C++, todos os avisos desapareceram. Até agora, falei sobre como tratar ponteiros em C e C++ como Spans do Swift. Mas há outros tipos idiomáticos em C++ que podem ser importados para o Swift e usados com segurança com anotações. Esses são tipos de visualização personalizados e tipos de contagem de referência. Primeiro, veremos como importar com segurança tipos de visualização de C++ personalizados. Um tipo de visualização é um struct que contém um ponteiro ou uma referência à memória que não possui. Portanto, o Span do Swift também é um tipo de visualização.

    Vmos ver mais de perto o que torna os Spans do Swift seguros. Nos bastidores, os Spans são marcados como um tipo especial do Swift: nonescapable. Tipos nonescapable são usados para implementar tipos que oferecem uma visualização da memória de outro tipo sem fazer uma cópia dela. Assim como o Span, o Swift garante que todos os tipos nonescapable não escapem de seu contexto atual. Assim, eles não duram mais que a memória para a qual apontam, por isso estão protegidos contra erros use-after-free. Tipos de visualização do C++ podem ser importados como nonescapable no Swift. Tudo o que preciso fazer é adicionar uma anotação.

    Veja um exemplo. O app tem um struct em C++ personalizado, ImageView, que armazena a largura e a altura de uma imagem e um ponteiro para os dados de pixel da imagem. imageView não possui esses dados de pixel. Ele pertence a outro objeto, que é responsável por liberar a memória quando ela não é mais necessária.

    Isso significa que não é seguro para imageView escapar. Se fosse, a visualização usaria memória subjacente já desalocada.

    Então eu quero ter certeza de que o tipo nunca escapa. Para isso, posso acrescentar a anotação SWIFT_NONESCAPABLE. Dessa forma, o compilador importa o tipo C++ como nonescapable. Uma boa regra geral é que, se você tiver um struct com uma visualização ou ponteiro para a memória que não possui, você deve usar essa anotação.

    Além de visualizações, é comum em C++ e outras linguagens que os tipos controlem a memória e usem contagem de referências. O Swift permite importar esses tipos com segurança usando anotações. Por exemplo, meu struct ImageBuffer em C++ possui seu imageData subjacente. Quando o struct é desalocado, o imageData também é desalocado. Quero importar o buffer de imagem como tipo de contagem de referência no Swift para o compilador gerenciar sua vida útil. Para fazer isso, usarei a anotação SWIFT_SHARED_REFERENCE para dizer ao compilador quais funções o Swift deve chamar para aumentar e diminuir a contagem de referência Agora, o Swift vê o buffer de imagem como um tipo de contagem de referência.

    Mas o compilador precisa de mais informações para retornar o buffer de imagem com segurança.

    Quando uma função C++ retorna um buffer de imagem, há duas situações possíveis. Se a função retornar uma imagem recém-criada, o chamador deverá liberá-la após concluir. Nesse caso, vou anotar o método como SWIFT_RETURNS_RETAINED. Isso diz ao compilador do Swift para liberar a imagem no chamador quando ela não for mais usada. Se a função retornar uma referência a uma imagem que existe, o chamador deverá reter a imagem se quiser mantê-la. Nesse caso, vou anotar o método como SWIFT_RETURNS_UNRETAINED. Isso diz ao compilador do Swift que ele deve reter a imagem se quiser mantê-la. A adição dessas anotações torna as expectativas de propriedade explícitas. Assim, o Swift pode gerenciar a memória com segurança.

    Anotar código para fornecer informações ausentes permite que o Swift use com segurança funções e tipos em C e C++. Essas anotações não alteram o modo como o código funciona. Elas apenas tornam explícitas as suposições no código.

    Vamos recapitular as anotações que abordamos e como usá-las.

    Se um parâmetro ou retorno de função for um ponteiro ou tipo de matriz e apontar para a memória de mais de um elemento, use a anotação counted_by para indicar o número de elementos. Se um parâmetro referenciar uma memória de propriedade de outros e o parâmetro não escapar a função, use noescape.

    Se o valor de retorno da função referenciar uma memória cuja vida útil depende da vida útil de um parâmetro, adicione a anotação lifetimebound. Ao adicionar essas informações, você permite que o Swift importe o ponteiro como um tipo de Span do Swift seguro que não precisa ser usado no local da chamada.

    Você também pode adicionar anotações para ajudar o Swift a gerenciar com segurança seus tipos em C++ personalizados. Use SWIFT_NONESCAPABLE se o tipo em C++ armazenar uma visualização, um ponteiro ou uma referência a uma memória que não possui. Isso dirá ao compilador para importar o tipo como nonescapable.

    Se seu tipo for de referência contada, você deverá usar SWIFT_SHARED_REFERENCE. Em seguida, o compilador gerenciará sua memória automaticamente.

    É muita informação. É um bom momento para pausar o vídeo e fazer um lanche ou beber águra, se quiser. Só prometa que voltará, pois mostrarei novas ferramentas que deixam os códigos em C e C++ mais seguros.

    Vou falar sobre como deixar os códigos em C e C++ mais seguros. No meu app, adicionei anotações para garantir que o Swift possa fazer chamadas seguras em C e C++. No entanto, os códigos C e C++ puros ainda permanecem não seguros. Estou a apenas um erro de um erro de segurança. O ideal seria reescrever esse código em Swift para ter total segurança. Às vezes, isso não é prático. Não é possível tornar C e C++ tão seguros quanto o Swift, mas veja ferramentas para aumentar a segurança dessas linguagens. Falarei sobre uma ferramenta que desenvolvemos para aumentar a segurança de limites para C++.

    Alguns de vocês podem se perguntar por que o C++ ainda não é seguro para limites, já que os Spans já armazenam informações de limites, como já falei. O problema é que subscritos em Spans como este não têm verificação de limites padrão no C++. E o mesmo vale para outros contêineres padrão, como vetores. O Xcode tem um recurso chamado C++ Standard Library Hardening. Ele garante verificação de limites em subscritos de visualizações e contêineres padrão do C++. Ele também adiciona algumas outras verificações de segurança à biblioteca padrão.

    Mesmo depois de ativar o C++ Standard Library Hardening, ainda há outro problema.

    Você ainda pode usar ponteiros brutos, que não podem ser verificados porque eles não têm informações de limites. Portanto, a melhor maneira de usar o C++ é evitar ponteiros brutos e usar tipos padrão, como Spans do C++.

    Para ajudar nisso, o Xcode permite ativar erros para quando você usar ponteiros não seguros no C++. Assim, você pode revisar seu código e trocar ponteiros brutos por Spans ou contêineres padrão do C++.

    Um alerta: Esses erros são sobre segurança de limites, não segurança de vida útil.

    Para segurança nos limites de C++, defina “Enforce Bounds-Safe Buffer Usage in C++” como Yes nos ajustes de compilação do projeto. Isso ativará o C++ Standard Library Hardening e o aviso de erros de uso de buffer não seguros.

    E o C? Diferentemente do C++, o C não tem tipos padrão como Spans que carreguem limites em ponteiros. Para o C, criamos uma nova extensão de linguagem para segurança dos limites. Agora você pode usá-la no Xcode. Com essa extensão de linguagem ativada, o compilador informará onde estão faltando informações de limite em todo o código em C. Você pode adicionar anotações de limite para expressar as informações ausentes. Neste exemplo, você pode adicionar a anotação counted_by no buffer, a mesma usada para interoperação segura do Swift e do C anteriormente.

    Depois, o compilador insere verificações em tempo de execução para impedir acessos fora dos limites.

    É possível ativar a segurança de limites para os arquivos C nos ajustes do Xcode. Para saber mais, confira a documentação sobre segurança de limites em llvn.org.

    Nesta palestra, descrevo como garantir a segurança no Swift e chamar com segurança código em C e C++. O C e o C++ nunca serão tão seguros quanto o Swift, mas podem ser mais seguros.

    Confira algumas dicas para ter a mais alta segurança ao combinar C, C++ e Swift.

    Ative a segurança rígida de memória no Swift. Isso alerta sobre construções não seguras e ajuda a localizar usos não seguros de APIs C e C++. Garanta a interação segura do Swift com APIs C e C++ não seguras adicionando anotações a elas.

    Torne o C e o C++ mais seguros por padrão. Para isso, ative os novos recursos de segurança de limites para o C e o C++.

    Estamos trabalhando com a comunidade de código aberto para o C, o C++ e o Swift funcionarem juntos com eficiência e segurança. Por isso, seu feedback e participação são importantes para nós.

    Faça um teste e dê sua opinião. Agradeço por assistir.

    • 3:19 - Unsafety can be subtle

      // Swift
      var imageData = [UInt8](repeating: 0, count: imageDataSize)
      filterImage(&imageData, imageData.count)
    • 4:01 - Strict memory safety

      // Swift
      var imageData = [UInt8](repeating: 0, count: imageDataSize)
      filterImage(&imageData, imageData.count)
      //warning: Expression uses unsafe constructs but is not marked with 'unsafe'
    • 8:00 - Raw pointers don't prevent out-of-bounds errors

      // C/C++
      void invertImage(uint8_t *imagePtr, size_t imageSize);
    • 8:21 - Raw pointers don't prevent out-of-bounds errors

      // Swift
      var imageData = [UInt8](repeating: 0, count: imageSize)
      invertImage(&imageData, imageSize)
    • 8:30 - Raw pointers don't prevent out-of-bounds errors

      // Swift
      var imageData = [UInt8](repeating: 0, count: imageSize)
      invertImage(&imageData, 1000000000000)
    • 8:48 - Solution for out-of-bounds error

      // Swift
      func invertImage(_ imagePtr : inout MutableSpan<UInt8>)
    • 8:54 - Solution for out-of-bounds error

      // Swift
      var imageDataSpan = imageData.mutableSpan
      invertImage(&imageDataSpan)
    • 9:58 - Express bounds information using __counted_by

      // C/C++
      void invertImage(uint8_t *__counted_by(imageSize) imagePtr __noescape, size_t imageSize);
    • 12:10 - Unsafe function declaration taking a C++ span

      // C++
      using CxxSpanOfByte = std::span<uint8_t>;
      void applyGrayscale(CxxSpanOfByte imageView);
    • 13:21 - Unsafe C++ function caching a C++ span

      // C++
      CxxSpanOfByte cachedView;
      void applyGrayscale(CxxSpanOfByte imageView) {
        cachedView = imageView;
        // Apply effect on image ...
      }
    • 14:08 - Swift Span prevents escaping scope

      // Swift
      var cachedView: MutableSpan<UInt8>?
      func applyGrayscale(_ imageView: inout MutableSpan<UInt8>) {
        cachedView = imageView // error: lifetime dependent value escapes its scope
        // Apply effect on image ...
      }
    • 15:18 - Express lifetime information using __noescape

      // C++
      CxxSpanOfByte cachedView;
      void applyGrayscale(CxxSpanOfByte imageView __noescape) {
        // Apply effect on image ...
      }
    • 15:56 - Safely use a C++ Span as a Swift Span

      // Swift
      var imageDataSpan = &imageData.mutableSpan
      applyGrayscale(&imageDataSpan)
    • 17:21 - Returned C++ Span is unsafe

      // C++
      CxxSpanOfByte scanImageRow(CxxSpanOfByte imageView,
                                 size_t width, size_t rowIndex);
    • 18:06 - Swift Spans prevent use-after-free by design

      // Swift
      func scanImageRow(_ imageView : inout MutableSpan<UInt8>,
                        _ width : Int, _ rowIndex : Int) -> MutableSpan<UInt8>
      // error: a function with a ~Escapable result requires '@lifetime(...)'
    • 18:47 - Express lifetime dependency with __lifetimebound

      // C++
      CxxSpanOfByte scanImageRow(CxxSpanOfByte imageView __lifetimebound,
                                 size_t width, size_t rowIndex);
    • 18:50 - Safely return a C++ Span as a Swift Span

      // Swift
      var imageDataSpan = imageData.mutableSpan
      var rowView = scanImageRow(&imageDataSpan, width, y)
    • 22:29 - Import a C++ view type as SWIFT_NONESCAPABLE

      // C++
      struct ImageView {
        std::span<uint8_t> pixelBytes;
        int width;
        int height;
      } SWIFT_NONESCAPABLE;
    • 23:31 - Import a C++ reference-counted type

      // C++
      struct ImageBuffer {
        std::vector<uint8_t> data;
        int width;
        int height;
        std::atomic<unsigned> refCount;
      } SWIFT_SHARED_REFERENCE(retain_image_buffer, release_image_buffer);
      
      void retain_image_buffer(ImageBuffer *_Nonnull buf);
      void release_image_buffer(ImageBuffer *_Nonnull buf);
    • 23:57 - Safely return a reference-counted type

      // C++
      ImageBuffer *_Nonnull createImage() SWIFT_RETURNS_RETAINED;
      ImageBuffer *_Nonnull getCachedImage() SWIFT_RETURNS_UNRETAINED;
    • 27:51 - C++ standard library hardening

      // C++
      void fill_array_with_indices(std::span<uint8_t> buffer) {
        for (size_t i = 0; i < buffer.size(); ++i) {
          buffer[i] = i;
        }
      }
    • 28:59 - C++ unsafe buffer usage errors

      // C++
      void fill_array_with_indices(uint8_t *buffer, size_t count) {
        for (size_t i = 0; i < count; ++i) {
          buffer[i] = i; // error: unsafe buffer access
        }
      }
    • 30:11 - Bounds safety extension for C

      // C
      void fill_array_with_indices(uint8_t *__counted_by(count) buf, size_t count) {
        for (size_t i = 0; i < count; ++i) {
          buf[i] = i;
        }
      }
    • 0:00 - Introdução
    • Saiba mais sobre a segurança dos apps, especialmente ao combinar Swift, uma linguagem segura por padrão, com C e C++, que podem ser vulneráveis. O Swift apresenta novos recursos para aumentar a segurança ao integrar estas linguagens: segurança de memória rigorosa, anotações para funções e tipos C/C++ e ferramentas para tornar código C/C++ mais seguro.

    • 2:39 - Encontrar uma chamada não segura no Swift
    • O exemplo demonstra um app escrito em Swift que faz interface com código C e C++ para filtros de imagens, o que pode apresentar riscos de segurança. O novo modo de compilador de segurança de memória rigorosa do Swift 6.2 é usado para identificar e sinalizar código inseguro, principalmente envolvendo ponteiros C e C++, possibilitando o aumento da segurança do app.

    • 4:55 - Chamar C/C++ com segurança
    • O Swift 6.2 apresenta “Span”, um novo tipo de ponteiro seguro. Ao anotar código C/C++ com informações de limites e vida útil, o Swift pode converter ponteiros desprotegidos em “Spans”, possibilitando chamadas de funções seguras do Swift sem necessidade de modificar o código C/C++ original. Saiba mais sobre o Span em “Melhorar o uso da memória e o desempenho com o Swift”.

    • 7:25 - Funções que usam ponteiros
    • Quando uma função utiliza um ponteiro bruto, ela não tem informações de limites para evitar que a função leia ou grave fora dos seus limites. Para que o compilador entenda a relação entre os ponteiros brutos e os tamanhos correspondentes, são necessárias as anotações “counted_by” e “noescape”. Quando o ponteiro recebe essas anotações, é possível chamar a função do Swift usando um Span. O exemplo também aborda as diferenças entre os tipos “Span” do Swift e do C++. Embora ambos tenham como objetivo o acesso seguro à memória contígua, o “Span” do C++ não tem informações sobre a vida útil, o que pode causar erros de uso após a liberação. Para atenuar isso, a anotação “noescape” é utilizada para indicar que um parâmetro, seja um “Span” do C++ ou um ponteiro bruto, não pode ser armazenado e utilizado fora do escopo da função. Ao aplicar essas anotações e usar o “Span”, o exemplo elimina o uso desprotegido de ponteiros, reduz o risco de bugs relacionados à memória e facilita a leitura e a manutenção do código, ao mesmo tempo em que permite uma interação perfeita entre as funções Swift e C/C++.

    • 17:13 - Funções que retornam ponteiros
    • Pode ser arriscado chamar uma função C/C++ que retorne um ponteiro ou um Span do C++, porque ela não controla a validade da memória para a qual está apontando. Para atenuar isso, uma anotação “lifetimebound” possibilita que o compilador imponha o uso seguro, eliminando bugs de uso após a liberação.

    • 20:16 - Importar tipos personalizados
    • No Swift, determinados tipos idiomáticos do C++ podem ser importados diretamente e usados de forma segura com anotações. Os tipos de visualização personalizados, que são structs que contêm ponteiros ou referências à memória que não possuem, podem ser importados como tipos inescapáveis usando a anotação “SWIFT_NONESCAPABLE”. Assim, eles não sobrevivem à memória para a qual apontam, impedindo bugs de uso após a liberação. Os tipos de contagem de referências, que são aqueles que possuem a memória à qual se referem e rastreiam as referências por meio de contagem, podem ser importados usando a anotação “SWIFT_SHARED_REFERENCE”. Isso permite que o Swift gerencie automaticamente a vida útil deles. Além disso, os valores de retorno de função podem ser anotados na forma de “SWIFT_RETURNS_RETAINED” ou “SWIFT_RETURNS_UNRETAINED” para especificar se o chamador é responsável por liberar ou reter o objeto de contagem de referências retornado, tornando explícitas as expectativas de propriedade e permitindo que o Swift gerencie a memória de forma segura.

    • 26:57 - Melhorar a segurança do C/C++
    • Há ferramentas para aumentar a segurança dos limites em C e C++. A proteção da biblioteca C++ padrão do Xcode possibilita verificações de limites em contêineres e views padrão, e também é possível ativar erros em caso de uso de ponteiros desprotegidos em C++. Para a segurança dos limites, defina “Impor o uso seguro de buffer dentro dos limites em C++” como “Sim” nas configurações de compilação do seu projeto. Para C, uma nova extensão de linguagem que pode ser usada no Xcode garante a segurança dos limites, exigindo anotações para expressar informações de limites e inserindo verificações dos limites em tempo de execução. Você pode ativar essa extensão de linguagem para todos os arquivos C nas configurações do seu projeto no Xcode.

    • 30:48 - Conclusão
    • Usando as informações desta sessão, você pode combinar códigos Swift, C e C++ de forma segura. As principais etapas incluem a ativação da segurança de memória rigorosa no Swift, a anotação de APIs C/C++ desprotegidas e a utilização de novos recursos de segurança de limites em C/C++. Incentivamos o feedback e a participação da comunidade a fim de melhorar a interoperabilidade.

Developer Footer

  • Vídeos
  • WWDC25
  • Combine C, C++ e Swift com segurança
  • Open Menu Close Menu
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • Icon Composer
    • SF Symbols
    Open Menu Close Menu
    • Accessibility
    • Accessories
    • App Store
    • Audio & Video
    • Augmented Reality
    • Business
    • Design
    • Distribution
    • Education
    • Fonts
    • Games
    • Health & Fitness
    • In-App Purchase
    • Localization
    • Maps & Location
    • Machine Learning & AI
    • Open Source
    • Security
    • Safari & Web
    Open Menu Close Menu
    • Documentation
    • Sample Code
    • Tutorials
    • Downloads
    • Forums
    • Videos
    Open Menu Close Menu
    • Support Articles
    • Contact Us
    • Bug Reporting
    • System Status
    Open Menu Close Menu
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles
    • Feedback Assistant
    Open Menu Close Menu
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program
    • News Partner Program
    • Video Partner Program
    • Security Bounty Program
    • Security Research Device Program
    Open Menu Close Menu
    • Meet with Apple
    • Apple Developer Centers
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Academies
    • WWDC
    Get the Apple Developer app.
    Copyright © 2025 Apple Inc. All rights reserved.
    Terms of Use Privacy Policy Agreements and Guidelines